diff --git a/examples/morse_decoding_flowgraph.grc b/examples/morse_decoding_flowgraph.grc
index a148221..71e9820 100644
--- a/examples/morse_decoding_flowgraph.grc
+++ b/examples/morse_decoding_flowgraph.grc
@@ -97,7 +97,7 @@
_coordinate
- (136, 120)
+ (216, 25)
gui_hint
@@ -171,6 +171,96 @@
8000
+
+ variable_qtgui_range
+
+ comment
+
+
+
+ value
+ 0
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (392, 49)
+
+
+ gui_hint
+
+
+
+ _rotation
+ 0
+
+
+ id
+ switch
+
+
+ label
+ Switch
+
+
+ min_len
+ 200
+
+
+ orient
+ Qt.Horizontal
+
+
+ start
+ 0
+
+
+ step
+ 1
+
+
+ stop
+ 1
+
+
+ rangeType
+ float
+
+
+ widget
+ counter_slider
+
+
+
+ variable
+
+ comment
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (16, 237)
+
+
+ _rotation
+ 0
+
+
+ id
+ taps
+
+
+ value
+ 12
+
+
analog_agc2_xx
@@ -199,7 +289,7 @@
_coordinate
- (672, 320)
+ (584, 368)
_rotation
@@ -211,7 +301,7 @@
id
- analog_agc2_xx_0
+ analog_agc2_xx_0_0
max_gain
@@ -293,53 +383,6 @@
8192
-
- audio_sink
-
- alias
-
-
-
- comment
-
-
-
- affinity
-
-
-
- device_name
-
-
-
- _enabled
- 1
-
-
- _coordinate
- (1032, 348)
-
-
- _rotation
- 0
-
-
- id
- audio_sink_0
-
-
- num_inputs
- 1
-
-
- ok_to_block
- True
-
-
- samp_rate
- samp_rate
-
-
blocks_add_xx
@@ -391,6 +434,57 @@
1
+
+ blocks_file_sink
+
+ append
+ False
+
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ file
+ /home/surligas/test.dat
+
+
+ _coordinate
+ (1104, 296)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_file_sink_0
+
+
+ type
+ float
+
+
+ unbuffered
+ False
+
+
+ vlen
+ 1
+
+
blocks_moving_average_xx
@@ -411,7 +505,7 @@
_coordinate
- (728, 134)
+ (880, 158)
_rotation
@@ -423,7 +517,7 @@
length
- 8
+ taps
max_iter
@@ -470,7 +564,7 @@
_coordinate
- (344, 276)
+ (216, 276)
_rotation
@@ -497,6 +591,108 @@
1
+
+ blocks_multiply_const_vxx
+
+ alias
+
+
+
+ comment
+
+
+
+ const
+ const
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (416, 396)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_multiply_const_vxx_0_0
+
+
+ type
+ float
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ vlen
+ 1
+
+
+
+ blocks_multiply_const_vxx
+
+ alias
+
+
+
+ comment
+
+
+
+ const
+ switch
+
+
+ affinity
+
+
+
+ _enabled
+ 2
+
+
+ _coordinate
+ (872, 340)
+
+
+ _rotation
+ 180
+
+
+ id
+ blocks_multiply_const_vxx_1
+
+
+ type
+ float
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ vlen
+ 1
+
+
blocks_multiply_xx
@@ -517,7 +713,7 @@
_coordinate
- (616, 136)
+ (768, 256)
_rotation
@@ -548,6 +744,61 @@
1
+
+ blocks_throttle
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (368, 276)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_throttle_0
+
+
+ ignoretag
+ True
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ samples_per_second
+ samp_rate
+
+
+ type
+ float
+
+
+ vlen
+ 1
+
+
blocks_wavfile_source
@@ -572,7 +823,7 @@
_coordinate
- (96, 237)
+ (40, 365)
_rotation
@@ -631,7 +882,7 @@
_coordinate
- (1032, 166)
+ (1096, 110)
gui_hint
@@ -735,7 +986,7 @@
label3
- Square
+
marker3
@@ -899,7 +1150,7 @@
nconnections
- 3
+ 1
size
@@ -958,6 +1209,37 @@
-1
+
+ satnogs_clear_text_msg_sink
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (1080, 544)
+
+
+ _rotation
+ 0
+
+
+ id
+ satnogs_clear_text_msg_sink_0
+
+
satnogs_cw_matched_filter_ff
@@ -982,7 +1264,7 @@
_coordinate
- (480, 262)
+ (536, 270)
_rotation
@@ -1009,27 +1291,107 @@
20
+
+ satnogs_cw_to_symbol
+
+ threshold
+ 20e3
+
+
+ alias
+
+
+
+ comment
+
+
+
+ conf_level
+ 0.85
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (856, 383)
+
+
+ _rotation
+ 0
+
+
+ id
+ satnogs_cw_to_symbol_0
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ sampling_rate
+ samp_rate
+
+
+ wpm
+ 20
+
+
+
+ satnogs_morse_decoder
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (848, 540)
+
+
+ _rotation
+ 0
+
+
+ id
+ satnogs_morse_decoder_0
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ unrecognized_char
+ ord('#')
+
+
- analog_agc2_xx_0
- audio_sink_0
- 0
- 0
-
-
- analog_agc2_xx_0
- blocks_multiply_xx_0
- 0
- 0
-
-
- analog_agc2_xx_0
- blocks_multiply_xx_0
- 0
- 1
-
-
- analog_agc2_xx_0
- qtgui_time_sink_x_0
+ analog_agc2_xx_0_0
+ satnogs_cw_matched_filter_ff_0
0
0
@@ -1045,15 +1407,39 @@
0
0
+
+ blocks_moving_average_xx_0
+ blocks_file_sink_0
+ 0
+ 0
+
+
+ blocks_moving_average_xx_0
+ blocks_multiply_const_vxx_1
+ 0
+ 0
+
blocks_moving_average_xx_0
qtgui_time_sink_x_0
0
- 2
+ 0
blocks_multiply_const_vxx_0
- satnogs_cw_matched_filter_ff_0
+ blocks_throttle_0
+ 0
+ 0
+
+
+ blocks_multiply_const_vxx_0_0
+ analog_agc2_xx_0_0
+ 0
+ 0
+
+
+ blocks_multiply_const_vxx_1
+ satnogs_cw_to_symbol_0
0
0
@@ -1063,6 +1449,12 @@
0
0
+
+ blocks_throttle_0
+ blocks_multiply_const_vxx_0_0
+ 0
+ 0
+
blocks_wavfile_source_0
blocks_add_xx_0
@@ -1071,14 +1463,26 @@
satnogs_cw_matched_filter_ff_0
- analog_agc2_xx_0
+ blocks_multiply_xx_0
0
0
satnogs_cw_matched_filter_ff_0
- qtgui_time_sink_x_0
+ blocks_multiply_xx_0
0
1
+
+ satnogs_cw_to_symbol_0
+ satnogs_morse_decoder_0
+ out
+ in
+
+
+ satnogs_morse_decoder_0
+ satnogs_clear_text_msg_sink_0
+ out
+ in
+
diff --git a/examples/test_matched_filter.grc b/examples/test_matched_filter.grc
index 0c03289..1691611 100644
--- a/examples/test_matched_filter.grc
+++ b/examples/test_matched_filter.grc
@@ -81,6 +81,69 @@
+
+ variable_qtgui_range
+
+ comment
+
+
+
+ value
+ 1
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (152, 113)
+
+
+ gui_hint
+
+
+
+ _rotation
+ 0
+
+
+ id
+ const
+
+
+ label
+ Signal Amplitude
+
+
+ min_len
+ 200
+
+
+ orient
+ Qt.Horizontal
+
+
+ start
+ 0
+
+
+ step
+ 0.01
+
+
+ stop
+ 5
+
+
+ rangeType
+ float
+
+
+ widget
+ counter_slider
+
+
variable
@@ -108,6 +171,33 @@
8000
+
+ variable
+
+ comment
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (8, 229)
+
+
+ _rotation
+ 0
+
+
+ id
+ taps
+
+
+ value
+ 12
+
+
analog_agc2_xx
@@ -128,7 +218,7 @@
decay_rate
- 2e-6
+ 6.25e-4
_enabled
@@ -136,7 +226,7 @@
_coordinate
- (752, 320)
+ (536, 384)
_rotation
@@ -148,7 +238,7 @@
id
- analog_agc2_xx_0
+ analog_agc2_xx_0_0
max_gain
@@ -230,53 +320,6 @@
8192
-
- audio_sink
-
- alias
-
-
-
- comment
-
-
-
- affinity
-
-
-
- device_name
-
-
-
- _enabled
- 1
-
-
- _coordinate
- (1032, 348)
-
-
- _rotation
- 0
-
-
- id
- audio_sink_0
-
-
- num_inputs
- 1
-
-
- ok_to_block
- True
-
-
- samp_rate
- samp_rate
-
-
blocks_add_xx
@@ -297,7 +340,7 @@
_coordinate
- (416, 440)
+ (240, 344)
_rotation
@@ -328,6 +371,218 @@
1
+
+ blocks_moving_average_xx
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (936, 150)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_moving_average_xx_0
+
+
+ length
+ taps
+
+
+ max_iter
+ 4000
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ scale
+ 1
+
+
+ type
+ float
+
+
+
+ blocks_multiply_const_vxx
+
+ alias
+
+
+
+ comment
+
+
+
+ const
+ const
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (424, 508)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_multiply_const_vxx_0
+
+
+ type
+ float
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ vlen
+ 1
+
+
+
+ blocks_multiply_xx
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (768, 176)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_multiply_xx_0
+
+
+ type
+ float
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ num_inputs
+ 2
+
+
+ vlen
+ 1
+
+
+
+ blocks_throttle
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (344, 356)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_throttle_0
+
+
+ ignoretag
+ True
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ samples_per_second
+ samp_rate
+
+
+ type
+ float
+
+
+ vlen
+ 1
+
+
blocks_wavfile_source
@@ -411,7 +666,7 @@
_coordinate
- (952, 166)
+ (1112, 166)
gui_hint
@@ -679,7 +934,7 @@
nconnections
- 2
+ 1
size
@@ -762,7 +1017,7 @@
_coordinate
- (536, 222)
+ (488, 182)
_rotation
@@ -790,14 +1045,8 @@
- analog_agc2_xx_0
- audio_sink_0
- 0
- 0
-
-
- analog_agc2_xx_0
- qtgui_time_sink_x_0
+ analog_agc2_xx_0_0
+ satnogs_cw_matched_filter_ff_0
0
0
@@ -809,7 +1058,31 @@
blocks_add_xx_0
- satnogs_cw_matched_filter_ff_0
+ blocks_throttle_0
+ 0
+ 0
+
+
+ blocks_moving_average_xx_0
+ qtgui_time_sink_x_0
+ 0
+ 0
+
+
+ blocks_multiply_const_vxx_0
+ analog_agc2_xx_0_0
+ 0
+ 0
+
+
+ blocks_multiply_xx_0
+ blocks_moving_average_xx_0
+ 0
+ 0
+
+
+ blocks_throttle_0
+ blocks_multiply_const_vxx_0
0
0
@@ -821,13 +1094,13 @@
satnogs_cw_matched_filter_ff_0
- analog_agc2_xx_0
+ blocks_multiply_xx_0
0
0
satnogs_cw_matched_filter_ff_0
- qtgui_time_sink_x_0
+ blocks_multiply_xx_0
0
1
diff --git a/grc/satnogs_cw_to_symbol.xml b/grc/satnogs_cw_to_symbol.xml
index 36bd9a7..46d447f 100644
--- a/grc/satnogs_cw_to_symbol.xml
+++ b/grc/satnogs_cw_to_symbol.xml
@@ -4,7 +4,7 @@
satnogs_cw_to_symbol
satnogs
import satnogs
- satnogs.cw_to_symbol($sampling_rate, $threshold, $wpm)
+ satnogs.cw_to_symbol($sampling_rate, $threshold, $conf_level, $wpm)
Sampling Rate
@@ -18,6 +18,13 @@
threshold
real
+
+
+ Confidence Level
+ conf_level
+ 0.9
+ real
+
Words per Minute
diff --git a/include/satnogs/cw_to_symbol.h b/include/satnogs/cw_to_symbol.h
index ac53400..32e6f02 100644
--- a/include/satnogs/cw_to_symbol.h
+++ b/include/satnogs/cw_to_symbol.h
@@ -51,9 +51,15 @@ namespace gr {
*
* @param sampling_rate the sampling rate of the signal
* @param threshold the activation threshold
+ * @param conf_level the confidence level, for the decisions made by
+ * the decoder. Higher values, means that the decoder would be more
+ * conservative, whereas lower may help in noisy environments but may
+ * trigger false alarms too, especially for the case of short pauses
+ * symbols
* @param wpm Morse code Words per Minute
*/
- static sptr make(double sampling_rate, float threshold, size_t wpm = 20);
+ static sptr make(double sampling_rate, float threshold,
+ float conf_level = 0.9, size_t wpm = 20);
};
} // namespace satnogs
diff --git a/lib/cw_to_symbol_impl.cc b/lib/cw_to_symbol_impl.cc
index 3aa39f9..113d825 100644
--- a/lib/cw_to_symbol_impl.cc
+++ b/lib/cw_to_symbol_impl.cc
@@ -24,7 +24,6 @@
#include
#include
-#include
#include "cw_to_symbol_impl.h"
namespace gr
@@ -33,34 +32,42 @@ namespace gr
{
cw_to_symbol::sptr
- cw_to_symbol::make (double sampling_rate, float threshold, size_t wpm)
+ cw_to_symbol::make (double sampling_rate, float threshold,
+ float conf_level, size_t wpm)
{
return gnuradio::get_initial_sptr (
- new cw_to_symbol_impl (sampling_rate, threshold, wpm));
+ new cw_to_symbol_impl (sampling_rate, threshold, conf_level, wpm));
}
/*
* The private constructor
*/
cw_to_symbol_impl::cw_to_symbol_impl (double sampling_rate, float threshold,
- size_t wpm) :
+ float conf_level, size_t wpm) :
gr::sync_block ("cw_to_symbol",
gr::io_signature::make (1, 1, sizeof(float)),
gr::io_signature::make (0, 0, 0)),
d_sampling_rate(sampling_rate),
d_act_thrshld(threshold),
- d_confidence_level(0.90),
+ d_confidence_level(conf_level),
d_dot_samples((1.2/wpm) / (1.0 / sampling_rate)),
d_dash_samples(3 * d_dot_samples),
d_short_pause_samples(3 * d_dot_samples),
d_long_pause_samples(7 * d_dot_samples),
d_state(IDLE),
d_state_cnt(0),
- d_pause_cnt(0)
+ d_pause_cnt(0),
+ d_seq_started(false)
{
message_port_register_out(pmt::mp("out"));
}
+ inline void
+ cw_to_symbol_impl::send_symbol_msg (morse_symbol_t s)
+ {
+ message_port_pub(pmt::mp("out"), pmt::from_long(s));
+ }
+
/*
* Our virtual destructor.
*/
@@ -71,6 +78,7 @@ namespace gr
inline void
cw_to_symbol_impl::set_idle ()
{
+ LOG_WARN("Enter IDLE");
d_state = IDLE;
d_state_cnt = 0;
d_pause_cnt = 0;
@@ -79,33 +87,32 @@ namespace gr
inline void
cw_to_symbol_impl::set_short_on ()
{
+ LOG_WARN("Enter SHORT ON");
d_state = SHORT_ON_PERIOD;
d_state_cnt = 1;
+ d_pause_cnt = 0;
}
inline void
cw_to_symbol_impl::set_long_on ()
{
+ LOG_WARN("Enter LONG ON");
d_state = LONG_ON_PERIOD;
- d_pause_cnt = 0;
}
inline void
- cw_to_symbol_impl::set_short_off (size_t borrow_cnt)
+ cw_to_symbol_impl::set_short_off ()
{
+ LOG_WARN("Enter SHORT OFF");
d_state = SHORT_OFF_PERIOD;
d_state_cnt = 0;
- d_pause_cnt += borrow_cnt;
-
- /* Due to time-slots borrowing we may be already at the Long pause */
- if(d_pause_cnt > d_short_pause_samples) {
- d_state = LONG_OFF_PERIOD;
- }
+ d_pause_cnt = 1;
}
inline void
cw_to_symbol_impl::set_long_off ()
{
+ LOG_WARN("Enter LONG OFF");
d_state = LONG_OFF_PERIOD;
}
@@ -124,7 +131,6 @@ namespace gr
if(in[i] > d_act_thrshld) {
set_short_on();
}
- // TODO Avoid unnecessary pause messages
break;
case SHORT_ON_PERIOD:
@@ -140,17 +146,16 @@ namespace gr
* Before going to short pause, check the confidence level.
* Perhaps a short symbol should be produced.
*
- * Otherwise, it was a false alarm. So the time-slots counted
- * so far should be assigned as pause time-slots.
+ * Otherwise, it was a false alarm.
*/
conf_lvl = ((float) d_state_cnt) / d_dot_samples;
if(conf_lvl > d_confidence_level){
- message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_DOT));
- set_short_off(0);
- }
- else{
- set_short_off(d_state_cnt);
+ LOG_DEBUG("Short space");
+ send_symbol_msg(MORSE_S_SPACE);
}
+
+ /* Go find a possible short pause symbol */
+ set_short_off();
}
break;
@@ -158,25 +163,37 @@ namespace gr
if( in[i] > d_act_thrshld ) {
d_state_cnt++;
}
- else{
- /*
- * In this case the FSM should continue at the SHORT_OFF state.
- * Before this depending the confidence for a long pulse, produce
- * a short or long pulse message
- */
+ else {
conf_lvl = ((float) d_state_cnt) / d_dash_samples;
- if(conf_lvl > d_confidence_level){
- message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_DASH));
+ if(conf_lvl > d_confidence_level) {
+ LOG_DEBUG("DASH");
+ send_symbol_msg(MORSE_DASH);
+ set_short_off();
+ break;
}
- else{
- message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_DOT));
+
+ /* Perhaps this was a short on symbol */
+ conf_lvl = ((float) d_state_cnt) / d_dot_samples;
+ if(conf_lvl > d_confidence_level) {
+ LOG_DEBUG("DOT");
+ send_symbol_msg(MORSE_DOT);
+ set_short_off();
}
- set_short_off(0);
+
}
break;
case SHORT_OFF_PERIOD:
if(in[i] > d_act_thrshld) {
+ /*
+ * Before going to ON state, again check if a short pause symbol
+ * should be produced
+ */
+ conf_lvl = ((float) d_pause_cnt) / d_short_pause_samples;
+ if(conf_lvl > d_confidence_level) {
+ LOG_DEBUG("Short space");
+ send_symbol_msg(MORSE_S_SPACE);
+ }
set_short_on();
}
else {
@@ -186,14 +203,32 @@ namespace gr
}
}
break;
+
case LONG_OFF_PERIOD:
if(in[i] > d_act_thrshld) {
+ conf_lvl = ((float) d_pause_cnt) / d_long_pause_samples;
+ if (conf_lvl > d_confidence_level) {
+ LOG_DEBUG("Long space");
+ send_symbol_msg (MORSE_L_SPACE);
+ set_idle();
+ break;
+ }
+ else {
+ LOG_DEBUG("Short space");
+ send_symbol_msg (MORSE_S_SPACE);
+ }
set_short_on();
}
else {
d_pause_cnt++;
+ /*
+ * If the pause duration is greater than the long pause symbol,
+ * definitely a long pause symbol should be produced
+ */
if(d_pause_cnt > d_long_pause_samples) {
- message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_L_SPACE));
+ LOG_DEBUG("Long space");
+ send_symbol_msg(MORSE_L_SPACE);
+ d_seq_started = false;
set_idle();
}
}
diff --git a/lib/cw_to_symbol_impl.h b/lib/cw_to_symbol_impl.h
index 790eac0..98812a0 100644
--- a/lib/cw_to_symbol_impl.h
+++ b/lib/cw_to_symbol_impl.h
@@ -21,6 +21,7 @@
#ifndef INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H
#define INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H
+#include
#include
namespace gr
@@ -48,6 +49,7 @@ namespace gr
cw_state_t d_state;
size_t d_state_cnt;
size_t d_pause_cnt;
+ bool d_seq_started;
inline void
set_idle ();
@@ -59,13 +61,17 @@ namespace gr
set_long_on ();
inline void
- set_short_off (size_t borrow_cnt);
+ set_short_off ();
inline void
set_long_off ();
+ inline void
+ send_symbol_msg (morse_symbol_t s);
+
public:
- cw_to_symbol_impl (double sampling_rate, float threshold, size_t wpm);
+ cw_to_symbol_impl (double sampling_rate, float threshold,
+ float conf_level, size_t wpm);
~cw_to_symbol_impl ();
// Where all the action really happens
diff --git a/lib/morse_decoder_impl.cc b/lib/morse_decoder_impl.cc
index f1a90b6..4d91e36 100644
--- a/lib/morse_decoder_impl.cc
+++ b/lib/morse_decoder_impl.cc
@@ -56,6 +56,11 @@ namespace gr
* word
*/
case MORSE_L_SPACE:
+ /* Just ignore the word separator if no word is yet decoded */
+ if (d_morse_tree.get_word_len() == 0) {
+ res = true;
+ break;
+ }
str = d_morse_tree.get_word();
d_morse_tree.reset();
message_port_pub(pmt::mp("out"), pmt::make_blob(str.c_str(),
diff --git a/lib/morse_tree.cc b/lib/morse_tree.cc
index 9d65eaa..b4bf901 100644
--- a/lib/morse_tree.cc
+++ b/lib/morse_tree.cc
@@ -217,6 +217,13 @@ namespace gr
}
break;
case MORSE_S_SPACE:
+ /*
+ * A short space received, but the decoder is still at the root.
+ * This is not in general an error so we return true
+ */
+ if(d_current == d_root){
+ return true;
+ }
c = d_current->get_char ();
d_current = d_root;
/*