From 65bbb0dafba465fa6a520f1636a3de875034ba40 Mon Sep 17 00:00:00 2001
From: "A. Maitland Bottoms" <bottoms@debian.org>
Date: Sun, 18 Oct 2020 21:51:16 -0400
Subject: [PATCH] freedv tx not sync block

Update FreeDV blocks to handle modes that rate shift: 2400A, 2400B
and also the new 2020 mode. Update .yml files for grc C++ generation.
---
 gr-vocoder/grc/vocoder_freedv_rx_ss.block.yml | 22 ++++++++--
 gr-vocoder/grc/vocoder_freedv_tx_ss.block.yml | 19 +++++++--
 .../include/gnuradio/vocoder/freedv_api.h     |  3 ++
 .../include/gnuradio/vocoder/freedv_tx_ss.h   |  5 ++-
 gr-vocoder/lib/freedv_tx_ss_impl.cc           | 42 ++++++++++++-------
 gr-vocoder/lib/freedv_tx_ss_impl.h            |  9 ++--
 6 files changed, 75 insertions(+), 25 deletions(-)

diff --git a/gr-vocoder/grc/vocoder_freedv_rx_ss.block.yml b/gr-vocoder/grc/vocoder_freedv_rx_ss.block.yml
index fd3392e13..ad3c169e2 100644
--- a/gr-vocoder/grc/vocoder_freedv_rx_ss.block.yml
+++ b/gr-vocoder/grc/vocoder_freedv_rx_ss.block.yml
@@ -1,14 +1,16 @@
 id: vocoder_freedv_rx_ss
 label: FreeDV demodulator
+flags: [ python, cpp ]
 
 parameters:
 -   id: mode
     label: Operating Mode
     dtype: int
     default: freedv_api.MODE_1600
-    options: [freedv_api.MODE_1600, freedv_api.MODE_700, freedv_api.MODE_700B, freedv_api.MODE_2400A,
-        freedv_api.MODE_2400B, freedv_api.MODE_800XA, freedv_api.MODE_700C, freedv_api.MODE_700D]
-    option_labels: ['1600', '700', 700B, 2400A, 2400B, 800XA, 700C, 700D]
+    options: [freedv_api.MODE_1600, freedv_api.MODE_700, freedv_api.MODE_700B,
+        freedv_api.MODE_2400A, freedv_api.MODE_2400B, freedv_api.MODE_800XA,
+        freedv_api.MODE_700C, freedv_api.MODE_700D, freedv_api.MODE_2020]
+    option_labels: ['1600', '700', 700B, 2400A, 2400B, 800XA, 700C, 700D, '2020']
 -   id: squelch_thresh
     label: Squelch Threshold
     dtype: float
@@ -39,6 +41,20 @@ templates:
     - set_squelch_en(${squelch_enable})
     - set_squelch_thresh(${squelch_thresh})
 
+cpp_templates:
+    includes: ['#include <gnuradio/vocoder/freedv_rx_ss.h>']
+    declarations: 'vocoder::freedv_rx_ss::sptr ${id};'
+    make: 'this->${id} = vocoder::freedv_rx_ss::make(${mode}, ${squelch_thresh}, ${interleave_frames});'
+    callbacks:
+    - set_squelch_en(${squelch_enable})
+    - set_squelch_thresh(${squelch_thresh})
+    link: ['gnuradio-vocoder']
+    translations:
+        "'": '"'
+        'True': 'true'
+        'False': 'false'
+        'freedv_api.': 'vocoder::freedv_api::'
+
 documentation: |-
     Not all modes may be supported by the underlying codec2 library.
     interleave_frames is an integer between 1 and 32, and is only used in the 700D mode.
diff --git a/gr-vocoder/grc/vocoder_freedv_tx_ss.block.yml b/gr-vocoder/grc/vocoder_freedv_tx_ss.block.yml
index 1fb13ec10..703768d71 100644
--- a/gr-vocoder/grc/vocoder_freedv_tx_ss.block.yml
+++ b/gr-vocoder/grc/vocoder_freedv_tx_ss.block.yml
@@ -1,14 +1,16 @@
 id: vocoder_freedv_tx_ss
 label: FreeDV modulator
+flags: [ python, cpp ]
 
 parameters:
 -   id: mode
     label: Operating Mode
     dtype: int
     default: freedv_api.MODE_1600
-    options: [freedv_api.MODE_1600, freedv_api.MODE_700, freedv_api.MODE_700B, freedv_api.MODE_2400A,
-        freedv_api.MODE_2400B, freedv_api.MODE_800XA, freedv_api.MODE_700C, freedv_api.MODE_700D]
-    option_labels: ['1600', '700', 700B, 2400A, 2400B, 800XA, 700C, 700D]
+    options: [freedv_api.MODE_1600, freedv_api.MODE_700, freedv_api.MODE_700B,
+        freedv_api.MODE_2400A, freedv_api.MODE_2400B, freedv_api.MODE_800XA,
+        freedv_api.MODE_700C, freedv_api.MODE_700D, freedv_api.MODE_2020]
+    option_labels: ['1600', '700', 700B, 2400A, 2400B, 800XA, 700C, 700D, '2020']
 -   id: txt_msg
     label: Text Message
     dtype: string
@@ -40,6 +42,17 @@ templates:
         from gnuradio.vocoder import freedv_api
     make: vocoder.freedv_tx_ss(${mode},${txt_msg},${interleave_frames})
 
+cpp_templates:
+    includes: ['#include <gnuradio/vocoder/freedv_tx_ss.h>']
+    declarations: 'vocoder::freedv_tx_ss::sptr ${id};'
+    make: 'this->${id} = vocoder::freedv_tx_ss::make(${mode}, ${txt_msg}, ${interleave_frames});'
+    link: ['gnuradio-vocoder']
+    translations:
+        "'": '"'
+        'True': 'true'
+        'False': 'false'
+        'freedv_api.': 'vocoder::freedv_api::'
+
 documentation: |-
     Not all modes may be supported by the underlying codec2 library.
     interleave_frames is an integer between 1 and 32, and is only used in the 700D mode.
diff --git a/gr-vocoder/include/gnuradio/vocoder/freedv_api.h b/gr-vocoder/include/gnuradio/vocoder/freedv_api.h
index c025432c5..02680b87a 100644
--- a/gr-vocoder/include/gnuradio/vocoder/freedv_api.h
+++ b/gr-vocoder/include/gnuradio/vocoder/freedv_api.h
@@ -70,6 +70,9 @@ public:
         SYNC_UNSYNC = FREEDV_SYNC_UNSYNC,
         SYNC_AUTO = FREEDV_SYNC_AUTO,
         SYNC_MANUAL = FREEDV_SYNC_MANUAL,
+#endif
+#ifdef FREEDV_MODE_2020
+        MODE_2020 = FREEDV_MODE_2020,
 #endif
     };
 
diff --git a/gr-vocoder/include/gnuradio/vocoder/freedv_tx_ss.h b/gr-vocoder/include/gnuradio/vocoder/freedv_tx_ss.h
index 3c39d3495..f1d95669a 100644
--- a/gr-vocoder/include/gnuradio/vocoder/freedv_tx_ss.h
+++ b/gr-vocoder/include/gnuradio/vocoder/freedv_tx_ss.h
@@ -23,7 +23,7 @@
 #ifndef INCLUDED_VOCODER_FREEDV_TX_H
 #define INCLUDED_VOCODER_FREEDV_TX_H
 
-#include <gnuradio/sync_block.h>
+#include <gnuradio/block.h>
 #include <gnuradio/vocoder/api.h>
 #include <gnuradio/vocoder/freedv_api.h>
 
@@ -37,9 +37,10 @@ namespace vocoder {
  * Input: Speech (audio) signal as 16-bit shorts, sampling rate 8 kHz.
  *
  * Output: Signal (audio) as 16-bit shorts, sampling rate 8 kHz.
+ *         (sampling rate is 48 kHz for 2400A and 2400B modes.)
  *
  */
-class VOCODER_API freedv_tx_ss : virtual public gr::sync_block
+class VOCODER_API freedv_tx_ss : virtual public gr::block
 {
 public:
     typedef boost::shared_ptr<freedv_tx_ss> sptr;
diff --git a/gr-vocoder/lib/freedv_tx_ss_impl.cc b/gr-vocoder/lib/freedv_tx_ss_impl.cc
index 784a32686..80aae3fc0 100644
--- a/gr-vocoder/lib/freedv_tx_ss_impl.cc
+++ b/gr-vocoder/lib/freedv_tx_ss_impl.cc
@@ -62,12 +62,12 @@ freedv_tx_ss::make(int mode, const std::string msg_txt, int interleave_frames)
 freedv_tx_ss_impl::freedv_tx_ss_impl(int mode,
                                      const std::string msg_txt,
                                      int interleave_frames)
-    : sync_block("vocoder_freedv_tx_ss",
-                 io_signature::make(1, 1, sizeof(short)),
-                 io_signature::make(1, 1, sizeof(short))),
-      d_mode(mode),
-      d_msg_text(msg_txt),
-      d_interleave_frames(interleave_frames)
+  : gr::block("vocoder_freedv_tx_ss",
+	      io_signature::make(1, 1, sizeof(short)),
+	      io_signature::make(1, 1, sizeof(short))),
+    d_mode(mode),
+    d_msg_text(msg_txt),
+    d_interleave_frames(interleave_frames)
 {
 #ifdef FREEDV_MODE_700D
     if (mode == FREEDV_MODE_700D) {
@@ -85,6 +85,7 @@ freedv_tx_ss_impl::freedv_tx_ss_impl(int mode,
     snprintf(d_cb_state.tx_str, 79, "%s", d_msg_text.c_str());
     d_cb_state.ptx_str = d_cb_state.tx_str;
     freedv_set_callback_txt(d_freedv, NULL, get_next_tx_char, (void*)&d_cb_state);
+    d_speech_samples = freedv_get_n_speech_samples(d_freedv);
     d_nom_modem_samples = freedv_get_n_nom_modem_samples(d_freedv);
     set_output_multiple(d_nom_modem_samples);
 }
@@ -123,18 +124,31 @@ void freedv_tx_ss_impl::set_tx_bpf(bool val)
         freedv_tx_ss_impl::set_tx_bpf(0);
 }
 
-int freedv_tx_ss_impl::work(int noutput_items,
-                            gr_vector_const_void_star& input_items,
-                            gr_vector_void_star& output_items)
+void freedv_tx_ss_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required)
+{
+    unsigned ninputs = ninput_items_required.size();
+    for (unsigned i = 0; i < ninputs; i++)
+      ninput_items_required[i] = (noutput_items / d_nom_modem_samples) * d_speech_samples;
+}
+
+int freedv_tx_ss_impl::general_work(int noutput_items,
+                                    gr_vector_int& ninput_items,
+				    gr_vector_const_void_star& input_items,
+				    gr_vector_void_star& output_items)
 {
     short* in = (short*)input_items[0];
     short* out = (short*)output_items[0];
-    int i;
+    int in_offset = 0, out_offset = 0;
+
+    while ((noutput_items - out_offset) >= d_nom_modem_samples &&
+           (ninput_items[0] - in_offset) >= d_speech_samples) {
+        freedv_tx(d_freedv, out + out_offset, in + in_offset);
+	out_offset += d_nom_modem_samples;
+        in_offset += d_speech_samples;
+    }
 
-    for (i = 0; i < (noutput_items / d_nom_modem_samples); i++)
-        freedv_tx(
-            d_freedv, &(out[i * d_nom_modem_samples]), &(in[i * d_nom_modem_samples]));
-    return noutput_items;
+    consume_each(in_offset);
+    return out_offset;
 }
 
 } /* namespace vocoder */
diff --git a/gr-vocoder/lib/freedv_tx_ss_impl.h b/gr-vocoder/lib/freedv_tx_ss_impl.h
index 5db48097e..13838fd38 100644
--- a/gr-vocoder/lib/freedv_tx_ss_impl.h
+++ b/gr-vocoder/lib/freedv_tx_ss_impl.h
@@ -72,9 +72,12 @@ public:
     void set_tx_bpf(int val);
 
     // Where all the action really happens
-    int work(int noutput_items,
-             gr_vector_const_void_star& input_items,
-             gr_vector_void_star& output_items);
+    void forecast(int noutput_items, gr_vector_int& ninput_items_required);
+
+    int general_work(int noutput_items,
+                     gr_vector_int& ninput_items,
+		     gr_vector_const_void_star& input_items,
+		     gr_vector_void_star& output_items);
 };
 
 } /* namespace vocoder */
-- 
2.20.1

