diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 899e60da..2f93c747 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -79,7 +79,12 @@ void WFMConfig::apply() const { audio::set_rate(audio::Rate::Hz_48000); } -void set_tones_data(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, +void set_tone(const uint32_t index, const uint32_t delta, const uint32_t duration) { + shared_memory.bb_data.tones_data.tone_defs[index].delta = delta; + shared_memory.bb_data.tones_data.tone_defs[index].duration = duration; +} + +void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, const bool dual_tone, const bool audio_out) { const TonesConfigureMessage message { bw, diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index ec31ec28..f276716c 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -55,7 +55,8 @@ struct WFMConfig { void apply() const; }; -void set_tones_data(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, +void set_tone(const uint32_t index, const uint32_t delta, const uint32_t duration); +void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, const bool dual_tone, const bool audio_out); void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration); void set_audiotx_data(const uint32_t divider, const uint32_t bw, const uint32_t gain_x10, diff --git a/firmware/application/bht.cpp b/firmware/application/bht.cpp index 3b6ca7fe..b54b151e 100644 --- a/firmware/application/bht.cpp +++ b/firmware/application/bht.cpp @@ -78,11 +78,36 @@ std::string gen_message_ep(uint8_t city_code, size_t family_code_ep, uint32_t re return ep_message; } +std::string gen_message_xy(const std::string& ascii_code) { + std::string local_code = ascii_code; + uint8_t ccir_message[20]; + uint8_t translate; + uint32_t c; + + // Replace repeats with E code + for (c = 1; c < 20; c++) + if (local_code[c] == local_code[c - 1]) local_code[c] = 'E'; + + for (c = 0; c < 20; c++) { + if (local_code[c] <= '9') + translate = local_code[c] - '0'; + else + translate = local_code[c] - 'A' + 10; + ccir_message[c] = (translate < 16) ? translate : 0; // Sanitize + } + + // Copy for baseband + memcpy(shared_memory.bb_data.tones_data.message, ccir_message, 20); + + // Return as text for display + return local_code; +} + std::string gen_message_xy(size_t header_code_a, size_t header_code_b, size_t city_code, size_t family_code, bool subfamily_wc, size_t subfamily_code, bool id_wc, size_t receiver_code, size_t relay_state_A, size_t relay_state_B, size_t relay_state_C, size_t relay_state_D) { - size_t c; uint8_t ccir_message[20]; + size_t c; // Xy CCIR frame diff --git a/firmware/application/bht.hpp b/firmware/application/bht.hpp index e0d2be77..192ddb6e 100644 --- a/firmware/application/bht.hpp +++ b/firmware/application/bht.hpp @@ -42,6 +42,7 @@ struct bht_city { //const rf::Frequency bht_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; std::string gen_message_ep(uint8_t city_code, size_t family_code_ep, uint32_t relay_state_A, uint32_t relay_state_B); +std::string gen_message_xy(const std::string& code); std::string gen_message_xy(size_t header_code_a, size_t header_code_b, size_t city_code, size_t family_code, bool subfamily_wc, size_t subfamily_code, bool id_wc, size_t receiver_code, size_t relay_state_A, size_t relay_state_B, size_t relay_state_C, size_t relay_state_D); diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 5e4d5592..6c2fd90d 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -23,7 +23,7 @@ // Color bitmaps generated with: // Gimp image > indexed colors (16), then "xxd -i *.bmp" -//BUG: RDS Radiotext is not recognized in Redsea (and car radio) +//TODO: CTCSS detector //BUG: RDS doesn't stop baseband when stopping tx ? //BUG: Check AFSK transmit end, skips last bits ? diff --git a/firmware/application/transmitter_model.cpp b/firmware/application/transmitter_model.cpp index 8fd0d022..71af7be6 100644 --- a/firmware/application/transmitter_model.cpp +++ b/firmware/application/transmitter_model.cpp @@ -171,6 +171,7 @@ void TransmitterModel::update_sampling_rate() { // protocols that need quick RX/TX turn-around. // Disabling baseband while changing sampling rates seems like a good idea... + radio::set_baseband_rate(sampling_rate()); update_tuning_frequency(); } diff --git a/firmware/application/ui_bht_tx.cpp b/firmware/application/ui_bht_tx.cpp index e967090a..d878140d 100644 --- a/firmware/application/ui_bht_tx.cpp +++ b/firmware/application/ui_bht_tx.cpp @@ -42,9 +42,6 @@ BHTView::~BHTView() { } void BHTView::generate_message() { - uint8_t ccir_message[20]; - uint32_t c; - if (tx_mode == SINGLE) { text_message.set( gen_message_xy(header_code_a.value(), header_code_b.value(), city_code_xy.value(), family_code_xy.value(), @@ -52,30 +49,16 @@ void BHTView::generate_message() { relay_states[0].selected_index(), relay_states[1].selected_index(), relay_states[2].selected_index(), relay_states[3].selected_index()) ); + /*} else { + text_message.set( + gen_message_ep(city_code_ep.value(), family_code_ep.selected_index_value(), + relay_states[0].selected_index(), relay_states[1].selected_index()) + );*/ } else if (tx_mode == SEQUENCE) { - for (c = 0; c < 20; c++) { - if (sequence_matin[seq_index].code[c] <= '9') - ccir_message[c] = sequence_matin[seq_index].code[c] - '0'; - else - ccir_message[c] = sequence_matin[seq_index].code[c] - 'A' + 10; - } - - // Replace repeats with E code - for (c = 1; c < 20; c++) - if (ccir_message[c] == ccir_message[c - 1]) ccir_message[c] = 14; - - // Copy for baseband - memcpy(shared_memory.bb_data.tones_data.message, ccir_message, 20); - - text_message.set(sequence_matin[seq_index].code); - //text_message.set_dirty(); + text_message.set( + gen_message_xy(sequence_matin[seq_index].code) + ); } - - /*else { - text_message.set( - gen_message_ep(city_code_ep.value(), family_code_ep.selected_index_value(), - relay_states[0].selected_index(), relay_states[1].selected_index()) - );*/ } void BHTView::start_tx() { @@ -83,24 +66,25 @@ void BHTView::start_tx() { generate_message(); + if (tx_mode == SINGLE) + progressbar.set_max(20); + else if (tx_mode == SEQUENCE) + progressbar.set_max(20 * XY_SEQ_COUNT); + transmitter_model.set_sampling_rate(1536000); 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(); // Setup tones for Xy - for (c = 0; c < 16; c++) { - shared_memory.bb_data.tones_data.tone_defs[c].delta = ccir_deltas[c]; - shared_memory.bb_data.tones_data.tone_defs[c].duration = XY_TONE_LENGTH; - } + for (c = 0; c < 16; c++) + baseband::set_tone(c, ccir_deltas[c], XY_TONE_LENGTH); - baseband::set_tones_data(transmitter_model.bandwidth(), XY_SILENCE, 20, false, false); + baseband::set_tones_config(transmitter_model.bandwidth(), XY_SILENCE, 20, false, false); } void BHTView::on_tx_progress(const int progress, const bool done) { - uint32_t c; + uint8_t c; uint8_t rs; if (tx_mode == SINGLE) { @@ -118,7 +102,6 @@ void BHTView::on_tx_progress(const int progress, const bool done) { rs = relay_states[0].selected_index(); if (rs > 0) relay_states[0].set_selected_index(rs ^ 3); - generate_message(); start_tx(); } } else { @@ -127,22 +110,21 @@ void BHTView::on_tx_progress(const int progress, const bool done) { } else if (tx_mode == SEQUENCE) { if (done) { transmitter_model.disable(); - progressbar.set_value(0); - if (seq_index < 13) { + if (seq_index < (XY_SEQ_COUNT - 1)) { for (c = 0; c < sequence_matin[seq_index].delay; c++) chThdSleepMilliseconds(1000); seq_index++; - generate_message(); start_tx(); } else { + progressbar.set_value(0); tx_mode = IDLE; tx_view.set_transmitting(false); } } else { - progressbar.set_value(progress); + progressbar.set_value((seq_index * 20) + progress); } } } @@ -168,7 +150,7 @@ BHTView::BHTView(NavigationView& nav) { &text_message, &checkbox_cligno, &tempo_cligno, - &button_seq, // Sequence + &button_seq, &tx_view }); @@ -182,7 +164,6 @@ BHTView::BHTView(NavigationView& nav) { subfamily_code.set_value(1); receiver_code.set_value(1); tempo_cligno.set_value(0); - progressbar.set_max(20); /* options_mode.on_change = [this](size_t mode, OptionsField::value_t) { _mode = mode; @@ -303,6 +284,7 @@ BHTView::BHTView(NavigationView& nav) { }; tx_view.on_stop = [this]() { + transmitter_model.disable(); tx_view.set_transmitting(false); tx_mode = IDLE; }; diff --git a/firmware/application/ui_bht_tx.hpp b/firmware/application/ui_bht_tx.hpp index ed72eb9c..b35e2a26 100644 --- a/firmware/application/ui_bht_tx.hpp +++ b/firmware/application/ui_bht_tx.hpp @@ -36,13 +36,15 @@ #include "encoders.hpp" #include "portapack.hpp" +#define XY_SEQ_COUNT 14 + namespace ui { class BHTView : public View { public: BHTView(NavigationView& nav); ~BHTView(); - + void focus() override; std::string title() const override { return "BHT transmit"; }; @@ -54,23 +56,8 @@ private: const std::string code; const uint32_t delay; }; - /* -2017-03-03 07:11:04 0000189000B1002B0000 18:9:0:00 R1=OFF (1) -2017-03-03 07:11:23 0000189200B2110B0000 18:9:2:00 R1=ON (4) -2017-03-03 07:11:39 0000189200B1110B0000 18:9:2:00 R1=OFF (4) -2017-03-03 07:12:31 0001189200B2110B0000 18:9:2:00 R1=ON (4) -2017-03-03 07:12:48 0001189200B1110B0000 18:9:2:00 R1=OFF (4) -2017-03-03 07:13:04 0000189000B0012B0000 18:9:0:00 R3=OFF (2) -2017-03-03 07:13:26 0001189200B1120B0000 18:9:2:00 R3=ON (6) -2017-03-03 07:13:43 0001189200B1110B0000 18:9:2:00 R3=OFF (6) -2017-03-03 07:14:00 0001181AAAB1000B0000 18:1:A:AA R1=OFF (10) -2017-03-03 07:14:17 0001189400B1000B0000 18:9:4:00 R1=OFF (7) -2017-03-03 07:14:31 0001189200B1120B0000 18:9:2:00 R3=ON (6) -2017-03-03 07:14:48 0001189200B1110B0000 18:9:2:00 R3=OFF (6) -2017-03-03 07:15:05 0001181AAAB1000B0000 18:1:A:AA -2017-03-03 07:15:22 0001189400B0100B0000 18:9:4:00 R2=OFF (8) -*/ - const sequence_t sequence_matin[14] = { + + const sequence_t sequence_matin[XY_SEQ_COUNT] = { { "0000189000B1002B0000", 19 }, // 18:9:0:00 R1=OFF (1) { "0000189200B2110B0000", 16 }, // 18:9:2:00 R1=ON (4) { "0000189200B1110B0000", 52 }, // 18:9:2:00 R1=OFF (4) @@ -94,10 +81,10 @@ private: }; tx_modes tx_mode = IDLE; - - void start_tx(); + void generate_message(); void on_tx_progress(const int progress, const bool done); + void start_tx(); const Style style_val { .font = font::fixed_8x16, @@ -217,10 +204,10 @@ private: }; ProgressBar progressbar { - { 5 * 8, 12 * 16, 20 * 8, 16 }, + { 3 * 8, 12 * 16, 20 * 8, 16 }, }; Text text_message { - { 5 * 8, 13 * 16, 20 * 8, 16 }, + { 3 * 8, 13 * 16, 20 * 8, 16 }, "" }; @@ -238,8 +225,8 @@ private: }; Button button_seq { - { 210, 13 * 16, 32, 32 }, - "SQ" + { 24 * 8, 13 * 16, 40, 32 }, + "Seq" }; TransmitterView tx_view { diff --git a/firmware/application/ui_coasterp.cpp b/firmware/application/ui_coasterp.cpp index c964660e..26faf602 100644 --- a/firmware/application/ui_coasterp.cpp +++ b/firmware/application/ui_coasterp.cpp @@ -58,7 +58,7 @@ void CoasterPagerView::generate_frame() { // Data for (c = 0; c < 8; c++) - frame[c + 11] = (sym_data.get_sym(c << 1) << 4) | sym_data.get_sym((c << 1) + 1); + frame[c + 11] = (sym_data.get_sym(c * 2) << 4) | sym_data.get_sym(c * 2 + 1); // Copy for baseband memcpy(shared_memory.bb_data.data, frame, 19); @@ -77,12 +77,30 @@ void CoasterPagerView::start_tx() { void CoasterPagerView::on_tx_progress(const int progress, const bool done) { (void)progress; + uint16_t address = 0; + uint32_t c; - if (tx_mode == SINGLE) { - if (done) { + if (done) { + if (tx_mode == SINGLE) { transmitter_model.disable(); tx_mode = IDLE; tx_view.set_transmitting(false); + } else if (tx_mode == SCAN) { + // Increment address + + for (c = 0; c < 4; c++) { + address <<= 4; + address |= sym_data.get_sym(12 + c); + } + + address++; + + for (c = 0; c < 4; c++) { + sym_data.set_sym(15 - c, address & 0x0F); + address >>= 4; + } + + start_tx(); } } } @@ -101,12 +119,10 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) { &tx_view }); + // Bytes to nibbles for (c = 0; c < 16; c++) sym_data.set_sym(c, (data_init[c >> 1] >> ((c & 1) ? 0 : 4)) & 0x0F); - /*checkbox_scan.on_select = [this](Checkbox&, bool v) { - };*/ - checkbox_scan.set_value(false); generate_frame(); @@ -120,7 +136,10 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) { tx_view.on_start = [this]() { if (tx_mode == IDLE) { - tx_mode = SINGLE; + if (checkbox_scan.value()) + tx_mode = SCAN; + else + tx_mode = SINGLE; tx_view.set_transmitting(true); start_tx(); } diff --git a/firmware/application/ui_coasterp.hpp b/firmware/application/ui_coasterp.hpp index 10db00ac..432cec78 100644 --- a/firmware/application/ui_coasterp.hpp +++ b/firmware/application/ui_coasterp.hpp @@ -44,7 +44,8 @@ public: private: enum tx_modes { IDLE = 0, - SINGLE + SINGLE, + SCAN }; tx_modes tx_mode = IDLE; @@ -54,17 +55,18 @@ private: void on_tx_progress(const int progress, const bool done); Labels labels { - { { 1 * 8, 3 * 8 }, "Data:", Color::light_grey() } + { { 1 * 8, 3 * 8 }, "Syscall pager TX beta", Color::light_grey() }, + { { 1 * 8, 8 * 8 }, "Data:", Color::light_grey() } }; SymField sym_data { - { 6 * 8, 3 * 8 }, + { 7 * 8, 8 * 8 }, 16, // 14 ? 12 ? SymField::SYMFIELD_HEX }; Checkbox checkbox_scan { - { 10 * 8, 8 * 8 }, + { 10 * 8, 14 * 8 }, 4, "Scan" }; diff --git a/firmware/application/ui_morse.cpp b/firmware/application/ui_morse.cpp index bd1f8a35..1ca6e852 100644 --- a/firmware/application/ui_morse.cpp +++ b/firmware/application/ui_morse.cpp @@ -108,7 +108,7 @@ bool MorseView::start_tx() { if (modulation == CW) { ookthread = chThdCreateStatic(ookthread_wa, sizeof(ookthread_wa), NORMALPRIO + 10, ookthread_fn, this); } else if (modulation == FM) { - baseband::set_tones_data(transmitter_model.bandwidth(), 0, symbol_count, false, false); + baseband::set_tones_config(transmitter_model.bandwidth(), 0, symbol_count, false, false); } return true; @@ -208,7 +208,7 @@ MorseView::MorseView( tx_view.on_stop = [this]() { if (ookthread) chThdTerminate(ookthread); transmitter_model.disable(); - baseband::set_tones_data(0, 0, 0, false, false); + baseband::set_tones_config(0, 0, 0, false, false); tx_view.set_transmitting(false); }; } diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index afb90419..84b344e0 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -306,11 +306,11 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { TransmitterCodedMenuView::TransmitterCodedMenuView(NavigationView& nav) { add_items<9>({ { - { "ADS-B Mode S", ui::Color::orange(),&bitmap_icon_adsb, [&nav](){ nav.push(); } }, - { "BHT Xy/EP", ui::Color::yellow(),&bitmap_icon_bht, [&nav](){ nav.push(); } }, + { "ADS-B Mode S", ui::Color::orange(), &bitmap_icon_adsb, [&nav](){ nav.push(); } }, + { "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push(); } }, { "Morse code", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push(); } }, { "Nuoptix DTMF timecode", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push(); } }, - { "NTTWorks burger pager", ui::Color::orange(), &bitmap_icon_burger, [&nav](){ nav.push(); } }, + { "NTTWorks burger pager", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push(); } }, { "OOK remote encoders", ui::Color::green(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, { "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push(); } }, diff --git a/firmware/application/ui_numbers.cpp b/firmware/application/ui_numbers.cpp index 382e9498..54fdd15c 100644 --- a/firmware/application/ui_numbers.cpp +++ b/firmware/application/ui_numbers.cpp @@ -122,8 +122,6 @@ void NumbersStationView::start_tx() { transmitter_model.set_sampling_rate(1536000U); 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(); diff --git a/firmware/application/ui_nuoptix.cpp b/firmware/application/ui_nuoptix.cpp index 7b952c47..8efe4dba 100644 --- a/firmware/application/ui_nuoptix.cpp +++ b/firmware/application/ui_nuoptix.cpp @@ -125,15 +125,13 @@ void NuoptixView::transmit(bool setup) { } for (c = 0; c < 16; c++) { - shared_memory.bb_data.tones_data.tone_defs[c * 2].delta = dtmf_deltas[c][0]; - shared_memory.bb_data.tones_data.tone_defs[c * 2].duration = NUOPTIX_TONE_LENGTH; - shared_memory.bb_data.tones_data.tone_defs[c * 2 + 1].delta = dtmf_deltas[c][1]; - shared_memory.bb_data.tones_data.tone_defs[c * 2 + 1].duration = NUOPTIX_TONE_LENGTH; + baseband::set_tone(c * 2, dtmf_deltas[c][0], NUOPTIX_TONE_LENGTH); + baseband::set_tone(c * 2 + 1, dtmf_deltas[c][1], NUOPTIX_TONE_LENGTH); } shared_memory.bb_data.tones_data.silence = NUOPTIX_TONE_LENGTH; // 49ms tone, 49ms space audio::set_rate(audio::Rate::Hz_24000); - baseband::set_tones_data(transmitter_model.bandwidth(), 0, 6 * 2, true, true); + baseband::set_tones_config(transmitter_model.bandwidth(), 0, 6 * 2, true, true); timecode++; } diff --git a/firmware/common/bch_code.cpp b/firmware/common/bch_code.cpp index cf1f895d..16422f35 100644 --- a/firmware/common/bch_code.cpp +++ b/firmware/common/bch_code.cpp @@ -346,7 +346,7 @@ BCHCode::BCHCode( valid = true; if (valid) { - for (i = 0; i < (m + 1); i++) { + for (i = 0; i < (size_t)(m + 1); i++) { p[i] = p_init[i]; } diff --git a/firmware/common/morse.cpp b/firmware/common/morse.cpp index d2ad6f93..6b7c14af 100644 --- a/firmware/common/morse.cpp +++ b/firmware/common/morse.cpp @@ -37,11 +37,10 @@ size_t morse_encode(std::string& message, const uint32_t time_unit_ms, size_t i, c; uint16_t code, code_size; uint8_t morse_message[256]; + uint32_t delta; *time_units = 0; - ToneDef * tone_defs = shared_memory.bb_data.tones_data.tone_defs; - i = 0; for (char& ch : message) { if (i > 256) return 0; // Message too long @@ -79,11 +78,11 @@ size_t morse_encode(std::string& message, const uint32_t time_unit_ms, // Setup tone "symbols" for (c = 0; c < 5; c++) { if (c < 2) - tone_defs[c].delta = TONES_F2D(tone); // Dot and dash + delta = TONES_F2D(tone); // Dot and dash else - tone_defs[c].delta = 0; // Pause + delta = 0; // Pause - tone_defs[c].duration = (TONES_SAMPLERATE * morse_symbols[c] * time_unit_ms) / 1000; + baseband::set_tone(c, delta, (TONES_SAMPLERATE * morse_symbols[c] * time_unit_ms) / 1000); } return i; diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index d3be8fec..6e114170 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ