From ba036de22680c5f46983f30144c23d212245842f Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 25 Sep 2017 18:46:50 +0200 Subject: Add function to display measurements on screen Use 'm' key to toggle display. --- src/amps/amps.h | 4 + src/amps/dsp.c | 7 + src/anetz/anetz.h | 4 + src/anetz/dsp.c | 38 ++-- src/bnetz/bnetz.c | 6 +- src/bnetz/bnetz.h | 7 + src/bnetz/dsp.c | 27 ++- src/cnetz/fsk_demod.c | 6 + src/cnetz/fsk_demod.h | 4 + src/common/Makefile.am | 3 +- src/common/debug.c | 2 + src/common/display.h | 45 ++++- src/common/display_iq.c | 2 - src/common/display_measurements.c | 359 ++++++++++++++++++++++++++++++++++++++ src/common/display_status.c | 2 +- src/common/display_wave.c | 2 - src/common/main_mobile.c | 31 +++- src/common/sdr.c | 46 ++++- src/common/sender.c | 23 ++- src/common/sender.h | 4 + src/common/sound_alsa.c | 48 ++++- src/nmt/dsp.c | 7 + src/nmt/nmt.h | 4 + src/r2000/dsp.c | 15 ++ src/r2000/r2000.h | 6 + src/tv/main.c | 1 + 26 files changed, 651 insertions(+), 52 deletions(-) create mode 100644 src/common/display_measurements.c (limited to 'src') diff --git a/src/amps/amps.h b/src/amps/amps.h index 5f82a23..d909208 100644 --- a/src/amps/amps.h +++ b/src/amps/amps.h @@ -46,6 +46,10 @@ typedef struct amps { enum amps_state state; int channel_busy; /* indicate channel is busy while receiving */ + /* display measurements */ + dispmeasparam_t *dmp_frame_level; + dispmeasparam_t *dmp_frame_quality; + /* system info */ amps_si si; diff --git a/src/amps/dsp.c b/src/amps/dsp.c index 95a0c09..2415f0a 100644 --- a/src/amps/dsp.c +++ b/src/amps/dsp.c @@ -268,6 +268,9 @@ int dsp_init_sender(amps_t *amps, int tolerant) /* be more tolerant when syncing */ amps->fsk_rx_sync_tolerant = tolerant; + amps->dmp_frame_level = display_measurements_add(&s->sender, "Frame Level", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + amps->dmp_frame_quality = display_measurements_add(&s->sender, "Frame Quality", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + return 0; error: @@ -606,6 +609,10 @@ prepare_frame: if (amps->fsk_rx_frame_count == amps->fsk_rx_frame_length) { int more; + /* update measurements */ + display_measurements_update(amps->dmp_frame_level, amps->fsk_rx_frame_level / (double)amps->fsk_rx_frame_count * 100.0, 0.0); + display_measurements_update(amps->dmp_frame_quality, amps->fsk_rx_frame_quality / (double)amps->fsk_rx_frame_count * 100.0, 0.0); + /* a complete frame was received, so we process it */ amps->fsk_rx_frame[amps->fsk_rx_frame_count] = '\0'; more = amps_decode_frame(amps, amps->fsk_rx_frame, amps->fsk_rx_frame_count, amps->fsk_rx_frame_level / (double)amps->fsk_rx_frame_count, amps->fsk_rx_frame_quality / amps->fsk_rx_frame_level, (amps->fsk_rx_sync == FSK_SYNC_NEGATIVE)); diff --git a/src/anetz/anetz.h b/src/anetz/anetz.h index dcfdb02..b43c5be 100644 --- a/src/anetz/anetz.h +++ b/src/anetz/anetz.h @@ -25,6 +25,10 @@ typedef struct anetz { char station_id[8]; /* current station ID */ struct timer timer; + /* display measurements */ + dispmeasparam_t *dmp_tone_level; + dispmeasparam_t *dmp_tone_quality; + /* dsp states */ enum dsp_mode dsp_mode; /* current mode: audio, durable tone 0 or 1, paging */ goertzel_t fsk_tone_goertzel[2]; /* filter for tone decoding */ diff --git a/src/anetz/dsp.c b/src/anetz/dsp.c index f133aa0..266f4d6 100644 --- a/src/anetz/dsp.c +++ b/src/anetz/dsp.c @@ -42,6 +42,8 @@ #define TX_PEAK_PAGE (15000.0 / DBM0_DEVIATION) /* 15 kHz, no emphasis */ #define MAX_DISPLAY (15000.0 / DBM0_DEVIATION) /* 15 kHz, no emphasis */ #define CHUNK_DURATION 0.010 /* 10 ms */ +#define TONE_THRESHOLD 0.05 +#define QUAL_THRESHOLD 0.5 // FIXME: how long until we detect a tone? #define TONE_DETECT_TH 8 /* chunk intervals to detect continuous tone */ @@ -108,6 +110,9 @@ int dsp_init_sender(anetz_t *anetz, double page_gain, int page_sequence) anetz->tone_phaseshift65536 = 65536.0 / ((double)anetz->sender.samplerate / tone); PDEBUG(DDSP, DEBUG_DEBUG, "TX %.0f Hz phaseshift = %.4f\n", tone, anetz->tone_phaseshift65536); + 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); + return 0; } @@ -123,7 +128,7 @@ void dsp_cleanup_sender(anetz_t *anetz) } /* Count duration of tone and indicate detection/loss to protocol handler. */ -static void fsk_receive_tone(anetz_t *anetz, int tone, int goodtone, double level) +static void fsk_receive_tone(anetz_t *anetz, int tone, int goodtone, double level, double quality) { /* lost tone because it is not good anymore or has changed */ if (!goodtone || tone != anetz->tone_detected) { @@ -145,7 +150,7 @@ static void fsk_receive_tone(anetz_t *anetz, int tone, int goodtone, double leve if (anetz->tone_count >= TONE_DETECT_TH) audio_reset_loss(&anetz->sender.loss); if (anetz->tone_count == TONE_DETECT_TH) { - PDEBUG_CHAN(DDSP, DEBUG_INFO, "Detecting continuous %.0f Hz tone. (level = %d%%)\n", fsk_tones[anetz->tone_detected], (int)(level * 100.0 + 0.5)); + 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); anetz_receive_tone(anetz, anetz->tone_detected); } } @@ -153,7 +158,7 @@ static void fsk_receive_tone(anetz_t *anetz, int tone, int goodtone, double leve /* Filter one chunk of audio an detect tone, quality and loss of signal. */ static void fsk_decode_chunk(anetz_t *anetz, sample_t *spl, int max) { - double level, result[2]; + double level, result[2], quality[2]; level = audio_level(spl, max); @@ -162,22 +167,25 @@ static void fsk_decode_chunk(anetz_t *anetz, sample_t *spl, int max) audio_goertzel(anetz->fsk_tone_goertzel, spl, max, 0, result, 2); - /* show quality of tone */ - if (anetz->sender.loopback) { - /* adjust level, so we get peak of sine curve */ - PDEBUG_CHAN(DDSP, DEBUG_NOTICE, "Tone %.0f: Level=%3.0f%% Quality=%3.0f%%\n", fsk_tones[1], level / 0.63662 * 100.0 / TX_PEAK_TONE, result[1] / level * 100.0); - } - if (level / 0.63 > 0.05 && result[0] / level > 0.5) - PDEBUG_CHAN(DDSP, DEBUG_INFO, "Tone %.0f: Level=%3.0f%% Quality=%3.0f%%\n", fsk_tones[0], level / 0.63662 * 100.0 / TX_PEAK_TONE, result[0] / level * 100.0); + /* 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); /* adjust level, so we get peak of sine curve */ /* indicate detected tone */ - if (level / 0.63 > 0.05 && result[0] / level > 0.5) - fsk_receive_tone(anetz, 0, 1, level / 0.63662 / TX_PEAK_TONE); - else if (level / 0.63 > 0.05 && result[1] / level > 0.5) - fsk_receive_tone(anetz, 1, 1, level / 0.63662 / TX_PEAK_TONE); + 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]); else - fsk_receive_tone(anetz, -1, 0, level / 0.63662 / TX_PEAK_TONE); + fsk_receive_tone(anetz, -1, 0, level, 0.0); } /* Process received audio stream from radio unit. */ diff --git a/src/bnetz/bnetz.c b/src/bnetz/bnetz.c index d9ccf3d..fc09893 100644 --- a/src/bnetz/bnetz.c +++ b/src/bnetz/bnetz.c @@ -445,16 +445,16 @@ void bnetz_receive_tone(bnetz_t *bnetz, int bit) } /* A digit was received. */ -void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm, double level_avg, double level_dev, double quality_avg) +void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm, double level_avg, double level_stddev, double quality_avg) { struct impulstelegramm *it; int digit = 0; /* drop any telegramm that is too bad */ - if (level_dev / level_avg > 0.2) + if (level_stddev / level_avg > 0.2) return; - PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: average=%.0f%% deviation=%.0f%% Quality: %.0f%%\n", level_avg * 100.0, level_dev / level_avg * 100.0, quality_avg * 100.0); + PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: average=%.0f%% standard deviation=%.0f%% Quality: %.0f%%\n", level_avg * 100.0, level_stddev / level_avg * 100.0, quality_avg * 100.0); it = bnetz_telegramm2digit(telegramm); if (it) { diff --git a/src/bnetz/bnetz.h b/src/bnetz/bnetz.h index 8f6cd64..608f067 100644 --- a/src/bnetz/bnetz.h +++ b/src/bnetz/bnetz.h @@ -75,6 +75,13 @@ typedef struct bnetz { struct timer timer; int trenn_count; /* count number of release messages */ + /* display measurements */ + dispmeasparam_t *dmp_tone_level; + dispmeasparam_t *dmp_tone_quality; + dispmeasparam_t *dmp_frame_level; + dispmeasparam_t *dmp_frame_stddev; + dispmeasparam_t *dmp_frame_quality; + /* dsp states */ enum dsp_mode dsp_mode; /* current mode: audio, durable tone 0 or 1, "Telegramm" */ fsk_t fsk; /* fsk modem instance */ diff --git a/src/bnetz/dsp.c b/src/bnetz/dsp.c index e8b4a2d..8d830be 100644 --- a/src/bnetz/dsp.c +++ b/src/bnetz/dsp.c @@ -112,6 +112,12 @@ int dsp_init_sender(bnetz_t *bnetz) bnetz->meter_phaseshift65536 = 65536.0 / ((double)bnetz->sender.samplerate / METERING_HZ); PDEBUG(DDSP, DEBUG_DEBUG, "dial_phaseshift = %.4f\n", bnetz->meter_phaseshift65536); + bnetz->dmp_tone_level = display_measurements_add(&bnetz->sender, "Tone Level", "%.1f %%", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + bnetz->dmp_tone_quality = display_measurements_add(&bnetz->sender, "Tone Quality", "%.1f %%", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + bnetz->dmp_frame_level = display_measurements_add(&bnetz->sender, "Frame Level", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + bnetz->dmp_frame_stddev = display_measurements_add(&bnetz->sender, "Frame Stddev", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + bnetz->dmp_frame_quality = display_measurements_add(&bnetz->sender, "Frame Quality", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + return 0; } @@ -161,13 +167,17 @@ static void fsk_receive_tone(bnetz_t *bnetz, int bit, int goodtone, double level /* Collect 16 data bits (digit) and check for sync mark '01110'. */ static void fsk_receive_bit(void *inst, int bit, double quality, double level) { - double level_avg, level_dev, quality_avg; + double level_avg, level_stddev, quality_avg; bnetz_t *bnetz = (bnetz_t *)inst; int i; /* normalize FSK level */ level /= TX_PEAK_FSK; + /* update measurements */ + display_measurements_update(bnetz->dmp_tone_level, level * 100.0 , 0.0); + display_measurements_update(bnetz->dmp_tone_quality, quality * 100.0, 0.0); + /* continuous tone detection */ if (level > 0.10 && quality > 0.10) { fsk_receive_tone(bnetz, bit, 1, level, quality); @@ -188,7 +198,7 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level) return; /* average level and quality */ - level_avg = level_dev = quality_avg = 0; + level_avg = level_stddev = quality_avg = 0; for (i = 0; i < 16; i++) { level_avg += bnetz->rx_telegramm_level[bnetz->rx_telegramm_qualidx]; quality_avg += bnetz->rx_telegramm_quality[bnetz->rx_telegramm_qualidx]; @@ -198,14 +208,19 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level) level_avg /= 16.0; quality_avg /= 16.0; for (i = 0; i < 16; i++) { level = bnetz->rx_telegramm_level[bnetz->rx_telegramm_qualidx]; - level_dev += (level - level_avg) * (level - level_avg); + level_stddev += (level - level_avg) * (level - level_avg); if (++bnetz->rx_telegramm_qualidx == 16) bnetz->rx_telegramm_qualidx = 0; } - level_dev = sqrt(level_dev / 16.0); + level_stddev = sqrt(level_stddev / 16.0); + + /* update measurements */ + display_measurements_update(bnetz->dmp_frame_level, level_avg * 100.0 , 0.0); + display_measurements_update(bnetz->dmp_frame_stddev, level_stddev / level_avg * 100.0, 0.0); + display_measurements_update(bnetz->dmp_frame_quality, quality_avg * 100.0, 0.0); - /* send telegramm */ - bnetz_receive_telegramm(bnetz, bnetz->rx_telegramm, level_avg, level_dev, quality_avg); + /* receive telegramm */ + bnetz_receive_telegramm(bnetz, bnetz->rx_telegramm, level_avg, level_stddev, quality_avg); } /* Process received audio stream from radio unit. */ diff --git a/src/cnetz/fsk_demod.c b/src/cnetz/fsk_demod.c index 3164217..6a921b7 100644 --- a/src/cnetz/fsk_demod.c +++ b/src/cnetz/fsk_demod.c @@ -192,6 +192,9 @@ int fsk_fm_init(fsk_fm_demod_t *fsk, cnetz_t *cnetz, int samplerate, double bitr printf("**** Writing decoder debug file '%s' ****\n", debug_filename); #endif + fsk->dmp_frame_level = display_measurements_add(&cnetz->sender, "Frame Level", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + fsk->dmp_frame_stddev = display_measurements_add(&cnetz->sender, "Frame Stddev", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + return 0; error: @@ -393,6 +396,9 @@ got_sync: /* received 662 bits after start of block (10 SPK blocks + 1 bit (== 2 level changes)) */ fsk->sync_time = fmod(fsk->sync_time - (66*10+2) + BITS_PER_SUPERFRAME, BITS_PER_SUPERFRAME); } + /* update measurements */ + display_measurements_update(fsk->dmp_frame_level, fabs(fsk->sync_level) / fsk->cnetz->fsk_deviation * 100.0, 0.0); + display_measurements_update(fsk->dmp_frame_stddev, fsk->sync_stddev / fabs(fsk->sync_level) * 100.0, 0.0); /* receive frame */ cnetz_decode_telegramm(fsk->cnetz, fsk->rx_buffer, fsk->sync_level, fsk->sync_time, fsk->sync_stddev); } diff --git a/src/cnetz/fsk_demod.h b/src/cnetz/fsk_demod.h index addce17..5e45a8b 100644 --- a/src/cnetz/fsk_demod.h +++ b/src/cnetz/fsk_demod.h @@ -56,6 +56,10 @@ typedef struct fsk_fm_demod { double change_when[256]; /* ring buffer to store time when level has changed */ uint8_t change_pos; /* index for next write */ + /* display measurements */ + dispmeasparam_t *dmp_frame_level; + dispmeasparam_t *dmp_frame_stddev; + /* debug */ FILE *debug_fp; /* file pointer for debugging output */ } fsk_fm_demod_t; diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 6cb64b6..0edd221 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -19,7 +19,8 @@ libcommon_a_SOURCES = \ fft.c \ fm_modulation.c \ fsk.c \ - display_wave.c + display_wave.c \ + display_measurements.c libmobile_a_SOURCES = \ sender.c \ diff --git a/src/common/debug.c b/src/common/debug.c index 512596a..d2eedb8 100644 --- a/src/common/debug.c +++ b/src/common/debug.c @@ -100,6 +100,7 @@ void _printdebug(const char *file, const char __attribute__((unused)) *function, // printf("%s%s:%d %s() %s: %s\033[0;39m", debug_cat[cat].color, file, line, function, debug_level[level], buffer); display_wave_limit_scroll(1); display_status_limit_scroll(1); + display_measurements_limit_scroll(1); #ifdef HAVE_SDR display_iq_limit_scroll(1); display_spectrum_limit_scroll(1); @@ -107,6 +108,7 @@ void _printdebug(const char *file, const char __attribute__((unused)) *function, printf("%s%s:%d %s: %s\033[0;39m", debug_cat[cat].color, file, line, debug_level[level], buffer); display_wave_limit_scroll(0); display_status_limit_scroll(0); + display_measurements_limit_scroll(0); #ifdef HAVE_SDR display_iq_limit_scroll(0); display_spectrum_limit_scroll(0); diff --git a/src/common/display.h b/src/common/display.h index 850e4d8..386a2d7 100644 --- a/src/common/display.h +++ b/src/common/display.h @@ -1,4 +1,5 @@ -#define DISPLAY_INTERVAL 0.04 +#define DISPLAY_INTERVAL 0.04 /* time (in seconds) for each interval */ +#define DISPLAY_PARAM_HISTORIES 25 /* number of intervals (should result in one seconds) */ #define MAX_DISPLAY_WIDTH 1024 @@ -11,6 +12,40 @@ typedef struct display_wave { sample_t buffer[MAX_DISPLAY_WIDTH]; } dispwav_t; +enum display_measurements_type { + DISPLAY_MEAS_LAST, /* display last value */ + DISPLAY_MEAS_PEAK, /* display peak value */ + DISPLAY_MEAS_PEAK2PEAK, /* display peak value of min..max range */ + DISPLAY_MEAS_AVG, /* display average value */ +}; + +enum display_measurements_bar { + DISPLAY_MEAS_LEFT, /* bar graph from left */ + DISPLAY_MEAS_CENTER, /* bar graph from center */ +}; + +typedef struct display_measurements_param { + struct display_measurements_param *next; + char name[32]; /* parameter name (e.g. 'Deviation') */ + char format[32]; /* unit name (e.g. "%.2f KHz") */ + enum display_measurements_type type; + enum display_measurements_bar bar; + double min; /* minimum value */ + double max; /* maximum value */ + double mark; /* mark (target) value */ + double value; /* current value (peak, sum...) */ + double value2; /* max value for min..max range */ + double last; /* last valid value (used for DISPLAY_MEAS_LAST) */ + int value_count; /* count number of values of one interval */ + double value_history[DISPLAY_PARAM_HISTORIES]; /* history of values of last second */ + double value2_history[DISPLAY_PARAM_HISTORIES]; /* stores max for min..max range */ + int value_history_pos; /* next history value to write */ +} dispmeasparam_t; + +typedef struct display_measurements { + dispmeasparam_t *head; +} dispmeas_t; + #define MAX_DISPLAY_IQ 1024 typedef struct display_iq { @@ -44,6 +79,14 @@ void display_status_channel(int channel, const char *type, const char *state); void display_status_subscriber(const char *number, const char *state); void display_status_end(void); +void display_measurements_init(sender_t *sender, int samplerate); +void display_measurements_exit(sender_t *sender); +void display_measurements_on(int on); +void display_measurements_limit_scroll(int on); +dispmeasparam_t *display_measurements_add(sender_t *sender, char *name, char *format, enum display_measurements_type type, enum display_measurements_bar bar, double min, double max, double mark); +void display_measurements_update(dispmeasparam_t *param, double value, double value2); +void display_measurements(double elapsed); + void display_iq_init(int samplerate); void display_iq_on(int on); void display_iq_limit_scroll(int on); diff --git a/src/common/display_iq.c b/src/common/display_iq.c index 14e17a4..c63a455 100644 --- a/src/common/display_iq.c +++ b/src/common/display_iq.c @@ -26,8 +26,6 @@ #include "sample.h" #include "sender.h" -#define DISPLAY_INTERVAL 0.04 - /* must be odd value! */ #define SIZE 23 diff --git a/src/common/display_measurements.c b/src/common/display_measurements.c new file mode 100644 index 0000000..103384d --- /dev/null +++ b/src/common/display_measurements.c @@ -0,0 +1,359 @@ +/* display measurements functions + * + * (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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sample.h" +#include "sender.h" + +#define MAX_NAME_LEN 16 +#define MAX_UNIT_LEN 16 + +static int has_init = 0; +static int measurements_on = 0; +double time_elapsed = 0.0; +static int lines_total = 0; +static char line[MAX_DISPLAY_WIDTH]; +static char line_color[MAX_DISPLAY_WIDTH]; + +void display_measurements_init(sender_t *sender, int __attribute__((unused)) samplerate) +{ + dispmeas_t *disp = &sender->dispmeas; + + memset(disp, 0, sizeof(*disp)); + has_init = 1; + lines_total = 0; + time_elapsed = 0.0; +} + +void display_measurements_exit(sender_t *sender) +{ + dispmeas_t *disp = &sender->dispmeas; + dispmeasparam_t *param = disp->head, *temp; + + while (param) { + temp = param; + param = param->next; + free(temp); + } + disp->head = NULL; + has_init = 0; +} + +static int color; + +static void display_line(int on, int w) +{ + int j; + + if (on) { + for (j = 0; j < w; j++) { + if (line_color[j] != color && line[j] != ' ') { + color = line_color[j]; + printf("\033[%d;3%dm", color / 10, color % 10); + } + putchar(line[j]); + } + } else { + for (j = 0; j < w; j++) + putchar(' '); + } + putchar('\n'); + lines_total++; +} + +static void print_measurements(int on) +{ + sender_t *sender; + dispmeasparam_t *param; + int i, j; + int width, h; + char text[128]; + double value = 0.0, value2 = 0.0, hold, hold2; + int bar_width, bar_left, bar_right, bar_hold, bar_mark; + + get_win_size(&width, &h); + + /* no display, if bar graph is less than one character */ + bar_width = width - MAX_NAME_LEN - MAX_UNIT_LEN; + if (bar_width < 1) + return; + + lines_total = 0; + color = -1; + printf("\0337\033[H"); + for (sender = sender_head; sender; sender = sender->next) { + memset(line, ' ', width); + memset(line_color, 7, width); + sprintf(line, "(chan %d", sender->kanal); + *strchr(line, '\0') = ')'; + display_line(on, width); + for (param = sender->dispmeas.head; param; param = param->next) { + memset(line, ' ', width); + memset(line_color, 7, width); + memset(line_color, 3, MAX_NAME_LEN); /* yellow */ + switch (param->type) { + case DISPLAY_MEAS_LAST: + value = param->value; + param->value = -NAN; + break; + case DISPLAY_MEAS_PEAK: + /* peak value */ + value = param->value; + param->value = -NAN; + param->value_count = 0; + break; + case DISPLAY_MEAS_PEAK2PEAK: + /* peak to peak value */ + value = param->value; + value2 = param->value2; + param->value = -NAN; + param->value2 = -NAN; + param->value_count = 0; + break; + case DISPLAY_MEAS_AVG: + /* average value */ + if (param->value_count) + value = param->value / (double)param->value_count; + else + value = -NAN; + param->value = 0.0; + param->value_count = 0; + break; + } + /* add current value to history */ + param->value_history[param->value_history_pos++] = value; + param->value2_history[param->value_history_pos++] = value2; + param->value_history_pos %= DISPLAY_PARAM_HISTORIES; + /* calculate hold values */ + hold = -NAN; + hold2 = -NAN; + switch (param->type) { + case DISPLAY_MEAS_LAST: + /* if we have valid value, we update 'last' */ + if (!isnan(value)) { + param->last = value; + hold = value; + } else + hold = param->last; + break; + case DISPLAY_MEAS_PEAK: + for (i = 0; i < DISPLAY_PARAM_HISTORIES; i++) { + if (isnan(param->value_history[i])) + continue; + if (isnan(hold) || param->value_history[i] > hold) + hold = param->value_history[i]; + } + break; + case DISPLAY_MEAS_PEAK2PEAK: + for (i = 0; i < DISPLAY_PARAM_HISTORIES; i++) { + if (isnan(param->value_history[i])) + continue; + if (isnan(hold) || param->value_history[i] < hold) + hold = param->value_history[i]; + if (isnan(hold2) || param->value2_history[i] > hold2) + hold2 = param->value2_history[i]; + } + if (!isnan(hold)) + hold = hold2 - hold; + if (!isnan(value)) + value = value2 - value; + break; + case DISPLAY_MEAS_AVG: + for (i = 0, j = 0; i < DISPLAY_PARAM_HISTORIES; i++) { + if (isnan(param->value_history[i])) + continue; + if (j == 0) + hold = 0.0; + hold += param->value_history[i]; + j++; + } + if (j) + hold /= j; + break; + } + /* "Deviation ::::::::::............ 4.5 KHz" */ + strncpy(line, param->name, (strlen(param->name) < MAX_NAME_LEN) ? strlen(param->name) : MAX_NAME_LEN); + if (isinf(value) || isnan(value)) { + bar_left = -1; + bar_right = -1; + } else if (param->bar == DISPLAY_MEAS_CENTER) { + if (value >= 0.0) { + bar_left = (-param->min) / (param->max - param->min) * ((double)bar_width - 1.0); + bar_right = (value - param->min) / (param->max - param->min) * ((double)bar_width - 1.0); + } else { + bar_left = (value - param->min) / (param->max - param->min) * ((double)bar_width - 1.0); + bar_right = (-param->min) / (param->max - param->min) * ((double)bar_width - 1.0); + } + } else { + bar_left = -1; + bar_right = (value - param->min) / (param->max - param->min) * ((double)bar_width - 1.0); + } + if (isinf(hold) || isnan(hold)) + bar_hold = -1; + else + bar_hold = (hold - param->min) / (param->max - param->min) * ((double)bar_width - 1.0); + if (isinf(param->mark)) + bar_mark = -1; + else + bar_mark = (param->mark - param->min) / (param->max - param->min) * ((double)bar_width - 1.0); + for (i = 0; i < bar_width; i++) { + line[i + MAX_NAME_LEN] = ':'; + if (i == bar_hold) + line_color[i + MAX_NAME_LEN] = 13; + else if (i == bar_mark) + line_color[i + MAX_NAME_LEN] = 14; + else if (i >= bar_left && i <= bar_right) + line_color[i + MAX_NAME_LEN] = 2; + else + line_color[i + MAX_NAME_LEN] = 4; + } + sprintf(text, param->format, hold); + if (isnan(hold)) + memset(line_color + width - MAX_UNIT_LEN, 4, MAX_UNIT_LEN); /* blue */ + else + memset(line_color + width - MAX_UNIT_LEN, 3, MAX_UNIT_LEN); /* yellow */ + strncpy(line + width - MAX_UNIT_LEN + 1, text, (strlen(text) < MAX_UNIT_LEN) ? strlen(text) : MAX_UNIT_LEN); + display_line(on, width); + } + } + /* reset color and position */ + printf("\033[0;39m\0338"); fflush(stdout); +} + +void display_measurements_on(int on) +{ + if (measurements_on) + print_measurements(0); + + if (on < 0) + measurements_on = 1 - measurements_on; + else + measurements_on = on; +} + +void display_measurements_limit_scroll(int on) +{ + int w, h; + + if (!measurements_on) + return; + + get_win_size(&w, &h); + + printf("\0337"); + printf("\033[%d;%dr", (on) ? lines_total + 1 : 1, h); + printf("\0338"); +} + +/* add new parameter on startup to the list of measurements */ +dispmeasparam_t *display_measurements_add(sender_t *sender, char *name, char *format, enum display_measurements_type type, enum display_measurements_bar bar, double min, double max, double mark) +{ + dispmeas_t *disp = &sender->dispmeas; + dispmeasparam_t *param, **param_p = &disp->head; + int i; + + if (!has_init) { + fprintf(stderr, "Not initialized prior adding measurement, please fix!\n"); + abort(); + } + + while (*param_p) + param_p = &((*param_p)->next); + *param_p = calloc(sizeof(dispmeasparam_t), 1); + if (!*param_p) + return NULL; + param = *param_p; + strncpy(param->name, name, sizeof(param->name) - 1); + strncpy(param->format, format, sizeof(param->format) - 1); + param->type = type; + param->bar = bar; + param->min = min; + param->max = max; + param->mark = mark; + param->value = -NAN; + param->value2 = -NAN; + param->last = -NAN; + for (i = 0; i < DISPLAY_PARAM_HISTORIES; i++) + param->value_history[i] = -NAN; + param->value_count = 0; + + return param; +} + +void display_measurements_update(dispmeasparam_t *param, double value, double value2) +{ + /* special case where we do not have an instance of the parameter */ + if (!param) + return; + + if (!has_init) { + fprintf(stderr, "Not initialized prior updating measurement value, please fix!\n"); + abort(); + } + + switch (param->type) { + case DISPLAY_MEAS_LAST: + param->value = value; + break; + case DISPLAY_MEAS_PEAK: + if (isnan(param->value) || value > param->value) + param->value = value; + break; + case DISPLAY_MEAS_PEAK2PEAK: + if (param->value_count == 0 || value < param->value) + param->value = value; + if (param->value_count == 0 || value2 > param->value2) + param->value2 = value2; + param->value_count++; + break; + case DISPLAY_MEAS_AVG: + param->value += value; + param->value_count++; + break; + default: + fprintf(stderr, "Paramer '%s' has unknown type %d, please fix!\n", param->name, param->type); + abort(); + } +} + +void display_measurements(double elapsed) +{ + if (!measurements_on) + return; + + if (!has_init) { + fprintf(stderr, "Not initialized prior display measurement values, please fix!\n"); + abort(); + } + + /* count and check if we need to display this time */ + time_elapsed += elapsed; + if (time_elapsed < DISPLAY_INTERVAL) + return; + time_elapsed = fmod(time_elapsed, DISPLAY_INTERVAL); + + print_measurements(1); +} + diff --git a/src/common/display_status.c b/src/common/display_status.c index 64ec79c..66ff9ac 100644 --- a/src/common/display_status.c +++ b/src/common/display_status.c @@ -30,7 +30,7 @@ static int line_count = 0; static int lines_total = 0; static char screen[MAX_HEIGHT_STATUS][MAX_DISPLAY_WIDTH]; -void print_status(int on) +static void print_status(int on) { int i, j; int w, h; diff --git a/src/common/display_wave.c b/src/common/display_wave.c index b42c584..1d729b2 100644 --- a/src/common/display_wave.c +++ b/src/common/display_wave.c @@ -26,8 +26,6 @@ #include "sample.h" #include "sender.h" -#define DISPLAY_INTERVAL 0.04 - #define HEIGHT 11 static int num_sender = 0; diff --git a/src/common/main_mobile.c b/src/common/main_mobile.c index 60ff519..f906d6d 100644 --- a/src/common/main_mobile.c +++ b/src/common/main_mobile.c @@ -152,10 +152,11 @@ void main_mobile_print_help(const char *arg0, const char *ext_usage) void main_mobile_print_hotkeys(void) { printf("\n"); - printf("Press digits '0'..'9' and then 'd' key to dial towards mobile station\n"); + printf("Press digits '0'..'9' and then 'd' key to dial towards mobile station.\n"); printf("Press 'h' key to hangup.\n"); printf("Press 'w' key to toggle display of RX wave form.\n"); printf("Press 'c' key to toggle display of channel status.\n"); + printf("Press 'm' key to toggle display of measurement value.\n"); #ifdef HAVE_SDR sdr_config_print_hotkeys(); #endif @@ -524,35 +525,49 @@ next_char: *quit = 1; goto next_char; case 'w': - /* toggle display */ + /* toggle wave display */ + display_status_on(0); + display_measurements_on(0); #ifdef HAVE_SDR display_iq_on(0); display_spectrum_on(0); #endif - display_status_on(0); display_wave_on(-1); goto next_char; case 'c': - /* toggle display */ + /* toggle call state display */ + display_wave_on(0); + display_measurements_on(0); #ifdef HAVE_SDR display_iq_on(0); display_spectrum_on(0); #endif - display_wave_on(0); display_status_on(-1); goto next_char; + case 'm': + /* toggle measurements display */ + display_wave_on(0); + display_status_on(0); +#ifdef HAVE_SDR + display_iq_on(0); + display_spectrum_on(0); +#endif + display_measurements_on(-1); + goto next_char; #ifdef HAVE_SDR case 'q': - /* toggle display */ + /* toggle IQ display */ display_wave_on(0); display_status_on(0); + display_measurements_on(0); display_spectrum_on(0); display_iq_on(-1); goto next_char; case 's': - /* toggle spectrum */ + /* toggle spectrum display */ display_wave_on(0); display_status_on(0); + display_measurements_on(0); display_iq_on(0); display_spectrum_on(-1); goto next_char; @@ -569,6 +584,8 @@ next_char: if (myhandler) myhandler(); + display_measurements((double)interval / 1000.0); + now = get_time(); /* sleep interval */ diff --git a/src/common/sdr.c b/src/common/sdr.c index 1e32c74..2e40833 100644 --- a/src/common/sdr.c +++ b/src/common/sdr.c @@ -32,8 +32,7 @@ enum paging_signal; #include "sample.h" #include "fm_modulation.h" #include "timer.h" -#include "wave.h" -#include "display.h" +#include "sender.h" #include "sdr_config.h" #include "sdr.h" #ifdef HAVE_UHD @@ -68,6 +67,9 @@ typedef struct sdr_chan { double rx_frequency; /* frequency used */ fm_mod_t mod; /* modulator instance */ fm_demod_t demod; /* demodulator instance */ + dispmeasparam_t *dmp_rf_level; + dispmeasparam_t *dmp_freq_offset; + dispmeasparam_t *dmp_deviation; } sdr_chan_t; typedef struct sdr { @@ -340,6 +342,15 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq goto error; } } + /* init measurements display */ + for (c = 0; c < channels; c++) { + sender_t *sender = get_sender_by_empfangsfrequenz(sdr->chan[c].rx_frequency); + if (!sender) + continue; + sdr->chan[c].dmp_rf_level = display_measurements_add(sender, "RF Level", "%.1f dB", DISPLAY_MEAS_AVG, DISPLAY_MEAS_LEFT, -96.0, 0.0, -INFINITY); + sdr->chan[c].dmp_freq_offset = display_measurements_add(sender, "Freq. Offset", "%+.2f KHz", DISPLAY_MEAS_AVG, DISPLAY_MEAS_CENTER, -max_deviation / 1000.0 * 2.0, max_deviation / 1000.0 * 2.0, 0.0); + sdr->chan[c].dmp_deviation = display_measurements_add(sender, "Deviation", "%.2f KHz", DISPLAY_MEAS_PEAK2PEAK, DISPLAY_MEAS_LEFT, 0.0, max_deviation / 1000.0 * 1.5, max_deviation / 1000.0); + } } if (sdr_config->swap_links) { @@ -747,7 +758,7 @@ int sdr_read(void *inst, sample_t **samples, int num, int channels) #endif if (count <= 0) return count; -} + } if (sdr->wave_rx_rec.fp) { sample_t *spl_list[2] = { sdr->wavespl0, sdr->wavespl1 }; @@ -769,8 +780,35 @@ int sdr_read(void *inst, sample_t **samples, int num, int channels) display_spectrum(buff, count); if (channels) { - for (c = 0; c < channels; c++) + for (c = 0; c < channels; c++) { fm_demodulate_complex(&sdr->chan[c].demod, samples[c], count, buff, sdr->modbuff_I, sdr->modbuff_Q); + sender_t *sender = get_sender_by_empfangsfrequenz(sdr->chan[c].rx_frequency); + if (!sender || !count) + continue; + double min, max, avg; + avg = 0.0; + for (s = 0; s < count; s++) { + /* average the square length of vector */ + avg += sdr->modbuff_I[s] * sdr->modbuff_I[s] + sdr->modbuff_Q[s] * sdr->modbuff_Q[s]; + } + avg = sqrt(avg /(double)count); /* RMS */ + avg = log10(avg) * 20; + display_measurements_update(sdr->chan[c].dmp_rf_level, avg, 0.0); + min = 0.0; + max = 0.0; + avg = 0.0; + for (s = 0; s < count; s++) { + avg += samples[c][s]; + if (s == 0 || samples[c][s] > max) + max = samples[c][s]; + if (s == 0 || samples[c][s] < min) + min = samples[c][s]; + } + avg /= (double)count; + display_measurements_update(sdr->chan[c].dmp_freq_offset, avg / 1000.0, 0.0); + /* use half min and max, because we want the deviation above/below (+-) center frequency. */ + display_measurements_update(sdr->chan[c].dmp_deviation, min / 2.0 / 1000.0, max / 2.0 / 1000.0); + } } return count; diff --git a/src/common/sender.c b/src/common/sender.c index 4d1b54e..9cd8c0b 100644 --- a/src/common/sender.c +++ b/src/common/sender.c @@ -44,7 +44,7 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf sender->kanal = kanal; sender->sendefrequenz = sendefrequenz; - sender->empfangsfrequenz = empfangsfrequenz; + sender->empfangsfrequenz = (loopback) ? sendefrequenz : empfangsfrequenz; strncpy(sender->audiodev, audiodev, sizeof(sender->audiodev) - 1); sender->samplerate = samplerate; sender->rx_gain = rx_gain; @@ -145,6 +145,7 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf sender_tailp = &sender->next; display_wave_init(sender, samplerate); + display_measurements_init(sender, samplerate); return 0; error: @@ -157,7 +158,6 @@ int sender_open_audio(int latspl) { sender_t *master, *inst; int channels; - double paging_frequency = 0.0; int i; int rc; @@ -171,13 +171,10 @@ int sender_open_audio(int latspl) for (inst = master; inst; inst = inst->slave) { channels++; } - double tx_f[channels], rx_f[channels]; + double tx_f[channels], rx_f[channels], paging_frequency = 0.0; for (i = 0, inst = master; inst; i++, inst = inst->slave) { tx_f[i] = inst->sendefrequenz; - if (inst->loopback) - rx_f[i] = inst->sendefrequenz; - else - rx_f[i] = inst->empfangsfrequenz; + rx_f[i] = inst->empfangsfrequenz; if (inst->ruffrequenz) paging_frequency = inst->ruffrequenz; } @@ -438,3 +435,15 @@ void sender_paging(sender_t *sender, int on) sender->paging_on = on; } +sender_t *get_sender_by_empfangsfrequenz(double freq) +{ + sender_t *sender; + + for (sender = sender_head; sender; sender = sender->next) { + if (sender->empfangsfrequenz == freq) + return sender; + } + + return NULL; +} + diff --git a/src/common/sender.h b/src/common/sender.h index 3a3136b..ca53de4 100644 --- a/src/common/sender.h +++ b/src/common/sender.h @@ -84,6 +84,9 @@ typedef struct sender { /* display wave */ dispwav_t dispwav; /* display wave form */ + + /* display measurements */ + dispmeas_t dispmeas; /* display measurements */ } sender_t; /* list of all senders */ @@ -99,4 +102,5 @@ void process_sender_audio(sender_t *sender, int *quit, int latspl); 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); +sender_t *get_sender_by_empfangsfrequenz(double freq); diff --git a/src/common/sound_alsa.c b/src/common/sound_alsa.c index 2719d07..a9c3ae1 100644 --- a/src/common/sound_alsa.c +++ b/src/common/sound_alsa.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "sample.h" #include "debug.h" @@ -30,6 +31,8 @@ typedef struct sound { double spl_deviation; /* how much deviation is one sample step */ double paging_phaseshift; /* phase to shift every sample */ double paging_phase; /* current phase */ + double rx_frequency[2]; /* rx frequency of radio connected to channel */ + dispmeasparam_t *dmp[2]; } sound_t; static int set_hw_params(snd_pcm_t *handle, int samplerate, int *channels) @@ -185,6 +188,18 @@ void *sound_open(const char *audiodev, double __attribute__((unused)) *tx_freque if (rc < 0) goto error; + if (rx_frequency) { + sender_t *sender; + int i; + for (i = 0; i < channels; i++) { + sound->rx_frequency[i] = rx_frequency[i]; + sender = get_sender_by_empfangsfrequenz(sound->rx_frequency[i]); + if (!sender) + continue; + sound->dmp[i] = display_measurements_add(sender, "RX Level", "%.1f dB", DISPLAY_MEAS_PEAK, DISPLAY_MEAS_LEFT, -96.0, 0.0, -INFINITY); + } + } + return sound; error: @@ -344,6 +359,7 @@ int sound_read(void *inst, sample_t **samples, int num, int channels) double spl_deviation = sound->spl_deviation; int16_t buff[num << 1]; int32_t spl; + int32_t max[2], a; int in, rc; int i, ii; @@ -372,25 +388,51 @@ int sound_read(void *inst, sample_t **samples, int num, int channels) return rc; } + if (rc == 0) + return rc; + if (sound->cchannels == 2) { if (channels < 2) { for (i = 0, ii = 0; i < rc; i++) { spl = buff[ii++]; spl += buff[ii++]; + a = (spl >= 0) ? spl : -spl; + if (i == 0 || a > max[0]) + max[0] = a; samples[0][i] = (double)spl * spl_deviation; } } else { for (i = 0, ii = 0; i < rc; i++) { - samples[0][i] = (double)buff[ii++] * spl_deviation; - samples[1][i] = (double)buff[ii++] * spl_deviation; + spl = buff[ii++]; + a = (spl >= 0) ? spl : -spl; + if (i == 0 || a > max[0]) + max[0] = a; + samples[0][i] = (double)spl * spl_deviation; + spl = buff[ii++]; + a = (spl >= 0) ? spl : -spl; + if (i == 0 || a > max[1]) + max[1] = a; + samples[1][i] = (double)spl * spl_deviation; } } } else { for (i = 0, ii = 0; i < rc; i++) { - samples[0][i] = (double)buff[ii++] * spl_deviation; + spl = buff[ii++]; + a = (spl >= 0) ? spl : -spl; + if (i == 0 || a > max[0]) + max[0] = a; + samples[0][i] = (double)spl * spl_deviation; } } + sender_t *sender; + for (i = 0; i < channels; i++) { + sender = get_sender_by_empfangsfrequenz(sound->rx_frequency[i]); + if (!sender) + continue; + display_measurements_update(sound->dmp[i], log10((double)max[i] / 32768.0) * 20, 0.0); + } + return rc; } diff --git a/src/nmt/dsp.c b/src/nmt/dsp.c index 6086d62..b95191b 100644 --- a/src/nmt/dsp.c +++ b/src/nmt/dsp.c @@ -152,6 +152,9 @@ int dsp_init_sender(nmt_t *nmt, double deviation_factor) /* dtmf */ dtmf_init(&nmt->dtmf, 8000); + nmt->dmp_frame_level = display_measurements_add(&nmt->sender, "Frame Level", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + nmt->dmp_frame_quality = display_measurements_add(&nmt->sender, "Frame Quality", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + return 0; } @@ -242,6 +245,10 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level) } level /= 140.0; quality /= 140.0; + /* update measurements */ + display_measurements_update(nmt->dmp_frame_level, level * 100.0, 0.0); + display_measurements_update(nmt->dmp_frame_quality, quality * 100.0, 0.0); + /* send telegramm */ 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%) */ diff --git a/src/nmt/nmt.h b/src/nmt/nmt.h index ae871e6..4d472d2 100644 --- a/src/nmt/nmt.h +++ b/src/nmt/nmt.h @@ -90,6 +90,10 @@ typedef struct nmt { char dialing[33]; /* dialed digits */ int mft_num; /* counter for digit for MFT */ + /* display measurements */ + dispmeasparam_t *dmp_frame_level; + dispmeasparam_t *dmp_frame_quality; + /* features */ int compandor; /* if compandor shall be used */ int supervisory; /* if set, use supervisory signal 1..4 */ diff --git a/src/r2000/dsp.c b/src/r2000/dsp.c index 10b3a97..ca61122 100644 --- a/src/r2000/dsp.c +++ b/src/r2000/dsp.c @@ -109,6 +109,13 @@ int dsp_init_sender(r2000_t *r2000) iir_highpass_init(&r2000->super_tx_hp, SUPER_CUTOFF_H, r2000->sender.samplerate, 2); iir_highpass_init(&r2000->super_rx_hp, SUPER_CUTOFF_H, r2000->sender.samplerate, 2); + r2000->dmp_frame_level = display_measurements_add(&r2000->sender, "Frame Level", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + r2000->dmp_frame_quality = display_measurements_add(&r2000->sender, "Frame Quality", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + if (r2000->sysinfo.chan_type == CHAN_TYPE_TC || r2000->sysinfo.chan_type == CHAN_TYPE_CC_TC) { + r2000->dmp_super_level = display_measurements_add(&r2000->sender, "Super Level", "%.1f %%", DISPLAY_MEAS_AVG, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + r2000->dmp_super_quality = display_measurements_add(&r2000->sender, "Super Quality", "%.1f %%", DISPLAY_MEAS_AVG, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); + } + return 0; } @@ -190,6 +197,10 @@ static void fsk_receive_bit(void *inst, int bit, double quality, double level) } level /= (double)r2000->rx_max; quality /= (double)r2000->rx_max; + /* update measurements */ + display_measurements_update(r2000->dmp_frame_level, level * 100.0, 0.0); + display_measurements_update(r2000->dmp_frame_quality, quality * 100.0, 0.0); + /* send frame to upper layer */ r2000_receive_frame(r2000, r2000->rx_frame, quality, level); } @@ -202,6 +213,10 @@ static void super_receive_bit(void *inst, int bit, double quality, double level) /* normalize supervisory level */ level /= TX_PEAK_SUPER; + /* update measurements (if dmp_* params are NULL, we omit this) */ + display_measurements_update(r2000->dmp_super_level, level * 100.0, 0.0); + display_measurements_update(r2000->dmp_super_quality, quality * 100.0, 0.0); + /* store bit */ r2000->super_rx_word = (r2000->super_rx_word << 1) | bit; r2000->super_rx_level[r2000->super_rx_index] = level; diff --git a/src/r2000/r2000.h b/src/r2000/r2000.h index 6d5ad46..bae6735 100644 --- a/src/r2000/r2000.h +++ b/src/r2000/r2000.h @@ -73,6 +73,12 @@ typedef struct r2000 { int page_try; /* the try number of calling the mobile */ int tx_frame_count; /* to count repeated frames */ + /* display measurements */ + dispmeasparam_t *dmp_frame_level; + dispmeasparam_t *dmp_frame_quality; + dispmeasparam_t *dmp_super_level; + dispmeasparam_t *dmp_super_quality; + /* features */ int compandor; /* if compandor shall be used */ diff --git a/src/tv/main.c b/src/tv/main.c index f7f5a35..7e133da 100644 --- a/src/tv/main.c +++ b/src/tv/main.c @@ -48,6 +48,7 @@ int num_kanal = 1; /* only one channel used for debugging */ void clear_console_text() {} void print_console_text() {} void display_status_limit_scroll() {} +void *get_sender_by_empfangsfrequenz() { return NULL; } static double __attribute__((__unused__)) modulation = 0.7; /* level of modulation for I/Q amplitudes */ static double frequency = 0.0; -- cgit v1.2.3