B-Netz: Add metering pulse support (Gebuehrenimpuls)

This commit is contained in:
Andreas Eversberg 2017-08-12 16:38:40 +02:00
parent 275be50225
commit 41bd9999b1
4 changed files with 100 additions and 18 deletions

View File

@ -41,19 +41,22 @@
static int new_callref = 0x40000000;
/* mobile originating call */
#define CARRIER_TO 0.08 /* 80 ms search for carrier */
#define DIALING_TO 3.8 /* timeout after channel allocation "Kanalbelegung" */
#define DIALING_TO2 0.5 /* timeout while receiving digits */
#define CARRIER_TO 0.08 /* 80 ms search for carrier */
#define DIALING_TO 3.8 /* timeout after channel allocation "Kanalbelegung" */
#define DIALING_TO2 0.5 /* timeout while receiving digits */
/* mobile terminating call */
#define ALERTING_TO 60 /* timeout after 60 seconds alerting the MS */
#define PAGING_TO 2.1 /* 700..2100 ms timeout after paging "Selektivruf" */
#define PAGE_TRIES 2 /* two tries */
#define SWITCH19_TIME 1.0 /* time to switch channel (radio should be tansmitting after that) */
#define SWITCHBACK_TIME 0.1 /* time to wait until switching back (latency of sound device shall be lower) */
#define ALERTING_TO 60 /* timeout after 60 seconds alerting the MS */
#define PAGING_TO 2.1 /* 700..2100 ms timeout after paging "Selektivruf" */
#define PAGE_TRIES 2 /* two tries */
#define SWITCH19_TIME 1.0 /* time to switch channel (radio should be tansmitting after that) */
#define SWITCHBACK_TIME 0.1 /* time to wait until switching back (latency of sound device shall be lower) */
#define TRENN_COUNT 4 /* min. 350 ms disconnect "Trennsignal" */
#define TRENN_COUNT_NA 96 /* 12 s disconnect "Trennsignal" if no answer */
#define TRENN_COUNT 4 /* min. 350 ms disconnect "Trennsignal" */
#define TRENN_COUNT_NA 96 /* 12 s disconnect "Trennsignal" if no answer */
#define METERING_DURATION 0.2 /* duration of metering pulse */
#define METERING_START 1.0 /* start metering 1 second after call start */
const char *bnetz_state_name(enum bnetz_state state)
{
@ -156,7 +159,7 @@ 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 use_sdr, 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, const char *read_tx_wave, int loopback, double loss_factor, const char *paging)
int bnetz_create(int kanal, const char *audiodev, int use_sdr, 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, const char *read_tx_wave, int loopback, double loss_factor, const char *paging, int metering)
{
bnetz_t *bnetz;
enum paging_signal paging_signal = PAGING_SIGNAL_NONE;
@ -232,6 +235,7 @@ error_paging:
}
bnetz->gfs = gfs;
bnetz->metering = metering;
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);
@ -429,6 +433,9 @@ void bnetz_receive_tone(bnetz_t *bnetz, int bit)
timer_stop(&bnetz->timer);
bnetz_new_state(bnetz, BNETZ_GESPRAECH);
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
/* start metering pulses if forced */
if (bnetz->metering < 0)
timer_start(&bnetz->timer, METERING_START);
call_in_answer(bnetz->callref, bnetz->station_id);
break;
}
@ -597,6 +604,9 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm, double level, d
timer_stop(&bnetz->timer);
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
bnetz_new_state(bnetz, BNETZ_GESPRAECH);
/* start metering pulses if enabled and supported by phone or if forced */
if (bnetz->metering < 0 || (bnetz->metering > 0 && (bnetz->dial_type == DIAL_TYPE_METER || bnetz->dial_type == DIAL_TYPE_METER_MUENZ)))
timer_start(&bnetz->timer, METERING_START);
/* setup call */
PDEBUG(DBNETZ, DEBUG_INFO, "Setup call to network.\n");
@ -627,9 +637,13 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm, double level, d
}
break;
case BNETZ_GESPRAECH:
#if 0
disabled, because any quality shall release the call.
lets see, if noise will not generate a release signal....
/* only good telegramms shall pass */
if (quality < 0.7)
return;
#endif
if (digit == 't') {
PDEBUG(DBNETZ, DEBUG_NOTICE, "Received 'Schlusssignal' from mobile station\n");
bnetz_release(bnetz, TRENN_COUNT);
@ -685,6 +699,22 @@ static void bnetz_timeout(struct timer *timer)
call_in_release(bnetz->callref, CAUSE_NOANSWER);
bnetz->callref = 0;
break;
case BNETZ_GESPRAECH:
switch (bnetz->dsp_mode) {
case DSP_MODE_AUDIO:
/* turn on merting pulse */
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO_METER);
timer_start(&bnetz->timer, METERING_DURATION);
break;
case DSP_MODE_AUDIO_METER:
/* turn off and wait given seconds for next metering cycle */
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
timer_start(&bnetz->timer, (double)abs(bnetz->metering) - METERING_DURATION);
break;
default:
break;
}
break;
default:
break;
}
@ -845,7 +875,8 @@ void call_rx_audio(int callref, sample_t *samples, int count)
if (!sender)
return;
if (bnetz->dsp_mode == DSP_MODE_AUDIO) {
if (bnetz->dsp_mode == DSP_MODE_AUDIO
|| bnetz->dsp_mode == DSP_MODE_AUDIO_METER) {
sample_t up[(int)((double)count * bnetz->sender.srstate.factor + 0.5) + 10];
count = samplerate_upsample(&bnetz->sender.srstate, samples, count, up);
jitter_save(&bnetz->sender.dejitter, up, count);

View File

@ -5,6 +5,7 @@
enum dsp_mode {
DSP_MODE_SILENCE, /* sending silence */
DSP_MODE_AUDIO, /* stream audio */
DSP_MODE_AUDIO_METER, /* stream audio */
DSP_MODE_0, /* send tone 0 */
DSP_MODE_1, /* send tone 1 */
DSP_MODE_TELEGRAMM, /* send "Telegramm" */
@ -52,6 +53,7 @@ typedef struct bnetz {
/* system info */
int gfs; /* 'Gruppenfreisignal' */
int metering; /* use metering pulses in seconds 0 = off, < 0 = force */
/* switch sender to channel 19 */
char paging_file[256]; /* if set, write to given file to switch to channel 19 or back */
@ -82,13 +84,13 @@ typedef struct bnetz {
int rx_telegramm_qualidx; /* index of quality array above */
int tone_detected; /* what tone has been detected */
int tone_count; /* how long has that tone been detected */
double phaseshift65536[2]; /* how much the phase of sine wave changes per sample */
double phase65536; /* current phase */
const char *tx_telegramm; /* carries bits of one frame to transmit */
int tx_telegramm_pos;
int samples_per_chunk; /* samples per loss detection interval */
sample_t *chunk_spl; /* chunk sample */
int chunk_pos; /* current received sample of chunk */
double meter_phaseshift65536; /* how much the phase of sine wave changes per sample */
double meter_phase65536; /* current phase */
/* loopback test for latency */
int loopback_count; /* count digits from 0 to 9 */
@ -97,7 +99,7 @@ typedef struct bnetz {
double bnetz_kanal2freq(int kanal, int unterband);
int bnetz_init(void);
int bnetz_create(int kanal, const char *audiodev, int use_sdr, 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, const char *read_tx_wave, int loopback, double loss_factor, const char *paging);
int bnetz_create(int kanal, const char *audiodev, int use_sdr, 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, const char *read_tx_wave, int loopback, double loss_factor, const char *paging, int metering);
void bnetz_destroy(sender_t *sender);
void bnetz_loss_indication(bnetz_t *bnetz);
void bnetz_receive_tone(bnetz_t *bnetz, int bit);

View File

@ -47,6 +47,7 @@
#define MAX_MODULATION 3000.0
#define DBM0_DEVIATION 2800.0 /* deviation of dBm0 at 1 kHz */
#define TX_PEAK_FSK (4000.0 / 2000.0 * 1000.0 / DBM0_DEVIATION)
#define TX_PEAK_METER (3000.0 / 2900.0 * 1000.0 / DBM0_DEVIATION) /* FIXME: really 3KHz deviation??? */
#define MAX_DISPLAY 1.4 /* something above dBm0 */
#define BIT_RATE 100.0
#define BIT_ADJUST 0.5 /* full adjustment on bit change */
@ -60,9 +61,17 @@
#define LOSS_INTERVAL 100 /* filter steps (milliseconds) for one second interval */
#define LOSS_TIME 12 /* duration of signal loss before release */
/* table for fast sine generation */
static sample_t dsp_metering[65536];
/* global init for FSK */
void dsp_init(void)
{
int i;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for metering tone.\n");
for (i = 0; i < 65536; i++)
dsp_metering[i] = sin((double)i / 65536.0 * 2.0 * PI) * TX_PEAK_METER;
}
static int fsk_send_bit(void *inst);
@ -99,6 +108,10 @@ int dsp_init_sender(bnetz_t *bnetz)
}
bnetz->chunk_spl = spl;
/* metering tone */
bnetz->meter_phaseshift65536 = 65536.0 / ((double)bnetz->sender.samplerate / METERING_HZ);
PDEBUG(DDSP, DEBUG_DEBUG, "dial_phaseshift = %.4f\n", bnetz->meter_phaseshift65536);
return 0;
}
@ -212,7 +225,8 @@ void sender_receive(sender_t *sender, sample_t *samples, int length)
/* fsk/tone signal */
fsk_receive(&bnetz->fsk, samples, length);
if (bnetz->dsp_mode == DSP_MODE_AUDIO && bnetz->callref) {
if ((bnetz->dsp_mode == DSP_MODE_AUDIO
|| bnetz->dsp_mode == DSP_MODE_AUDIO_METER) && bnetz->callref) {
int count;
count = samplerate_downsample(&bnetz->sender.srstate, samples, length);
@ -257,6 +271,25 @@ static int fsk_send_bit(void *inst)
}
}
/* Add metering pulse tone to audio stream. Keep phase for next call of function. */
static void metering_tone(bnetz_t *bnetz, sample_t *samples, int length)
{
double phaseshift, phase;
int i;
phaseshift = bnetz->meter_phaseshift65536;
phase = bnetz->meter_phase65536;
for (i = 0; i < length; i++) {
*samples++ += dsp_metering[(uint16_t)phase];
phase += phaseshift;
if (phase >= 65536)
phase -= 65536;
}
bnetz->meter_phase65536 = phase;
}
/* Provide stream of audio toward radio unit */
void sender_send(sender_t *sender, sample_t *samples, int length)
{
@ -269,7 +302,10 @@ again:
memset(samples, 0, length * sizeof(*samples));
break;
case DSP_MODE_AUDIO:
case DSP_MODE_AUDIO_METER:
jitter_load(&bnetz->sender.dejitter, samples, length);
if (bnetz->dsp_mode == DSP_MODE_AUDIO_METER)
metering_tone(bnetz, samples, length);
break;
case DSP_MODE_0:
case DSP_MODE_1:
@ -294,6 +330,8 @@ const char *bnetz_dsp_mode_name(enum dsp_mode mode)
return "SILENCE";
case DSP_MODE_AUDIO:
return "AUDIO";
case DSP_MODE_AUDIO_METER:
return "AUDIO + METERING PULSE";
case DSP_MODE_0:
return "TONE 0";
case DSP_MODE_1:

View File

@ -37,6 +37,7 @@
#include "ansage.h"
int gfs = 2;
int metering = 20;
const char *paging = "tone";
double lossdetect = 0;
@ -53,6 +54,11 @@ 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(" -M --gebuehrenimpuls <secods> | -<seconds> | 0\n");
printf(" Send metering pulses every given number of seconds or 0 to turn off.\n");
printf(" Pulses will only be sent on outgoing calls and only if mobile station\n");
printf(" supports it and only for outgoing calls. Use negative value to force\n");
printf(" metering pulses for all phones and all calls. (default = %d)\n", metering);
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");
@ -79,12 +85,13 @@ static int handle_options(int argc, char **argv)
static struct option long_options_special[] = {
{"gfs", 1, 0, 'G'},
{"gebuehrenimpuls", 1, 0, 'M'},
{"paging", 1, 0, 'P'},
{"loss", 1, 0, 'L'},
{0, 0, 0, 0},
};
set_options_common("G:P:L:", long_options_special);
set_options_common("G:M:P:L:", long_options_special);
while (1) {
int option_index = 0, c;
@ -108,6 +115,10 @@ static int handle_options(int argc, char **argv)
gfs = atoi(optarg);
skip_args += 2;
break;
case 'M':
metering = atoi(optarg);
skip_args += 2;
break;
case 'P':
paging = strdup(optarg);
skip_args += 2;
@ -181,7 +192,7 @@ int main(int argc, char *argv[])
/* create transceiver instance */
for (i = 0; i < num_kanal; i++) {
rc = bnetz_create(kanal[i], audiodev[i], use_sdr, samplerate, rx_gain, gfs, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, (double)lossdetect / 100.0, paging);
rc = bnetz_create(kanal[i], audiodev[i], use_sdr, samplerate, rx_gain, gfs, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, (double)lossdetect / 100.0, paging, metering);
if (rc < 0) {
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
goto fail;