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. 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. 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) on-hook: ..... (enter 0..9 or d=dial)
</pre> </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. 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. 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. mncc_sock.c:137 notice : MNCC socket connected.
dsp.c:159 info : Detecting continous tone: 2070:Level= 80% Quality=100% 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'. 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); PDEBUG(DAMPS, DEBUG_DEBUG, "Creating 'AMPS' instance for channel = %d (sample rate %d).\n", channel, samplerate);
/* init general part of transceiver */ /* 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) { if (rc < 0) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to init transceiver process!\n"); PDEBUG(DAMPS, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error; 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); PDEBUG(DANETZ, DEBUG_DEBUG, "Creating 'A-Netz' instance for 'Kanal' = %d (sample rate %d).\n", kanal, samplerate);
/* init general part of transceiver */ /* 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) { if (rc < 0) {
PDEBUG(DANETZ, DEBUG_ERROR, "Failed to init 'Sender' processing!\n"); PDEBUG(DANETZ, DEBUG_ERROR, "Failed to init 'Sender' processing!\n");
goto error; goto error;

View File

@ -109,23 +109,23 @@ double bnetz_kanal2freq(int kanal, int unterband)
return freq * 1e6; 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) static void switch_channel_19(bnetz_t *bnetz, int on)
{ {
/* affects only if pilot signal is used */ /* affects only if paging signal is used */
sender_pilot(&bnetz->sender, on); 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; FILE *fp;
fp = fopen(bnetz->pilot_file, "w"); fp = fopen(bnetz->paging_file, "w");
if (!fp) { 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; 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); 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); static void bnetz_go_idle(bnetz_t *bnetz);
/* Create transceiver instance and link to a list. */ /* 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; bnetz_t *bnetz;
enum pilot_signal pilot_signal = PILOT_SIGNAL_NONE; enum paging_signal paging_signal = PAGING_SIGNAL_NONE;
char pilot_file[256] = "", pilot_on[256] = "", pilot_off[256] = ""; char paging_file[256] = "", paging_on[256] = "", paging_off[256] = "";
int rc; int rc;
if (!(kanal >= 1 && kanal <= 39) && !(kanal >= 50 && kanal <= 86)) { 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; return -EINVAL;
} }
if (!strcmp(pilot, "notone")) if (!strcmp(paging, "notone"))
pilot_signal = PILOT_SIGNAL_NOTONE; paging_signal = PAGING_SIGNAL_NOTONE;
else else
if (!strcmp(pilot, "tone")) if (!strcmp(paging, "tone"))
pilot_signal = PILOT_SIGNAL_TONE; paging_signal = PAGING_SIGNAL_TONE;
else else
if (!strcmp(pilot, "positive")) if (!strcmp(paging, "positive"))
pilot_signal = PILOT_SIGNAL_POSITIVE; paging_signal = PAGING_SIGNAL_POSITIVE;
else else
if (!strcmp(pilot, "negative")) if (!strcmp(paging, "negative"))
pilot_signal = PILOT_SIGNAL_NEGATIVE; paging_signal = PAGING_SIGNAL_NEGATIVE;
else { else {
char *p; char *p;
strncpy(pilot_file, pilot, sizeof(pilot_file) - 1); strncpy(paging_file, paging, sizeof(paging_file) - 1);
p = strchr(pilot_file, '='); p = strchr(paging_file, '=');
if (!p) { if (!p) {
error_pilot: error_paging:
PDEBUG(DBNETZ, DEBUG_ERROR, "Given pilot file (to switch to channel 19) is missing parameters. Use <file>=<on>:<off> format!\n"); PDEBUG(DBNETZ, DEBUG_ERROR, "Given paging file (to switch to channel 19) is missing parameters. Use <file>=<on>:<off> format!\n");
return -EINVAL; return -EINVAL;
} }
*p++ = '\0'; *p++ = '\0';
strncpy(pilot_on, p, sizeof(pilot_on) - 1); strncpy(paging_on, p, sizeof(paging_on) - 1);
p = strchr(pilot_file, ':'); p = strchr(paging_on, ':');
if (!p) if (!p)
goto error_pilot; goto error_paging;
*p++ = '\0'; *p++ = '\0';
strncpy(pilot_off, p, sizeof(pilot_off) - 1); strncpy(paging_off, p, sizeof(paging_off) - 1);
} }
bnetz = calloc(1, sizeof(bnetz_t)); 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); 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 */ /* 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) { if (rc < 0) {
PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n"); PDEBUG(DBNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error; goto error;
} }
bnetz->sender.ruffrequenz = bnetz_kanal2freq(19, 0);
/* init audio processing */ /* init audio processing */
rc = dsp_init_sender(bnetz); rc = dsp_init_sender(bnetz);
@ -216,9 +217,9 @@ error_pilot:
} }
bnetz->gfs = gfs; bnetz->gfs = gfs;
strncpy(bnetz->pilot_file, pilot_file, sizeof(bnetz->pilot_file) - 1); strncpy(bnetz->paging_file, paging_file, sizeof(bnetz->paging_file) - 1);
strncpy(bnetz->pilot_on, pilot_on, sizeof(bnetz->pilot_on) - 1); strncpy(bnetz->paging_on, paging_on, sizeof(bnetz->paging_on) - 1);
strncpy(bnetz->pilot_off, pilot_off, sizeof(bnetz->pilot_off) - 1); strncpy(bnetz->paging_off, paging_off, sizeof(bnetz->paging_off) - 1);
timer_init(&bnetz->timer, bnetz_timeout, bnetz); timer_init(&bnetz->timer, bnetz_timeout, bnetz);
/* go into idle state */ /* go into idle state */

View File

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

View File

@ -36,8 +36,8 @@
#include "ansage.h" #include "ansage.h"
int gfs = 2; int gfs = 2;
int num_pilot = 0; int num_paging = 0;
const char *pilot[MAX_SENDER] = { "tone" }; const char *paging[MAX_SENDER] = { "tone" };
double lossdetect = 0; double lossdetect = 0;
void print_help(const char *arg0) 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(" 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(" full 15 Watts. If supported, the phone uses the channel with low power\n");
printf(" (Kanal kleiner Leistung).\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(" Send a tone, give a signal or write to a file when switching to\n");
printf(" channel 19. (paging the phone).\n"); printf(" channel 19. (paging the phone).\n");
printf(" 'tone', 'positive', 'negative' is sent on second audio channel.\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(" '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(" 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(" /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(" -L --loss <volume>\n");
printf(" Detect loss of carrier by detecting steady noise above given volume in\n"); printf(" Detect loss of carrier by detecting steady noise above given volume in\n");
printf(" percent. (disabled by default)\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[] = { static struct option long_options_special[] = {
{"gfs", 1, 0, 'G'}, {"gfs", 1, 0, 'G'},
{"pilot", 1, 0, 'P'}, {"paging", 1, 0, 'P'},
{"loss", 1, 0, 'L'}, {"loss", 1, 0, 'L'},
{0, 0, 0, 0}, {0, 0, 0, 0},
}; };
@ -109,7 +109,7 @@ static int handle_options(int argc, char **argv)
skip_args += 2; skip_args += 2;
break; break;
case 'P': case 'P':
OPT_ARRAY(num_pilot, pilot, strdup(optarg)) OPT_ARRAY(num_paging, paging, strdup(optarg))
skip_args += 2; skip_args += 2;
break; break;
case 'L': 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"); fprintf(stderr, "You need to specify as many sound devices as you have channels.\n");
exit(0); exit(0);
} }
if (num_kanal == 1 && num_pilot == 0) if (num_kanal == 1 && num_paging == 0)
num_pilot = 1; /* use defualt */ num_paging = 1; /* use defualt */
if (num_kanal != num_pilot) { if (num_kanal != num_paging) {
fprintf(stderr, "You need to specify as many pilot tone settings as you have channels.\n"); fprintf(stderr, "You need to specify as many paging tone settings as you have channels.\n");
exit(0); exit(0);
} }
@ -187,13 +187,13 @@ int main(int argc, char *argv[])
/* create transceiver instance */ /* create transceiver instance */
for (i = 0; i < num_kanal; i++) { 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) { if (rc < 0) {
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n"); fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
goto fail; 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("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); 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 */ /* init general part of transceiver */
/* do not enable emphasis, since it is done by cnetz code, not by common sender code */ /* 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) { if (rc < 0) {
PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n"); PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error; goto error;

View File

@ -473,7 +473,7 @@ int call_init(const char *station_id, const char *audiodev, int samplerate, int
return 0; return 0;
/* open sound device for call control */ /* 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) { if (!call.sound) {
PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n"); PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n");
@ -671,7 +671,7 @@ void process_call(int c)
jitter_load(&call.dejitter, up, count); jitter_load(&call.dejitter, up, count);
} }
spl_list[0] = up; 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) { if (rc < 0) {
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc); PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc);
if (rc == -EPIPE) if (rc == -EPIPE)

View File

@ -17,12 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "filter.h" #include "filter.h"
#include "sdr.h" #include "sender.h"
#ifdef HAVE_UHD #ifdef HAVE_UHD
#include "uhd.h" #include "uhd.h"
#endif #endif
@ -42,7 +43,9 @@ typedef struct sdr_chan {
} sdr_chan_t; } sdr_chan_t;
typedef struct sdr { 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) */ double spl_deviation; /* how to convert a sample step into deviation (Hz) */
int channels; /* number of frequencies */ int channels; /* number of frequencies */
double samplerate; /* IQ rate */ double samplerate; /* IQ rate */
@ -73,10 +76,10 @@ int sdr_init(const char *device_args, double rx_gain, double tx_gain)
return 0; 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; sdr_t *sdr;
double center_frequency; double tx_center_frequency, rx_center_frequency;
int rc; int rc;
int c; int c;
@ -95,8 +98,14 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq
sdr->spl_deviation = sample_deviation; sdr->spl_deviation = sample_deviation;
sdr->amplitude = 0.4 / (double)channels; // FIXME: actual amplitude 0.1? 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 */ /* 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) { if (!sdr->chan) {
PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n");
goto error; 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); 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].tx_frequency = tx_frequency[c];
sdr->chan[c].rx_frequency = rx_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[0], bandwidth, samplerate);
filter_lowpass_init(&sdr->chan[c].rx_lp[1], 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) */ /* calculate required bandwidth (IQ rate) */
if (channels == 1) { double tx_low_frequency = sdr->chan[0].tx_frequency, tx_high_frequency = sdr->chan[0].tx_frequency;
PDEBUG(DSDR, DEBUG_INFO, "Single frequency, so we use sample rate as IQ bandwidth: %.6f MHz\n", sdr->samplerate / 1e6); double rx_low_frequency = sdr->chan[0].rx_frequency, rx_high_frequency = sdr->chan[0].rx_frequency;
center_frequency = sdr->chan[0].tx_frequency; double range;
} else {
double low_frequency = sdr->chan[0].tx_frequency, high_frequency = sdr->chan[0].tx_frequency, range;
for (c = 1; c < channels; c++) { for (c = 1; c < channels; c++) {
if (sdr->chan[c].tx_frequency < low_frequency) if (sdr->chan[c].tx_frequency < tx_low_frequency)
low_frequency = sdr->chan[c].tx_frequency; tx_low_frequency = sdr->chan[c].tx_frequency;
if (sdr->chan[c].tx_frequency > high_frequency) if (sdr->chan[c].tx_frequency > tx_high_frequency)
high_frequency = sdr->chan[c].tx_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;
} }
range = high_frequency - low_frequency; if (sdr->paging_channel) {
PDEBUG(DSDR, DEBUG_INFO, "Range between frequencies: %.6f MHz\n", range / 1e6); 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) { 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.... // 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"); PDEBUG(DSDR, DEBUG_NOTICE, "The sample rate must be at least twice the range between frequencies. Please increment samplerate!\n");
goto error; goto error;
} }
center_frequency = (high_frequency + low_frequency) / 2.0; 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);
PDEBUG(DSDR, DEBUG_INFO, "Using center frequency: %.6f MHz\n", center_frequency / 1e6); /* set offsets to center frequency */
for (c = 0; c < channels; c++) { for (c = 0; c < channels; c++) {
sdr->chan[c].offset = sdr->chan[c].tx_frequency - center_frequency; double rx_offset;
sdr->chan[c].rx_rot = 2 * M_PI * -sdr->chan[c].offset / sdr->samplerate; sdr->chan[c].offset = sdr->chan[c].tx_frequency - tx_center_frequency;
PDEBUG(DSDR, DEBUG_INFO, "Frequency #%d offset: %.6f MHz\n", c, sdr->chan[c].offset / 1e6); 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); PDEBUG(DSDR, DEBUG_INFO, "Using gain: TX %.1f dB, RX %.1f dB\n", sdr_tx_gain, sdr_rx_gain);
#ifdef HAVE_UHD #ifdef HAVE_UHD
#warning hack rc = uhd_open(sdr_device_args, tx_center_frequency, rx_center_frequency, sdr->samplerate, sdr_rx_gain, sdr_tx_gain);
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);
if (rc) if (rc)
goto error; goto error;
#endif #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; sdr_t *sdr = (sdr_t *)inst;
float buff[num * 2]; float buff[num * 2];
int c, s, ss; int c, s, ss;
double rate, phase, amplitude, dev; double rate, offset, phase, amplitude, dev;
int sent; int sent;
if (channels != sdr->channels) { if (channels != sdr->channels) {
@ -186,11 +226,16 @@ int sdr_write(void *inst, int16_t **samples, int num, int channels)
amplitude = sdr->amplitude; amplitude = sdr->amplitude;
memset(buff, 0, sizeof(buff)); memset(buff, 0, sizeof(buff));
for (c = 0; c < channels; c++) { for (c = 0; c < channels; c++) {
/* modulate */
phase = sdr->chan[c].tx_phase; 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++) { for (s = 0, ss = 0; s < num; s++) {
/* deviation is defined by the sample value and the offset */ /* 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 #ifdef FAST_SINE
phase += 256.0 * dev / rate; phase += 256.0 * dev / rate;
if (phase < 0.0) 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); Q[s] = i * sin(phase) + q * cos(phase);
} }
sdr->chan[c].rx_phase = 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[0], I, count, 1);
filter_lowpass_process(&sdr->chan[c].rx_lp[1], Q, count, 1); filter_lowpass_process(&sdr->chan[c].rx_lp[1], Q, count, 1);
last_phase = sdr->chan[c].rx_last_phase; 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); 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); 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_read(void *inst, int16_t **samples, int num, int channels);
int sdr_get_inbuffer(void *inst); int sdr_get_inbuffer(void *inst);

View File

@ -32,7 +32,7 @@ static sender_t **sender_tailp = &sender_head;
int cant_recover = 0; int cant_recover = 0;
/* Init transceiver instance and link to list of transceivers. */ /* 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; sender_t *master, *slave;
int rc = 0; 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->de_emphasis = de_emphasis;
sender->loopback = loopback; sender->loopback = loopback;
sender->loss_volume = loss_volume; sender->loss_volume = loss_volume;
#ifdef HAVE_SDR sender->paging_signal = paging_signal;
if (!strcmp(audiodev, "sdr"))
pilot_signal = PILOT_SIGNAL_NONE;
#endif
sender->pilot_signal = pilot_signal;
sender->pilotton_phaseshift = 1.0 / ((double)samplerate / 1000.0);
PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Creating 'Sender' instance\n"); 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; break;
} }
if (master) { if (master) {
if (master->pilot_signal != PILOT_SIGNAL_NONE) { if (master->paging_signal != PAGING_SIGNAL_NONE && !!strcmp(master->audiodev, "sdr")) {
PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because second channel is used for pilot signal!\n", master->kanal); 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; rc = -EBUSY;
goto error; goto error;
} }
if (pilot_signal != PILOT_SIGNAL_NONE) { if (paging_signal != PAGING_SIGNAL_NONE && !!strcmp(audiodev, "sdr")) {
PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because we need a stereo channel for pilot signal!\n", master->kanal); 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; rc = -EBUSY;
goto error; goto error;
} }
@ -95,10 +90,6 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf
/* link audio device */ /* link audio device */
#ifdef HAVE_SDR #ifdef HAVE_SDR
if (!strcmp(audiodev, "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_open = sdr_open;
sender->audio_close = sdr_close; sender->audio_close = sdr_close;
sender->audio_read = sdr_read; sender->audio_read = sdr_read;
@ -169,6 +160,7 @@ int sender_open_audio(void)
{ {
sender_t *master, *inst; sender_t *master, *inst;
int channels; int channels;
double paging_frequency = 0.0;
int i; int i;
for (master = sender_head; master; master = master->next) { for (master = sender_head; master; master = master->next) {
@ -188,10 +180,12 @@ int sender_open_audio(void)
rx_f[i] = inst->sendefrequenz; rx_f[i] = inst->sendefrequenz;
else else
rx_f[i] = inst->empfangsfrequenz; rx_f[i] = inst->empfangsfrequenz;
if (inst->ruffrequenz)
paging_frequency = inst->ruffrequenz;
} }
/* open device */ /* 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) { if (!master->audio) {
PDEBUG(DSENDER, DEBUG_ERROR, "No audio device!\n"); PDEBUG(DSENDER, DEBUG_ERROR, "No audio device!\n");
return -EIO; return -EIO;
@ -226,27 +220,6 @@ void sender_destroy(sender_t *sender)
jitter_destroy(&sender->dejitter); 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) static void gain_samples(int16_t *samples, int length, double gain)
{ {
int i; int i;
@ -271,16 +244,12 @@ void process_sender_audio(sender_t *sender, int *quit, int latspl)
/* count instances for audio channel */ /* count instances for audio channel */
for (num_chan = 0, inst = sender; inst; num_chan++, inst = inst->slave); 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]; 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]; samples[i] = buff[i];
}
count = sender->audio_get_inbuffer(sender->audio); count = sender->audio_get_inbuffer(sender->audio);
if (count < 0) { if (count < 0) {
@ -321,41 +290,12 @@ cant_recover:
/* do pre emphasis towards radio, not wave_write */ /* do pre emphasis towards radio, not wave_write */
if (inst->pre_emphasis) if (inst->pre_emphasis)
pre_emphasis(&inst->estate, samples[i], count); pre_emphasis(&inst->estate, samples[i], count);
} /* set paging signal */
switch (sender->pilot_signal) { paging_signal[i] = sender->paging_signal;
case PILOT_SIGNAL_TONE: on[i] = sender->paging_on;
/* 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;
} }
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) { if (rc < 0) {
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc); PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc);
if (rc == -EPIPE) { 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 #define MAX_SENDER 16
/* how to send a 'pilot' signal (trigger transmitter) */ /* how to send a 'paging' signal (trigger transmitter) */
enum pilot_signal { enum paging_signal {
PILOT_SIGNAL_NONE = 0, PAGING_SIGNAL_NONE = 0,
PILOT_SIGNAL_TONE, PAGING_SIGNAL_TONE,
PILOT_SIGNAL_NOTONE, PAGING_SIGNAL_NOTONE,
PILOT_SIGNAL_POSITIVE, PAGING_SIGNAL_POSITIVE,
PILOT_SIGNAL_NEGATIVE, PAGING_SIGNAL_NEGATIVE,
}; };
/* common structure of each transmitter */ /* common structure of each transmitter */
@ -30,15 +30,16 @@ typedef struct sender {
int kanal; /* channel number */ int kanal; /* channel number */
double sendefrequenz; /* transmitter frequency */ double sendefrequenz; /* transmitter frequency */
double empfangsfrequenz; /* receiver 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 bandwidth; /* max NF frequency to be transmitted unaffected by filtering */
double sample_deviation; /* frequency deviation of one sample step (after pre-emphasis) */ double sample_deviation; /* frequency deviation of one sample step (after pre-emphasis) */
/* audio */ /* audio */
void *audio; void *audio;
char audiodev[64]; /* audio device name (alsa or sdr) */ 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 *); 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_read)(void *, int16_t **, int, int);
int (*audio_get_inbuffer)(void *); int (*audio_get_inbuffer)(void *);
int samplerate; int samplerate;
@ -67,11 +68,9 @@ typedef struct sender {
double loss_volume; double loss_volume;
loss_t loss; loss_t loss;
/* pilot tone */ /* paging tone */
enum pilot_signal pilot_signal; /* if pilot signal is used and how it is performed */ enum paging_signal paging_signal; /* if paging signal is used and how it is performed */
int pilot_on; /* 1 or 0 for on or off */ int paging_on; /* 1 or 0 for on or off */
double pilotton_phaseshift; /* phase to shift every sample */
double pilotton_phase; /* current phase */
/* display wave */ /* display wave */
dispwav_t dispwav; /* display wave form */ dispwav_t dispwav; /* display wave form */
@ -81,11 +80,11 @@ typedef struct sender {
extern sender_t *sender_head; extern sender_t *sender_head;
extern int cant_recover; 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); void sender_destroy(sender_t *sender);
int sender_open_audio(void); int sender_open_audio(void);
void process_sender_audio(sender_t *sender, int *quit, int latspl); void process_sender_audio(sender_t *sender, int *quit, int latspl);
void sender_send(sender_t *sender, int16_t *samples, int count); void sender_send(sender_t *sender, int16_t *samples, int count);
void sender_receive(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); 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_read(void *inst, int16_t **samples, int num, int channels);
int sound_get_inbuffer(void *inst); int sound_get_inbuffer(void *inst);

View File

@ -21,11 +21,13 @@
#include <stdint.h> #include <stdint.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include "debug.h" #include "debug.h"
#include "sound.h" #include "sender.h"
typedef struct sound { typedef struct sound {
snd_pcm_t *phandle, *chandle; snd_pcm_t *phandle, *chandle;
int pchannels, cchannels; int pchannels, cchannels;
double paging_phaseshift; /* phase to shift every sample */
double paging_phase; /* current phase */
} sound_t; } sound_t;
static int set_hw_params(snd_pcm_t *handle, int samplerate, int *channels) 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; 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; sound_t *sound;
int rc; int rc;
@ -144,6 +146,8 @@ void *sound_open(const char *audiodev, double __attribute__((unused)) *tx_freque
return NULL; 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); rc = snd_pcm_open(&sound->phandle, audiodev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (rc < 0) { if (rc < 0) {
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to open '%s' for playback! (%s)\n", audiodev, snd_strerror(rc)); 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); 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; sound_t *sound = (sound_t *)inst;
int16_t buff[num << 1]; int16_t buff[num << 1];
@ -208,15 +256,22 @@ int sound_write(void *inst, int16_t **samples, int num, int channels)
int i, ii; int i, ii;
if (sound->pchannels == 2) { 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++) { for (i = 0, ii = 0; i < num; i++) {
buff[ii++] = samples[0][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[0][i];
buff[ii++] = samples[1][i];
} }
} else { } else {
for (i = 0, ii = 0; i < num; i++) { for (i = 0, ii = 0; i < num; i++) {
buff[ii++] = samples[0][i]; buff[ii++] = samples[0][i];
buff[ii++] = samples[1][i]; buff[ii++] = samples[0][i];
} }
} }
rc = snd_pcm_writei(sound->phandle, buff, num); 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); PDEBUG(DNMT, DEBUG_DEBUG, "Creating 'NMT' instance for channel = %d (sample rate %d).\n", channel, samplerate);
/* init general part of transceiver */ /* 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) { if (rc < 0) {
PDEBUG(DNMT, DEBUG_ERROR, "Failed to init transceiver process!\n"); PDEBUG(DNMT, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error; goto error;