diff --git a/src/bnetz/bnetz.c b/src/bnetz/bnetz.c index 539e3c6..af3f82a 100644 --- a/src/bnetz/bnetz.c +++ b/src/bnetz/bnetz.c @@ -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); diff --git a/src/bnetz/bnetz.h b/src/bnetz/bnetz.h index 4d1b298..39d979c 100644 --- a/src/bnetz/bnetz.h +++ b/src/bnetz/bnetz.h @@ -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); diff --git a/src/bnetz/dsp.c b/src/bnetz/dsp.c index 5b6c393..59b618c 100644 --- a/src/bnetz/dsp.c +++ b/src/bnetz/dsp.c @@ -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: diff --git a/src/bnetz/main.c b/src/bnetz/main.c index 874f189..23d7cb9 100644 --- a/src/bnetz/main.c +++ b/src/bnetz/main.c @@ -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 | - | 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 | =:\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;