SDR: Turn TX power off if requested by network
The power level is ramped smoothly within 1 ms up or down. R2000, AMPS and C-Netz turn off power when voice channel is not i use. C-Netz turns off power between OgK timeslots.
This commit is contained in:
@@ -690,6 +690,7 @@ void process_call(int c)
|
||||
|
||||
/* handle audio, if sound device is used */
|
||||
sample_t samples[call.latspl + 10], *samples_list[1];
|
||||
uint8_t *power_list[1];
|
||||
int count;
|
||||
int rc;
|
||||
|
||||
@@ -725,7 +726,8 @@ void process_call(int c)
|
||||
jitter_load(&call.dejitter, samples, count);
|
||||
}
|
||||
samples_list[0] = samples;
|
||||
rc = sound_write(call.sound, samples_list, count, NULL, NULL, 1);
|
||||
power_list[0] = NULL;
|
||||
rc = sound_write(call.sound, samples_list, power_list, count, NULL, NULL, 1);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc);
|
||||
if (rc == -EPIPE)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include "sample.h"
|
||||
#include "fm_modulation.h"
|
||||
@@ -30,17 +31,30 @@
|
||||
/* init FM modulator */
|
||||
int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(mod, 0, sizeof(*mod));
|
||||
mod->samplerate = samplerate;
|
||||
mod->offset = offset;
|
||||
mod->amplitude = amplitude;
|
||||
|
||||
#ifdef FAST_SINE
|
||||
int i;
|
||||
mod->ramp_length = samplerate * 0.001;
|
||||
mod->ramp_tab = calloc(mod->ramp_length, sizeof(*mod->ramp_tab));
|
||||
if (!mod->ramp_tab) {
|
||||
fprintf(stderr, "No mem!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
mod->state = MOD_STATE_OFF;
|
||||
|
||||
/* generate ramp up with ramp_length */
|
||||
for (i = 0; i < mod->ramp_length; i++)
|
||||
mod->ramp_tab[i] = 0.5 - cos(M_PI * i / mod->ramp_length) / 2.0;
|
||||
|
||||
#ifdef FAST_SINE
|
||||
mod->sin_tab = calloc(65536+16384, sizeof(*mod->sin_tab));
|
||||
if (!mod->sin_tab) {
|
||||
fprintf(stderr, "No mem!\n");
|
||||
fm_mod_exit(mod);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -54,6 +68,10 @@ int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitud
|
||||
|
||||
void fm_mod_exit(fm_mod_t *mod)
|
||||
{
|
||||
if (mod->ramp_tab) {
|
||||
free(mod->ramp_tab);
|
||||
mod->ramp_tab = NULL;
|
||||
}
|
||||
if (mod->sin_tab) {
|
||||
free(mod->sin_tab);
|
||||
mod->sin_tab = NULL;
|
||||
@@ -61,10 +79,11 @@ void fm_mod_exit(fm_mod_t *mod)
|
||||
}
|
||||
|
||||
/* do frequency modulation of samples and add them to existing baseband */
|
||||
void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, int length, float *baseband)
|
||||
void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int length, float *baseband)
|
||||
{
|
||||
double dev, rate, phase, offset;
|
||||
int s, ss;
|
||||
int ramp, ramp_length;
|
||||
double *ramp_tab;
|
||||
#ifdef FAST_SINE
|
||||
double *sin_tab, *cos_tab;
|
||||
#else
|
||||
@@ -74,6 +93,9 @@ void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, int length, float *
|
||||
rate = mod->samplerate;
|
||||
phase = mod->phase;
|
||||
offset = mod->offset;
|
||||
ramp = mod->ramp;
|
||||
ramp_length = mod->ramp_length;
|
||||
ramp_tab = mod->ramp_tab;
|
||||
#ifdef FAST_SINE
|
||||
sin_tab = mod->sin_tab;
|
||||
cos_tab = mod->sin_tab + 16384;
|
||||
@@ -81,30 +103,127 @@ void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, int length, float *
|
||||
amplitude = mod->amplitude;
|
||||
#endif
|
||||
|
||||
/* modulate */
|
||||
for (s = 0, ss = 0; s < length; s++) {
|
||||
/* deviation is defined by the frequency value and the offset */
|
||||
dev = offset + frequency[s];
|
||||
again:
|
||||
switch (mod->state) {
|
||||
case MOD_STATE_ON:
|
||||
/* modulate */
|
||||
while (length) {
|
||||
/* is power is not set, ramp down */
|
||||
if (!(*power)) {
|
||||
mod->state = MOD_STATE_RAMP_DOWN;
|
||||
break;
|
||||
}
|
||||
/* deviation is defined by the frequency value and the offset */
|
||||
dev = offset + *frequency++;
|
||||
power++;
|
||||
length--;
|
||||
#ifdef FAST_SINE
|
||||
phase += 65536.0 * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 65536.0;
|
||||
else if (phase >= 65536.0)
|
||||
phase -= 65536.0;
|
||||
baseband[ss++] += cos_tab[(uint16_t)phase];
|
||||
baseband[ss++] += sin_tab[(uint16_t)phase];
|
||||
phase += 65536.0 * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 65536.0;
|
||||
else if (phase >= 65536.0)
|
||||
phase -= 65536.0;
|
||||
*baseband++ += cos_tab[(uint16_t)phase];
|
||||
*baseband++ += sin_tab[(uint16_t)phase];
|
||||
#else
|
||||
phase += 2.0 * M_PI * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 2.0 * M_PI;
|
||||
else if (phase >= 2.0 * M_PI)
|
||||
phase -= 2.0 * M_PI;
|
||||
baseband[ss++] += cos(phase) * amplitude;
|
||||
baseband[ss++] += sin(phase) * amplitude;
|
||||
phase += 2.0 * M_PI * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 2.0 * M_PI;
|
||||
else if (phase >= 2.0 * M_PI)
|
||||
phase -= 2.0 * M_PI;
|
||||
*baseband++ += cos(phase) * amplitude;
|
||||
*baseband++ += sin(phase) * amplitude;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case MOD_STATE_RAMP_DOWN:
|
||||
while (length) {
|
||||
/* if power is set, ramp up */
|
||||
if (*power) {
|
||||
mod->state = MOD_STATE_RAMP_UP;
|
||||
break;
|
||||
}
|
||||
if (ramp == 0) {
|
||||
mod->state = MOD_STATE_OFF;
|
||||
break;
|
||||
}
|
||||
dev = offset + *frequency++;
|
||||
power++;
|
||||
length--;
|
||||
#ifdef FAST_SINE
|
||||
phase += 65536.0 * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 65536.0;
|
||||
else if (phase >= 65536.0)
|
||||
phase -= 65536.0;
|
||||
*baseband++ += cos_tab[(uint16_t)phase] * ramp_tab[ramp];
|
||||
*baseband++ += sin_tab[(uint16_t)phase] * ramp_tab[ramp];
|
||||
#else
|
||||
phase += 2.0 * M_PI * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 2.0 * M_PI;
|
||||
else if (phase >= 2.0 * M_PI)
|
||||
phase -= 2.0 * M_PI;
|
||||
*baseband++ += cos(phase) * amplitude * ramp_tab[ramp];
|
||||
*baseband++ += sin(phase) * amplitude * ramp_tab[ramp];
|
||||
#endif
|
||||
ramp--;
|
||||
}
|
||||
break;
|
||||
case MOD_STATE_OFF:
|
||||
while (length) {
|
||||
/* if power is set, ramp up */
|
||||
if (*power) {
|
||||
mod->state = MOD_STATE_RAMP_UP;
|
||||
break;
|
||||
}
|
||||
frequency++;
|
||||
power++;
|
||||
length--;
|
||||
baseband += 2;
|
||||
}
|
||||
break;
|
||||
case MOD_STATE_RAMP_UP:
|
||||
while (length) {
|
||||
/* is power is not set, ramp down */
|
||||
if (!(*power)) {
|
||||
mod->state = MOD_STATE_RAMP_DOWN;
|
||||
break;
|
||||
}
|
||||
if (ramp == ramp_length - 1) {
|
||||
mod->state = MOD_STATE_ON;
|
||||
break;
|
||||
}
|
||||
/* deviation is defined by the frequency value and the offset */
|
||||
dev = offset + *frequency++;
|
||||
power++;
|
||||
length--;
|
||||
#ifdef FAST_SINE
|
||||
phase += 65536.0 * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 65536.0;
|
||||
else if (phase >= 65536.0)
|
||||
phase -= 65536.0;
|
||||
*baseband++ += cos_tab[(uint16_t)phase] * ramp_tab[ramp];
|
||||
*baseband++ += sin_tab[(uint16_t)phase] * ramp_tab[ramp];
|
||||
#else
|
||||
phase += 2.0 * M_PI * dev / rate;
|
||||
if (phase < 0.0)
|
||||
phase += 2.0 * M_PI;
|
||||
else if (phase >= 2.0 * M_PI)
|
||||
phase -= 2.0 * M_PI;
|
||||
*baseband++ += cos(phase) * amplitude * ramp_tab[ramp];
|
||||
*baseband++ += sin(phase) * amplitude * ramp_tab[ramp];
|
||||
#endif
|
||||
ramp++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (length)
|
||||
goto again;
|
||||
|
||||
mod->phase = phase;
|
||||
mod->ramp = ramp;
|
||||
}
|
||||
|
||||
/* init FM demodulator */
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
#include "../common/iir_filter.h"
|
||||
|
||||
enum fm_mod_state {
|
||||
MOD_STATE_OFF, /* transmitter off, no IQ vector */
|
||||
MOD_STATE_ON, /* transmitter on, FM modulated IQ vector */
|
||||
MOD_STATE_RAMP_UP, /* use half cos to ramp up IQ vector */
|
||||
MOD_STATE_RAMP_DOWN, /* use half cos to ramp down IQ vector */
|
||||
};
|
||||
|
||||
typedef struct fm_mod {
|
||||
double samplerate; /* sample rate of in and out */
|
||||
double offset; /* offset to calculated center frequency */
|
||||
double amplitude; /* how much amplitude to add to the buff */
|
||||
double phase; /* current phase of FM (used to shift and modulate ) */
|
||||
double *sin_tab; /* sine/cosine table for modulation */
|
||||
enum fm_mod_state state;/* state of transmit power */
|
||||
double *ramp_tab; /* half cosine ramp up */
|
||||
int ramp; /* current ramp position */
|
||||
int ramp_length; /* number of values in ramp */
|
||||
} fm_mod_t;
|
||||
|
||||
int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude);
|
||||
void fm_mod_exit(fm_mod_t *mod);
|
||||
void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, int num, float *baseband);
|
||||
void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int num, float *baseband);
|
||||
|
||||
typedef struct fm_demod {
|
||||
double samplerate; /* sample rate of in and out */
|
||||
|
||||
@@ -557,7 +557,7 @@ void sdr_close(void *inst)
|
||||
}
|
||||
}
|
||||
|
||||
int sdr_write(void *inst, sample_t **samples, int num, enum paging_signal __attribute__((unused)) *paging_signal, int *on, int channels)
|
||||
int sdr_write(void *inst, sample_t **samples, uint8_t **power, int num, enum paging_signal __attribute__((unused)) *paging_signal, int *on, int channels)
|
||||
{
|
||||
sdr_t *sdr = (sdr_t *)inst;
|
||||
float buffer[num * 2], *buff = NULL;
|
||||
@@ -576,9 +576,9 @@ int sdr_write(void *inst, sample_t **samples, int num, enum paging_signal __attr
|
||||
for (c = 0; c < channels; c++) {
|
||||
/* switch to paging channel, if requested */
|
||||
if (on[c] && sdr->paging_channel)
|
||||
fm_modulate_complex(&sdr->chan[sdr->paging_channel].mod, samples[c], num, buff);
|
||||
fm_modulate_complex(&sdr->chan[sdr->paging_channel].mod, samples[c], power[c], num, buff);
|
||||
else
|
||||
fm_modulate_complex(&sdr->chan[c].mod, samples[c], num, buff);
|
||||
fm_modulate_complex(&sdr->chan[c].mod, samples[c], power[c], num, buff);
|
||||
}
|
||||
} else {
|
||||
buff = (float *)samples;
|
||||
|
||||
@@ -3,7 +3,7 @@ int sdr_init(int sdr_uhd, int sdr_soapy, int channel, const char *device_args, c
|
||||
int sdr_start(void *inst);
|
||||
void *sdr_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, double bandwidth, double sample_deviation);
|
||||
void sdr_close(void *inst);
|
||||
int sdr_write(void *inst, sample_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels);
|
||||
int sdr_write(void *inst, sample_t **samples, uint8_t **power, int num, enum paging_signal *paging_signal, int *on, int channels);
|
||||
int sdr_read(void *inst, sample_t **samples, int num, int channels);
|
||||
int sdr_get_tosend(void *inst, int latspl);
|
||||
|
||||
|
||||
@@ -298,10 +298,12 @@ void process_sender_audio(sender_t *sender, int *quit, int latspl)
|
||||
/* count instances for audio channel */
|
||||
for (num_chan = 0, inst = sender; inst; num_chan++, inst = inst->slave);
|
||||
sample_t buff[num_chan][latspl], *samples[num_chan];
|
||||
uint8_t pbuff[num_chan][latspl], *power[num_chan];
|
||||
enum paging_signal paging_signal[num_chan];
|
||||
int on[num_chan];
|
||||
for (i = 0; i < num_chan; i++) {
|
||||
samples[i] = buff[i];
|
||||
power[i] = pbuff[i];
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIME_CONSUMPTION
|
||||
@@ -334,7 +336,7 @@ cant_recover:
|
||||
if (inst->loopback == 3)
|
||||
jitter_load(&inst->dejitter, samples[i], count);
|
||||
else
|
||||
sender_send(inst, samples[i], count);
|
||||
sender_send(inst, samples[i], power[i], count);
|
||||
/* internal loopback: loop back TX audio to RX */
|
||||
if (inst->loopback == 1) {
|
||||
display_wave(inst, samples[i], count, inst->max_display);
|
||||
@@ -358,7 +360,7 @@ cant_recover:
|
||||
if (sender->wave_tx_play.fp)
|
||||
wave_read(&sender->wave_tx_play, samples, count);
|
||||
|
||||
rc = sender->audio_write(sender->audio, samples, count, paging_signal, on, num_chan);
|
||||
rc = sender->audio_write(sender->audio, samples, power, count, paging_signal, on, num_chan);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc);
|
||||
if (rc == -EPIPE) {
|
||||
|
||||
@@ -44,7 +44,7 @@ typedef struct sender {
|
||||
void *(*audio_open)(const char *, double *, double *, int, double, int, double, double);
|
||||
int (*audio_start)(void *);
|
||||
void (*audio_close)(void *);
|
||||
int (*audio_write)(void *, sample_t **, int, enum paging_signal *, int *, int);
|
||||
int (*audio_write)(void *, sample_t **, uint8_t **, int, enum paging_signal *, int *, int);
|
||||
int (*audio_read)(void *, sample_t **, int, int);
|
||||
int (*audio_get_tosend)(void *, int);
|
||||
int samplerate;
|
||||
@@ -96,7 +96,7 @@ void sender_set_fm(sender_t *sender, double max_deviation, double max_modulation
|
||||
int sender_open_audio(void);
|
||||
int sender_start_audio(void);
|
||||
void process_sender_audio(sender_t *sender, int *quit, int latspl);
|
||||
void sender_send(sender_t *sender, sample_t *samples, int count);
|
||||
void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int count);
|
||||
void sender_receive(sender_t *sender, sample_t *samples, int count);
|
||||
void sender_paging(sender_t *sender, int on);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ enum paging_signal;
|
||||
void *sound_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, double bandwidth, double sample_deviation);
|
||||
int sound_start(void *inst);
|
||||
void sound_close(void *inst);
|
||||
int sound_write(void *inst, sample_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels);
|
||||
int sound_write(void *inst, sample_t **samples, uint8_t **power, int num, enum paging_signal *paging_signal, int *on, int channels);
|
||||
int sound_read(void *inst, sample_t **samples, int num, int channels);
|
||||
int sound_get_tosend(void *inst, int latspl);
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ static void gen_paging_tone(sound_t *sound, int16_t *samples, int length, enum p
|
||||
}
|
||||
}
|
||||
|
||||
int sound_write(void *inst, sample_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels)
|
||||
int sound_write(void *inst, sample_t **samples, uint8_t __attribute__((unused)) **power, int num, enum paging_signal *paging_signal, int *on, int channels)
|
||||
{
|
||||
sound_t *sound = (sound_t *)inst;
|
||||
double spl_deviation = sound->spl_deviation;
|
||||
|
||||
Reference in New Issue
Block a user