Skip to content

Commit 7d51460

Browse files
authored
Merge pull request drowe67#209 from drowe67/ms-reliable-text
Add reliable_text library to codec2 to enable PSK Reporter support. Great work Mooneer!
2 parents 7e5403c + d9af518 commit 7d51460

18 files changed

+906
-28
lines changed

CMakeLists.txt

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,86 @@ if(UNIX) # Uses pthreads
782782
)
783783
endif()
784784

785+
# -------------------------------------------------------------------------
786+
# Reliable Text
787+
# -------------------------------------------------------------------------
788+
add_test(NAME test_freedv_reliable_text_truncate_string
789+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
790+
./freedv_tx 1600 ../../raw/ve9qrp.raw - --reliabletext AB1CDEFGH > 1600_reliable.raw 2>/dev/null;
791+
./freedv_rx 1600 1600_reliable.raw /dev/null --txtrx 1600_reliable.txt --reliabletext 2>/dev/null;
792+
grep 'AB1CDEFG' 1600_reliable.txt | wc -l")
793+
set_tests_properties(test_freedv_reliable_text_truncate_string PROPERTIES PASS_REGULAR_EXPRESSION "20")
794+
795+
add_test(NAME test_freedv_reliable_text_ideal_1600
796+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
797+
./freedv_tx 1600 ../../raw/ve9qrp.raw - --reliabletext AB1CDEF > 1600_reliable.raw 2>/dev/null;
798+
./freedv_rx 1600 1600_reliable.raw /dev/null --txtrx 1600_reliable.txt --reliabletext 2>/dev/null;
799+
cat 1600_reliable.txt | wc -l")
800+
set_tests_properties(test_freedv_reliable_text_ideal_1600 PROPERTIES PASS_REGULAR_EXPRESSION "20")
801+
802+
add_test(NAME test_freedv_reliable_text_ideal_700D
803+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
804+
./freedv_tx 700D ../../raw/ve9qrp.raw - --reliabletext AB1CDEF --txbpf 1 --clip 1 > 700D_reliable.raw 2>/dev/null;
805+
./freedv_rx 700D 700D_reliable.raw /dev/null --txtrx 700D_reliable.txt --reliabletext 2>/dev/null;
806+
cat 700D_reliable.txt | wc -l")
807+
set_tests_properties(test_freedv_reliable_text_ideal_700D PROPERTIES PASS_REGULAR_EXPRESSION "21")
808+
809+
add_test(NAME test_freedv_reliable_text_ideal_700E
810+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
811+
./freedv_tx 700E ../../raw/ve9qrp.raw - --reliabletext AB1CDEF --txbpf 1 --clip 1 > 700E_reliable.raw 2>/dev/null;
812+
./freedv_rx 700E 700E_reliable.raw /dev/null --txtrx 700E_reliable.txt --reliabletext 2>/dev/null;
813+
cat 700E_reliable.txt | wc -l")
814+
set_tests_properties(test_freedv_reliable_text_ideal_700E PROPERTIES PASS_REGULAR_EXPRESSION "21")
815+
816+
add_test(NAME test_freedv_reliable_text_awgn_1600
817+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
818+
./freedv_tx 1600 ../../raw/ve9qrp.raw - --reliabletext AB1CDEF | ./cohpsk_ch - - -25 --Fs 8000 -f -5 > 1600_reliable.raw 2>/dev/null;
819+
./freedv_rx 1600 1600_reliable.raw /dev/null --txtrx 1600_reliable.txt --reliabletext 2>/dev/null;
820+
if [ `cat 1600_reliable.txt | wc -l` -ge 10 ]; then echo 1; fi")
821+
set_tests_properties(test_freedv_reliable_text_awgn_1600 PROPERTIES PASS_REGULAR_EXPRESSION "1")
822+
823+
add_test(NAME test_freedv_reliable_text_awgn_700D
824+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
825+
./freedv_tx 700D ../../raw/ve9qrp.raw - --reliabletext AB1CDEF --txbpf 1 --clip 1 | ./cohpsk_ch - - -12 --Fs 8000 -f -5 > 700D_reliable.raw 2>/dev/null;
826+
./freedv_rx 700D 700D_reliable.raw /dev/null --txtrx 700D_reliable.txt --reliabletext 2>/dev/null;
827+
if [ `cat 700D_reliable.txt | wc -l` -ge 10 ]; then echo 1; fi")
828+
set_tests_properties(test_freedv_reliable_text_awgn_700D PROPERTIES PASS_REGULAR_EXPRESSION "1")
829+
830+
add_test(NAME test_freedv_reliable_text_awgn_700E
831+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
832+
./freedv_tx 700E ../../raw/ve9qrp.raw - --reliabletext AB1CDEF --txbpf 1 --clip 1 | ./cohpsk_ch - - -15 --Fs 8000 -f -5 > 700E_reliable.raw 2>/dev/null;
833+
./freedv_rx 700E 700E_reliable.raw /dev/null --txtrx 700E_reliable.txt --reliabletext 2>/dev/null;
834+
if [ `cat 700E_reliable.txt | wc -l` -ge 10 ]; then echo 1; fi")
835+
set_tests_properties(test_freedv_reliable_text_awgn_700E PROPERTIES PASS_REGULAR_EXPRESSION "1")
836+
837+
add_test(NAME test_freedv_reliable_text_fade_1600
838+
COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/unittest; ./reliable_text_fade.sh 1600 -28 3 0 '${CMAKE_CURRENT_BINARY_DIR}/src'")
839+
840+
add_test(NAME test_freedv_reliable_text_fade_700D
841+
COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/unittest; ./reliable_text_fade.sh 700D -19 8 1 '${CMAKE_CURRENT_BINARY_DIR}/src'")
842+
843+
add_test(NAME test_freedv_reliable_text_fade_700E
844+
COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/unittest; ./reliable_text_fade.sh 700E -22 9 1 '${CMAKE_CURRENT_BINARY_DIR}/src'")
845+
846+
if(LPCNET)
847+
add_test(NAME test_freedv_reliable_text_ideal_2020
848+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
849+
./freedv_tx 2020 ../../raw/ve9qrp.raw - --reliabletext AB1CDEF > 2020_reliable.raw 2>/dev/null;
850+
./freedv_rx 2020 2020_reliable.raw /dev/null --txtrx 2020_reliable.txt --reliabletext 2>/dev/null;
851+
cat 2020_reliable.txt | wc -l")
852+
set_tests_properties(test_freedv_reliable_text_ideal_2020 PROPERTIES PASS_REGULAR_EXPRESSION "9")
853+
854+
add_test(NAME test_freedv_reliable_text_awgn_2020
855+
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
856+
./freedv_tx 2020 ../../raw/ve9qrp.raw - --reliabletext AB1CDEF | ./cohpsk_ch - - -22 --Fs 8000 -f -5 > 2020_reliable.raw 2>/dev/null;
857+
./freedv_rx 2020 2020_reliable.raw /dev/null --txtrx 2020_reliable.txt --reliabletext 2>/dev/null;
858+
if [ `cat 2020_reliable.txt | wc -l` -ge 9 ]; then echo 1; fi")
859+
set_tests_properties(test_freedv_reliable_text_awgn_1600 PROPERTIES PASS_REGULAR_EXPRESSION "1")
860+
861+
add_test(NAME test_freedv_reliable_text_fade_2020
862+
COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/unittest; ./reliable_text_fade.sh 2020 -26 6 0 '${CMAKE_CURRENT_BINARY_DIR}/src'")
863+
endif(LPCNET)
864+
785865
# -------------------------------------------------------------------------
786866
# FreeDv API memory leaks
787867
# -------------------------------------------------------------------------

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ set(CODEC2_SRCS
212212
H_1024_2048_4f.c
213213
ldpc_codes.c
214214
lpcnet_freq.c
215+
reliable_text.c
215216
)
216217

217218
set(CODEC2_PUBLIC_HEADERS
@@ -225,6 +226,7 @@ set(CODEC2_PUBLIC_HEADERS
225226
comp.h
226227
modem_stats.h
227228
freedv_api.h
229+
reliable_text.h
228230
${CODEC2_VERSION_PATH}/version.h
229231
)
230232

src/freedv_1600.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void freedv_comptx_fdmdv_1600(struct freedv *f, COMP mod_out[]) {
8181
char s[2];
8282
if (f->freedv_get_next_tx_char != NULL) {
8383
s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
84-
f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
84+
f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, f->varicode_dec_states.code_num);
8585
f->varicode_bit_index = 0;
8686
}
8787
}

src/freedv_2020.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ void freedv_comptx_2020(struct freedv *f, COMP mod_out[]) {
139139
char s[2];
140140
if (f->freedv_get_next_tx_char != NULL) {
141141
s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
142-
f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
142+
f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, f->varicode_dec_states.code_num);
143143
f->varicode_bit_index = 0;
144144
}
145145
}
@@ -207,9 +207,11 @@ int freedv_comprx_2020(struct freedv *f, COMP demod_in[]) {
207207
rx_status |= FREEDV_RX_SYNC;
208208
if (ofdm->sync_state == trial) rx_status |= FREEDV_RX_TRIAL_SYNC;
209209

210+
int txt_sym_index = 0;
211+
210212
ofdm_demod(ofdm, rx_bits, demod_in);
211213
ofdm_extract_uw(ofdm, ofdm->rx_np, ofdm->rx_amp, rx_uw);
212-
ofdm_disassemble_qpsk_modem_packet(ofdm, ofdm->rx_np, ofdm->rx_amp, payload_syms, payload_amps, txt_bits);
214+
ofdm_disassemble_qpsk_modem_packet_with_text_amps(ofdm, ofdm->rx_np, ofdm->rx_amp, payload_syms, payload_amps, txt_bits, &txt_sym_index);
213215

214216
f->sync = 1;
215217

@@ -280,6 +282,12 @@ int freedv_comprx_2020(struct freedv *f, COMP demod_in[]) {
280282
/* If modem is synced we can decode txt bits */
281283

282284
for(k=0; k<f->ofdm_ntxtbits; k++) {
285+
if (k % 2 == 0 && (f->freedv_put_next_rx_symbol != NULL))
286+
{
287+
(*f->freedv_put_next_rx_symbol)(f->callback_state_sym, ofdm->rx_np[txt_sym_index], ofdm->rx_amp[txt_sym_index]);
288+
txt_sym_index++;
289+
}
290+
283291
//fprintf(stderr, "txt_bits[%d] = %d\n", k, rx_bits[i]);
284292
n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, &txt_bits[k], 1, 1);
285293
if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {

src/freedv_700.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ void freedv_comptx_ofdm(struct freedv *f, COMP mod_out[]) {
235235
char s[2];
236236
if (f->freedv_get_next_tx_char != NULL) {
237237
s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
238-
f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
238+
f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, f->varicode_dec_states.code_num);
239239
f->varicode_bit_index = 0;
240240
}
241241
}
@@ -441,7 +441,8 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz, int demod_i
441441

442442
if (ofdm->modem_frame == (ofdm->np-1)) {
443443
/* we have received enough modem frames to complete packet and run LDPC decoder */
444-
ofdm_disassemble_qpsk_modem_packet(ofdm, rx_syms, rx_amps, payload_syms, payload_amps, txt_bits);
444+
int txt_sym_index = 0;
445+
ofdm_disassemble_qpsk_modem_packet_with_text_amps(ofdm, rx_syms, rx_amps, payload_syms, payload_amps, txt_bits, &txt_sym_index);
445446

446447
COMP payload_syms_de[Npayloadsymsperpacket];
447448
float payload_amps_de[Npayloadsymsperpacket];
@@ -493,6 +494,11 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz, int demod_i
493494

494495
/* decode txt bits (if used) */
495496
for(k=0; k<f->ofdm_ntxtbits; k++) {
497+
if (k % 2 == 0 && (f->freedv_put_next_rx_symbol != NULL))
498+
{
499+
(*f->freedv_put_next_rx_symbol)(f->callback_state_sym, rx_syms[txt_sym_index], rx_amps[txt_sym_index]);
500+
txt_sym_index++;
501+
}
496502
n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, &txt_bits[k], 1, 1);
497503
if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
498504
(*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);

src/freedv_api.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,35 @@ void freedv_set_callback_txt(struct freedv *f, freedv_callback_rx rx, freedv_cal
10811081
}
10821082
}
10831083

1084+
/*---------------------------------------------------------------------------*\
1085+
1086+
FUNCTION....: freedv_set_callback_txt_sym
1087+
AUTHOR......: Mooneer Salem
1088+
DATE CREATED: 19 August 2021
1089+
1090+
Set the callback functions and the callback state pointer that will
1091+
be used to provide the raw symbols for the aux txt channel. The
1092+
freedv_callback_rx_sym is a function pointer that will be called to
1093+
return received symbols. The callback state is a user-defined
1094+
void pointer that will be passed to the callback function. Any or
1095+
all can be NULL, and the default is all NULL.
1096+
1097+
The function signature is:
1098+
void receive_sym(void *callback_state, COMP sym, COMP amp);
1099+
1100+
Note: Active for OFDM modes only (700D/E, 2020).
1101+
\*---------------------------------------------------------------------------*/
1102+
1103+
void freedv_set_callback_txt_sym(struct freedv *f, freedv_callback_rx_sym rx, void *state)
1104+
{
1105+
if (FDV_MODE_ACTIVE( FREEDV_MODE_700D, f->mode ) ||
1106+
FDV_MODE_ACTIVE( FREEDV_MODE_700E, f->mode ) ||
1107+
FDV_MODE_ACTIVE( FREEDV_MODE_2020, f->mode ) ) {
1108+
f->freedv_put_next_rx_symbol = rx;
1109+
f->callback_state_sym = state;
1110+
}
1111+
}
1112+
10841113
/*---------------------------------------------------------------------------*\
10851114
10861115
FUNCTION....: freedv_set_callback_protocol

src/freedv_api.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ struct freedv_advanced {
145145

146146
// Called when text message char is decoded
147147
typedef void (*freedv_callback_rx)(void *, char);
148+
typedef void (*freedv_callback_rx_sym)(void *, _Complex float, float);
148149
// Called when new text message char is needed
149150
typedef char (*freedv_callback_tx)(void *);
150151
typedef void (*freedv_calback_error_pattern)
@@ -211,6 +212,7 @@ int freedv_check_crc16_unpacked(unsigned char *unpacked_bits, int nbits);
211212
// Set parameters ------------------------------------------------------------
212213

213214
void freedv_set_callback_txt (struct freedv *freedv, freedv_callback_rx rx, freedv_callback_tx tx, void *callback_state);
215+
void freedv_set_callback_txt_sym (struct freedv *freedv, freedv_callback_rx_sym rx, void *callback_state);
214216
void freedv_set_callback_protocol (struct freedv *freedv, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state);
215217
void freedv_set_callback_data (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state);
216218
void freedv_set_test_frames (struct freedv *freedv, int test_frames);

src/freedv_api_internal.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,10 @@ struct freedv {
170170

171171
char (*freedv_get_next_tx_char)(void *callback_state);
172172
void (*freedv_put_next_rx_char)(void *callback_state, char c);
173+
void (*freedv_put_next_rx_symbol)(void *callback_state, _Complex float sym, float amp);
173174
void *callback_state;
174-
175+
void *callback_state_sym;
176+
175177
/* user defined functions to produce and consume protocol bits */
176178
/* Protocol bits are packed MSB-first */
177179
void (*freedv_put_next_proto)(void *callback_state, char *proto_bits_packed);

src/freedv_rx.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <string.h>
3737
#include <errno.h>
3838

39+
#include "reliable_text.h"
3940
#include "freedv_api.h"
4041
#include "modem_stats.h"
4142

@@ -44,27 +45,36 @@
4445
/* optioal call-back function for received txt characters */
4546
void my_put_next_rx_char(void *states, char c) { fprintf((FILE*)states, "%c", c); }
4647

48+
static FILE* reliable_tx_fp;
49+
reliable_text_t reliable_text_obj;
50+
51+
void on_reliable_text_rx(reliable_text_t rt, const char* txt_ptr, int length, void* state)
52+
{
53+
fprintf(reliable_tx_fp, "%s\n", txt_ptr);
54+
reliable_text_reset(reliable_text_obj);
55+
}
56+
4757
int main(int argc, char *argv[]) {
4858
FILE *fin, *fout, *ftxt_rx = NULL;
49-
struct freedv *freedv;
5059
int nin, nout, nout_total = 0, frame = 0;
5160
struct MODEM_STATS stats = {0};
5261
int mode;
5362
int sync;
5463
float snr_est;
5564
float clock_offset;
56-
int use_testframes, verbose, discard, use_complex, use_dpsk;
65+
int use_testframes, verbose, discard, use_complex, use_dpsk, use_reliabletext;
5766
int use_squelch, highpassthroughgain;
5867
float squelch = 0;
5968
int i;
60-
69+
struct freedv *freedv;
70+
6171
if (argc < 4) {
6272
char f2020[80] = {0};
6373
#ifdef __LPCNET__
6474
sprintf(f2020,"|2020");
6575
#endif
6676
printf("usage: %s 1600|700C|700D|700E|2400A|2400B|800XA%s InputModemSpeechFile OutputSpeechRawFile\n"
67-
" [--testframes] [-v] [--discard] [--usecomplex] [--dpsk] [--squelch leveldB] [--txtrx filename]\n"
77+
" [--testframes] [-v] [--discard] [--usecomplex] [--dpsk] [--squelch leveldB] [--txtrx filename] [--reliabletext]\n"
6878
" [--highpassthroughgain]\n", argv[0],f2020);
6979
printf("e.g %s 1600 hts1a_fdmdv.raw hts1a_out.raw\n", argv[0]);
7080
exit(1);
@@ -100,7 +110,7 @@ int main(int argc, char *argv[]) {
100110
exit(1);
101111
}
102112

103-
use_testframes = verbose = discard = use_complex = use_dpsk = use_squelch = 0;
113+
use_testframes = verbose = discard = use_complex = use_dpsk = use_squelch = 0; use_reliabletext = 0;
104114
highpassthroughgain = 0;
105115

106116
if (argc > 4) {
@@ -119,6 +129,9 @@ int main(int argc, char *argv[]) {
119129
else if (strcmp(argv[i], "--txtrx") == 0) {
120130
ftxt_rx = fopen(argv[i+1], "wt"); i++;
121131
assert(ftxt_rx != NULL);
132+
} else if (strcmp(argv[i], "--reliabletext") == 0) {
133+
use_reliabletext = 1;
134+
// received text is saved to file specified by --txtrx.
122135
} else {
123136
fprintf(stderr, "unkown option: %s\n", argv[i]);
124137
exit(1);
@@ -143,7 +156,21 @@ int main(int argc, char *argv[]) {
143156

144157
/* install optional handler for recevied txt characters */
145158
if (ftxt_rx != NULL)
146-
freedv_set_callback_txt(freedv, my_put_next_rx_char, NULL, ftxt_rx);
159+
{
160+
if (use_reliabletext)
161+
{
162+
reliable_tx_fp = ftxt_rx;
163+
164+
reliable_text_obj = reliable_text_create();
165+
assert(reliable_text_obj != NULL);
166+
reliable_text_set_string(reliable_text_obj, "AB1CDEF", 7); // not used
167+
reliable_text_use_with_freedv(reliable_text_obj, freedv, on_reliable_text_rx, NULL);
168+
}
169+
else
170+
{
171+
freedv_set_callback_txt(freedv, my_put_next_rx_char, NULL, ftxt_rx);
172+
}
173+
}
147174

148175
/* note use of API functions to tell us how big our buffers need to be -----*/
149176

@@ -238,6 +265,12 @@ int main(int argc, char *argv[]) {
238265
}
239266
}
240267

268+
if (use_reliabletext)
269+
{
270+
reliable_text_destroy(reliable_text_obj);
271+
}
272+
241273
freedv_close(freedv);
274+
242275
return 0;
243276
}

0 commit comments

Comments
 (0)