B-Netz: Add metering pulse support (Gebuehrenimpuls)
This commit is contained in:
parent
275be50225
commit
41bd9999b1
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue