From: drowe67 Date: Mon, 9 Apr 2018 02:49:00 +0000 (+0000) Subject: first pass at horus_demod, compiles OK but untested, need Cmake integration next X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=e1a1bbccde61255b377ffbcdd06d7d0a2dc9de90;p=freetel-svn-tracking.git first pass at horus_demod, compiles OK but untested, need Cmake integration next git-svn-id: https://svn.code.sf.net/p/freetel/code@3455 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/src/horus_api.c b/codec2-dev/src/horus_api.c index c829a8d9..d6f2851f 100644 --- a/codec2-dev/src/horus_api.c +++ b/codec2-dev/src/horus_api.c @@ -128,7 +128,9 @@ void horus_close (struct horus *hstates) { uint32_t horus_nin(struct horus *hstates) { assert(hstates != NULL); - return fsk_nin(hstates->fsk); + int nin = fsk_nin(hstates->fsk); + assert(nin <= horus_get_max_demod_in(hstates)); + return nin; } int horus_find_uw(struct horus *hstates) { @@ -327,6 +329,21 @@ int horus_get_mode(struct horus *hstates) { return hstates->mode; } +int horus_get_Fs(struct horus *hstates) { + assert(hstates != NULL); + return hstates->Fs; +} + +int horus_get_mFSK(struct horus *hstates) { + assert(hstates != NULL); + return hstates->mFSK; +} + +int horus_get_max_demod_in(struct horus *hstates) { + /* copied from fsk_demod.c, a nicer fsk_max_nin function would be useful */ + return sizeof(short)*(hstates->fsk->N + hstates->fsk->Ts*2); +} + int horus_get_max_ascii_out_len(struct horus *hstates) { if (hstates->mode == HORUS_MODE_RTTY) { return hstates->max_packet_len/10; /* 7 bit ASCII, plus 3 sync bits */ @@ -345,15 +362,24 @@ void horus_get_modem_stats(struct horus *hstates, int *sync, float *snr_est) { *sync = 0; - /* TODO SNR is actually an Eb/No est for FSK - should we scale - Eb/No for SNR in 3kHz? */ + /* SNR scaled from Eb/No est returned by FSK to SNR in 3000 Hz */ fsk_get_demod_stats(hstates->fsk, &stats); - *snr_est = stats.snr_est; + *snr_est = stats.snr_est + 10*log10(hstates->Rs/3000); } void horus_get_modem_extended_stats (struct horus *hstates, struct MODEM_STATS *stats) { + int i; + assert(hstates != NULL); + fsk_get_demod_stats(hstates->fsk, stats); + + stats->snr_est = stats->snr_est + 10*log10(hstates->Rs/3000); + + assert(hstates->mFSK <= MODEM_STATS_MAX_F_EST); + for (i=0; imFSK; i++) { + stats->f_est[i] = hstates->fsk->f_est[i]; + } } diff --git a/codec2-dev/src/horus_api.h b/codec2-dev/src/horus_api.h index 515bb545..c3fd1a24 100644 --- a/codec2-dev/src/horus_api.h +++ b/codec2-dev/src/horus_api.h @@ -56,11 +56,14 @@ int horus_rx (struct horus *hstates, char ascii_out[], short demod_ int horus_get_version (void); int horus_get_mode (struct horus *hstates); +int horus_get_Fs (struct horus *hstates); +int horus_get_mFSK (struct horus *hstates); void horus_get_modem_stats (struct horus *hstates, int *sync, float *snr_est); void horus_get_modem_extended_stats (struct horus *hstates, struct MODEM_STATS *stats); -/* how much storage you need for ascii_out[] */ +/* how much storage you need for demod_in[] and ascii_out[] */ +int horus_get_max_demod_in (struct horus *hstates); int horus_get_max_ascii_out_len (struct horus *hstates); #endif diff --git a/codec2-dev/src/horus_demod.c b/codec2-dev/src/horus_demod.c new file mode 100644 index 00000000..65216d42 --- /dev/null +++ b/codec2-dev/src/horus_demod.c @@ -0,0 +1,230 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: horus_demod.c + AUTHOR......: David Rowe + DATE CREATED: April 2018 + + Command line demo program for the Horus API, that exercises + horus_api.c using file input/output (can be stdin/stdout for real + time operation). Prints JSON stats, just like Brady's fsk_demod.c + + Can operate in Horus RTTY or Binary mode. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2018 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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 Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include + +#include "horus_api.h" +#include "fsk.h" +#include "horus_l2.h" + +int main(int argc, char *argv[]) { + struct horus *hstates; + struct MODEM_STATS stats; + FILE *fin,*fout; + int i,j,Ndft,mode; + int stats_ctr,stats_loop, stats_rate; + float loop_time; + int enable_stats = 0; + + stats_loop = 0; + stats_rate = 8; + + int o = 0; + int opt_idx = 0; + while ( o != -1 ) { + static struct option long_opts[] = { + {"help", no_argument, 0, 'h'}, + {"mode", required_argument, 0, 'm'}, + {"stats", optional_argument, 0, 't'}, + {0, 0, 0, 0} + }; + + o = getopt_long(argc,argv,"hm:t::",long_opts,&opt_idx); + + switch(o) { + case 'm': + mode = -1; + if ((strcmp(optarg, "RTTY") == 0) || (strcmp(optarg, "rtty") == 0)) { + mode = HORUS_MODE_RTTY; + } + if ((strcmp(optarg, "BINARY") == 0) || (strcmp(optarg, "binary") == 0)) { + mode = HORUS_MODE_BINARY; + } + if (mode = -1) { + fprintf(stderr, "use --mode RTTY or --mode binary\n"); + exit(1); + } + break; + case 't': + enable_stats = 1; + if (optarg != NULL){ + stats_rate = atoi(optarg); + if (stats_rate == 0) { + stats_rate = 8; + } + } + break; + case 'h': + case '?': + goto helpmsg; + break; + } + + int dx = optind; + + if( (argc - dx) < 1) { + fprintf(stderr, "Too few arguments\n"); + goto helpmsg; + } + + if( (argc - dx) > 5){ + fprintf(stderr, "Too many arguments\n"); + helpmsg: + fprintf(stderr,"usage: %s -m RTTY|binary [-t [r]] InputModemRawFile OutputAsciiFile\n",argv[0]); + fprintf(stderr,"\n"); + fprintf(stderr,"InputModemRawFile - 48 kHz 16 bit shorts real modem signal from radio\n"); + fprintf(stderr," -m RTTY|binary\n"); + fprintf(stderr,"--mode=RTTY|binary[r] - RTTY or binary Horus protcols\n"); + fprintf(stderr," -t[r] --stats=[r] - Print out modem statistics to stderr in JSON.\n"); + fprintf(stderr," r, if provided, sets the number of modem frames" + "between statistic printouts\n"); + exit(1); + } + + /* Open files */ + + if (strcmp(argv[dx + 1],"-")==0) { + fin = stdin; + } else { + fin = fopen(argv[dx + 1],"rb"); + } + + if (strcmp(argv[dx + 2],"-")==0) { + fout = stdout; + } else { + fout = fopen(argv[dx + 4],"w"); + } + + if ((fin==NULL) || (fout==NULL)) { + fprintf(stderr,"Couldn't open test vector files\n"); + exit(1); + } + } + + /* end command line processing */ + + hstates = horus_open(mode); + if (hstates == NULL) { + fprintf(stderr, "Couldn't open Horus API\n"); + exit(1); + } + + if (enable_stats) { + loop_time = (float)horus_nin(hstates)/horus_get_Fs(hstates); + stats_loop = (int)(1.0/(stats_rate*loop_time)); + stats_ctr = 0; + } + + int max_demod_in = horus_get_max_demod_in(hstates); + short demod_in[max_demod_in]; + int max_ascii_out = horus_get_max_ascii_out_len(hstates); + char ascii_out[max_ascii_out]; + + /* Main loop ----------------------------------------------------------------------- */ + + while( fread(demod_in, sizeof(short), horus_nin(hstates), fin) == horus_nin(hstates) ) { + + if (horus_rx(hstates, ascii_out, demod_in)) { + fprintf(stdout, "%s\n", ascii_out); + } + + if (enable_stats && stats_ctr <= 0) { + + horus_get_modem_extended_stats(hstates, &stats); + + /* Print standard 2FSK stats */ + + fprintf(stderr,"{\"EbNodB\": %2.2f,\t\"ppm\": %d,",stats.snr_est, (int)stats.clock_offset); + fprintf(stderr,"\t\"f1_est\":%.1f,\t\"f2_est\":%.1f",stats.f_est[0], stats.f_est[1]); + + /* Print 4FSK stats if in 4FSK mode */ + + if (horus_get_mFSK(hstates) == 4) { + fprintf(stderr,",\t\"f3_est\":%.1f,\t\"f4_est\":%.1f", stats.f_est[2], stats.f_est[3]); + } + + /* Print the eye diagram */ + + fprintf(stderr,",\t\"eye_diagram\":["); + for(i=0;ifsk->Ndft/2; + for(i=0; ifsk->fft_est)[i]); + if(i