From 6c6402571758340c640bd2350599ff6a9e5ffeb6 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 24 Jul 2017 16:18:10 +0200 Subject: Move FFSK modem from NMT to common code, so it can be used by other networks --- src/common/Makefile.am | 1 + src/common/ffsk.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++ src/common/ffsk.h | 27 +++++ src/nmt/dms.c | 9 +- src/nmt/dms.h | 2 + src/nmt/dsp.c | 260 +++++++++++-------------------------------------- src/nmt/dsp.h | 1 - src/nmt/main.c | 3 + src/nmt/nmt.c | 4 +- src/nmt/nmt.h | 37 +++---- src/test/test_dms.c | 10 +- 11 files changed, 371 insertions(+), 239 deletions(-) create mode 100644 src/common/ffsk.c create mode 100644 src/common/ffsk.h (limited to 'src') diff --git a/src/common/Makefile.am b/src/common/Makefile.am index abdb4b5..f719c6e 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -24,6 +24,7 @@ libcommon_a_SOURCES = \ compandor.c \ fft.c \ fm_modulation.c \ + ffsk.c \ sender.c \ display_wave.c \ display_status.c \ diff --git a/src/common/ffsk.c b/src/common/ffsk.c new file mode 100644 index 0000000..fdbf255 --- /dev/null +++ b/src/common/ffsk.c @@ -0,0 +1,256 @@ +/* FFSK audio processing (NMT / Radiocom 2000) + * + * (C) 2017 by Andreas Eversberg + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define CHAN ffsk->channel + +#include +#include +#include +#include +#include +#include +#include "../common/sample.h" +#include "../common/debug.h" +#include "ffsk.h" + +#define PI M_PI + +#define BIT_RATE 1200 /* baud rate */ +#define FILTER_STEPS 0.1 /* step every 1/12000 sec */ + +/* two signaling tones */ +static double ffsk_freq[2] = { + 1800.0, + 1200.0, +}; + +static sample_t dsp_tone_bit[2][2][65536]; /* polarity, bit, phase */ + +/* global init for FFSK */ +void ffsk_global_init(double peak_fsk) +{ + int i; + double s; + + PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for FFSK tones.\n"); + for (i = 0; i < 65536; i++) { + s = sin((double)i / 65536.0 * 2.0 * PI); + /* bit(1) 1 cycle */ + dsp_tone_bit[0][1][i] = s * peak_fsk; + dsp_tone_bit[1][1][i] = -s * peak_fsk; + /* bit(0) 1.5 cycles */ + s = sin((double)i / 65536.0 * 3.0 * PI); + dsp_tone_bit[0][0][i] = s * peak_fsk; + dsp_tone_bit[1][0][i] = -s * peak_fsk; + } +} + +/* Init FFSK */ +int ffsk_init(ffsk_t *ffsk, void *inst, void (*receive_bit)(void *inst, int bit, double quality, double level), int channel, int samplerate) +{ + sample_t *spl; + int i; + + /* a symbol rate of 1200 Hz, times check interval of FILTER_STEPS */ + if (samplerate < (double)BIT_RATE / (double)FILTER_STEPS) { + PDEBUG(DDSP, DEBUG_ERROR, "Sample rate must be at least 12000 Hz to process FSK+supervisory signal.\n"); + return -EINVAL; + } + + memset(ffsk, 0, sizeof(*ffsk)); + ffsk->inst = inst; + ffsk->receive_bit = receive_bit; + ffsk->channel = channel; + ffsk->samplerate = samplerate; + + ffsk->samples_per_bit = (double)ffsk->samplerate / (double)BIT_RATE; + ffsk->bits_per_sample = 1.0 / ffsk->samples_per_bit; + PDEBUG(DDSP, DEBUG_DEBUG, "Use %.4f samples for full bit duration @ %d.\n", ffsk->samples_per_bit, ffsk->samplerate); + + /* allocate ring buffers, one bit duration */ + ffsk->filter_size = floor(ffsk->samples_per_bit); /* buffer holds one bit (rounded down) */ + spl = calloc(1, ffsk->filter_size * sizeof(*spl)); + if (!spl) { + PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n"); + ffsk_cleanup(ffsk); + return -ENOMEM; + } + ffsk->filter_spl = spl; + ffsk->filter_bit = -1; + + /* count symbols */ + for (i = 0; i < 2; i++) + audio_goertzel_init(&ffsk->goertzel[i], ffsk_freq[i], ffsk->samplerate); + ffsk->phaseshift65536 = 65536.0 / ffsk->samples_per_bit; + PDEBUG(DDSP, DEBUG_DEBUG, "fsk_phaseshift = %.4f\n", ffsk->phaseshift65536); + + return 0; +} + +/* Cleanup transceiver instance. */ +void ffsk_cleanup(ffsk_t *ffsk) +{ + PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup DSP for Transceiver.\n"); + + if (ffsk->filter_spl) { + free(ffsk->filter_spl); + ffsk->filter_spl = NULL; + } +} + +//#define DEBUG_MODULATOR +//#define DEBUG_FILTER +//#define DEBUG_QUALITY + +/* Filter one chunk of audio an detect tone, quality and loss of signal. + * The chunk is a window of 1/1200s. This window slides over audio stream + * and is processed every 1/12000s. (one step) */ +static inline void ffsk_decode_step(ffsk_t *ffsk, int pos) +{ + double level, result[2], softbit, quality; + int max; + sample_t *spl; + int bit; + + max = ffsk->filter_size; + spl = ffsk->filter_spl; + + level = audio_level(spl, max); + /* limit level to prevent division by zero */ + if (level < 0.001) + level = 0.001; + + audio_goertzel(ffsk->goertzel, spl, max, pos, result, 2); + + /* calculate soft bit from both frequencies */ + softbit = (result[1] / level - result[0] / level + 1.0) / 2.0; +//printf("%.3f: %.3f\n", level, softbit); + /* scale it, since both filters overlap by some percent */ +#define MIN_QUALITY 0.33 + softbit = (softbit - MIN_QUALITY) / (1.0 - MIN_QUALITY - MIN_QUALITY); +#ifdef DEBUG_FILTER +// printf("|%s", debug_amplitude(result[0]/level)); +// printf("|%s| low=%.3f high=%.3f level=%d\n", debug_amplitude(result[1]/level), result[0]/level, result[1]/level, (int)level); + printf("|%s| softbit=%.3f\n", debug_amplitude(softbit), softbit); +#endif + if (softbit > 1) + softbit = 1; + if (softbit < 0) + softbit = 0; + if (softbit > 0.5) + bit = 1; + else + bit = 0; + + if (ffsk->filter_bit != bit) { + /* If we have a bit change, move sample counter towards one half bit duration. + * We may have noise, so the bit change may be wrong or not at the correct place. + * This can cause bit slips. + * Therefore we change the sample counter only slightly, so bit slips may not + * happen so quickly. + * */ +#ifdef DEBUG_FILTER + puts("bit change"); +#endif + ffsk->filter_bit = bit; + if (ffsk->filter_sample < 5) + ffsk->filter_sample++; + if (ffsk->filter_sample > 5) + ffsk->filter_sample--; + } else if (--ffsk->filter_sample == 0) { + /* if sample counter bit reaches 0, we reset sample counter to one bit duration */ +#ifdef DEBUG_FILTER + puts("sample"); +#endif +// quality = result[bit] / level; + if (softbit > 0.5) + quality = softbit * 2.0 - 1.0; + else + quality = 1.0 - softbit * 2.0; +#ifdef DEBUG_QUALITY + printf("|%s| quality=%.2f ", debug_amplitude(softbit), quality); + printf("|%s|\n", debug_amplitude(quality)); +#endif + /* adjust level, so a peak level becomes 100% */ + ffsk->receive_bit(ffsk->inst, bit, quality, level / 0.63662); + ffsk->filter_sample = 10; + } +} + +void ffsk_receive(ffsk_t *ffsk, sample_t *sample, int length) +{ + sample_t *spl; + int max, pos; + double step, bps; + int i; + + /* write received samples to decode buffer */ + max = ffsk->filter_size; + pos = ffsk->filter_pos; + step = ffsk->filter_step; + bps = ffsk->bits_per_sample; + spl = ffsk->filter_spl; + for (i = 0; i < length; i++) { +#ifdef DEBUG_MODULATOR + printf("|%s|\n", debug_amplitude((double)samples[i] / 2333.0 /*fsk peak*/ / 2.0)); +#endif + /* write into ring buffer */ + spl[pos++] = sample[i]; + if (pos == max) + pos = 0; + /* if 1/10th of a bit duration is reached, decode buffer */ + step += bps; + if (step >= FILTER_STEPS) { + step -= FILTER_STEPS; + ffsk_decode_step(ffsk, pos); + } + } + ffsk->filter_step = step; + ffsk->filter_pos = pos; +} + +/* render frame */ +int ffsk_render_frame(ffsk_t *ffsk, const char *frame, int length, sample_t *sample) +{ + int bit, polarity; + double phaseshift, phase; + int count = 0, i; + + polarity = ffsk->polarity; + phaseshift = ffsk->phaseshift65536; + phase = ffsk->phase65536; + for (i = 0; i < length; i++) { + bit = (frame[i] == '1'); + do { + *sample++ = dsp_tone_bit[polarity][bit][(uint16_t)phase]; + count++; + phase += phaseshift; + } while (phase < 65536.0); + phase -= 65536.0; + /* flip polarity when we have 1.5 sine waves */ + if (bit == 0) + polarity = 1 - polarity; + } + ffsk->phase65536 = phase; + ffsk->polarity = polarity; + + /* return number of samples created for frame */ + return count; +} + diff --git a/src/common/ffsk.h b/src/common/ffsk.h new file mode 100644 index 0000000..84fc52a --- /dev/null +++ b/src/common/ffsk.h @@ -0,0 +1,27 @@ +#include "../common/goertzel.h" + +typedef struct ffsk { + void *inst; + void (*receive_bit)(void *inst, int bit, double quality, double level); + int channel; /* channel number */ + int samplerate; /* current sample rate */ + double samples_per_bit; /* number of samples for one bit (1200 Baud) */ + double bits_per_sample; /* fraction of a bit per sample */ + goertzel_t goertzel[2]; /* filter for fsk decoding */ + int polarity; /* current polarity state of bit */ + sample_t *filter_spl; /* array to hold ring buffer for bit decoding */ + int filter_size; /* size of ring buffer */ + int filter_pos; /* position to write next sample */ + double filter_step; /* counts bit duration, to trigger decoding every 10th bit */ + int filter_bit; /* last bit state, so we detect a bit change */ + int filter_sample; /* count until it is time to sample bit */ + double phaseshift65536; /* how much the phase of fsk synbol changes per sample */ + double phase65536; /* current phase */ +} ffsk_t; + +void ffsk_global_init(double peak_fsk); +int ffsk_init(ffsk_t *ffsk, void *inst, void (*receive_bit)(void *inst, int bit, double quality, double level), int channel, int samplerate); +void ffsk_cleanup(ffsk_t *ffsk); +void ffsk_receive(ffsk_t *ffsk, sample_t *sample, int lenght); +int ffsk_render_frame(ffsk_t *ffsk, const char *frame, int length, sample_t *sample); + diff --git a/src/nmt/dms.c b/src/nmt/dms.c index 2fcaf3c..8a27be0 100644 --- a/src/nmt/dms.c +++ b/src/nmt/dms.c @@ -25,7 +25,6 @@ #include "../common/debug.h" #include "../common/timer.h" #include "nmt.h" -#include "dsp.h" #define MUTE_DURATION 0.300 /* 200ms, and about 95ms for the frame itself */ @@ -288,7 +287,8 @@ static void dms_encode_dt(nmt_t *nmt, uint8_t d, uint8_t s, uint8_t n, uint8_t * #endif /* render wave form */ - dms->frame_length = fsk_render_frame(nmt, frame, 127, dms->frame_spl); + test_dms_frame(frame, 127); // used by test program + dms->frame_length = ffsk_render_frame(&nmt->ffsk, frame, 127, dms->frame_spl); dms->frame_valid = 1; dms->frame_pos = 0; if (dms->frame_length > dms->frame_size) { @@ -335,7 +335,8 @@ static void dms_encode_rr(nmt_t *nmt, uint8_t d, uint8_t s, uint8_t n) #endif /* render wave form */ - dms->frame_length = fsk_render_frame(nmt, frame, 77, dms->frame_spl); + test_dms_frame(frame, 77); // used by test program + dms->frame_length = ffsk_render_frame(&nmt->ffsk, frame, 77, dms->frame_spl); dms->frame_valid = 1; dms->frame_pos = 0; if (dms->frame_length > dms->frame_size) { @@ -662,7 +663,7 @@ void fsk_receive_bit_dms(nmt_t *nmt, int bit, double quality, double level) memset(dms->rx_frame_quality, 0, sizeof(dms->rx_frame_quality)); /* set muting of receive path */ - nmt->fsk_filter_mute = (int)((double)nmt->sender.samplerate * MUTE_DURATION); + nmt->rx_mute = (int)((double)nmt->sender.samplerate * MUTE_DURATION); return; } diff --git a/src/nmt/dms.h b/src/nmt/dms.h index e4bfd37..1810e00 100644 --- a/src/nmt/dms.h +++ b/src/nmt/dms.h @@ -60,3 +60,5 @@ void dms_send(nmt_t *nmt, const uint8_t *data, int length, int eight_bits); void dms_all_sent(nmt_t *nmt); void dms_receive(nmt_t *nmt, const uint8_t *data, int length, int eight_bits); +void test_dms_frame(const char *frame, int length); + diff --git a/src/nmt/dsp.c b/src/nmt/dsp.c index adc588b..0a1ba2d 100644 --- a/src/nmt/dsp.c +++ b/src/nmt/dsp.c @@ -59,9 +59,8 @@ #define COMPANDOR_0DB 1.0 /* A level of 0dBm (1.0) shall be unaccected */ #define TX_PEAK_FSK (4200.0 / 1800.0 * 1000.0 / DBM0_DEVIATION) #define TX_PEAK_SUPER (300.0 / 4015.0 * 1000.0 / DBM0_DEVIATION) +#define BIT_RATE 1200 #define MAX_DISPLAY 1.4 /* something above dBm0 */ -#define BIT_RATE 1200 /* baud rate */ -#define FILTER_STEPS 0.1 /* step every 1/12000 sec */ #define DIALTONE_HZ 425.0 /* dial tone frequency */ #define TX_PEAK_DIALTONE 0.5 /* dial tone peak FIXME */ #define SUPER_DURATION 0.25 /* duration of supervisory signal measurement */ @@ -69,12 +68,6 @@ #define SUPER_DETECT_COUNT 6 /* number of measures to detect supervisory signal */ #define MUTE_DURATION 0.280 /* a tiny bit more than two frames */ -/* two signaling tones */ -static double fsk_freq[2] = { - 1800.0, - 1200.0, -}; - /* two supervisory tones */ static double super_freq[5] = { 3955.0, /* 0-Signal 1 */ @@ -85,48 +78,39 @@ static double super_freq[5] = { }; /* table for fast sine generation */ -static sample_t dsp_tone_bit[2][2][65536]; /* polarity, bit, phase */ static sample_t dsp_sine_super[65536]; static sample_t dsp_sine_dialtone[65536]; -/* global init for FSK */ +/* global init for FFSK */ void dsp_init(void) { int i; double s; - PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for supervisory signal.\n"); + PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for supervisory signal and dial tone.\n"); for (i = 0; i < 65536; i++) { s = sin((double)i / 65536.0 * 2.0 * PI); /* supervisor sine */ dsp_sine_super[i] = s * TX_PEAK_SUPER; /* dialtone sine */ dsp_sine_dialtone[i] = s * TX_PEAK_DIALTONE; - /* bit(1) 1 cycle */ - dsp_tone_bit[0][1][i] = s * TX_PEAK_FSK; - dsp_tone_bit[1][1][i] = -s * TX_PEAK_FSK; - /* bit(0) 1.5 cycles */ - s = sin((double)i / 65536.0 * 3.0 * PI); - dsp_tone_bit[0][0][i] = s * TX_PEAK_FSK; - dsp_tone_bit[1][0][i] = -s * TX_PEAK_FSK; } + + ffsk_global_init(TX_PEAK_FSK); } +static void fsk_receive_bit(void *inst, int bit, double quality, double level); + /* Init FSK of transceiver */ int dsp_init_sender(nmt_t *nmt, double deviation_factor) { sample_t *spl; + double samples_per_bit; int i; /* attack (3ms) and recovery time (13.5ms) according to NMT specs */ init_compandor(&nmt->cstate, 8000, 3.0, 13.5, COMPANDOR_0DB); - /* a symbol rate of 1200 Hz, times check interval of FILTER_STEPS */ - if (nmt->sender.samplerate < (double)BIT_RATE / (double)FILTER_STEPS) { - PDEBUG(DDSP, DEBUG_ERROR, "Sample rate must be at least 12000 Hz to process FSK+supervisory signal.\n"); - return -EINVAL; - } - PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Init DSP for Transceiver.\n"); /* set modulation parameters */ @@ -135,22 +119,16 @@ int dsp_init_sender(nmt_t *nmt, double deviation_factor) PDEBUG(DDSP, DEBUG_DEBUG, "Using FSK level of %.3f (%.3f KHz deviation @ 1500 Hz)\n", TX_PEAK_FSK * deviation_factor, 3.5 * deviation_factor); PDEBUG(DDSP, DEBUG_DEBUG, "Using Supervisory level of %.3f (%.3f KHz deviation @ 4015 Hz)\n", TX_PEAK_SUPER * deviation_factor, 0.3 * deviation_factor); - nmt->fsk_samples_per_bit = (double)nmt->sender.samplerate / (double)BIT_RATE; - nmt->fsk_bits_per_sample = 1.0 / nmt->fsk_samples_per_bit; - PDEBUG(DDSP, DEBUG_DEBUG, "Use %.4f samples for full bit duration @ %d.\n", nmt->fsk_samples_per_bit, nmt->sender.samplerate); - - /* allocate ring buffers, one bit duration */ - nmt->fsk_filter_size = floor(nmt->fsk_samples_per_bit); /* buffer holds one bit (rounded down) */ - spl = calloc(1, nmt->fsk_filter_size * sizeof(*spl)); - if (!spl) { - PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n"); - return -ENOMEM; + /* init ffsk */ + if (ffsk_init(&nmt->ffsk, nmt, fsk_receive_bit, nmt->sender.kanal, nmt->sender.samplerate) < 0) { + PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "FFSK init failed!\n"); + return -EINVAL; } - nmt->fsk_filter_spl = spl; - nmt->fsk_filter_bit = -1; /* allocate transmit buffer for a complete frame, add 10 to be safe */ - nmt->frame_size = 166.0 * (double)nmt->fsk_samples_per_bit + 10; + + samples_per_bit = (double)nmt->sender.samplerate / (double)BIT_RATE; + nmt->frame_size = 166.0 * samples_per_bit + 10; spl = calloc(nmt->frame_size, sizeof(*spl)); if (!spl) { PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n"); @@ -159,7 +137,7 @@ int dsp_init_sender(nmt_t *nmt, double deviation_factor) nmt->frame_spl = spl; /* allocate DMS transmit buffer for a complete frame, add 10 to be safe */ - nmt->dms.frame_size = 127.0 * (double)nmt->fsk_samples_per_bit + 10; + nmt->dms.frame_size = 127.0 * samples_per_bit + 10; spl = calloc(nmt->dms.frame_size, sizeof(*spl)); if (!spl) { PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n"); @@ -176,12 +154,6 @@ int dsp_init_sender(nmt_t *nmt, double deviation_factor) } nmt->super_filter_spl = spl; - /* count symbols */ - for (i = 0; i < 2; i++) - audio_goertzel_init(&nmt->fsk_goertzel[i], fsk_freq[i], nmt->sender.samplerate); - nmt->fsk_phaseshift65536 = 65536.0 / nmt->fsk_samples_per_bit; - PDEBUG(DDSP, DEBUG_DEBUG, "fsk_phaseshift = %.4f\n", nmt->fsk_phaseshift65536); - /* count supervidory tones */ for (i = 0; i < 5; i++) { audio_goertzel_init(&nmt->super_goertzel[i], super_freq[i], nmt->sender.samplerate); @@ -207,6 +179,8 @@ void dsp_cleanup_sender(nmt_t *nmt) { PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup DSP for Transceiver.\n"); + ffsk_cleanup(&nmt->ffsk); + if (nmt->frame_spl) { free(nmt->frame_spl); nmt->frame_spl = NULL; @@ -215,10 +189,6 @@ void dsp_cleanup_sender(nmt_t *nmt) free(nmt->dms.frame_spl); nmt->dms.frame_spl = NULL; } - if (nmt->fsk_filter_spl) { - free(nmt->fsk_filter_spl); - nmt->fsk_filter_spl = NULL; - } if (nmt->super_filter_spl) { free(nmt->super_filter_spl); nmt->super_filter_spl = NULL; @@ -226,29 +196,38 @@ void dsp_cleanup_sender(nmt_t *nmt) } /* Check for SYNC bits, then collect data bits */ -static void fsk_receive_bit(nmt_t *nmt, int bit, double quality, double level) +static void fsk_receive_bit(void *inst, int bit, double quality, double level) { - double frames_elapsed; + nmt_t *nmt = (nmt_t *)inst; + uint64_t frames_elapsed; int i; + /* normalize FSK level */ + level /= TX_PEAK_FSK; + + nmt->rx_bits_count++; + + if (nmt->dms_call) + fsk_receive_bit_dms(nmt, bit, quality, level); + // printf("bit=%d quality=%.4f\n", bit, quality); - if (!nmt->fsk_filter_in_sync) { - nmt->fsk_filter_sync = (nmt->fsk_filter_sync << 1) | bit; + if (!nmt->rx_in_sync) { + nmt->rx_sync = (nmt->rx_sync << 1) | bit; /* level and quality */ - nmt->fsk_filter_level[nmt->fsk_filter_count & 0xff] = level; - nmt->fsk_filter_quality[nmt->fsk_filter_count & 0xff] = quality; - nmt->fsk_filter_count++; + nmt->rx_level[nmt->rx_count & 0xff] = level; + nmt->rx_quality[nmt->rx_count & 0xff] = quality; + nmt->rx_count++; /* check if pattern 1010111100010010 matches */ - if (nmt->fsk_filter_sync != 0xaf12) + if (nmt->rx_sync != 0xaf12) return; /* average level and quality */ level = quality = 0; for (i = 0; i < 16; i++) { - level += nmt->fsk_filter_level[(nmt->fsk_filter_count - 1 - i) & 0xff]; - quality += nmt->fsk_filter_quality[(nmt->fsk_filter_count - 1 - i) & 0xff]; + level += nmt->rx_level[(nmt->rx_count - 1 - i) & 0xff]; + quality += nmt->rx_quality[(nmt->rx_count - 1 - i) & 0xff]; } level /= 16.0; quality /= 16.0; // printf("sync (level = %.2f, quality = %.2f\n", level, quality); @@ -262,114 +241,38 @@ static void fsk_receive_bit(nmt_t *nmt, int bit, double quality, double level) nmt->rx_bits_count_current = nmt->rx_bits_count - 26.0; /* rest sync register */ - nmt->fsk_filter_sync = 0; - nmt->fsk_filter_in_sync = 1; - nmt->fsk_filter_count = 0; + nmt->rx_sync = 0; + nmt->rx_in_sync = 1; + nmt->rx_count = 0; /* set muting of receive path */ - nmt->fsk_filter_mute = (int)((double)nmt->sender.samplerate * MUTE_DURATION); + nmt->rx_mute = (int)((double)nmt->sender.samplerate * MUTE_DURATION); return; } /* read bits */ - nmt->fsk_filter_frame[nmt->fsk_filter_count] = bit + '0'; - nmt->fsk_filter_level[nmt->fsk_filter_count] = level; - nmt->fsk_filter_quality[nmt->fsk_filter_count] = quality; - if (++nmt->fsk_filter_count != 140) + nmt->rx_frame[nmt->rx_count] = bit + '0'; + nmt->rx_level[nmt->rx_count] = level; + nmt->rx_quality[nmt->rx_count] = quality; + if (++nmt->rx_count != 140) return; /* end of frame */ - nmt->fsk_filter_frame[140] = '\0'; - nmt->fsk_filter_in_sync = 0; + nmt->rx_frame[140] = '\0'; + nmt->rx_in_sync = 0; /* average level and quality */ level = quality = 0; for (i = 0; i < 140; i++) { - level += nmt->fsk_filter_level[i]; - quality += nmt->fsk_filter_quality[i]; + level += nmt->rx_level[i]; + quality += nmt->rx_quality[i]; } level /= 140.0; quality /= 140.0; /* send telegramm */ - frames_elapsed = (nmt->rx_bits_count_current - nmt->rx_bits_count_last) / 166.0; + frames_elapsed = (nmt->rx_bits_count_current - nmt->rx_bits_count_last + 83) / 166; /* round to nearest frame */ /* convert level so that received level at TX_PEAK_FSK results in 1.0 (100%) */ - nmt_receive_frame(nmt, nmt->fsk_filter_frame, quality, level, frames_elapsed); -} - -//#define DEBUG_MODULATOR -//#define DEBUG_FILTER -//#define DEBUG_QUALITY - -/* Filter one chunk of audio an detect tone, quality and loss of signal. - * The chunk is a window of 1/1200s. This window slides over audio stream - * and is processed every 1/12000s. (one step) */ -static inline void fsk_decode_step(nmt_t *nmt, int pos) -{ - double level, result[2], softbit, quality; - int max; - sample_t *spl; - int bit; - - max = nmt->fsk_filter_size; - spl = nmt->fsk_filter_spl; - - /* count time in bits */ - nmt->rx_bits_count += FILTER_STEPS; - - level = audio_level(spl, max); - /* limit level to prevent division by zero */ - if (level < 0.001) - level = 0.001; - - audio_goertzel(nmt->fsk_goertzel, spl, max, pos, result, 2); - - /* calculate soft bit from both frequencies */ - softbit = (result[1] / level - result[0] / level + 1.0) / 2.0; -//printf("%.3f: %.3f\n", level, softbit); - /* scale it, since both filters overlap by some percent */ -#define MIN_QUALITY 0.33 - softbit = (softbit - MIN_QUALITY) / (1.0 - MIN_QUALITY - MIN_QUALITY); -#ifdef DEBUG_FILTER -// printf("|%s", debug_amplitude(result[0]/level)); -// printf("|%s| low=%.3f high=%.3f level=%d\n", debug_amplitude(result[1]/level), result[0]/level, result[1]/level, (int)level); - printf("|%s| softbit=%.3f\n", debug_amplitude(softbit), softbit); -#endif - if (softbit > 1) - softbit = 1; - if (softbit < 0) - softbit = 0; - if (softbit > 0.5) - bit = 1; - else - bit = 0; - - if (nmt->fsk_filter_bit != bit) { - /* if we have a bit change, reset sample counter to one half bit duration */ -#ifdef DEBUG_FILTER - puts("bit change"); -#endif - nmt->fsk_filter_bit = bit; - nmt->fsk_filter_sample = 5; - } else if (--nmt->fsk_filter_sample == 0) { - /* if sample counter bit reaches 0, we reset sample counter to one bit duration */ -#ifdef DEBUG_FILTER - puts("sample"); -#endif -// quality = result[bit] / level; - if (softbit > 0.5) - quality = softbit * 2.0 - 1.0; - else - quality = 1.0 - softbit * 2.0; -#ifdef DEBUG_QUALITY - printf("|%s| quality=%.2f ", debug_amplitude(softbit), quality); - printf("|%s|\n", debug_amplitude(quality)); -#endif - /* adjust level, so a peak level becomes 100% */ - fsk_receive_bit(nmt, bit, quality, level / 0.63662 / TX_PEAK_FSK); - if (nmt->dms_call) - fsk_receive_bit_dms(nmt, bit, quality, level / 0.63662 / TX_PEAK_FSK); - nmt->fsk_filter_sample = 10; - } + nmt_receive_frame(nmt, nmt->rx_frame, quality, level, frames_elapsed); } /* compare supervisory signal against noise floor on 3900 Hz */ @@ -425,7 +328,6 @@ void sender_receive(sender_t *sender, sample_t *samples, int length) nmt_t *nmt = (nmt_t *) sender; sample_t *spl; int max, pos; - double step, bps; int i; /* write received samples to decode buffer */ @@ -442,34 +344,15 @@ void sender_receive(sender_t *sender, sample_t *samples, int length) } nmt->super_filter_pos = pos; - /* write received samples to decode buffer */ - max = nmt->fsk_filter_size; - pos = nmt->fsk_filter_pos; - step = nmt->fsk_filter_step; - bps = nmt->fsk_bits_per_sample; - spl = nmt->fsk_filter_spl; + ffsk_receive(&nmt->ffsk, samples, length); + + /* muting audio while receiving frame */ for (i = 0; i < length; i++) { -#ifdef DEBUG_MODULATOR - printf("|%s|\n", debug_amplitude((double)samples[i] / TX_PEAK_FSK / 2.0)); -#endif - /* write into ring buffer */ - spl[pos++] = samples[i]; - if (pos == max) - pos = 0; - /* muting audio while receiving frame */ - if (nmt->fsk_filter_mute && !nmt->sender.loopback) { + if (nmt->rx_mute && !nmt->sender.loopback) { samples[i] = 0; - nmt->fsk_filter_mute--; - } - /* if 1/10th of a bit duration is reached, decode buffer */ - step += bps; - if (step >= FILTER_STEPS) { - step -= FILTER_STEPS; - fsk_decode_step(nmt, pos); + nmt->rx_mute--; } } - nmt->fsk_filter_step = step; - nmt->fsk_filter_pos = pos; if ((nmt->dsp_mode == DSP_MODE_AUDIO || nmt->dsp_mode == DSP_MODE_DTMF) && nmt->trans && nmt->trans->callref) { @@ -494,35 +377,6 @@ void sender_receive(sender_t *sender, sample_t *samples, int length) nmt->sender.rxbuf_pos = 0; } -/* render frame */ -int fsk_render_frame(nmt_t *nmt, const char *frame, int length, sample_t *sample) -{ - int bit, polarity; - double phaseshift, phase; - int count = 0, i; - - polarity = nmt->fsk_polarity; - phaseshift = nmt->fsk_phaseshift65536; - phase = nmt->fsk_phase65536; - for (i = 0; i < length; i++) { - bit = (frame[i] == '1'); - do { - *sample++ = dsp_tone_bit[polarity][bit][(uint16_t)phase]; - count++; - phase += phaseshift; - } while (phase < 65536.0); - phase -= 65536.0; - /* flip polarity when we have 1.5 sine waves */ - if (bit == 0) - polarity = 1 - polarity; - } - nmt->fsk_phase65536 = phase; - nmt->fsk_polarity = polarity; - - /* return number of samples created for frame */ - return count; -} - static int fsk_frame(nmt_t *nmt, sample_t *samples, int length) { const char *frame; @@ -539,7 +393,7 @@ next_frame: return length; } /* render frame */ - nmt->frame_length = fsk_render_frame(nmt, frame, 166, nmt->frame_spl); + nmt->frame_length = ffsk_render_frame(&nmt->ffsk, frame, 166, nmt->frame_spl); nmt->frame_pos = 0; if (nmt->frame_length > nmt->frame_size) { PDEBUG_CHAN(DDSP, DEBUG_ERROR, "Frame exceeds buffer, please fix!\n"); diff --git a/src/nmt/dsp.h b/src/nmt/dsp.h index 34f04e6..fff2dba 100644 --- a/src/nmt/dsp.h +++ b/src/nmt/dsp.h @@ -2,7 +2,6 @@ void dsp_init(void); int dsp_init_sender(nmt_t *nmt, double deviation_factor); void dsp_cleanup_sender(nmt_t *nmt); -int fsk_render_frame(nmt_t *nmt, const char *frame, int length, sample_t *sample); void nmt_set_dsp_mode(nmt_t *nmt, enum dsp_mode mode); void super_reset(nmt_t *nmt); diff --git a/src/nmt/main.c b/src/nmt/main.c index 396f7d0..d29ee62 100644 --- a/src/nmt/main.c +++ b/src/nmt/main.c @@ -427,3 +427,6 @@ fail: return 0; } +// dummy, will be replaced by DMS test program +void test_dms_frame(const char __attribute__((unused)) *frame, int __attribute__((unused)) length) {} + diff --git a/src/nmt/nmt.c b/src/nmt/nmt.c index 01a7b3c..847be72 100644 --- a/src/nmt/nmt.c +++ b/src/nmt/nmt.c @@ -1527,7 +1527,7 @@ static void tx_active(nmt_t *nmt, frame_t *frame) * general handlers to call sub handling */ -void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, double frames_elapsed) +void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, int frames_elapsed) { frame_t frame; int rc; @@ -1541,7 +1541,7 @@ void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double leve } /* frame counter */ - nmt->rx_frame_count += (int)(frames_elapsed + 0.5); + nmt->rx_frame_count += frames_elapsed; PDEBUG_CHAN(DNMT, (nmt->sender.loopback) ? DEBUG_NOTICE : DEBUG_DEBUG, "Received frame %s\n", nmt_frame_name(frame.mt)); diff --git a/src/nmt/nmt.h b/src/nmt/nmt.h index 1ed438e..3f9577c 100644 --- a/src/nmt/nmt.h +++ b/src/nmt/nmt.h @@ -1,8 +1,8 @@ -#include "../common/goertzel.h" #include "../common/sender.h" #include "../common/compandor.h" #include "../common/dtmf.h" #include "../common/call.h" +#include "../common/ffsk.h" #include "dms.h" #include "sms.h" @@ -96,40 +96,29 @@ typedef struct nmt { /* dsp states */ enum dsp_mode dsp_mode; /* current mode: audio, durable tone 0 or 1, paging */ - double fsk_samples_per_bit; /* number of samples for one bit (1200 Baud) */ - double fsk_bits_per_sample; /* fraction of a bit per sample */ + ffsk_t ffsk; /* ffsk processing */ int super_samples; /* number of samples in buffer for supervisory detection */ - goertzel_t fsk_goertzel[2]; /* filter for fsk decoding */ goertzel_t super_goertzel[5]; /* filter for supervisory decoding */ - int fsk_polarity; /* current polarity state of bit */ - sample_t *fsk_filter_spl; /* array to hold ring buffer for bit decoding */ - int fsk_filter_size; /* size of ring buffer */ - int fsk_filter_pos; /* position to write next sample */ - double fsk_filter_step; /* counts bit duration, to trigger decoding every 10th bit */ - int fsk_filter_bit; /* last bit state, so we detect a bit change */ - int fsk_filter_sample; /* count until it is time to sample bit */ - uint16_t fsk_filter_sync; /* shift register to detect sync */ - int fsk_filter_in_sync; /* if we are in sync and receive bits */ - int fsk_filter_mute; /* mute count down after sync */ - char fsk_filter_frame[141]; /* receive frame (one extra byte to terminate string) */ - int fsk_filter_count; /* next bit to receive */ - double fsk_filter_level[256]; /* level infos */ - double fsk_filter_quality[256];/* quality infos */ sample_t *super_filter_spl; /* array with sample buffer for supervisory detection */ int super_filter_pos; /* current sample position in filter_spl */ double super_phaseshift65536[4];/* how much the phase of sine wave changes per sample */ double super_phase65536; /* current phase */ double dial_phaseshift65536; /* how much the phase of sine wave changes per sample */ double dial_phase65536; /* current phase */ - double fsk_phaseshift65536; /* how much the phase of fsk synbol changes per sample */ - double fsk_phase65536; /* current phase */ + uint16_t rx_sync; /* shift register to detect sync */ + int rx_in_sync; /* if we are in sync and receive bits */ + int rx_mute; /* mute count down after sync */ + char rx_frame[141]; /* receive frame (one extra byte to terminate string) */ + int rx_count; /* next bit to receive */ + double rx_level[256]; /* level infos */ + double rx_quality[256]; /* quality infos */ sample_t *frame_spl; /* samples to store a complete rendered frame */ int frame_size; /* total size of sample buffer */ int frame_length; /* current length of data in sample buffer */ int frame_pos; /* current sample position in frame_spl */ - double rx_bits_count; /* sample counter */ - double rx_bits_count_current; /* sample counter of current frame */ - double rx_bits_count_last; /* sample counter of last frame */ + uint64_t rx_bits_count; /* sample counter */ + uint64_t rx_bits_count_current; /* sample counter of current frame */ + uint64_t rx_bits_count_last; /* sample counter of last frame */ int super_detected; /* current detection state flag */ int super_detect_count; /* current number of consecutive detections/losses */ @@ -149,7 +138,7 @@ int nmt_create(int nmt_system, const char *country, int channel, enum nmt_chan_t void nmt_check_channels(int nmt_system); void nmt_destroy(sender_t *sender); void nmt_go_idle(nmt_t *nmt); -void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, double frames_elapsed); +void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, int frames_elapsed); const char *nmt_get_frame(nmt_t *nmt); void nmt_rx_super(nmt_t *nmt, int tone, double quality); void timeout_mt_paging(struct transaction *trans); diff --git a/src/test/test_dms.c b/src/test/test_dms.c index a35a6f1..c71f87c 100644 --- a/src/test/test_dms.c +++ b/src/test/test_dms.c @@ -56,14 +56,12 @@ void dms_all_sent(nmt_t *nmt) } /* receive bits from DMS */ -int fsk_render_frame(nmt_t *nmt, const char *frame, int length, sample_t *sample) +void test_dms_frame(const char *frame, int length) { printf("(getting %d bits from DMS layer)\n", length); memcpy(current_bits, frame, length); current_bit_count = length; - - return nmt->fsk_samples_per_bit * length; } nmt_t *alloc_nmt(void) @@ -71,9 +69,11 @@ nmt_t *alloc_nmt(void) nmt_t *nmt; nmt = calloc(sizeof(*nmt), 1); + nmt->sender.samplerate = 40 * 1200; dms_init_sender(nmt); - nmt->fsk_samples_per_bit = 40; - nmt->dms.frame_size = nmt->fsk_samples_per_bit * 127 + 10; + ffsk_global_init(1.0); + ffsk_init(&nmt->ffsk, nmt, NULL, 1, nmt->sender.samplerate); + nmt->dms.frame_size = nmt->ffsk.samples_per_bit * 127 + 10; nmt->dms.frame_spl = calloc(nmt->dms.frame_size, sizeof(nmt->dms.frame_spl[0])); dms_reset(nmt); -- cgit v1.2.3