diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 07917f9..e1fbdf7 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -24,6 +24,7 @@ list(APPEND debug_blocks satnogs_debug_msg_source.xml satnogs_debug_msg_source_raw.xml satnogs_leo_channel.xml + satnogs_cw_encoder.xml ) list(APPEND enabled_blocks @@ -50,7 +51,6 @@ install(FILES ${enabled_blocks} satnogs_ogg_source.xml satnogs_noaa_apt_sink.xml - satnogs_frame_file_sink.xml + satnogs_frame_file_sink.xml DESTINATION share/gnuradio/grc/blocks satnogs_iq_sink.xml - satnogs_cw_encoder.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/satnogs_cw_encoder.xml b/grc/satnogs_cw_encoder.xml index c3d5288..6ac5c15 100644 --- a/grc/satnogs_cw_encoder.xml +++ b/grc/satnogs_cw_encoder.xml @@ -1,38 +1,39 @@ - cw_encoder + CW Encoder satnogs_cw_encoder - [satnogs] + [SatNOGS]/Debug import satnogs satnogs.cw_encoder($samp_rate, $cw_freq, $wpm) - + - ... - ... - ... + Sample Rate + samp_rate + samp_rate + real + + + + CW Frequency + cw_freq + 700 + real + + + + Words per minute + wpm + 20 + int - - in - + symbol + message - out - + complex diff --git a/include/satnogs/CMakeLists.txt b/include/satnogs/CMakeLists.txt index 63b6843..d8e1ee5 100644 --- a/include/satnogs/CMakeLists.txt +++ b/include/satnogs/CMakeLists.txt @@ -21,10 +21,11 @@ # Install public header files ######################################################################## list(APPEND DEBUG_HEADER_FILES - morse_debug_source.h - debug_msg_source_raw.h - debug_msg_source.h - leo_channel.h + morse_debug_source.h + debug_msg_source_raw.h + debug_msg_source.h + leo_channel.h + cw_encoder.h ) list(APPEND HEADER_FILES @@ -64,7 +65,6 @@ install(FILES ${HEADER_FILES} ogg_source.h noaa_apt_sink.h - frame_file_sink.h + frame_file_sink.h DESTINATION include/satnogs iq_sink.h DESTINATION - cw_encoder.h DESTINATION include/satnogs ) \ No newline at end of file diff --git a/include/satnogs/morse.h b/include/satnogs/morse.h index e5e3044..af643b5 100644 --- a/include/satnogs/morse.h +++ b/include/satnogs/morse.h @@ -2,7 +2,8 @@ /* * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * - * Copyright (C) 2016, Libre Space Foundation + * Copyright (C) 2016,2017 + * Libre Space Foundation * * 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 @@ -27,10 +28,11 @@ * The different Morse symbols */ typedef enum { - MORSE_DOT = 0,//!< MORSE_DOT Morse dot (.) symbol - MORSE_DASH, //!< MORSE_DASH Morse dash (-) symbol - MORSE_S_SPACE,//!< MORSE_S_SPACE Morse short space between characters - MORSE_L_SPACE //!< MORSE_L_SPACE Morse long space between words + MORSE_DOT = 0, //!< Morse dot (.) symbol + MORSE_DASH, //!< Morse dash (-) symbol + MORSE_INTRA_SPACE, //!< Space between dot and dash symbols + MORSE_S_SPACE, //!< Morse short space between characters + MORSE_L_SPACE //! +#include #include "cw_encoder_impl.h" namespace gr { namespace satnogs { - const std::vector cw_encoder_impl::cw_chars ( - { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', - '3', '4', '5', '6', '7', '8', '9', '0' }); - const std::vector cw_encoder_impl::cw_symbols ( - { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", - ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", - "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", ".----", - "..---", "...--", "....-", ".....", "-....", "--...", "---..", - "----.", "-----" }); - cw_encoder::sptr cw_encoder::make(double samp_rate, double cw_freq, size_t wpm) { @@ -60,11 +50,11 @@ namespace gr { d_wpm (wpm), d_dot_samples ((1.2 / wpm) / (1.0 / samp_rate)), d_window_size (0), - d_nco (), - d_word (new uint8_t[2048]), - d_remaining (0) + d_windows_remaining (0), + d_cw_symbol (MORSE_L_SPACE), + d_nco () { - message_port_register_in(pmt::mp("word")); + message_port_register_in(pmt::mp("symbol")); /* * Try to split the CW pulses in smaller windows for dealing efficiently @@ -82,6 +72,7 @@ namespace gr { d_window_size++; } + set_output_multiple(d_window_size); d_nco.set_freq ((2 * M_PI * cw_freq) / samp_rate); } @@ -90,31 +81,6 @@ namespace gr { */ cw_encoder_impl::~cw_encoder_impl() { - delete [] d_word; - } - - static inline size_t - find_char_idx(const char* characters, size_t len, char c) - { - size_t i; - for(i = 0; i < len; i++) { - if(characters[i] == c){ - return i; - } - } - return len; - } - - std::string - cw_encoder_impl::get_cw_symbol (char c) - { - size_t i; - for(i = 0; i < cw_chars.size(); i++) { - if(cw_chars[i] == c) { - return cw_symbols[i]; - } - } - return ""; } int @@ -122,19 +88,56 @@ namespace gr { gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - gr_complex *out = (gr_complex *) output_items[0]; size_t available; + size_t i; + gr_complex *out = (gr_complex *) output_items[0]; - if(d_remaining == 0) { - pmt::pmt_t w = delete_head_blocking(pmt::mp("word")); - if(pmt::blob_length(w) > 2048) { - return 0; - } - d_word = (uint8_t *) pmt::blob_data(w); - d_remaining = pmt::blob_length(w); + if(noutput_items < 0) { + return noutput_items; } - return noutput_items; + if(d_windows_remaining == 0) { + pmt::pmt_t symbol = delete_head_blocking(pmt::mp("symbol")); + d_cw_symbol = (morse_symbol_t) pmt::to_long(symbol); + /* Reset NCO so the amplitude starts from zero */ + d_nco.set_freq ((2 * M_PI * d_cw_freq) / d_samp_rate); + switch(d_cw_symbol) { + case MORSE_DOT: + case MORSE_INTRA_SPACE: + d_windows_remaining = d_dot_samples / d_window_size; + break; + case MORSE_DASH: + case MORSE_S_SPACE: + d_windows_remaining = (d_dot_samples / d_window_size) * 3; + break; + case MORSE_L_SPACE: + d_windows_remaining = (d_dot_samples / d_window_size) * 7; + break; + default: + LOG_WARN("Unrecognized CW symbol"); + return 0; + } + } + + for(i = 0; i < (size_t)noutput_items / d_window_size; i++) { + switch(d_cw_symbol){ + case MORSE_S_SPACE: + case MORSE_L_SPACE: + case MORSE_INTRA_SPACE: + memset (out + i * d_window_size, 0, + d_window_size * sizeof(gr_complex)); + break; + case MORSE_DOT: + case MORSE_DASH: + d_nco.sincos(out + i * d_window_size, d_window_size, 1.0); + break; + } + d_windows_remaining--; + if(d_windows_remaining == 0) { + return (i + 1) * d_window_size; + } + } + return i * d_window_size; } } /* namespace satnogs */ diff --git a/lib/cw_encoder_impl.h b/lib/cw_encoder_impl.h index bc92e9d..747cf8d 100644 --- a/lib/cw_encoder_impl.h +++ b/lib/cw_encoder_impl.h @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace gr @@ -40,16 +41,16 @@ namespace gr const size_t d_wpm; const size_t d_dot_samples; size_t d_window_size; + size_t d_windows_remaining; + morse_symbol_t d_cw_symbol; gr::fxpt_nco d_nco; - uint8_t *d_word; - size_t d_remaining; + + std::string get_cw_symbol(char c); public: - static const std::vector cw_chars; - static const std::vector cw_symbols; cw_encoder_impl (double samp_rate, double cw_freq, size_t wpm); ~cw_encoder_impl (); diff --git a/lib/morse_debug_source_impl.cc b/lib/morse_debug_source_impl.cc index 7fd4425..448fe09 100644 --- a/lib/morse_debug_source_impl.cc +++ b/lib/morse_debug_source_impl.cc @@ -2,7 +2,8 @@ /* * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * - * Copyright (C) 2016, Libre Space Foundation + * Copyright (C) 2016, 2017 + * Libre Space Foundation * * 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 @@ -27,55 +28,55 @@ #include #include -namespace gr { - namespace satnogs { +namespace gr +{ + namespace satnogs + { morse_debug_source::sptr - morse_debug_source::make(const std::string& debug_seq, - bool inject_errors, - float error_prob) + morse_debug_source::make (const std::string& debug_seq, bool inject_errors, + float error_prob) { - return gnuradio::get_initial_sptr - (new morse_debug_source_impl(debug_seq, inject_errors, error_prob)); + return gnuradio::get_initial_sptr ( + new morse_debug_source_impl (debug_seq, inject_errors, error_prob)); } /* * The private constructor */ - morse_debug_source_impl::morse_debug_source_impl(std::string debug_seq, - bool inject_errors, - float error_prob) - : gr::block("morse_debug_source", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(0, 0, 0)), - d_inject_errors(inject_errors), - d_p(error_prob), - d_run(true), - d_chars { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0' }, - d_symbols { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", - "....", "..", ".---", "-.-", ".-..", "--", "-.", - "---", ".--.", "--.-", ".-.", "...", "-", "..-", - "...-", ".--", "-..-", "-.--", "--..", ".----", - "..---", "...--", "....-", ".....", "-....", "--...", - "---..", "----.", "-----"} + morse_debug_source_impl::morse_debug_source_impl (std::string debug_seq, + bool inject_errors, + float error_prob) : + gr::block ("morse_debug_source", + gr::io_signature::make (0, 0, 0), + gr::io_signature::make (0, 0, 0)), + d_inject_errors (inject_errors), + d_p (error_prob), + d_run (true), + d_chars + { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }, + d_symbols + { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", + ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", + ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", + "--..", ".----", "..---", "...--", "....-", ".....", "-....", + "--...", "---..", "----.", "-----" } { - message_port_register_out(pmt::mp("out")); - d_thread = std::thread(&morse_debug_source_impl::send_debug_msg, - this, - debug_seq); + message_port_register_out (pmt::mp ("out")); + d_thread = std::thread (&morse_debug_source_impl::send_debug_msg, this, + debug_seq); } static inline size_t - find_char_idx(const char* characters, size_t len, char c) + find_char_idx (const char* characters, size_t len, char c) { size_t i; - for(i = 0; i < len; i++) { - if(characters[i] == c){ - return i; - } + for (i = 0; i < len; i++) { + if (characters[i] == c) { + return i; + } } return len; } @@ -89,65 +90,69 @@ namespace gr { std::string s; char c; std::random_device rd; - std::mt19937 gen(rd()); - std::bernoulli_distribution error_distr(d_p); + std::mt19937 gen (rd ()); + std::bernoulli_distribution error_distr (d_p); bool inject_error; - size_t len = sentence.length(); - pmt::pmt_t port = pmt::mp("out"); + size_t len = sentence.length (); + pmt::pmt_t port = pmt::mp ("out"); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - - while(d_run) { + std::this_thread::sleep_for (std::chrono::milliseconds (1000)); + + while (d_run) { /* Not the best approach, but hey, this is only for debug */ - for(i = 0; i < len; i++){ - c = std::toupper(sentence[i]); - if(c == ' '){ - message_port_pub(port, pmt::from_long(MORSE_L_SPACE)); - } + for (i = 0; i < len; i++) { + c = std::toupper (sentence[i]); + if (c == ' ') { + message_port_pub (port, pmt::from_long (MORSE_L_SPACE)); + } - idx = find_char_idx(d_chars, sizeof(d_chars), c); - if(idx != sizeof(d_chars)){ + idx = find_char_idx (d_chars, sizeof(d_chars), c); + if (idx != sizeof(d_chars)) { - s = d_symbols[idx]; - /* Get from the random distribution if an error should be injected */ - inject_error = d_inject_errors && error_distr(gen); - for(j = 0; j < s.length(); j++) { - if(s[j] == '.'){ - if(inject_error){ - message_port_pub(port, pmt::from_long(MORSE_DASH)); - } - else{ - message_port_pub(port, pmt::from_long(MORSE_DOT)); - } - } - else{ - if(inject_error){ - message_port_pub(port, pmt::from_long(MORSE_DOT)); - } - else{ - message_port_pub(port, pmt::from_long(MORSE_DASH)); - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } + s = d_symbols[idx]; + /* Get from the random distribution if an error should be injected */ + inject_error = d_inject_errors && error_distr (gen); + for (j = 0; j < s.length (); j++) { + if (s[j] == '.') { + if (inject_error) { + message_port_pub (port, pmt::from_long (MORSE_DASH)); + message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE)); - /* Send also a character delimiter after waiting a little */ - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - message_port_pub(port, pmt::from_long(MORSE_S_SPACE)); - } - } - message_port_pub(port, pmt::from_long(MORSE_L_SPACE)); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + else { + message_port_pub (port, pmt::from_long (MORSE_DOT)); + message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE)); + } + } + else { + if (inject_error) { + message_port_pub (port, pmt::from_long (MORSE_DOT)); + message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE)); + } + else { + message_port_pub (port, pmt::from_long (MORSE_DASH)); + message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE)); + } + } + std::this_thread::sleep_for (std::chrono::milliseconds (100)); + } + + /* Send also a character delimiter */ + message_port_pub (port, pmt::from_long (MORSE_S_SPACE)); + } + } + message_port_pub (port, pmt::from_long (MORSE_L_SPACE)); + std::this_thread::sleep_for (std::chrono::milliseconds (1000)); } } /* * Our virtual destructor. */ - morse_debug_source_impl::~morse_debug_source_impl() + morse_debug_source_impl::~morse_debug_source_impl () { d_run = false; - d_thread.join(); + d_thread.join (); } } /* namespace satnogs */ diff --git a/lib/morse_decoder_impl.cc b/lib/morse_decoder_impl.cc index 221156e..0e4e543 100644 --- a/lib/morse_decoder_impl.cc +++ b/lib/morse_decoder_impl.cc @@ -2,7 +2,8 @@ /* * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * - * Copyright (C) 2016, Libre Space Foundation + * Copyright (C) 2016, 2017 + * Libre Space Foundation * * 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 @@ -34,7 +35,7 @@ namespace gr morse_decoder::make (char unrecognized_char) { return gnuradio::get_initial_sptr ( - new morse_decoder_impl (unrecognized_char)); + new morse_decoder_impl (unrecognized_char)); } void @@ -45,50 +46,54 @@ namespace gr morse_symbol_t s; s = (morse_symbol_t) pmt::to_long (msg); - switch(s) { - case MORSE_DOT: - case MORSE_DASH: - case MORSE_S_SPACE: - res = d_morse_tree.received_symbol(s); - break; - /* - * If a word separator occurs it is a good time to retrieve the decoded - * word - */ - case MORSE_L_SPACE: - /* - * Inject a character separator, for the morse decoder to commit - * the outstanding character - */ - res = d_morse_tree.received_symbol(MORSE_S_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(), - str.length())); - break; - default: - LOG_ERROR("Unknown Morse symbol"); - return; - } + switch (s) + { + case MORSE_DOT: + case MORSE_DASH: + case MORSE_S_SPACE: + res = d_morse_tree.received_symbol (s); + break; + /* + * If a word separator occurs it is a good time to retrieve the decoded + * word + */ + case MORSE_L_SPACE: + /* + * Inject a character separator, for the morse decoder to commit + * the outstanding character + */ + res = d_morse_tree.received_symbol (MORSE_S_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 (), str.length ())); + break; + case MORSE_INTRA_SPACE: + /*Ignore it */ + break; + default: + LOG_ERROR("Unknown Morse symbol"); + return; + } /* * If the decoding return false, it means that either an non decode-able * character situation occurred or the maximum word limit reached */ if (!s) { - if(d_morse_tree.get_max_word_len() == d_morse_tree.get_word_len()){ - str = d_morse_tree.get_word(); - d_morse_tree.reset(); - std::cout << "Received word: " << str << std::endl; - } + if (d_morse_tree.get_max_word_len () == d_morse_tree.get_word_len ()) { + str = d_morse_tree.get_word (); + d_morse_tree.reset (); + std::cout << "Received word: " << str << std::endl; + } } - else{ - LOG_DEBUG("Something went wrong"); + else { + LOG_DEBUG("Something went wrong"); } } @@ -96,17 +101,16 @@ namespace gr * The private constructor */ morse_decoder_impl::morse_decoder_impl (char unrecognized_char) : - gr::block ("morse_decoder", - gr::io_signature::make (0, 0, 0), - gr::io_signature::make (0, 0, 0)), - d_morse_tree (unrecognized_char) + gr::block ("morse_decoder", gr::io_signature::make (0, 0, 0), + gr::io_signature::make (0, 0, 0)), + d_morse_tree (unrecognized_char) { /* Register the input and output msg handler */ message_port_register_in (pmt::mp ("in")); - message_port_register_out(pmt::mp("out")); + message_port_register_out (pmt::mp ("out")); set_msg_handler ( - pmt::mp ("in"), - boost::bind (&morse_decoder_impl::symbol_msg_handler, this, _1)); + pmt::mp ("in"), + boost::bind (&morse_decoder_impl::symbol_msg_handler, this, _1)); } } /* namespace satnogs */