diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index d9293eee8..7139f559c 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -135,6 +135,7 @@ set(CPPSRC touch_adc.cpp encoder.cpp audio.cpp + afsk.cpp ${COMMON}/lcd_ili9341.cpp ${COMMON}/ui.cpp ${COMMON}/ui_text.cpp diff --git a/firmware/application/Makefile b/firmware/application/Makefile index b4a168bad..0defcfc39 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -2454,6 +2454,30 @@ __/common/wm8731.cpp.s: cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/wm8731.cpp.s .PHONY : __/common/wm8731.cpp.s +afsk.obj: afsk.cpp.obj +.PHONY : afsk.obj + +# target to build an object file +afsk.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/afsk.cpp.obj +.PHONY : afsk.cpp.obj + +afsk.i: afsk.cpp.i +.PHONY : afsk.i + +# target to preprocess a source file +afsk.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/afsk.cpp.i +.PHONY : afsk.cpp.i + +afsk.s: afsk.cpp.s +.PHONY : afsk.s + +# target to generate assembly for a file +afsk.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/afsk.cpp.s +.PHONY : afsk.cpp.s + ais_app.obj: ais_app.cpp.obj .PHONY : ais_app.obj @@ -4411,6 +4435,9 @@ help: @echo "... __/common/wm8731.obj" @echo "... __/common/wm8731.i" @echo "... __/common/wm8731.s" + @echo "... afsk.obj" + @echo "... afsk.i" + @echo "... afsk.s" @echo "... ais_app.obj" @echo "... ais_app.i" @echo "... ais_app.s" diff --git a/firmware/application/afsk.cpp b/firmware/application/afsk.cpp new file mode 100644 index 000000000..f7efc0910 --- /dev/null +++ b/firmware/application/afsk.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "afsk.hpp" + +#include "portapack_persistent_memory.hpp" + +namespace afsk { + +void generate_data(const char * in_message, char * out_data) { + const afsk_formats_t * format_def; + uint8_t pm, pp, bit, cp, cur_byte, new_byte; + uint16_t dp; + + format_def = &afsk_formats[portapack::persistent_memory::afsk_format()]; + + if (format_def->parity == ODD) + pm = 1; // Odd parity + else + pm = 0; // Even parity + + if (format_def->data_bits == 7) { + if (!format_def->use_LUT) { + for (dp = 0; dp < strlen(in_message); dp++) { + pp = pm; + new_byte = 0; + cur_byte = in_message[dp]; + for (cp = 0; cp < 7; cp++) { + bit = (cur_byte >> cp) & 1; + pp += bit; + new_byte |= (bit << (7 - cp)); + } + if (format_def->parity != NONE) new_byte |= (pp & 1); + out_data[dp] = new_byte; + } + out_data[dp++] = 0; + out_data[dp] = 0; + } else { + for (dp = 0; dp < strlen(in_message); dp++) { + pp = pm; + + // Do not apply LUT on checksum (last byte) ? + if (dp != strlen(in_message) - 1) + cur_byte = alt_lookup[(uint8_t)in_message[dp] & 0x7F]; + else + cur_byte = in_message[dp]; + + for (cp = 0; cp < 8; cp++) + if ((cur_byte >> cp) & 1) pp++; + + out_data[dp * 2] = cur_byte; + out_data[(dp * 2) + 1] = 0xFE; + if (format_def->parity != NONE) out_data[(dp * 2) + 1] |= (pp & 1); + } + out_data[dp * 2] = 0; + out_data[(dp * 2) + 1] = 0; + } + } else { + /* + for (dp = 0; dp < strlen(in_message); dp++) { + pp = pm; + + // Do not apply LUT on checksum (last byte) ? + if (dp != strlen(in_message) - 1) + cur_byte = alt_lookup[(uint8_t)in_message[dp] & 0x7F]; + else + cur_byte = in_message[dp]; + + for (cp = 0; cp < 8; cp++) + if ((cur_byte >> cp) & 1) pp++; + + out_data[dp * 2] = cur_byte; + out_data[(dp * 2) + 1] = 0xFE | (pp & 1); + } + out_data[dp * 2] = 0; + out_data[(dp * 2) + 1] = 0; + */ + } + + /* + // MSB first + for (dp = 0; dp < strlen(lcr_message); dp++) { + pp = pm; + cur_byte = lcr_message[dp]; + for (cp = 0; cp < 7; cp++) + if ((cur_byte >> cp) & 1) pp++; + lcr_message_data[dp] = (cur_byte << 1) | (pp & 1); + } + }*/ +} + +} /* namespace afsk */ diff --git a/firmware/application/afsk.hpp b/firmware/application/afsk.hpp new file mode 100644 index 000000000..b78b0864b --- /dev/null +++ b/firmware/application/afsk.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "ui.hpp" +#include +#include + +#ifndef __AFSK_H__ +#define __AFSK_H__ + +namespace afsk { + +#define AFSK_MODES_COUNT 4 + +enum parity_enum { + NONE = 0, + EVEN, + ODD +}; + +struct afsk_formats_t { + std::string fullname; + std::string shortname; + uint8_t data_bits; + parity_enum parity; + uint8_t stop_bits; + bool MSB_first; + bool use_LUT; +}; + +const afsk_formats_t afsk_formats[4] = { + { "7-Even-1 R", "7E1", 7, EVEN, 1, false, false }, + { "7E1 LUT ", "7Ea", 7, EVEN, 1, true, true }, + { "7-Odd-1 ", "7o1", 7, ODD, 1, true, false }, + { "8-Even-0 ", "8E0", 8, EVEN, 1, true, false } +}; + +// TODO: Complete table +const char alt_lookup[128] = { + 0, 0, 0, 0x5F, 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 !"#$%&'()*+,-./ + 0xF5, 0, 0x94, 0x55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1C, 0, 0, // 30 0123456789:;<=>? + 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{|}~ +}; + +void generate_data(const char * in_message, char * out_data); + +} /* namespace afsk */ + +#endif/*__AFSK_H__*/ diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index f2558eeb3..1b130989a 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -24,11 +24,9 @@ // Gimp image > indexed colors (16), then "xxd -i *.bmp" //BUG: No audio in about when shown second time -//BUG: Description doesn't show up first time going to system>module info (UI drawn on top) //TODO: Check AFSK transmit end, skips last bits ? -//TODO: Weird LCR AFSK scrambling ? -//TODO: Use msgpack ! +//TODO: Use msgpack for settings, lists... on sd card //TODO: Frequency manager //TODO: Morse coder @@ -55,6 +53,7 @@ //TODO: Persistent playdead ! //TODO: Show MD5 mismatches for modules not found, etc... //TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule +//BUG: Description doesn't show up first time going to system>module info (UI drawn on top) //TODO: Draw on touchscreen and transmit as spectrum paint //TODO: Two players tic-tac-toe diff --git a/firmware/application/ui_afsksetup.cpp b/firmware/application/ui_afsksetup.cpp index 74fe49565..b6dfa95f5 100644 --- a/firmware/application/ui_afsksetup.cpp +++ b/firmware/application/ui_afsksetup.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -19,19 +20,14 @@ * Boston, MA 02110-1301, USA. */ -#include "ui_rds.hpp" #include "ui_afsksetup.hpp" #include "ui_receiver.hpp" #include "ch.h" -#include "ff.h" -#include "hackrf_gpio.hpp" #include "portapack.hpp" -#include "radio.hpp" #include "string_format.hpp" -#include "hackrf_hal.hpp" #include "portapack_shared_memory.hpp" #include "portapack_persistent_memory.hpp" @@ -39,6 +35,7 @@ #include using namespace portapack; +using namespace afsk; namespace ui { @@ -46,11 +43,7 @@ void AFSKSetupView::focus() { button_setfreq.focus(); } -void AFSKSetupView::paint(Painter& painter) { - (void)painter; -} - -void AFSKSetupView::updfreq(rf::Frequency f) { +void AFSKSetupView::update_freq(rf::Frequency f) { char finalstr[9] = {0}; portapack::persistent_memory::set_tuned_frequency(f); @@ -69,12 +62,19 @@ AFSKSetupView::AFSKSetupView( NavigationView& nav ) { + using name_t = std::string; + using value_t = int32_t; + using option_t = std::pair; + using options_t = std::vector; + options_t format_options; uint8_t rpt; + size_t i; add_children({ { - &text_title, + &text_setfreq, &button_setfreq, - &button_setbps, + &text_bps, + &options_bps, &text_mark, &field_mark, &text_space, @@ -83,62 +83,45 @@ AFSKSetupView::AFSKSetupView( &field_bw, &text_repeat, &field_repeat, - //&checkbox_lsb, - //&checkbox_parity, - //&checkbox_datasize, - &checkbox_altformat, - &button_done + &text_format, + &options_format, + &button_save } }); - //if (portapack::persistent_memory::afsk_config() & 1) checkbox_lsb.set_value(true); - //if (portapack::persistent_memory::afsk_config() & 2) checkbox_parity.set_value(true); - //if (portapack::persistent_memory::afsk_config() & 4) checkbox_datasize.set_value(true); - if (portapack::persistent_memory::afsk_config() & 8) checkbox_altformat.set_value(true); + for (i = 0; i < AFSK_MODES_COUNT; i++) + format_options.emplace_back(std::make_pair(afsk_formats[i].fullname, i)); - updfreq(portapack::persistent_memory::tuned_frequency()); + options_format.set_options(format_options); + options_format.set_selected_index(portapack::persistent_memory::afsk_format()); - field_mark.set_value(portapack::persistent_memory::afsk_mark_freq()*100); - field_space.set_value(portapack::persistent_memory::afsk_space_freq()*100); + update_freq(portapack::persistent_memory::tuned_frequency()); + + field_mark.set_value(portapack::persistent_memory::afsk_mark_freq() * 25); + field_space.set_value(portapack::persistent_memory::afsk_space_freq() * 25); field_bw.set_value(portapack::persistent_memory::afsk_bw()); - rpt = (portapack::persistent_memory::afsk_config() >> 8) & 0xFF; - if (rpt > 99) rpt = 5; + rpt = portapack::persistent_memory::afsk_repeats(); + if ((rpt > 99) || (!rpt)) rpt = 5; field_repeat.set_value(rpt); - button_setfreq.on_select = [this,&nav](Button&){ + button_setfreq.on_select = [this,&nav](Button&) { auto new_view = nav.push(portapack::persistent_memory::tuned_frequency()); new_view->on_changed = [this](rf::Frequency f) { - updfreq(f); + update_freq(f); }; }; - if (portapack::persistent_memory::afsk_bitrate() == 1200) { - button_setbps.set_text("1200 bps"); - } else { - button_setbps.set_text("2400 bps"); - } - - button_setbps.on_select = [this](Button&){ - if (portapack::persistent_memory::afsk_bitrate() == 1200) { - portapack::persistent_memory::set_afsk_bitrate(2400); - button_setbps.set_text("2400 bps"); - } else { - portapack::persistent_memory::set_afsk_bitrate(1200); - button_setbps.set_text("1200 bps"); - } - }; + options_bps.set_by_value(portapack::persistent_memory::afsk_bitrate()); - button_done.on_select = [this,&nav](Button&){ + button_save.on_select = [this,&nav](Button&) { uint32_t afsk_config = 0; - portapack::persistent_memory::set_afsk_mark(field_mark.value()/100); - portapack::persistent_memory::set_afsk_space(field_space.value()/100); + portapack::persistent_memory::set_afsk_bitrate(options_bps.selected_index_value()); + portapack::persistent_memory::set_afsk_mark(field_mark.value() / 25); + portapack::persistent_memory::set_afsk_space(field_space.value() / 25); portapack::persistent_memory::set_afsk_bw(field_bw.value()); - //if (checkbox_lsb.value() == true) afsk_config |= 1; - //if (checkbox_parity.value() == true) afsk_config |= 2; - //if (checkbox_datasize.value() == true) afsk_config |= 4; - if (checkbox_altformat.value() == true) afsk_config |= 8; - afsk_config |= (field_repeat.value() << 8); + afsk_config |= (options_format.selected_index() << 16); + afsk_config |= (field_repeat.value() << 24); portapack::persistent_memory::set_afsk_config(afsk_config); nav.pop(); diff --git a/firmware/application/ui_afsksetup.hpp b/firmware/application/ui_afsksetup.hpp index d61835789..2d85cf000 100644 --- a/firmware/application/ui_afsksetup.hpp +++ b/firmware/application/ui_afsksetup.hpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -19,17 +20,13 @@ * Boston, MA 02110-1301, USA. */ +#include "afsk.hpp" + #include "ui.hpp" #include "ui_widget.hpp" #include "ui_painter.hpp" -#include "ui_menu.hpp" #include "ui_navigation.hpp" #include "ui_font_fixed_8x16.hpp" -#include "clock_manager.hpp" -#include "message.hpp" -#include "rf_path.hpp" -#include "max2837.hpp" -#include "volume.hpp" namespace ui { @@ -37,23 +34,36 @@ class AFSKSetupView : public View { public: AFSKSetupView(NavigationView& nav); - void updfreq(rf::Frequency f); void focus() override; - void paint(Painter& painter) override; + + std::string title() const override { return "AFSK setup"; }; private: - Text text_title { - { 40, 32, 160, 16 }, - "AFSK modulator setup" - }; + void update_freq(rf::Frequency f); + Text text_setfreq { + { 8, 32, 104, 16 }, + "Frequency:" + }; Button button_setfreq { - { 8, 64, 104, 32 }, + { 8, 48, 104, 32 }, "---.----M" }; - Button button_setbps { - { 128, 64, 96, 32 }, - "----bps" + + Text text_bps { + { 128, 40, 104, 16 }, + "Speed:" + }; + OptionsField options_bps { + { 128, 60 }, + 7, + { + { "600bps ", 600 }, + { "1200bps", 1200 }, + { "2400bps", 2400 }, + { "4800bps", 4800 }, + { "9600bps", 9600 } + } }; Text text_mark { @@ -86,8 +96,8 @@ private: }; NumberField field_bw { { 172, 104 }, - 3, - { 1, 40 }, + 2, + { 1, 50 }, 1, ' ' }; @@ -104,30 +114,19 @@ private: ' ' }; - Checkbox checkbox_altformat { - { 8, 150 }, - 11, - "Alt. format" + Text text_format { + { 16, 152, 7 * 8, 16 }, + "Format:" + }; + OptionsField options_format { + { 80, 152 }, + 10, + { + } }; - Checkbox checkbox_lsb { - { 8, 150 }, - 9, - "LSB first" - }; - Checkbox checkbox_parity { - { 8, 180 }, - 11, - "Even parity" - }; - Checkbox checkbox_datasize { - { 8, 210 }, - 6, - "8 bits" - }; - - Button button_done { - { 72, 250, 96, 48 }, + Button button_save { + { 72, 250, 96, 40 }, "Save" }; }; diff --git a/firmware/application/ui_lcr.cpp b/firmware/application/ui_lcr.cpp index 3b71d75b7..8dc4e34ea 100644 --- a/firmware/application/ui_lcr.cpp +++ b/firmware/application/ui_lcr.cpp @@ -24,6 +24,7 @@ #include "ui_afsksetup.hpp" #include "ui_debug.hpp" +#include "afsk.hpp" #include "baseband_api.hpp" #include "string_format.hpp" @@ -33,6 +34,7 @@ #include using namespace portapack; +using namespace afsk; namespace ui { @@ -46,25 +48,21 @@ LCRView::~LCRView() { } 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 }, + const char lcr_init[8] = { 127, 127, 127, 127, 127, 127, 127, 15 }; // Modem sync and SOM + const char ec_lut[4][2] = { { 'A', 0x00 }, // Eclairage (Auto, Jour, Nuit) { 'J', 0x00 }, - { 'N', 0x00 } }; + { 'N', 0x00 }, + { 'S', 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; + + uint8_t i; button_setrgsb.set_text(rgsb); // Pad litterals to 7 chars (not required ?) - for (i = 0; i < 5; i++) { - while (strlen(litteral[i]) < 7) { + for (i = 0; i < 5; i++) + while (strlen(litteral[i]) < 7) strcat(litteral[i], " "); - } - } // Compose LCR message memset(lcr_message, 0, 512); @@ -89,74 +87,21 @@ void LCRView::generate_message() { // Checksum checksum = 0; i = 7; // Skip modem sync - while (lcr_message[i]) { - checksum ^= lcr_message[i]; - i++; - } + while (lcr_message[i]) + checksum ^= lcr_message[i++]; + checksum ^= eom[0]; // EOM char checksum &= 0x7F; // Trim eom[1] = checksum; strcat(lcr_message, eom); - //if (persistent_memory::afsk_config() & 2) - pm = 0; // Even parity - //else - // pm = 1; // Odd parity - - if (!(persistent_memory::afsk_config() & 8)) { - // Normal format - for (dp = 0; dp < strlen(lcr_message); dp++) { - pp = pm; - new_byte = 0; - cur_byte = lcr_message[dp]; - for (cp = 0; cp < 7; cp++) { - bit = (cur_byte >> cp) & 1; - pp += bit; - new_byte |= (bit << (7 - cp)); - } - lcr_message_data[dp] = new_byte | (pp & 1); - } - lcr_message_data[dp++] = 0; - lcr_message_data[dp] = 0; - } else { - // Alt format - for (dp = 0; dp < strlen(lcr_message); dp++) { - pp = pm; - // Do not apply LUT on checksum (last byte) ? - if (dp != strlen(lcr_message) - 1) - cur_byte = alt_lookup[(uint8_t)lcr_message[dp] & 0x7F]; - else - cur_byte = lcr_message[dp]; - for (cp = 0; cp < 8; cp++) { - if ((cur_byte >> cp) & 1) pp++; - } - lcr_message_data[dp * 2] = cur_byte; - lcr_message_data[(dp * 2) + 1] = 0xFE | (pp & 1); - } - lcr_message_data[dp * 2] = 0; - lcr_message_data[(dp * 2) + 1] = 0; - } - - //if (persistent_memory::afsk_config() & 1) { - // LSB first - // See above - /*} else { - // MSB first - for (dp=0;dp>cp)&1) pp++; - } - lcr_message_data[dp] = (cur_byte<<1)|(pp&1); - } - }*/ + afsk::generate_data(lcr_message, lcr_message_data); } void LCRView::paint(Painter& painter) { uint8_t i; - char finalstr[24] = {0}; + std::string final_str; static constexpr Style style_orange { .font = font::fixed_8x16, @@ -180,18 +125,13 @@ void LCRView::paint(Painter& painter) { button_setrgsb.set_text(rgsb); - // 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"); - else - strcat(finalstr, "NRM"); - text_recap.set(finalstr); + // Recap: freq @ bps + final_str = to_string_dec_int(portapack::persistent_memory::tuned_frequency() / 1000, 6); + final_str += '@'; + final_str += to_string_dec_int(portapack::persistent_memory::afsk_bitrate(), 4); + final_str += "bps "; + final_str += afsk_formats[portapack::persistent_memory::afsk_format()].shortname; + text_recap.set(final_str); } void LCRView::update_progress() { @@ -212,7 +152,7 @@ void LCRView::update_progress() { strcat(str, " "); strcat(str, to_string_dec_uint(scan_index + 1).c_str()); strcat(str, "/"); - strcat(str, to_string_dec_uint(LCR_SCAN_COUNT).c_str()); + strcat(str, to_string_dec_uint(scan_count).c_str()); text_status.set(str); progress.set_value(scan_progress); } else { @@ -235,7 +175,7 @@ void LCRView::on_txdone(int n) { } } else { // Done transmitting - if ((tx_mode == SCAN) && (scan_index < (LCR_SCAN_COUNT - 1))) { + if ((tx_mode == SCAN) && (scan_index < (scan_count - 1))) { transmitter_model.disable(); if (abort_scan) { // Kill scan process @@ -250,7 +190,7 @@ void LCRView::on_txdone(int n) { } else { // Next address scan_index++; - strcpy(rgsb, RGSB_list[scan_index]); + strcpy(rgsb, &scan_list[options_scanlist.selected_index()].addresses[scan_index * 5]); scan_progress++; repeat_index = 1; update_progress(); @@ -267,7 +207,7 @@ void LCRView::on_txdone(int n) { } void LCRView::start_tx(const bool scan) { - bool afsk_alt_format; + uint8_t afsk_format; uint8_t afsk_repeats; afsk_repeats = portapack::persistent_memory::afsk_repeats(); @@ -275,11 +215,12 @@ void LCRView::start_tx(const bool scan) { if (scan) { if (tx_mode != SCAN) { scan_index = 0; + scan_count = scan_list[options_scanlist.selected_index()].count; scan_progress = 1; repeat_index = 1; tx_mode = SCAN; - strcpy(rgsb, RGSB_list[0]); - progress.set_max(LCR_SCAN_COUNT * afsk_repeats); + strcpy(rgsb, &scan_list[options_scanlist.selected_index()].addresses[0]); + progress.set_max(scan_count * afsk_repeats); update_progress(); } } else { @@ -291,10 +232,21 @@ void LCRView::start_tx(const bool scan) { generate_message(); - if (portapack::persistent_memory::afsk_config() & 8) - afsk_alt_format = true; - else - afsk_alt_format = false; + switch (portapack::persistent_memory::afsk_format()) { + case 0: + case 1: + case 2: + afsk_format = 0; + break; + + case 3: + afsk_format = 1; + break; + + default: + afsk_format = 0; + } + transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); transmitter_model.set_baseband_configuration({ @@ -311,11 +263,11 @@ void LCRView::start_tx(const bool scan) { 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, + portapack::persistent_memory::afsk_mark_freq() * (0x40000 * 256) / (228000 / 25), + portapack::persistent_memory::afsk_space_freq() * (0x40000 * 256) / (228000 / 25), afsk_repeats, portapack::persistent_memory::afsk_bw() * 115, // See proc_fsk_lcr.cpp - afsk_alt_format + afsk_format ); } @@ -327,11 +279,8 @@ LCRView::LCRView(NavigationView& nav) { std::string label; baseband::run_image(portapack::spi_flash::image_tag_afsk); - - memset(litteral, 0, 5 * 8); - memset(rgsb, 0, 5); - strcpy(rgsb, RGSB_list[0]); + strcpy(rgsb, &scan_list[options_scanlist.selected_index()].addresses[0]); add_children({ { &text_recap, @@ -342,6 +291,8 @@ LCRView::LCRView(NavigationView& nav) { &progress, &button_lcrdebug, &button_transmit, + &text_scanlist, + &options_scanlist, &button_scan, &button_clear } }); diff --git a/firmware/application/ui_lcr.hpp b/firmware/application/ui_lcr.hpp index ffc879694..876427442 100644 --- a/firmware/application/ui_lcr.hpp +++ b/firmware/application/ui_lcr.hpp @@ -28,8 +28,6 @@ namespace ui { -#define LCR_SCAN_COUNT 36 - class LCRView : public View { public: LCRView(NavigationView& nav); @@ -41,16 +39,17 @@ public: std::string title() const override { return "LCR transmit"; }; private: - enum tx_modes { - IDLE = 0, - SINGLE, - SCAN + struct scan_list_t { + uint8_t count; + const char * addresses; }; - // afsk_config() - tx_modes tx_mode = IDLE; - bool abort_scan = false; - double scan_progress; - const char RGSB_list[LCR_SCAN_COUNT][5] = { + + scan_list_t scan_list[2] = { + { 36, &RGSB_list_Lille[0][0] }, + { 23, &RGSB_list_Reims[0][0] } + }; + + const char RGSB_list_Lille[36][5] = { "AI10", "AI20", "AI30", "AI40", "AI50", "AI60", "AI70", "AJ10", "AJ20", "AJ30", "AJ40", "AJ50", @@ -62,14 +61,35 @@ private: "EbM0", "EbN0", "EbO0", "EbP0", "EbS0" }; - char litteral[5][8]; - char rgsb[5]; + + const char RGSB_list_Reims[23][5] = { + "AI10", "AI20", "AI30", "AI40", + "AI50", "AI60", "AI70", + "AJ10", "AJ20", "AJ30", "AJ40", + "AJ50", "AJ60", "AJ70", + "AK10", "AK20", "AK50", "AK60", + "AK70", + "AP10" + }; + + enum tx_modes { + IDLE = 0, + SINGLE, + SCAN + }; + + tx_modes tx_mode = IDLE; + bool abort_scan = false; + uint8_t scan_count; + double scan_progress; + unsigned int scan_index; + char litteral[5][8] = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }; + char rgsb[5] = { 0 }; char lcr_message[512]; char lcr_message_data[512]; char checksum = 0; rf::Frequency f; uint8_t repeat_index; - unsigned int scan_index; void generate_message(); void update_progress(); @@ -79,7 +99,7 @@ private: radio::Configuration lcr_radio_config = { 0, - 2280000, // ? + 2280000, 2500000, // ? rf::Direction::Transmit, true, @@ -91,17 +111,6 @@ private: // 2: 94 ? // 9: 85 ? - const char alt_lookup[128] = { - 0, 0, 0, 0x5F, 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 !"#$%&'()*+,-./ - 0xF5, 0, 0x94, 0x55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1C, 0, 0, // 30 0123456789:;<=>? - 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{|}~ - }; - const Style style_val { .font = font::fixed_8x16, .background = Color::green(), @@ -128,7 +137,8 @@ private: { { "EC:Auto", 0 }, { "EC:Jour", 1 }, - { "EC:Nuit", 2 } + { "EC:Nuit", 2 }, + { "EC:S ? ", 3 } } }; @@ -146,6 +156,11 @@ private: "DEBUG" }; + Button button_clear { + { 174, 64, 50, 9 * 16 }, + "CLEAR" + }; + Text text_status { { 16, 224, 128, 16 }, "Ready" @@ -158,13 +173,21 @@ private: { 16, 270, 64, 32 }, "TX" }; - Button button_scan { - { 88, 270, 64, 32 }, - "SCAN" + Text text_scanlist { + { 88, 268, 80, 16 }, + "Scan list:" }; - Button button_clear { - { 160, 270, 64, 32 }, - "CLEAR" + OptionsField options_scanlist { + { 88, 284 }, + 6, + { + { "Lille ", 0 }, + { "Reims ", 1 } + } + }; + Button button_scan { + { 168, 270, 56, 32 }, + "SCAN" }; MessageHandlerRegistration message_handler_tx_done { diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 9a1024972..1d665c263 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -87,10 +87,7 @@ MenuView::MenuView() { } MenuView::~MenuView() { - /* TODO: Double-check this */ - for (auto child : children_) { - delete child; - } + time::signal_tick_second -= signal_token_tick_second; } void MenuView::on_tick_second() { diff --git a/firmware/application/ui_setup.cpp b/firmware/application/ui_setup.cpp index ea448d12c..2caa8edc6 100644 --- a/firmware/application/ui_setup.cpp +++ b/firmware/application/ui_setup.cpp @@ -257,10 +257,10 @@ SetUIView::SetUIView(NavigationView& nav) { } void SetUIView::focus() { - button_ok.focus(); + checkbox_showsplash.focus(); } -void ModInfoView::on_show() { +/*void ModInfoView::on_show() { if (modules_nb) update_infos(0); } @@ -436,12 +436,12 @@ void ModInfoView::focus() { option_modules.focus(); else button_ok.focus(); -} +}*/ SetupMenuView::SetupMenuView(NavigationView& nav) { - add_items<7>({ { + add_items<6>({ { { "UI", ui::Color::white(), [&nav](){ nav.push(); } }, - { "SD card modules", ui::Color::white(), [&nav](){ nav.push(); } }, + //{ "SD card modules", ui::Color::white(), [&nav](){ nav.push(); } }, { "Date/Time", ui::Color::white(), [&nav](){ nav.push(); } }, { "Frequency correction", ui::Color::white(), [&nav](){ nav.push(); } }, { "Antenna Bias Voltage", ui::Color::white(), [&nav](){ nav.push(); } }, diff --git a/firmware/application/ui_setup.hpp b/firmware/application/ui_setup.hpp index ba116e1b2..2148f3e7f 100644 --- a/firmware/application/ui_setup.hpp +++ b/firmware/application/ui_setup.hpp @@ -308,7 +308,7 @@ private: }; }; -class ModInfoView : public View { +/*class ModInfoView : public View { public: ModInfoView(NavigationView& nav); void focus() override; @@ -376,7 +376,7 @@ private: { 4 * 8, 272, 64, 24 }, "Ok" }; -}; +};*/ class SetupMenuView : public MenuView { public: diff --git a/firmware/baseband/proc_afsk.cpp b/firmware/baseband/proc_afsk.cpp index 82c664489..624072f1a 100644 --- a/firmware/baseband/proc_afsk.cpp +++ b/firmware/baseband/proc_afsk.cpp @@ -29,22 +29,24 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) { - // This is called at 2280000/2048 = 1113Hz + // This is called at 2.28M/2048 = 1113Hz if (!configured) return; for (size_t i = 0; i= (10 - 1)) { - s = 0; - + // Tone synthesis at 2.28M/10 = 228kHz + if (!s) { + s = 10 - 1; if (sample_count >= afsk_samples_per_bit) { - if (configured == true) { + if (configured) { cur_byte = message_data[byte_pos]; ext_byte = message_data[byte_pos + 1]; + if (!(cur_byte | ext_byte)) { + // End of data if (repeat_counter < afsk_repeat) { + // Repeat bit_pos = 0; byte_pos = 0; cur_byte = message_data[0]; @@ -53,36 +55,33 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) { shared_memory.application_queue.push(message); repeat_counter++; } else { - message.n = 0; - shared_memory.application_queue.push(message); + // Stop cur_byte = 0; ext_byte = 0; + message.n = 0; + shared_memory.application_queue.push(message); configured = false; } } } - if (!afsk_alt_format) { + if (afsk_format == 0) { // 0bbbbbbbp1 // Start, 7-bit data, parity, stop - gbyte = 0; - gbyte = cur_byte << 1; - gbyte |= 1; - } else { + gbyte = (cur_byte << 1) | 1; + } else if (afsk_format == 1) { // 0bbbbbbbbp // Start, 8-bit data, parity - gbyte = 0; - gbyte = cur_byte << 1; - gbyte |= (ext_byte & 1); + gbyte = (cur_byte << 1) | (ext_byte & 1); } cur_bit = (gbyte >> (9 - bit_pos)) & 1; - if (bit_pos == 9) { + if (bit_pos >= 9) { bit_pos = 0; - if (!afsk_alt_format) + if (afsk_format == 0) byte_pos++; - else + else if (afsk_format == 1) byte_pos += 2; } else { bit_pos++; @@ -97,10 +96,10 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) { else tone_phase += afsk_phase_inc_space; } else { - s++; + s--; } - tone_sample = (sine_table_i8[(tone_phase & 0x03FC0000)>>18]); + tone_sample = (sine_table_i8[(tone_phase & 0x03FC0000) >> 18]); // FM // 1<<18 = 262144 @@ -108,17 +107,18 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) { frq = tone_sample * afsk_bw; phase = (phase + frq); - sphase = phase + (64<<18); + sphase = phase + (64 << 18); - re = (sine_table_i8[(sphase & 0x03FC0000)>>18]); - im = (sine_table_i8[(phase & 0x03FC0000)>>18]); + re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]); + im = (sine_table_i8[(phase & 0x03FC0000) >> 18]); - buffer.p[i] = {(int8_t)re,(int8_t)im}; + 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, 512); afsk_samples_per_bit = message.afsk_samples_per_bit; @@ -126,8 +126,9 @@ void AFSKProcessor::on_message(const Message* const p) { afsk_phase_inc_space = message.afsk_phase_inc_space; afsk_repeat = message.afsk_repeat - 1; afsk_bw = message.afsk_bw; - afsk_alt_format = message.afsk_alt_format; + afsk_format = message.afsk_format; + s = 0; sample_count = afsk_samples_per_bit; repeat_counter = 0; bit_pos = 0; diff --git a/firmware/baseband/proc_afsk.hpp b/firmware/baseband/proc_afsk.hpp index 3a2e46397..19d8bb402 100644 --- a/firmware/baseband/proc_afsk.hpp +++ b/firmware/baseband/proc_afsk.hpp @@ -42,12 +42,12 @@ private: uint32_t afsk_phase_inc_space; uint8_t afsk_repeat; uint32_t afsk_bw; - bool afsk_alt_format; + uint8_t afsk_format; char message_data[512]; uint8_t repeat_counter = 0; int8_t re, im; - uint8_t s; + uint8_t s = 0; uint8_t bit_pos = 0; uint16_t byte_pos = 0; char cur_byte = 0; diff --git a/firmware/bitmaps/fox.bmp b/firmware/bitmaps/fox.bmp index 2556fa220..9c491783a 100644 Binary files a/firmware/bitmaps/fox.bmp and b/firmware/bitmaps/fox.bmp differ diff --git a/firmware/bitmaps/fox_rle.bmp b/firmware/bitmaps/fox_rle.bmp deleted file mode 100644 index 9c491783a..000000000 Binary files a/firmware/bitmaps/fox_rle.bmp and /dev/null differ diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index c81a1724e..71a9d64b8 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -530,14 +530,14 @@ public: const uint32_t afsk_phase_inc_space, const uint8_t afsk_repeat, const uint32_t afsk_bw, - const bool afsk_alt_format + const uint8_t afsk_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) + afsk_format(afsk_format) { memcpy(message_data, data, 512); } @@ -547,7 +547,7 @@ public: uint32_t afsk_phase_inc_space; uint8_t afsk_repeat; uint32_t afsk_bw; - bool afsk_alt_format; + uint8_t afsk_format; char message_data[512]; }; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 970150a65..be4e41a7e 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -36,16 +36,16 @@ using portapack::memory::map::backup_ram; namespace portapack { namespace persistent_memory { -constexpr rf::Frequency tuned_frequency_reset_value { 858750000 }; +constexpr rf::Frequency tuned_frequency_reset_value { 88000000 }; using ppb_range_t = range_t; constexpr ppb_range_t ppb_range { -99000, 99000 }; constexpr ppb_t ppb_reset_value { 0 }; using afsk_freq_range_t = range_t; -constexpr afsk_freq_range_t afsk_freq_range { 1, 60 }; -constexpr int32_t afsk_mark_reset_value { 12 }; -constexpr int32_t afsk_space_reset_value { 22 }; +constexpr afsk_freq_range_t afsk_freq_range { 1, 400 }; +constexpr int32_t afsk_mark_reset_value { 48 }; +constexpr int32_t afsk_space_reset_value { 88 }; using afsk_bitrate_range_t = range_t; constexpr afsk_bitrate_range_t afsk_bitrate_range { 600, 9600 }; @@ -63,7 +63,7 @@ struct data_t { // AFSK modem int32_t afsk_mark_freq; - int32_t afsk_space_freq; // Todo: optimize size, only 256 bytes of NVRAM ! + int32_t afsk_space_freq; // Todo: reduce size, only 256 bytes of NVRAM ! int32_t afsk_bitrate; int32_t afsk_bw; uint32_t afsk_config; @@ -139,8 +139,12 @@ uint32_t afsk_config() { return data->afsk_config; } +uint8_t afsk_format() { + return ((data->afsk_config >> 16) & 0xFF); +} + uint8_t afsk_repeats() { - return (data->afsk_config >> 8); + return (data->afsk_config >> 24); } void set_afsk_config(const uint32_t new_value) { diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 99bd62fc6..30b6542c8 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -47,6 +47,7 @@ int32_t afsk_bitrate(); void set_afsk_bitrate(const int32_t new_value); uint32_t afsk_config(); +uint8_t afsk_format(); uint8_t afsk_repeats(); void set_afsk_config(const uint32_t new_value); diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index 6ae7006c5..600723ebb 100644 Binary files a/firmware/portapack-h1-firmware.bin and b/firmware/portapack-h1-firmware.bin differ