2016-03-01 17:40:38 +00:00
|
|
|
/* A-Netz signal processing
|
|
|
|
*
|
|
|
|
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2016-12-09 15:34:33 +00:00
|
|
|
#define CHAN anetz->sender.kanal
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <math.h>
|
2017-01-27 15:57:34 +00:00
|
|
|
#include "../common/sample.h"
|
2016-03-01 17:40:38 +00:00
|
|
|
#include "../common/debug.h"
|
|
|
|
#include "../common/timer.h"
|
|
|
|
#include "../common/call.h"
|
|
|
|
#include "anetz.h"
|
|
|
|
#include "dsp.h"
|
|
|
|
|
|
|
|
#define PI 3.1415927
|
|
|
|
|
2016-07-24 08:26:01 +00:00
|
|
|
/* signaling */
|
2017-01-29 06:25:12 +00:00
|
|
|
#define MAX_DEVIATION 15000.0
|
|
|
|
#define MAX_MODULATION 4000.0
|
|
|
|
#define DBM0_DEVIATION 10500.0 /* deviation of dBm0 at 1 kHz */
|
|
|
|
#define TX_PEAK_TONE (10500.0 / DBM0_DEVIATION) /* 10.5 kHz, no emphasis */
|
|
|
|
#define TX_PEAK_PAGE (15000.0 / DBM0_DEVIATION) /* 15 kHz, no emphasis */
|
|
|
|
#define MAX_DISPLAY (15000.0 / DBM0_DEVIATION) /* 15 kHz, no emphasis */
|
2016-03-01 17:40:38 +00:00
|
|
|
#define CHUNK_DURATION 0.010 /* 10 ms */
|
2017-09-25 16:46:50 +00:00
|
|
|
#define TONE_THRESHOLD 0.05
|
|
|
|
#define QUAL_THRESHOLD 0.5
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
// FIXME: how long until we detect a tone?
|
2016-07-24 10:28:18 +00:00
|
|
|
#define TONE_DETECT_TH 8 /* chunk intervals to detect continuous tone */
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
/* carrier loss detection */
|
|
|
|
#define LOSS_INTERVAL 100 /* filter steps (chunk durations) for one second interval */
|
|
|
|
#define LOSS_TIME 12 /* duration of signal loss before release */
|
|
|
|
|
2016-07-24 08:26:01 +00:00
|
|
|
/* two signaling tones */
|
2016-03-01 17:40:38 +00:00
|
|
|
static double fsk_tones[2] = {
|
|
|
|
2280.0,
|
|
|
|
1750.0,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* table for fast sine generation */
|
2017-01-29 06:25:12 +00:00
|
|
|
static sample_t dsp_sine_tone[65536];
|
|
|
|
static sample_t dsp_sine_page[65536];
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
/* global init for audio processing */
|
|
|
|
void dsp_init(void)
|
|
|
|
{
|
|
|
|
int i;
|
2016-05-05 11:11:15 +00:00
|
|
|
double s;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2016-05-05 11:11:15 +00:00
|
|
|
PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine tables.\n");
|
2017-01-29 06:25:12 +00:00
|
|
|
for (i = 0; i < 65536; i++) {
|
|
|
|
s = sin((double)i / 65536.0 * 2.0 * PI);
|
|
|
|
dsp_sine_tone[i] = s * TX_PEAK_TONE;
|
|
|
|
dsp_sine_page[i] = s * TX_PEAK_PAGE;
|
2016-05-05 11:11:15 +00:00
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Init transceiver instance. */
|
2017-01-08 10:22:24 +00:00
|
|
|
int dsp_init_sender(anetz_t *anetz, double page_gain, int page_sequence)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2017-01-27 15:57:34 +00:00
|
|
|
sample_t *spl;
|
2016-05-05 11:11:15 +00:00
|
|
|
int i;
|
|
|
|
double tone;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2016-12-09 15:34:33 +00:00
|
|
|
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Init DSP for 'Sender'.\n");
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
/* set modulation parameters */
|
|
|
|
sender_set_fm(&anetz->sender, MAX_DEVIATION * page_gain, MAX_MODULATION, DBM0_DEVIATION, MAX_DISPLAY);
|
2017-01-06 11:22:51 +00:00
|
|
|
|
2017-01-08 10:22:24 +00:00
|
|
|
anetz->page_gain = page_gain;
|
2016-11-13 04:51:09 +00:00
|
|
|
anetz->page_sequence = page_sequence;
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
audio_init_loss(&anetz->sender.loss, LOSS_INTERVAL, anetz->sender.loss_volume, LOSS_TIME);
|
|
|
|
|
|
|
|
anetz->samples_per_chunk = anetz->sender.samplerate * CHUNK_DURATION;
|
2016-03-15 18:26:13 +00:00
|
|
|
PDEBUG(DDSP, DEBUG_DEBUG, "Using %d samples per chunk duration.\n", anetz->samples_per_chunk);
|
2017-01-27 15:57:34 +00:00
|
|
|
spl = calloc(anetz->samples_per_chunk, sizeof(sample_t));
|
2016-03-01 17:40:38 +00:00
|
|
|
if (!spl) {
|
2016-03-15 18:26:13 +00:00
|
|
|
PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n");
|
2016-03-01 17:40:38 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
anetz->fsk_filter_spl = spl;
|
|
|
|
|
|
|
|
anetz->tone_detected = -1;
|
|
|
|
|
2017-01-27 15:57:34 +00:00
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
audio_goertzel_init(&anetz->fsk_tone_goertzel[i], fsk_tones[i], anetz->sender.samplerate);
|
2016-05-05 11:11:15 +00:00
|
|
|
tone = fsk_tones[(anetz->sender.loopback == 0) ? 0 : 1];
|
2017-01-29 06:25:12 +00:00
|
|
|
anetz->tone_phaseshift65536 = 65536.0 / ((double)anetz->sender.samplerate / tone);
|
|
|
|
PDEBUG(DDSP, DEBUG_DEBUG, "TX %.0f Hz phaseshift = %.4f\n", tone, anetz->tone_phaseshift65536);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-09-25 16:46:50 +00:00
|
|
|
anetz->dmp_tone_level = display_measurements_add(&anetz->sender, "Tone Level", "%.1f %%", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0);
|
|
|
|
anetz->dmp_tone_quality = display_measurements_add(&anetz->sender, "Tone Quality", "%.1f %%", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0);
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleanup transceiver instance. */
|
|
|
|
void dsp_cleanup_sender(anetz_t *anetz)
|
|
|
|
{
|
2016-12-09 15:34:33 +00:00
|
|
|
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup DSP for 'Sender'.\n");
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
if (anetz->fsk_filter_spl) {
|
|
|
|
free(anetz->fsk_filter_spl);
|
|
|
|
anetz->fsk_filter_spl = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Count duration of tone and indicate detection/loss to protocol handler. */
|
2017-09-25 16:46:50 +00:00
|
|
|
static void fsk_receive_tone(anetz_t *anetz, int tone, int goodtone, double level, double quality)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
/* lost tone because it is not good anymore or has changed */
|
|
|
|
if (!goodtone || tone != anetz->tone_detected) {
|
|
|
|
if (anetz->tone_count >= TONE_DETECT_TH) {
|
2016-12-09 15:34:33 +00:00
|
|
|
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Lost %.0f Hz tone after %.0f ms.\n", fsk_tones[anetz->tone_detected], 1000.0 * CHUNK_DURATION * anetz->tone_count);
|
2016-03-01 17:40:38 +00:00
|
|
|
anetz_receive_tone(anetz, -1);
|
|
|
|
}
|
|
|
|
if (goodtone)
|
|
|
|
anetz->tone_detected = tone;
|
|
|
|
else
|
|
|
|
anetz->tone_detected = -1;
|
|
|
|
anetz->tone_count = 0;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
anetz->tone_count++;
|
|
|
|
|
|
|
|
if (anetz->tone_count >= TONE_DETECT_TH)
|
|
|
|
audio_reset_loss(&anetz->sender.loss);
|
|
|
|
if (anetz->tone_count == TONE_DETECT_TH) {
|
2017-09-25 16:46:50 +00:00
|
|
|
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Detecting continuous %.0f Hz tone. (level = %.0f%%, quality =%.0f%%)\n", fsk_tones[anetz->tone_detected], level * 100.0, quality * 100.0);
|
2016-03-01 17:40:38 +00:00
|
|
|
anetz_receive_tone(anetz, anetz->tone_detected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Filter one chunk of audio an detect tone, quality and loss of signal. */
|
2017-01-27 15:57:34 +00:00
|
|
|
static void fsk_decode_chunk(anetz_t *anetz, sample_t *spl, int max)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2017-09-25 16:46:50 +00:00
|
|
|
double level, result[2], quality[2];
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
level = audio_level(spl, max);
|
|
|
|
|
|
|
|
if (audio_detect_loss(&anetz->sender.loss, level))
|
|
|
|
anetz_loss_indication(anetz);
|
|
|
|
|
2017-01-27 15:57:34 +00:00
|
|
|
audio_goertzel(anetz->fsk_tone_goertzel, spl, max, 0, result, 2);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-09-25 16:46:50 +00:00
|
|
|
/* normalize quality of tones and level */
|
|
|
|
quality[0] = result[0] / level;
|
|
|
|
quality[1] = result[1] / level;
|
|
|
|
/* adjust level, so we get peak of sine curve */
|
|
|
|
level = level / 0.63662 / TX_PEAK_TONE;
|
|
|
|
/* show tones */
|
|
|
|
display_measurements_update(anetz->dmp_tone_level, level * 100.0, 0.0);
|
|
|
|
display_measurements_update(anetz->dmp_tone_quality, quality[1] * 100.0, 0.0);
|
|
|
|
if ((level > TONE_THRESHOLD && quality[1] > QUAL_THRESHOLD) || anetz->sender.loopback)
|
|
|
|
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Tone %.0f: Level=%3.0f%% Quality=%3.0f%%\n", fsk_tones[1], level * 100.0, quality[1] * 100.0);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
/* adjust level, so we get peak of sine curve */
|
2016-05-05 11:11:15 +00:00
|
|
|
/* indicate detected tone */
|
2017-09-25 16:46:50 +00:00
|
|
|
if (level > TONE_THRESHOLD && quality[0] > QUAL_THRESHOLD)
|
|
|
|
fsk_receive_tone(anetz, 0, 1, level, quality[0]);
|
|
|
|
else if (level > TONE_THRESHOLD && quality[1] > QUAL_THRESHOLD)
|
|
|
|
fsk_receive_tone(anetz, 1, 1, level, quality[1]);
|
2016-03-01 17:40:38 +00:00
|
|
|
else
|
2017-09-25 16:46:50 +00:00
|
|
|
fsk_receive_tone(anetz, -1, 0, level, 0.0);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Process received audio stream from radio unit. */
|
2017-01-27 15:57:34 +00:00
|
|
|
void sender_receive(sender_t *sender, sample_t *samples, int length)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
anetz_t *anetz = (anetz_t *) sender;
|
2017-01-27 15:57:34 +00:00
|
|
|
sample_t *spl;
|
2016-03-01 17:40:38 +00:00
|
|
|
int max, pos;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* write received samples to decode buffer */
|
|
|
|
max = anetz->samples_per_chunk;
|
|
|
|
pos = anetz->fsk_filter_pos;
|
|
|
|
spl = anetz->fsk_filter_spl;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
spl[pos++] = samples[i];
|
|
|
|
if (pos == max) {
|
|
|
|
pos = 0;
|
|
|
|
fsk_decode_chunk(anetz, spl, max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
anetz->fsk_filter_pos = pos;
|
|
|
|
|
|
|
|
/* Forward audio to network (call process). */
|
2016-08-21 07:00:55 +00:00
|
|
|
if (anetz->dsp_mode == DSP_MODE_AUDIO && anetz->callref) {
|
2016-03-01 17:40:38 +00:00
|
|
|
int count;
|
|
|
|
|
2017-01-27 15:57:34 +00:00
|
|
|
count = samplerate_downsample(&anetz->sender.srstate, samples, length);
|
2016-03-01 17:40:38 +00:00
|
|
|
spl = anetz->sender.rxbuf;
|
|
|
|
pos = anetz->sender.rxbuf_pos;
|
|
|
|
for (i = 0; i < count; i++) {
|
2017-01-27 15:57:34 +00:00
|
|
|
spl[pos++] = samples[i];
|
2016-03-01 17:40:38 +00:00
|
|
|
if (pos == 160) {
|
2016-08-21 07:00:55 +00:00
|
|
|
call_tx_audio(anetz->callref, spl, 160);
|
2016-03-01 17:40:38 +00:00
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
anetz->sender.rxbuf_pos = pos;
|
|
|
|
} else
|
|
|
|
anetz->sender.rxbuf_pos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set 4 paging frequencies */
|
|
|
|
void dsp_set_paging(anetz_t *anetz, double *freq)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
anetz->paging_phaseshift65536[i] = 65536.0 / ((double)anetz->sender.samplerate / freq[i]);
|
|
|
|
anetz->paging_phase65536[i] = 0;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate audio stream of 4 simultanious paging tones. Keep phase for next call of function.
|
2017-01-29 06:25:12 +00:00
|
|
|
* Use TX_PEAK_PAGE*page_gain for all tones, which gives peak of 1/4th for each individual tone. */
|
2017-01-27 15:57:34 +00:00
|
|
|
static void fsk_paging_tone(anetz_t *anetz, sample_t *samples, int length)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2017-01-29 06:25:12 +00:00
|
|
|
double *phaseshift, *phase;
|
2016-03-01 17:40:38 +00:00
|
|
|
int i;
|
2017-01-08 10:22:24 +00:00
|
|
|
double sample;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
phaseshift = anetz->paging_phaseshift65536;
|
|
|
|
phase = anetz->paging_phase65536;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
for (i = 0; i < length; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
sample = dsp_sine_page[(uint16_t)phase[0]]
|
|
|
|
+ dsp_sine_page[(uint16_t)phase[1]]
|
|
|
|
+ dsp_sine_page[(uint16_t)phase[2]]
|
|
|
|
+ dsp_sine_page[(uint16_t)phase[3]];
|
2017-01-08 10:22:24 +00:00
|
|
|
*samples++ = sample / 4.0 * anetz->page_gain;
|
2016-03-01 17:40:38 +00:00
|
|
|
phase[0] += phaseshift[0];
|
|
|
|
phase[1] += phaseshift[1];
|
|
|
|
phase[2] += phaseshift[2];
|
|
|
|
phase[3] += phaseshift[3];
|
2017-01-29 06:25:12 +00:00
|
|
|
if (phase[0] >= 65536) phase[0] -= 65536;
|
|
|
|
if (phase[1] >= 65536) phase[1] -= 65536;
|
|
|
|
if (phase[2] >= 65536) phase[2] -= 65536;
|
|
|
|
if (phase[3] >= 65536) phase[3] -= 65536;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-13 16:45:46 +00:00
|
|
|
/* Generate audio stream of 4 sequenced paging tones. Keep phase for next call
|
|
|
|
* of function.
|
|
|
|
*
|
2017-01-08 10:22:24 +00:00
|
|
|
* Use TX_PEAK_PAGE for each tone, that is four times higher per tone.
|
2016-11-13 16:45:46 +00:00
|
|
|
*
|
|
|
|
* Click removal when changing tones that have individual phase:
|
|
|
|
* When tone changes to next tone, a transition of 2ms is performed. The last
|
|
|
|
* tone is faded out and the new tone faded in.
|
|
|
|
*/
|
2017-01-27 15:57:34 +00:00
|
|
|
static void fsk_paging_tone_sequence(anetz_t *anetz, sample_t *samples, int length, int numspl)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2017-01-29 06:25:12 +00:00
|
|
|
double *phaseshift, *phase;
|
2016-11-13 16:45:46 +00:00
|
|
|
int tone, count, transition;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
phaseshift = anetz->paging_phaseshift65536;
|
|
|
|
phase = anetz->paging_phase65536;
|
2016-03-01 17:40:38 +00:00
|
|
|
tone = anetz->paging_tone;
|
|
|
|
count = anetz->paging_count;
|
2016-11-13 16:45:46 +00:00
|
|
|
transition = anetz->paging_transition;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
while (length) {
|
2016-11-13 16:45:46 +00:00
|
|
|
/* use tone, but during transition of tones, keep phase 0 degrees (high level) until next tone reaches 0 degrees (high level) */
|
|
|
|
if (!transition)
|
2017-01-29 06:25:12 +00:00
|
|
|
*samples++ = dsp_sine_page[(uint16_t)phase[tone]] * anetz->page_gain;
|
2016-11-13 16:45:46 +00:00
|
|
|
else {
|
|
|
|
/* fade between old an new tone */
|
|
|
|
*samples++
|
2017-01-29 06:25:12 +00:00
|
|
|
= (double)dsp_sine_page[(uint16_t)phase[(tone - 1) & 3]] * (double)(transition - count) / (double)transition / 2.0 * anetz->page_gain
|
|
|
|
+ (double)dsp_sine_page[(uint16_t)phase[tone]] * (double)count / (double)transition / 2.0 * anetz->page_gain;
|
2016-11-13 16:45:46 +00:00
|
|
|
}
|
2016-11-13 04:51:09 +00:00
|
|
|
phase[0] += phaseshift[0];
|
|
|
|
phase[1] += phaseshift[1];
|
|
|
|
phase[2] += phaseshift[2];
|
|
|
|
phase[3] += phaseshift[3];
|
2017-01-29 06:25:12 +00:00
|
|
|
if (phase[0] >= 65536) phase[0] -= 65536;
|
|
|
|
if (phase[1] >= 65536) phase[1] -= 65536;
|
|
|
|
if (phase[2] >= 65536) phase[2] -= 65536;
|
|
|
|
if (phase[3] >= 65536) phase[3] -= 65536;
|
2016-11-13 16:45:46 +00:00
|
|
|
count++;
|
|
|
|
if (transition && count == transition) {
|
|
|
|
transition = 0;
|
|
|
|
/* reset counter again, when transition ends */
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
if (count >= numspl) {
|
|
|
|
/* start transition to next tone (lasts 2 ms) */
|
|
|
|
transition = anetz->sender.samplerate / 500;
|
|
|
|
/* reset counter here, when transition starts */
|
2016-03-01 17:40:38 +00:00
|
|
|
count = 0;
|
|
|
|
if (++tone == 4)
|
|
|
|
tone = 0;
|
|
|
|
}
|
|
|
|
length--;
|
|
|
|
}
|
|
|
|
|
|
|
|
anetz->paging_tone = tone;
|
|
|
|
anetz->paging_count = count;
|
2016-11-13 16:45:46 +00:00
|
|
|
anetz->paging_transition = transition;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate audio stream from tone. Keep phase for next call of function. */
|
2017-01-27 15:57:34 +00:00
|
|
|
static void fsk_tone(anetz_t *anetz, sample_t *samples, int length)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
double phaseshift, phase;
|
|
|
|
int i;
|
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
phaseshift = anetz->tone_phaseshift65536;
|
|
|
|
phase = anetz->tone_phase65536;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
for (i = 0; i < length; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
*samples++ = dsp_sine_tone[(uint16_t)phase];
|
2016-03-01 17:40:38 +00:00
|
|
|
phase += phaseshift;
|
2017-01-29 06:25:12 +00:00
|
|
|
if (phase >= 65536)
|
|
|
|
phase -= 65536;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
anetz->tone_phase65536 = phase;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Provide stream of audio toward radio unit */
|
2017-08-19 10:27:05 +00:00
|
|
|
void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
anetz_t *anetz = (anetz_t *) sender;
|
|
|
|
|
2017-08-19 10:27:05 +00:00
|
|
|
memset(power, 1, length);
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
switch (anetz->dsp_mode) {
|
|
|
|
case DSP_MODE_SILENCE:
|
|
|
|
memset(samples, 0, length * sizeof(*samples));
|
|
|
|
break;
|
|
|
|
case DSP_MODE_AUDIO:
|
2017-01-04 13:14:02 +00:00
|
|
|
jitter_load(&anetz->sender.dejitter, samples, length);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
|
|
|
case DSP_MODE_TONE:
|
|
|
|
fsk_tone(anetz, samples, length);
|
|
|
|
break;
|
|
|
|
case DSP_MODE_PAGING:
|
2016-11-13 04:51:09 +00:00
|
|
|
if (anetz->page_sequence)
|
|
|
|
fsk_paging_tone_sequence(anetz, samples, length, anetz->page_sequence * anetz->sender.samplerate / 1000);
|
2016-03-01 17:40:38 +00:00
|
|
|
else
|
|
|
|
fsk_paging_tone(anetz, samples, length);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-09 15:34:33 +00:00
|
|
|
const char *anetz_dsp_mode_name(enum dsp_mode mode)
|
|
|
|
{
|
|
|
|
static char invalid[16];
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case DSP_MODE_SILENCE:
|
|
|
|
return "SILENCE";
|
|
|
|
case DSP_MODE_AUDIO:
|
|
|
|
return "AUDIO";
|
|
|
|
case DSP_MODE_TONE:
|
|
|
|
return "TONE";
|
|
|
|
case DSP_MODE_PAGING:
|
|
|
|
return "PAGING";
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(invalid, "invalid(%d)", mode);
|
|
|
|
return invalid;
|
|
|
|
}
|
|
|
|
|
2017-01-02 09:13:43 +00:00
|
|
|
void anetz_set_dsp_mode(anetz_t *anetz, enum dsp_mode mode, int detect_reset)
|
2016-06-04 13:14:20 +00:00
|
|
|
{
|
2016-12-09 15:34:33 +00:00
|
|
|
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "DSP mode %s -> %s\n", anetz_dsp_mode_name(anetz->dsp_mode), anetz_dsp_mode_name(mode));
|
2016-06-04 13:14:20 +00:00
|
|
|
anetz->dsp_mode = mode;
|
2016-11-13 16:45:46 +00:00
|
|
|
/* reset sequence paging */
|
|
|
|
anetz->paging_tone = 0;
|
|
|
|
anetz->paging_count = 0;
|
|
|
|
anetz->paging_transition = 0;
|
2017-01-02 09:13:43 +00:00
|
|
|
/* reset tone detector */
|
|
|
|
if (detect_reset)
|
|
|
|
anetz->tone_detected = -1;
|
2016-06-04 13:14:20 +00:00
|
|
|
}
|
|
|
|
|