diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 9fb4f63a9..1c8bad997 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -24,10 +24,8 @@ //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) -//BUG: Crash after TX stop (unregister message !) -//TODO: Show MD5 mismatches for modules not found, etc... -//TODO: Frequency manager ! +//TODO: Frequency manager //TODO: Weird LCR AFSK scrambling ? //TODO: SD card wiper //TODO: Draw on touchscreen and transmit as spectrum paint @@ -41,6 +39,7 @@ //TODO: GSM channel detector //TODO: AFSK receiver //TODO: SIGFOX RX/TX +//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 //TODO: Check bw setting in LCR TX //TODO: Bodet :) @@ -48,7 +47,6 @@ //TODO: Setup: Play dead by default ? Enable/disable ? //TODO: Hide statusview when playing dead //TODO: Persistent playdead ! -//TODO: LCR EC=A,J,N //TODO: LCR full message former (see norm) //TODO: AFSK NRZI //TODO: TX power setting diff --git a/firmware/application/ui_about.hpp b/firmware/application/ui_about.hpp index 3d8caab1a..4619723f9 100644 --- a/firmware/application/ui_about.hpp +++ b/firmware/application/ui_about.hpp @@ -138,17 +138,17 @@ private: }; Text text_firmware { - { 0, 128, 240, 16 }, + { 0, 236, 240, 16 }, "Git Commit Hash " GIT_REVISION, }; Text text_cpld_hackrf { - { 0, 144, 11*8, 16 }, + { 0, 252, 11*8, 16 }, "HackRF CPLD", }; Text text_cpld_hackrf_status { - { 240 - 3*8, 144, 3*8, 16 }, + { 240 - 3*8, 252, 3*8, 16 }, "???" }; diff --git a/firmware/application/ui_xylos.cpp b/firmware/application/ui_xylos.cpp index 3ef118439..10634e1bf 100644 --- a/firmware/application/ui_xylos.cpp +++ b/firmware/application/ui_xylos.cpp @@ -122,152 +122,139 @@ XylosView::~XylosView() { baseband::shutdown(); } -void XylosView::upd_message() { +void XylosView::generate_message() { uint8_t c; - - ccirmessage[0] = (header_code_a.value() / 10) + 0x30; - ccirmessage[1] = (header_code_a.value() % 10) + 0x30; - ccirmessage[2] = (header_code_b.value() / 10) + 0x30; - ccirmessage[3] = (header_code_b.value() % 10) + 0x30; - ccirmessage[4] = (city_code.value() / 10) + 0x30; - ccirmessage[5] = (city_code.value() % 10) + 0x30; - ccirmessage[6] = family_code.value() + 0x30; + // Init CCIR message + memcpy(ccir_message, ccir_base, 21); + + // Header + ccir_message[0] = (header_code_a.value() / 10) + 0x30; + ccir_message[1] = (header_code_a.value() % 10) + 0x30; + ccir_message[2] = (header_code_b.value() / 10) + 0x30; + ccir_message[3] = (header_code_b.value() % 10) + 0x30; + + // Addresses + ccir_message[4] = (city_code.value() / 10) + 0x30; + ccir_message[5] = (city_code.value() % 10) + 0x30; + ccir_message[6] = family_code.value() + 0x30; if (checkbox_wcsubfamily.value() == false) - ccirmessage[7] = subfamily_code.value() + 0x30; + ccir_message[7] = subfamily_code.value() + 0x30; else - ccirmessage[7] = 'A'; + ccir_message[7] = 'A'; if (checkbox_wcid.value() == false) { - ccirmessage[8] = (receiver_code.value() / 10) + 0x30; - ccirmessage[9] = (receiver_code.value() % 10) + 0x30; + ccir_message[8] = (receiver_code.value() / 10) + 0x30; + ccir_message[9] = (receiver_code.value() % 10) + 0x30; } else { - ccirmessage[8] = 'A'; - ccirmessage[9] = 'A'; + ccir_message[8] = 'A'; + ccir_message[9] = 'A'; } - ccirmessage[10] = 'B'; + // Commands + ccir_message[11] = options_ra.selected_index() + 0x30; + ccir_message[12] = options_rb.selected_index() + 0x30; + ccir_message[13] = options_rc.selected_index() + 0x30; + ccir_message[14] = options_rd.selected_index() + 0x30; - ccirmessage[11] = options_ra.selected_index() + 0x30; - ccirmessage[12] = options_rb.selected_index() + 0x30; - ccirmessage[13] = options_rc.selected_index() + 0x30; - ccirmessage[14] = options_rd.selected_index() + 0x30; - - ccirmessage[15] = 'B'; - - ccirmessage[16] = '0'; - ccirmessage[17] = '0'; - ccirmessage[18] = '0'; - ccirmessage[19] = '0'; - - // Repeats elimination - for (c = 1; c < 20; c++) { - if (ccirmessage[c] == ccirmessage[c - 1]) ccirmessage[c] = 'E'; - } - - ccirmessage[20] = 0; + // Get rid of repeats with E code + for (c = 1; c < 20; c++) + if (ccir_message[c] == ccir_message[c - 1]) ccir_message[c] = 'E'; // Display as text - text_message.set(ccirmessage); + text_message.set(ccir_message); - // ASCII to frequency LUT index - for (c=0; c<20; c++) { - if (ccirmessage[c] > '9') - ccirmessage[c] -= 0x37; - else - ccirmessage[c] -= 0x30; - } - - ccirmessage[20] = 0xFF; + ascii_to_ccir(ccir_message); } void XylosView::start_tx() { - upd_message(); - //audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); + + transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); transmitter_model.set_baseband_configuration({ .mode = 0, .sampling_rate = 1536000U, .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_xylos_data(ccirmessage); + baseband::set_xylos_data(ccir_message); +} + + // ASCII to frequency LUT index +void XylosView::ascii_to_ccir(char *ascii) { + uint8_t c; + + for (c = 0; c < 20; c++) { + if (ascii[c] > '9') + ascii[c] -= 0x37; + else + ascii[c] -= 0x30; + } + + // EOM code for baseband + ascii[20] = 0xFF; } void XylosView::on_txdone(const int n) { - int c, sr; + size_t sr; - if (testing == true) { + if (tx_mode == TESTING) { if (n == 25) { transmitter_model.disable(); - if (sequence_idx != 9) { + /*if (sequence_idx != 9) { chThdSleepMilliseconds(15000); - memcpy(ccirmessage, &xylos_sequence[sequence_idx][0], 21); + memcpy(ccir_message, &xylos_sequence[sequence_idx][0], 21); // ASCII to frequency LUT index for (c=0; c<20; c++) { - if (ccirmessage[c] > '9') - ccirmessage[c] -= 0x37; + if (ccir_message[c] > '9') + ccir_message[c] -= 0x37; else - ccirmessage[c] -= 0x30; + ccir_message[c] -= 0x30; } - ccirmessage[20] = 0xFF; + ccir_message[20] = 0xFF; //memcpy(shared_memory.xylosdata, ccirmessage, 21); TODO !!! sequence_idx++; - txing = true; + tx_mode = TESTING; transmitter_model.enable(); - } else { + } else {*/ button_txtest.set_style(&style()); button_txtest.set_text("TEST"); - testing = false; - } + tx_mode = IDLE; + //} } } else { if (n == 25) { - audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max); + //audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max); transmitter_model.disable(); progress.set_value(0); - if (inc_cnt) { - chThdSleepMilliseconds(1000); - header_code_b.set_value(header_code_b.value() + 1); - - upd_message(); - start_tx(); - - inc_cnt--; + if (checkbox_cligno.value() == false) { + tx_mode = IDLE; + button_transmit.set_style(&style_val); + button_transmit.set_text("START"); } else { - header_code_b.set_value(header_init); - if (checkbox_cligno.value() == false) { - txing = false; - button_transmit.set_style(&style_val); - button_transmit.set_text("START"); - } else { - if (checkbox_hinc.value()) - inc_cnt = 3; - else - inc_cnt = 0; - - chThdSleepMilliseconds(tempo_cligno.value() * 1000); - - // Invert relay states - sr = options_ra.selected_index(); - if (sr > 0) options_ra.set_selected_index(sr ^ 3); - sr = options_rb.selected_index(); - if (sr > 0) options_rb.set_selected_index(sr ^ 3); - sr = options_rc.selected_index(); - if (sr > 0) options_rc.set_selected_index(sr ^ 3); - sr = options_rd.selected_index(); - if (sr > 0) options_rd.set_selected_index(sr ^ 3); - - upd_message(); - start_tx(); - } + chThdSleepMilliseconds(tempo_cligno.value() * 1000); + + // Invert relay states + sr = options_ra.selected_index(); + if (sr > 0) options_ra.set_selected_index(sr ^ 3); + sr = options_rb.selected_index(); + if (sr > 0) options_rb.set_selected_index(sr ^ 3); + sr = options_rc.selected_index(); + if (sr > 0) options_rc.set_selected_index(sr ^ 3); + sr = options_rd.selected_index(); + if (sr > 0) options_rd.set_selected_index(sr ^ 3); + + generate_message(); + start_tx(); } } else { progress.set_value((n + 1) * 5); @@ -276,10 +263,11 @@ void XylosView::on_txdone(const int n) { } XylosView::XylosView(NavigationView& nav) { + (void)nav; + baseband::run_image(portapack::spi_flash::image_tag_xylos); add_children({ { - &checkbox_hinc, &button_txtest, &text_header, &header_code_a, @@ -325,27 +313,27 @@ XylosView::XylosView(NavigationView& nav) { header_code_a.on_change = [this](int32_t v) { (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; header_code_b.on_change = [this](int32_t v) { (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; city_code.on_change = [this](int32_t v) { (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; family_code.on_change = [this](int32_t v) { (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; subfamily_code.on_change = [this](int32_t v) { (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; receiver_code.on_change = [this](int32_t v) { (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; subfamily_code.hidden(true); @@ -358,7 +346,7 @@ XylosView::XylosView(NavigationView& nav) { subfamily_code.hidden(false); text_subfamily.set_style(&style()); } - XylosView::upd_message(); + XylosView::generate_message(); }; receiver_code.hidden(true); @@ -372,119 +360,75 @@ XylosView::XylosView(NavigationView& nav) { text_receiver.set_style(&style()); } receiver_code.set_dirty(); - XylosView::upd_message(); + XylosView::generate_message(); }; options_ra.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; options_rb.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; options_rc.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; options_rd.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; (void)v; - XylosView::upd_message(); + XylosView::generate_message(); }; button_transmit.set_style(&style_val); - XylosView::upd_message(); + XylosView::generate_message(); - /*button_txtest.on_select = [this](Button&) { - const uint8_t ccirtest[21] = { 11, 13, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 14, 12, 10, 12, 14, 0, 9, 0xFF }; - if (txing == false) { - EventDispatcher::message_map().unregister_handler(Message::ID::TXDone); - - EventDispatcher::message_map().register_handler(Message::ID::TXDone, - [this](Message* const p) { - const auto message = static_cast(p); - if (message->n == 25) { - audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max); - transmitter_model.disable(); - txing = false; - button_txtest.set_style(&style()); - button_txtest.set_text("TEST"); - } - } - ); - - memcpy(ccirmessage, ccirtest, 21); - shared_memory.transmit_done = false; - memcpy(shared_memory.xylosdata, ccirmessage, 21); - - transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); - - audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); - - txing = true; - button_txtest.set_style(&style_cancel); - button_txtest.set_text("Wait"); - transmitter_model.enable(); - } - };*/ - - // Sequence testing: + // Transmission and tones testing button_txtest.on_select = [this](Button&) { - int c; + // Tones going up in pitch + const uint8_t ccir_test[21] = { 11, 13, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 14, 12, 10, 12, 14, 0, 9, 0xFF }; - if (txing == false) { - sequence_idx = 0; - - memcpy(ccirmessage, &xylos_sequence[sequence_idx][0], 21); - // ASCII to frequency LUT index - for (c=0; c<20; c++) { - if (ccirmessage[c] > '9') - ccirmessage[c] -= 0x37; - else - ccirmessage[c] -= 0x30; - } - ccirmessage[20] = 0xFF; - //memcpy(shared_memory.xylosdata, ccirmessage, 21); TODO !!! - - sequence_idx++; - - transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); - - txing = true; - testing = true; + if (tx_mode == IDLE) { + tx_mode = TESTING; + memcpy(ccir_message, ccir_test, 21); + //audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); button_txtest.set_style(&style_cancel); button_txtest.set_text("Wait"); - transmitter_model.enable(); + start_tx(); } }; + + // Sequence playback + /*button_txtest.on_select = [this](Button&) { + if (tx_mode == IDLE) { + tx_mode = TESTING; + sequence_idx = 0; + + memcpy(ccir_message, &xylos_sequence[sequence_idx][0], 21); + + ascii_to_ccir(ccir_message); + + sequence_idx++; + button_txtest.set_style(&style_cancel); + button_txtest.set_text("Wait"); + start_tx(); + } + };*/ + + // Single transmit button_transmit.on_select = [this](Button&) { - - if (txing == false) { - upd_message(); - - if (checkbox_hinc.value()) - inc_cnt = 3; - else - inc_cnt = 0; - header_init = header_code_b.value(); - - //shared_memory.transmit_done = false; - //memcpy(shared_memory.xylosdata, ccirmessage, 21); - - transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); - - audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); - - txing = true; - testing = false; + if (tx_mode == IDLE) { + // audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); + tx_mode = SINGLE; button_transmit.set_style(&style_cancel); button_transmit.set_text("Wait"); + generate_message(); start_tx(); } }; diff --git a/firmware/application/ui_xylos.hpp b/firmware/application/ui_xylos.hpp index 7acd9846e..7ecf67c45 100644 --- a/firmware/application/ui_xylos.hpp +++ b/firmware/application/ui_xylos.hpp @@ -150,12 +150,18 @@ public: void focus() override; private: - int inc_cnt; - int header_init; - bool txing = false; - bool testing = false; + enum tx_modes { + IDLE = 0, + SINGLE, + SEQUENCE, + TESTING + }; + + tx_modes tx_mode = IDLE; const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; - char ccirmessage[21]; + char ccir_message[21]; + + const char ccir_base[21] = "0000000000B0000B0000"; const char xylos_sequence[9][21] = { "0E0E18920EB1E10B0E0E", @@ -171,8 +177,9 @@ private: int sequence_idx; + void ascii_to_ccir(char *ascii); void start_tx(); - void upd_message(); + void generate_message(); void on_txdone(const int n); const Style style_val { @@ -191,12 +198,6 @@ private: .foreground = Color::grey(), }; - Checkbox checkbox_hinc { - { 21 * 8, 12}, - 2, - "+3" - }; - Text text_header { { 8 * 8, 1 * 16, 7 * 8, 16 }, "Header:" diff --git a/firmware/baseband-tx.bin b/firmware/baseband-tx.bin deleted file mode 100644 index d7f2a1b1d..000000000 Binary files a/firmware/baseband-tx.bin and /dev/null differ diff --git a/firmware/baseband.bin b/firmware/baseband.bin deleted file mode 100644 index a877db80c..000000000 Binary files a/firmware/baseband.bin and /dev/null differ diff --git a/firmware/baseband/proc_xylos.cpp b/firmware/baseband/proc_xylos.cpp index a9ce01ea9..29e8513c4 100644 --- a/firmware/baseband/proc_xylos.cpp +++ b/firmware/baseband/proc_xylos.cpp @@ -42,7 +42,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { for (size_t i = 0; i= (5-1)) { + if (s >= (2-1)) { s = 0; if (silence) { @@ -55,15 +55,15 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { } else { if (sample_count >= CCIR_TONELENGTH) { if (transmit_done == false) { - 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)) { - message.n = 25; // End of message code - transmit_done = true; - shared_memory.application_queue.push(message); + 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); + } } sample_count = 0; @@ -81,7 +81,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { re = 0; im = 0; } else { - sample = (sine_table_f32[(aphase & 0x03FF0000)>>18]*127); // 255 here before + sample = (sine_table_f32[(aphase & 0x03FC0000)>>18]*127); // 255 here before // Audio preview sample generation: 1536000/48000 = 32 /*if (as >= 31) { @@ -92,13 +92,13 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { }*/ //FM - frq = sample * 1000; // 500 was here + frq = sample * 800; // ? phase = (phase + frq); sphase = phase + (256<<16); - re = (sine_table_f32[(sphase & 0x03FF0000)>>18]*15); - im = (sine_table_f32[(phase & 0x03FF0000)>>18]*15); + re = (sine_table_f32[(sphase & 0x03FC0000)>>18]*127); + im = (sine_table_f32[(phase & 0x03FC0000)>>18]*127); } buffer.p[i] = {(int8_t)re,(int8_t)im}; diff --git a/firmware/baseband/proc_xylos.hpp b/firmware/baseband/proc_xylos.hpp index 2b9b84001..761c01240 100644 --- a/firmware/baseband/proc_xylos.hpp +++ b/firmware/baseband/proc_xylos.hpp @@ -31,9 +31,9 @@ #include "audio_output.hpp" #include "baseband_thread.hpp" -#define CCIR_TONELENGTH (15360*2)-1 // 1536000/10/10 -#define PHASEV (436.91/2) // (65536*1024)/1536000*10 -#define SILENCE (46080*2)-1 // 400ms +#define CCIR_TONELENGTH (15360*5)-1 // 1536000/10/10 +#define PHASEV (436.91/5) // (65536*1024)/1536000*10 +#define SILENCE (46080*5)-1 // 400ms class XylosProcessor : public BasebandProcessor { public: diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 6895ad041..0a95e282e 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -102,12 +102,12 @@ struct region_t { constexpr region_t bootstrap { .offset = 0x00000, - .size = 0x10000, + .size = 0x8000, }; constexpr region_t images { - .offset = 0x10000, - .size = 0x30000, + .offset = 0x8000, + .size = 0x38000, }; constexpr region_t application { diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index 6ed98779a..335b0f009 100644 Binary files a/firmware/portapack-h1-firmware.bin and b/firmware/portapack-h1-firmware.bin differ diff --git a/firmware/tools/make_spi_image.py b/firmware/tools/make_spi_image.py index d5d98328a..57cf8a920 100755 --- a/firmware/tools/make_spi_image.py +++ b/firmware/tools/make_spi_image.py @@ -56,12 +56,12 @@ images = ( { 'name': 'bootstrap', 'data': bootstrap_image, - 'size': 0x10000, + 'size': 0x8000, }, { 'name': 'baseband', 'data': baseband_image, - 'size': 0x30000, + 'size': 0x38000, }, { 'name': 'application',