diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index f6300779..70a8235b 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -85,6 +85,21 @@ void set_xylos_data(const char ccir_message[]) { send_message(&message); } +void set_afsk_data(const char message_data[], const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, + const uint32_t afsk_phase_inc_space, const uint8_t afsk_repeat, const uint32_t afsk_bw, + const bool afsk_alt_format) { + const AFSKConfigureMessage message { + message_data, + afsk_samples_per_bit, + afsk_phase_inc_mark, + afsk_phase_inc_space, + afsk_repeat, + afsk_bw, + afsk_alt_format + }; + send_message(&message); +} + static bool baseband_image_running = false; void run_image(const portapack::spi_flash::image_tag_t image_tag) { diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index a2bcea90..5b04fae5 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -53,6 +53,9 @@ struct WFMConfig { }; void set_xylos_data(const char ccir_message[]); +void set_afsk_data(const char message_data[], const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, + const uint32_t afsk_phase_inc_space, const uint8_t afsk_repeat, const uint32_t afsk_bw, + const bool afsk_alt_format); void run_image(const portapack::spi_flash::image_tag_t image_tag); void shutdown(); diff --git a/firmware/application/ui_lcr.cpp b/firmware/application/ui_lcr.cpp index 904e1fb2..bff88367 100644 --- a/firmware/application/ui_lcr.cpp +++ b/firmware/application/ui_lcr.cpp @@ -32,7 +32,6 @@ #include "hackrf_gpio.hpp" #include "portapack.hpp" #include "event_m0.hpp" -#include "radio.hpp" #include "string_format.hpp" @@ -52,16 +51,19 @@ void LCRView::focus() { } LCRView::~LCRView() { - radio::disable(); + transmitter_model.disable(); + baseband::shutdown(); } -void LCRView::make_frame() { +void LCRView::generate_message() { + // Modem sync and SOM + const char lcr_init[8] = { 127, 127, 127, 127, 127, 127, 127, 15 }; + // Eclairage (Auto, Jour, Nuit) const char ec_lut[3][2] = { { 'A', 0x00 }, { 'J', 0x00 }, - { 'N', 0x00 } - }; - char eom[3] = { 3, 0, 0 }; // EOM and space for checksum - uint8_t i, pm; + { 'N', 0x00 } }; + char eom[3] = { 3, 0, 0 }; // EOM and space for checksum + uint8_t i, pm, bit; uint16_t dp; uint8_t cp, pp, cur_byte, new_byte; @@ -74,63 +76,56 @@ void LCRView::make_frame() { } } - // Make LCR frame - memset(lcrframe, 0, 256); - lcrframe[0] = 127; // Modem sync - lcrframe[1] = 127; - lcrframe[2] = 127; - lcrframe[3] = 127; - lcrframe[4] = 127; - lcrframe[5] = 127; - lcrframe[6] = 127; - lcrframe[7] = 15; // SOM + // Compose LCR message + memset(lcr_message, 0, 256); + memcpy(lcr_message, lcr_init, 8); - strcat(lcrframe, rgsb); - strcat(lcrframe, "PA "); + strcat(lcr_message, rgsb); // Address + strcat(lcr_message, "PA "); if (checkbox_am_a.value() == true) { - strcat(lcrframe, "AM=1 AF=\""); - strcat(lcrframe, litteral[0]); - strcat(lcrframe, "\" CL=0 "); + strcat(lcr_message, "AM=1 AF=\""); + strcat(lcr_message, litteral[0]); + strcat(lcr_message, "\" CL=0 "); } if (checkbox_am_b.value() == true) { - strcat(lcrframe, "AM=2 AF=\""); - strcat(lcrframe, litteral[1]); - strcat(lcrframe, "\" CL=0 "); + strcat(lcr_message, "AM=2 AF=\""); + strcat(lcr_message, litteral[1]); + strcat(lcr_message, "\" CL=0 "); } if (checkbox_am_c.value() == true) { - strcat(lcrframe, "AM=3 AF=\""); - strcat(lcrframe, litteral[2]); - strcat(lcrframe, "\" CL=0 "); + strcat(lcr_message, "AM=3 AF=\""); + strcat(lcr_message, litteral[2]); + strcat(lcr_message, "\" CL=0 "); } if (checkbox_am_d.value() == true) { - strcat(lcrframe, "AM=4 AF=\""); - strcat(lcrframe, litteral[3]); - strcat(lcrframe, "\" CL=0 "); + strcat(lcr_message, "AM=4 AF=\""); + strcat(lcr_message, litteral[3]); + strcat(lcr_message, "\" CL=0 "); } if (checkbox_am_e.value() == true) { - strcat(lcrframe, "AM=5 AF=\""); - strcat(lcrframe, litteral[4]); - strcat(lcrframe, "\" CL=0 "); + strcat(lcr_message, "AM=5 AF=\""); + strcat(lcr_message, litteral[4]); + strcat(lcr_message, "\" CL=0 "); } - strcat(lcrframe, "EC="); - strcat(lcrframe, ec_lut[options_ec.selected_index()]); - strcat(lcrframe, " SAB=0"); + strcat(lcr_message, "EC="); + strcat(lcr_message, ec_lut[options_ec.selected_index()]); + strcat(lcr_message, " SAB=0"); - memcpy(lcrstring, lcrframe, 256); + memcpy(lcr_string, lcr_message, 256); // Checksum checksum = 0; i = 7; // Skip modem sync - while (lcrframe[i]) { - checksum ^= lcrframe[i]; + while (lcr_message[i]) { + checksum ^= lcr_message[i]; i++; } checksum ^= eom[0]; // EOM char - checksum &= 0x7F; + checksum &= 0x7F; // Trim eom[1] = checksum; - strcat(lcrframe, eom); + strcat(lcr_message, eom); //if (persistent_memory::afsk_config() & 2) pm = 0; // Even parity @@ -138,30 +133,31 @@ void LCRView::make_frame() { // pm = 1; // Odd parity if (!(persistent_memory::afsk_config() & 8)) { - // Clear format - for (dp = 0; dp < strlen(lcrframe); dp++) { + // Normal format + for (dp = 0; dp < strlen(lcr_message); dp++) { pp = pm; new_byte = 0; - cur_byte = lcrframe[dp]; + cur_byte = lcr_message[dp]; for (cp = 0; cp < 7; cp++) { - if ((cur_byte >> cp) & 1) pp++; - new_byte |= (((cur_byte >> cp) & 1) << (7 - cp)); + bit = (cur_byte >> cp) & 1; + pp += bit; + new_byte |= (bit << (7 - cp)); } - lcrframe_f[dp] = new_byte | (pp & 1); + lcr_message_data[dp] = new_byte | (pp & 1); } - lcrframe_f[dp] = 0; + lcr_message_data[dp] = 0; } else { // Alt format - for (dp = 0; dp < strlen(lcrframe); dp++) { + for (dp = 0; dp < strlen(lcr_message); dp++) { pp = pm; - cur_byte = alt_lookup[lcrframe[dp]]; + cur_byte = alt_lookup[(uint8_t)lcr_message[dp] & 0x7F]; for (cp = 0; cp < 8; cp++) { if ((cur_byte >> cp) & 1) pp++; } - lcrframe_f[dp * 2] = cur_byte; - lcrframe_f[(dp * 2) + 1] = pp & 1; + lcr_message_data[dp * 2] = cur_byte; + lcr_message_data[(dp * 2) + 1] = pp & 1; } - lcrframe_f[dp * 2] = 0; + lcr_message_data[dp * 2] = 0; } //if (persistent_memory::afsk_config() & 1) { @@ -169,13 +165,13 @@ void LCRView::make_frame() { // See above /*} else { // MSB first - for (dp=0;dp>cp)&1) pp++; } - lcrframe_f[dp] = (cur_byte<<1)|(pp&1); + lcr_message_data[dp] = (cur_byte<<1)|(pp&1); } }*/ } @@ -206,14 +202,17 @@ void LCRView::paint(Painter& painter) { button_setrgsb.set_text(rgsb); - // Recap: tx freq @ bps / ALT + // Recap: freq @ bps / ALT auto fstr = to_string_dec_int(portapack::persistent_memory::tuned_frequency() / 1000, 6); auto bstr = to_string_dec_int(portapack::persistent_memory::afsk_bitrate(), 4); strcpy(finalstr, fstr.c_str()); strcat(finalstr, "@"); strcat(finalstr, bstr.c_str()); strcat(finalstr, "bps"); - if (portapack::persistent_memory::afsk_config() & 8) strcat(finalstr, " ALT"); + if (portapack::persistent_memory::afsk_config() & 8) + strcat(finalstr, " ALT"); + else + strcat(finalstr, " NRM"); text_recap.set(finalstr); } @@ -226,9 +225,8 @@ void LCRView::on_txdone(int n) { strcat(str, rgsb); text_status.set(str); progress.set_value(0); - radio::disable(); - txing = false; - scanning = false; + transmitter_model.disable(); + tx_mode = IDLE; abort_scan = false; button_scan.set_style(&style_val); button_scan.set_text("SCAN"); @@ -236,8 +234,8 @@ void LCRView::on_txdone(int n) { } if (n > 0) { - if (scanning) { - scan_progress += 0.555f; + if (tx_mode == SCAN) { + scan_progress += 0.555f; // 100/(37*5) progress.set_value(scan_progress); } else { text_status.set(" "); @@ -247,71 +245,52 @@ void LCRView::on_txdone(int n) { progress.set_value((6 - n) * 20); } } else { - if (scanning && (scan_index < 36)) { - radio::disable(); + if ((tx_mode == SCAN) && (scan_index < LCR_SCAN_COUNT)) { + transmitter_model.disable(); // Next address strcpy(rgsb, RGSB_list[scan_index]); - make_frame(); - - memset(shared_memory.radio_data, 0, 256); - memcpy(shared_memory.radio_data, lcrframe_f, 256); - shared_memory.afsk_transmit_done = false; - shared_memory.afsk_repeat = 5; + generate_message(); text_status.set(" "); strcpy(str, to_string_dec_int(scan_index).c_str()); - strcat(str, "/36"); + strcat(str, "/"); + strcat(str, to_string_dec_uint(LCR_SCAN_COUNT).c_str()); text_status.set(str); scan_progress += 0.694f; progress.set_value(scan_progress); scan_index++; - radio::disable(); + // start_tx ? } else { text_status.set("Ready "); progress.set_value(0); - radio::disable(); - txing = false; - scanning = false; + transmitter_model.disable(); + tx_mode = IDLE; button_scan.set_style(&style_val); button_scan.set_text("SCAN"); } } } -void LCRView::start_tx() { +void LCRView::start_tx(const bool scan) { char str[16]; + bool afsk_alt_format; - if (scanning) { + if (scan) { + tx_mode = SCAN; scan_index = 0; strcpy(rgsb, RGSB_list[0]); + } else { + tx_mode = SINGLE; } - make_frame(); - - lcr_radio_config.tuning_frequency = portapack::persistent_memory::tuned_frequency(); - - shared_memory.afsk_samples_per_bit = 228000 / portapack::persistent_memory::afsk_bitrate(); - shared_memory.afsk_phase_inc_mark = portapack::persistent_memory::afsk_mark_freq() * (0x40000 * 256) / 2280; - shared_memory.afsk_phase_inc_space = portapack::persistent_memory::afsk_space_freq() * (0x40000 * 256) / 2280; + generate_message(); - if (portapack::persistent_memory::afsk_config() & 8) - shared_memory.afsk_alt_format = true; - else - shared_memory.afsk_alt_format = false; - - shared_memory.afsk_fmmod = portapack::persistent_memory::afsk_bw() * 8; - - memset(shared_memory.radio_data, 0, 256); - memcpy(shared_memory.radio_data, lcrframe_f, 256); - - shared_memory.afsk_transmit_done = false; - shared_memory.afsk_repeat = 5; //(portapack::persistent_memory::afsk_config() >> 8) & 0xFF; - - if (scanning) { + if (tx_mode == SCAN) { text_status.set(" "); - strcat(str, "1/36"); + strcpy(str, "1/"); + strcat(str, to_string_dec_uint(LCR_SCAN_COUNT).c_str()); text_status.set(str); progress.set_value(1); scan_index++; @@ -321,19 +300,42 @@ void LCRView::start_tx() { text_status.set(str); progress.set_value(20); } + + if (portapack::persistent_memory::afsk_config() & 8) + afsk_alt_format = true; + else + afsk_alt_format = false; - txing = true; - radio::enable(lcr_radio_config); + transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); + transmitter_model.set_baseband_configuration({ + .mode = 0, + .sampling_rate = 2280000U, + .decimation_factor = 1, + }); + transmitter_model.set_rf_amp(true); + transmitter_model.set_lna(40); + transmitter_model.set_vga(40); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + baseband::set_afsk_data( + lcr_message_data, + 228000 / portapack::persistent_memory::afsk_bitrate(), + portapack::persistent_memory::afsk_mark_freq() * (0x40000 * 256) / 2280, + portapack::persistent_memory::afsk_space_freq() * (0x40000 * 256) / 2280, + 5, + portapack::persistent_memory::afsk_bw() * 115, // See proc_fsk_lcr.cpp + afsk_alt_format + ); } LCRView::LCRView(NavigationView& nav) { - baseband::run_image(portapack::spi_flash::image_tag_lcr); + baseband::run_image(portapack::spi_flash::image_tag_afsk); memset(litteral, 0, 5 * 8); memset(rgsb, 0, 5); strcpy(rgsb, RGSB_list[0]); - button_setrgsb.set_text(rgsb); add_children({ { &text_recap, @@ -358,7 +360,9 @@ LCRView::LCRView(NavigationView& nav) { &button_clear } }); - options_ec.set_selected_index(0); + button_setrgsb.set_text(rgsb); + + options_ec.set_selected_index(0); // Auto checkbox_am_a.set_value(true); checkbox_am_b.set_value(false); @@ -394,29 +398,27 @@ LCRView::LCRView(NavigationView& nav) { }; button_lcrdebug.on_select = [this,&nav](Button&) { - make_frame(); - nav.push(lcrstring, checksum); + generate_message(); + nav.push(lcr_string, checksum); }; button_transmit.on_select = [this](Button&) { - if (txing == false) start_tx(); + if (tx_mode == IDLE) start_tx(false); }; button_scan.on_select = [this](Button&) { - if (txing == false) { - scanning = true; + if (tx_mode == IDLE) { scan_progress = 0; button_scan.set_style(&style_cancel); button_scan.set_text("ABORT"); - start_tx(); + start_tx(true); } else { abort_scan = true; } }; button_clear.on_select = [this, &nav](Button&) { - if (txing == false) { - scanning = false; + if (tx_mode == IDLE) { memset(litteral, 0, 5 * 8); options_ec.set_selected_index(0); checkbox_am_a.set_value(true); @@ -425,7 +427,7 @@ LCRView::LCRView(NavigationView& nav) { checkbox_am_d.set_value(true); checkbox_am_e.set_value(true); set_dirty(); - start_tx(); + start_tx(false); } }; } diff --git a/firmware/application/ui_lcr.hpp b/firmware/application/ui_lcr.hpp index 8d455fa2..bcbed9ae 100644 --- a/firmware/application/ui_lcr.hpp +++ b/firmware/application/ui_lcr.hpp @@ -36,43 +36,51 @@ namespace ui { +#define LCR_SCAN_COUNT 36 + class LCRView : public View { public: LCRView(NavigationView& nav); ~LCRView(); - std::string title() const override { return "LCR transmit"; }; void focus() override; void paint(Painter& painter) override; + + std::string title() const override { return "LCR transmit"; }; private: - bool txing = false; - bool scanning = false; + enum tx_modes { + IDLE = 0, + SINGLE, + SCAN + }; + + tx_modes tx_mode = IDLE; bool abort_scan = false; double scan_progress; - const char RGSB_list[37][5] = { + const char RGSB_list[LCR_SCAN_COUNT][5] = { + "AI10", "AI20", "AI30", "AI40", + "AI50", "AI60", "AI70", "AJ10", + "AJ20", "AJ30", "AJ40", "AJ50", + "AJ60", "AJ70", "AK10", "EAA0", "EAB0", "EAC0", "EAD0", "EbA0", "EbB0", "EbC0", "EbD0", "EbE0", "EbF0", "EbG0", "EbH0", "EbI0", "EbJ0", "EbK0", "EbL0", "EbM0", "EbN0", "EbO0", "EbP0", - "EbS0", "EAD0", "AI10", "AI20", - "AI30", "AI40", "AI50", "AI60", - "AI70", "AJ10", "AJ20", "AJ30", - "AJ40", "AJ50", "AJ60", "AJ70", - "AK10" + "EbS0" }; char litteral[5][8]; char rgsb[5]; - char lcrstring[256]; + char lcr_message[256]; + char lcr_string[256]; // For debugging, can remove + char lcr_message_data[256]; char checksum = 0; - char lcrframe[256]; - char lcrframe_f[256]; rf::Frequency f; int scan_index; - void make_frame(); - void start_tx(); + void generate_message(); + void start_tx(const bool scan); void on_txdone(int n); radio::Configuration lcr_radio_config = { @@ -89,7 +97,7 @@ private: // 2: 94 ? // 9: 85 ? - const char alt_lookup[256] = { + const char alt_lookup[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0F, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 0xF8, 0, 0x99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 !"#$%&'()*+,-./ @@ -97,15 +105,7 @@ private: 0, 0x3C, 0x9C, 0x5D, 0, 0, 0, 0, 0, 0x44, 0x85, 0, 0xD5, 0x14, 0, 0, // 40 @ABCDEFGHIJKLMNO 0xF0, 0, 0, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50 PQRSTUVWXYZ[\]^_ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60 `abcdefghijklmno - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7F, // 70 pqrstuvwxyz{|}~ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7F // 70 pqrstuvwxyz{|}~ }; const Style style_val { @@ -125,7 +125,7 @@ private: }; OptionsField options_ec { - { 19 * 8, 6 }, + { 20 * 8, 6 }, 7, { { "EC:Auto", 0 }, diff --git a/firmware/application/ui_rds.cpp b/firmware/application/ui_rds.cpp index df98a1c9..2bdf5252 100644 --- a/firmware/application/ui_rds.cpp +++ b/firmware/application/ui_rds.cpp @@ -157,8 +157,9 @@ void RDSView::gen_PSN(const char * psname) { group[c][3] = makeblock(group[c][3], RDS_OFFSET_D); } - for (c = 0; c < 16; c++) - shared_memory.radio_data[c] = group[c >> 2][c & 3]; + // Todo + //for (c = 0; c < 16; c++) + // shared_memory.radio_data[c] = group[c >> 2][c & 3]; shared_memory.bit_length = 4 * 4 * 26; } @@ -197,8 +198,9 @@ void RDSView::gen_RadioText(const char * radiotext) { group[i + 3] = makeblock(group[i + 3], RDS_OFFSET_D); } - for (c = 0; c < (groups * 4); c++) - shared_memory.radio_data[c] = group[c]; + // Todo + //for (c = 0; c < (groups * 4); c++) + // shared_memory.radio_data[c] = group[c]; shared_memory.bit_length = groups * 4 * 26; } diff --git a/firmware/application/ui_xylos.cpp b/firmware/application/ui_xylos.cpp index 10634e1b..705467e9 100644 --- a/firmware/application/ui_xylos.cpp +++ b/firmware/application/ui_xylos.cpp @@ -31,7 +31,6 @@ #include "ff.h" #include "hackrf_gpio.hpp" #include "portapack.hpp" -#include "radio.hpp" #include "baseband_api.hpp" #include "hackrf_hal.hpp" @@ -118,7 +117,7 @@ void XylosView::focus() { } XylosView::~XylosView() { - receiver_model.disable(); + transmitter_model.disable(); baseband::shutdown(); } @@ -257,7 +256,7 @@ void XylosView::on_txdone(const int n) { start_tx(); } } else { - progress.set_value((n + 1) * 5); + progress.set_value(n * 5); } } } @@ -313,80 +312,80 @@ XylosView::XylosView(NavigationView& nav) { header_code_a.on_change = [this](int32_t v) { (void)v; - XylosView::generate_message(); + generate_message(); }; header_code_b.on_change = [this](int32_t v) { (void)v; - XylosView::generate_message(); + generate_message(); }; city_code.on_change = [this](int32_t v) { (void)v; - XylosView::generate_message(); + generate_message(); }; family_code.on_change = [this](int32_t v) { (void)v; - XylosView::generate_message(); + generate_message(); }; subfamily_code.on_change = [this](int32_t v) { (void)v; - XylosView::generate_message(); + generate_message(); }; receiver_code.on_change = [this](int32_t v) { (void)v; - XylosView::generate_message(); + generate_message(); }; subfamily_code.hidden(true); text_subfamily.set_style(&style_grey); checkbox_wcsubfamily.on_select = [this](Checkbox&) { if (checkbox_wcsubfamily.value() == true) { - subfamily_code.hidden(true); + receiver_code.set_focusable(false); text_subfamily.set_style(&style_grey); } else { - subfamily_code.hidden(false); + receiver_code.set_focusable(true); text_subfamily.set_style(&style()); } - XylosView::generate_message(); + generate_message(); }; receiver_code.hidden(true); text_receiver.set_style(&style_grey); checkbox_wcid.on_select = [this](Checkbox&) { if (checkbox_wcid.value() == true) { - receiver_code.hidden(true); + receiver_code.set_focusable(false); text_receiver.set_style(&style_grey); } else { - receiver_code.hidden(false); + receiver_code.set_focusable(true); text_receiver.set_style(&style()); } receiver_code.set_dirty(); - XylosView::generate_message(); + generate_message(); }; options_ra.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::generate_message(); + generate_message(); }; options_rb.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::generate_message(); + generate_message(); }; options_rc.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::generate_message(); + generate_message(); }; options_rd.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::generate_message(); + generate_message(); }; button_transmit.set_style(&style_val); - XylosView::generate_message(); + generate_message(); // Transmission and tones testing button_txtest.on_select = [this](Button&) { diff --git a/firmware/application/ui_xylos.hpp b/firmware/application/ui_xylos.hpp index 7ecf67c4..8cba3de2 100644 --- a/firmware/application/ui_xylos.hpp +++ b/firmware/application/ui_xylos.hpp @@ -145,9 +145,10 @@ class XylosView : public View { public: XylosView(NavigationView& nav); ~XylosView(); - std::string title() const override { return "Xylos transmit"; }; void focus() override; + + std::string title() const override { return "Xylos transmit"; }; private: enum tx_modes { @@ -158,7 +159,9 @@ private: }; tx_modes tx_mode = IDLE; + const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; + char ccir_message[21]; const char ccir_base[21] = "0000000000B0000B0000"; @@ -175,7 +178,7 @@ private: "0E03181AEAB10E0B0E0E" }; - int sequence_idx; + unsigned int sequence_idx; void ascii_to_ccir(char *ascii); void start_tx(); @@ -267,7 +270,7 @@ private: 2, { 0, 99 }, 1, - ' ' + '0' }; Checkbox checkbox_wcid { { 20 * 8, 6 * 16 }, diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 11831238..7d571dbb 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -340,12 +340,12 @@ set(MODE_CPPSRC ) DeclareTargets(PATX audio_tx) -### FSK LCR +### AFSK set(MODE_CPPSRC - proc_fsk_lcr.cpp + proc_afsk.cpp ) -DeclareTargets(PLCR lcr) +DeclareTargets(PAFS afsk) ### Epar diff --git a/firmware/baseband/proc_fsk_lcr.cpp b/firmware/baseband/proc_afsk.cpp similarity index 52% rename from firmware/baseband/proc_fsk_lcr.cpp rename to firmware/baseband/proc_afsk.cpp index 7ab5a820..17a836d0 100644 --- a/firmware/baseband/proc_fsk_lcr.cpp +++ b/firmware/baseband/proc_afsk.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -19,45 +20,49 @@ * Boston, MA 02110-1301, USA. */ -#include "proc_fsk_lcr.hpp" +#include "proc_afsk.hpp" #include "portapack_shared_memory.hpp" -#include "sine_table.hpp" +#include "sine_table_int8.hpp" #include "event_m4.hpp" #include -void LCRFSKProcessor::execute(const buffer_c8_t& buffer) { +void AFSKProcessor::execute(const buffer_c8_t& buffer) { + + // This is called at 2280000/2048 = 1113Hz + + if (!configured) return; for (size_t i = 0; i= 9) { + // Tone generation at 2280000/10 = 228kHz + if (s >= (10 - 1)) { s = 0; - if (sample_count >= shared_memory.afsk_samples_per_bit) { - if (shared_memory.afsk_transmit_done == false) { - cur_byte = shared_memory.radio_data[byte_pos]; - ext_byte = shared_memory.radio_data[byte_pos + 1]; + if (sample_count >= afsk_samples_per_bit) { + if (configured == true) { + cur_byte = message_data[byte_pos]; + ext_byte = message_data[byte_pos + 1]; } if (!cur_byte) { - if (shared_memory.afsk_repeat) { - shared_memory.afsk_repeat--; + if (afsk_repeat) { + afsk_repeat--; bit_pos = 0; byte_pos = 0; - cur_byte = shared_memory.radio_data[0]; - ext_byte = shared_memory.radio_data[1]; - message.n = shared_memory.afsk_repeat; + cur_byte = message_data[0]; + ext_byte = message_data[1]; + message.n = afsk_repeat; shared_memory.application_queue.push(message); } else { message.n = 0; - shared_memory.afsk_transmit_done = true; + configured = false; shared_memory.application_queue.push(message); cur_byte = 0; ext_byte = 0; } } - if (shared_memory.afsk_alt_format) { + if (afsk_alt_format) { // 0bbbbbbbbp // Start, 8-bit data, parity gbyte = 0; @@ -75,7 +80,7 @@ void LCRFSKProcessor::execute(const buffer_c8_t& buffer) { if (bit_pos == 9) { bit_pos = 0; - if (!shared_memory.afsk_alt_format) + if (!afsk_alt_format) byte_pos++; else byte_pos += 2; @@ -88,30 +93,52 @@ void LCRFSKProcessor::execute(const buffer_c8_t& buffer) { sample_count++; } if (cur_bit) - aphase += shared_memory.afsk_phase_inc_mark; + tone_phase += afsk_phase_inc_mark; else - aphase += shared_memory.afsk_phase_inc_space; + tone_phase += afsk_phase_inc_space; } else { s++; } - sample = (sine_table_f32[(aphase & 0x03FF0000)>>18]*255); + tone_sample = (sine_table_i8[(tone_phase & 0x03FC0000)>>18]); - //FM - frq = sample * shared_memory.afsk_fmmod; + // FM + // 1<<18 = 262144 + // m = (262144 * BW) / 2280000 (* 115, see ui_lcr afsk_bw setting) + frq = tone_sample * afsk_bw; phase = (phase + frq); - sphase = phase + (256<<16); + sphase = phase + (64<<18); - re = (sine_table_f32[(sphase & 0x03FF0000)>>18]*127); - im = (sine_table_f32[(phase & 0x03FF0000)>>18]*127); + re = (sine_table_i8[(sphase & 0x03FC0000)>>18]); + im = (sine_table_i8[(phase & 0x03FC0000)>>18]); buffer.p[i] = {(int8_t)re,(int8_t)im}; } } +void AFSKProcessor::on_message(const Message* const p) { + const auto message = *reinterpret_cast(p); + if (message.id == Message::ID::AFSKConfigure) { + memcpy(message_data, message.message_data, 256); + afsk_samples_per_bit = message.afsk_samples_per_bit; + afsk_phase_inc_mark = message.afsk_phase_inc_mark; + afsk_phase_inc_space = message.afsk_phase_inc_space; + afsk_repeat = message.afsk_repeat; + afsk_bw = message.afsk_bw; + afsk_alt_format = message.afsk_alt_format; + + bit_pos = 0; + byte_pos = 0; + cur_byte = 0; + ext_byte = 0; + cur_bit = 0; + configured = true; + } +} + int main() { - EventDispatcher event_dispatcher { std::make_unique() }; + EventDispatcher event_dispatcher { std::make_unique() }; event_dispatcher.run(); return 0; } diff --git a/firmware/baseband/proc_fsk_lcr.hpp b/firmware/baseband/proc_afsk.hpp similarity index 73% rename from firmware/baseband/proc_fsk_lcr.hpp rename to firmware/baseband/proc_afsk.hpp index bbcfca0b..d198d8ba 100644 --- a/firmware/baseband/proc_fsk_lcr.hpp +++ b/firmware/baseband/proc_afsk.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -19,19 +20,31 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __PROC_FSK_LCR_H__ -#define __PROC_FSK_LCR_H__ +#ifndef __PROC_AFSK_H__ +#define __PROC_AFSK_H__ #include "baseband_processor.hpp" #include "baseband_thread.hpp" -class LCRFSKProcessor : public BasebandProcessor { +class AFSKProcessor : public BasebandProcessor { public: void execute(const buffer_c8_t& buffer) override; + + void on_message(const Message* const p) override; private: + bool configured = false; + BasebandThread baseband_thread { 2280000, this, NORMALPRIO + 20, baseband::Direction::Transmit }; + uint32_t afsk_samples_per_bit; + uint32_t afsk_phase_inc_mark; + uint32_t afsk_phase_inc_space; + uint8_t afsk_repeat; + uint32_t afsk_bw; + bool afsk_alt_format; + char message_data[256]; + int8_t re, im; uint8_t s; uint8_t bit_pos = 0, byte_pos = 0; @@ -40,8 +53,9 @@ private: uint16_t gbyte; uint8_t cur_bit = 0; uint32_t sample_count; - uint32_t aphase, phase, sphase; - int32_t sample, sig, frq; + uint32_t tone_phase, phase, sphase; + int32_t tone_sample, sig, frq; + TXDoneMessage message; }; diff --git a/firmware/baseband/proc_rds.cpp b/firmware/baseband/proc_rds.cpp index 01199f2e..e06fe39f 100644 --- a/firmware/baseband/proc_rds.cpp +++ b/firmware/baseband/proc_rds.cpp @@ -30,7 +30,8 @@ void RDSProcessor::execute(const buffer_c8_t& buffer) { uint32_t * rdsdata; - rdsdata = (uint32_t *)shared_memory.radio_data; + // TODO + //rdsdata = (uint32_t *)shared_memory.radio_data; for (size_t i = 0; i < buffer.count; i++) { diff --git a/firmware/baseband/proc_xylos.cpp b/firmware/baseband/proc_xylos.cpp index 29e8513c..973441e4 100644 --- a/firmware/baseband/proc_xylos.cpp +++ b/firmware/baseband/proc_xylos.cpp @@ -26,7 +26,7 @@ #include "audio_output.hpp" #include "portapack_shared_memory.hpp" -#include "sine_table.hpp" +#include "sine_table_int8.hpp" #include "event_m4.hpp" #include @@ -35,18 +35,17 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { // This is called at 1536000/2048 = 750Hz - if( !configured ) { - return; - } + if (!configured) return; for (size_t i = 0; i= (2-1)) { + // Tone generation at 1536000/5 = 307.2kHz + if (s >= (5 - 1)) { s = 0; if (silence) { - if (sample_count >= SILENCE) { + // Just occupy channel with carrier + if (sample_count >= CCIR_SILENCE) { silence = false; sample_count = CCIR_TONELENGTH; } else { @@ -54,16 +53,14 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { } } else { if (sample_count >= CCIR_TONELENGTH) { - if (transmit_done == false) { - digit = xylosdata[byte_pos++]; - if ((digit == 0xFF) || (byte_pos >= 21)) { - message.n = 25; // End of message code - transmit_done = true; - shared_memory.application_queue.push(message); - } else { - message.n = byte_pos; // Inform UI about progress (just as eye candy) - shared_memory.application_queue.push(message); - } + digit = xylosdata[byte_pos++]; + if ((digit == 0xFF) || (byte_pos >= 21)) { + configured = false; + message.n = 25; // End of message code + shared_memory.application_queue.push(message); + } else { + message.n = byte_pos; // Inform UI about progress (just as eye candy) + shared_memory.application_queue.push(message); } sample_count = 0; @@ -71,7 +68,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { sample_count++; } - aphase += ccir_phases[digit]; + tone_phase += ccir_phases[digit]; } } else { s++; @@ -81,7 +78,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { re = 0; im = 0; } else { - sample = (sine_table_f32[(aphase & 0x03FC0000)>>18]*127); // 255 here before + tone_sample = (sine_table_i8[(tone_phase & 0x03FC0000)>>18]); // Audio preview sample generation: 1536000/48000 = 32 /*if (as >= 31) { @@ -90,15 +87,17 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { } else { as++; }*/ - - //FM - frq = sample * 800; // ? + + // FM + // 1<<18 = 262144 + // m = (262144 * BW) / 1536000 / 2 + frq = tone_sample * 853; // 10kHz BW phase = (phase + frq); - sphase = phase + (256<<16); + sphase = phase + (64<<18); - re = (sine_table_f32[(sphase & 0x03FC0000)>>18]*127); - im = (sine_table_f32[(phase & 0x03FC0000)>>18]*127); + re = (sine_table_i8[(sphase & 0x03FC0000)>>18]); + im = (sine_table_i8[(phase & 0x03FC0000)>>18]); } buffer.p[i] = {(int8_t)re,(int8_t)im}; @@ -115,7 +114,7 @@ void XylosProcessor::on_message(const Message* const p) { digit = 0; sample_count = CCIR_TONELENGTH; as = 0; - transmit_done = false; + silence = true; configured = true; } } diff --git a/firmware/baseband/proc_xylos.hpp b/firmware/baseband/proc_xylos.hpp index 761c0124..124ce985 100644 --- a/firmware/baseband/proc_xylos.hpp +++ b/firmware/baseband/proc_xylos.hpp @@ -24,16 +24,13 @@ #define __PROC_XYLOS_H__ #include "baseband_processor.hpp" - -#include "dsp_decimate.hpp" -#include "dsp_demodulate.hpp" - -#include "audio_output.hpp" #include "baseband_thread.hpp" -#define CCIR_TONELENGTH (15360*5)-1 // 1536000/10/10 -#define PHASEV (436.91/5) // (65536*1024)/1536000*10 -#define SILENCE (46080*5)-1 // 400ms +//#include "audio_output.hpp" + +#define CCIR_TONELENGTH (15360*2)-1 // 1536000/10/10 +#define CCIR_PHASEINC (436.91/2) // (65536*1024)/1536000*10 +#define CCIR_SILENCE (122880)-1 // 400ms class XylosProcessor : public BasebandProcessor { public: @@ -43,27 +40,26 @@ public: private: bool configured = false; - bool transmit_done = false; BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit }; - uint32_t ccir_phases[16] = { - (uint32_t)(1981*PHASEV), - (uint32_t)(1124*PHASEV), - (uint32_t)(1197*PHASEV), - (uint32_t)(1275*PHASEV), - (uint32_t)(1358*PHASEV), - (uint32_t)(1446*PHASEV), - (uint32_t)(1540*PHASEV), - (uint32_t)(1640*PHASEV), - (uint32_t)(1747*PHASEV), - (uint32_t)(1860*PHASEV), - (uint32_t)(2400*PHASEV), - (uint32_t)(930*PHASEV), - (uint32_t)(2247*PHASEV), - (uint32_t)(991*PHASEV), - (uint32_t)(2110*PHASEV), - (uint32_t)(1055*PHASEV) + const uint32_t ccir_phases[16] = { + (uint32_t)(1981*CCIR_PHASEINC), + (uint32_t)(1124*CCIR_PHASEINC), + (uint32_t)(1197*CCIR_PHASEINC), + (uint32_t)(1275*CCIR_PHASEINC), + (uint32_t)(1358*CCIR_PHASEINC), + (uint32_t)(1446*CCIR_PHASEINC), + (uint32_t)(1540*CCIR_PHASEINC), + (uint32_t)(1640*CCIR_PHASEINC), + (uint32_t)(1747*CCIR_PHASEINC), + (uint32_t)(1860*CCIR_PHASEINC), + (uint32_t)(2400*CCIR_PHASEINC), + (uint32_t)(930*CCIR_PHASEINC), + (uint32_t)(2247*CCIR_PHASEINC), + (uint32_t)(991*CCIR_PHASEINC), + (uint32_t)(2110*CCIR_PHASEINC), + (uint32_t)(1055*CCIR_PHASEINC) }; char xylosdata[21]; @@ -72,8 +68,8 @@ private: uint8_t byte_pos = 0; uint8_t digit = 0; uint32_t sample_count = CCIR_TONELENGTH; - uint32_t aphase, phase, sphase; - int32_t sample, frq; + uint32_t tone_phase, phase, sphase; + int32_t tone_sample, frq; bool silence = true; TXDoneMessage message; diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index a2643cd9..df1d1c9a 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -68,7 +68,7 @@ public: TXDone = 20, Retune = 21, XylosConfigure = 22, - AFSKData = 23, + AFSKConfigure = 23, ModuleID = 24, FIFOSignal = 25, FIFOData = 26, @@ -512,14 +512,34 @@ public: int64_t freq = 0; }; -class AFSKDataMessage : public Message { +class AFSKConfigureMessage : public Message { public: - constexpr AFSKDataMessage( - ) : Message { ID::AFSKData } + AFSKConfigureMessage( + const char data[], + const uint32_t afsk_samples_per_bit, + const uint32_t afsk_phase_inc_mark, + const uint32_t afsk_phase_inc_space, + const uint8_t afsk_repeat, + const uint32_t afsk_bw, + const bool afsk_alt_format + ) : Message { ID::AFSKConfigure }, + afsk_samples_per_bit(afsk_samples_per_bit), + afsk_phase_inc_mark(afsk_phase_inc_mark), + afsk_phase_inc_space(afsk_phase_inc_space), + afsk_repeat(afsk_repeat), + afsk_bw(afsk_bw), + afsk_alt_format(afsk_alt_format) { + memcpy(message_data, data, 256); } - int16_t data[128] = {0}; + uint32_t afsk_samples_per_bit; + uint32_t afsk_phase_inc_mark; + uint32_t afsk_phase_inc_space; + uint8_t afsk_repeat; + uint32_t afsk_bw; + bool afsk_alt_format; + char message_data[256]; }; class FIFOSignalMessage : public Message { diff --git a/firmware/common/portapack_shared_memory.hpp b/firmware/common/portapack_shared_memory.hpp index 2940688d..45359aaa 100644 --- a/firmware/common/portapack_shared_memory.hpp +++ b/firmware/common/portapack_shared_memory.hpp @@ -47,17 +47,8 @@ struct SharedMemory { char m4_panic_msg[32] { 0 }; - uint8_t radio_data[256]; size_t bit_length; - uint32_t afsk_samples_per_bit; - uint32_t afsk_phase_inc_mark; - uint32_t afsk_phase_inc_space; - uint8_t afsk_repeat; - uint32_t afsk_fmmod; - bool afsk_transmit_done; - bool afsk_alt_format; - JammerRange jammer_ranges[16]; char epardata[13]; diff --git a/firmware/common/sine_table_int8.hpp b/firmware/common/sine_table_int8.hpp new file mode 100644 index 00000000..828b6db5 --- /dev/null +++ b/firmware/common/sine_table_int8.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * 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 + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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 General Public License + * along with this program; see the file COPYING.If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __SINE_TABLE_I8_H__ +#define __SINE_TABLE_I8_H__ + +#include + +static const int8_t sine_table_i8[256] = { + 0, 2, 5, 8, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, + 48, 51, 54, 57, 59, 62, 65, 67, 70, 73, 75, 78, 80, 83, 85, 87, + 90, 92, 94, 96, 98, 100, 102, 104, 105, 107, 109, 110, 112, 113, 115, 116, + 117, 118, 120, 121, 121, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127, + 127, 127, 127, 127, 126, 126, 126, 125, 125, 124, 123, 122, 121, 121, 120, 118, + 117, 116, 115, 113, 112, 110, 109, 107, 105, 104, 102, 100, 98, 96, 94, 92, + 90, 87, 85, 83, 80, 78, 75, 73, 70, 67, 65, 62, 59, 57, 54, 51, + 48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 8, 5, 2, + 0, -3, -6, -9, -13, -16, -19, -22, -25, -28, -31, -34, -37, -40, -43, -46, + -49, -52, -55, -58, -60, -63, -66, -68, -71, -74, -76, -79, -81, -84, -86, -88, + -91, -93, -95, -97, -99, -101, -103, -105, -106, -108, -110, -111, -113, -114, -116, -117, + -118, -119, -121, -122, -122, -123, -124, -125, -126, -126, -127, -127, -127, -128, -128, -128, + -128, -128, -128, -128, -127, -127, -127, -126, -126, -125, -124, -123, -122, -122, -121, -119, + -118, -117, -116, -114, -113, -111, -110, -108, -106, -105, -103, -101, -99, -97, -95, -93, + -91, -88, -86, -84, -81, -79, -76, -74, -71, -68, -66, -63, -60, -58, -55, -52, + -49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -13, -9, -6, -3 +}; + +#endif/*__SINE_TABLE_I8_H__*/ diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 0a95e282..a6bf8ead 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -73,7 +73,7 @@ constexpr image_tag_t image_tag_wideband_spectrum { 'P', 'S', 'P', 'E' }; constexpr image_tag_t image_tag_jammer { 'P', 'J', 'A', 'M' }; constexpr image_tag_t image_tag_audio_tx { 'P', 'A', 'T', 'X' }; -constexpr image_tag_t image_tag_lcr { 'P', 'L', 'C', 'R' }; +constexpr image_tag_t image_tag_afsk { 'P', 'A', 'F', 'S' }; constexpr image_tag_t image_tag_epar { 'P', 'E', 'P', 'R' }; constexpr image_tag_t image_tag_play_audio { 'P', 'P', 'A', 'U' }; constexpr image_tag_t image_tag_xylos { 'P', 'X', 'Y', 'L' }; diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index 335b0f00..e2157b8b 100644 Binary files a/firmware/portapack-h1-firmware.bin and b/firmware/portapack-h1-firmware.bin differ