diff --git a/firmware/Makefile b/firmware/Makefile index 337a656d8..b7d9459be 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -59,11 +59,11 @@ program: $(TARGET).bin modules sleep 1s hackrf_spiflash -w $(TARGET).bin -modules: +modules: $(TARGET_BASEBAND).bin $(TARGET_BASEBAND_TX).bin $(MAKE_MODULES_FILE) $(MODULES) $(TARGET).bin: modules $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND).bin $(TARGET_BASEBAND_TX).bin $(TARGET_APPLICATION).bin - $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND).bin $(TARGET_APPLICATION).bin $(TARGET).bin + $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND_TX).bin $(TARGET_APPLICATION).bin $(TARGET).bin $(TARGET_BOOTSTRAP).bin: $(TARGET_BOOTSTRAP).elf $(CP) -O binary $(TARGET_BOOTSTRAP).elf $(TARGET_BOOTSTRAP).bin diff --git a/firmware/application/m4_startup.cpp b/firmware/application/m4_startup.cpp index 5924a1fbf..59fc511a1 100644 --- a/firmware/application/m4_startup.cpp +++ b/firmware/application/m4_startup.cpp @@ -94,7 +94,7 @@ void m4_switch(const char * hash) { // Ask M4 to enter loop in RAM BasebandConfiguration baseband_switch { - .mode = 0xFF, + .mode = SWITCH, .sampling_rate = 0, .decimation_factor = 1, }; diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 94d0a7d63..ab6d387f6 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -19,6 +19,8 @@ * Boston, MA 02110-1301, USA. */ +//TODO: Enum modulation modes (baseband) +//TODO: More gfx, cute icons :) //TODO: check jammer bandwidths //TODO: GSM channel detector //TODO: wait_for_switch() in baseband-tx ! @@ -27,7 +29,7 @@ //TODO: Reset baseband if module not found (instead of lockup in RAM loop) //TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule //TODO: LCD backlight PWM -//TODO: BUG: Crash after TX stop +//TODO: BUG: Crash after TX stop (unregister message !) //TODO: Check bw setting in LCR TX //TODO: BUG: Crash after PSN entry in RDS TX //TODO: Dynamically load baseband code depending on mode (disable M4 & interrupts, load, reset) diff --git a/firmware/application/modules.h b/firmware/application/modules.h deleted file mode 100644 index 86c07db71..000000000 --- a/firmware/application/modules.h +++ /dev/null @@ -1,2 +0,0 @@ -const char md5_baseband[16] = {0xce,0x87,0x2b,0x2c,0x9e,0x74,0xe8,0x1c,0x1c,0xe9,0xfc,0xc2,0x40,0xc3,0x32,0xd5,}; -const char md5_baseband_tx[16] = {0x1b,0xef,0x34,0x50,0x45,0xd7,0xae,0x7c,0xb5,0x4f,0x0c,0x5a,0x80,0xa0,0xbc,0x05,}; diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 23087077a..406d41087 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -130,7 +130,7 @@ void ReceiverModel::disable() { /* TODO: This is a dumb hack to stop baseband from working so hard. */ BasebandConfigurationMessage message { .configuration = { - .mode = -1, + .mode = NONE, .sampling_rate = 0, .decimation_factor = 1, } diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index 71b4c7db1..296d60d86 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -81,7 +81,7 @@ private: uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum }; int32_t vga_gain_db_ { 32 }; BasebandConfiguration baseband_configuration { - .mode = 1, /* TODO: Enum! */ + .mode = NONE, .sampling_rate = 3072000, .decimation_factor = 4, }; diff --git a/firmware/application/transmitter_model.cpp b/firmware/application/transmitter_model.cpp index 9cf18cb03..6ca9c390d 100644 --- a/firmware/application/transmitter_model.cpp +++ b/firmware/application/transmitter_model.cpp @@ -80,11 +80,11 @@ void TransmitterModel::set_sampling_rate(uint32_t hz) { update_baseband_configuration(); } -uint32_t TransmitterModel::modulation() const { +mode_type TransmitterModel::modulation() const { return baseband_configuration.mode; } -void TransmitterModel::set_modulation(int32_t v) { +void TransmitterModel::set_modulation(mode_type v) { baseband_configuration.mode = v; update_modulation(); } @@ -114,7 +114,7 @@ void TransmitterModel::disable() { /* TODO: This is a dumb hack to stop baseband from working so hard. */ BasebandConfigurationMessage message { .configuration = { - .mode = -1, + .mode = NONE, .sampling_rate = 0, .decimation_factor = 1, } @@ -152,6 +152,11 @@ void TransmitterModel::update_modulation() { update_baseband_configuration(); } +void TransmitterModel::set_baseband_configuration(const BasebandConfiguration config) { + baseband_configuration = config; + update_baseband_configuration(); +} + void TransmitterModel::update_baseband_configuration() { radio::streaming_disable(); @@ -164,3 +169,4 @@ void TransmitterModel::update_baseband_configuration() { radio::streaming_enable(); } + diff --git a/firmware/application/transmitter_model.hpp b/firmware/application/transmitter_model.hpp index 8cab94f01..d8506935c 100644 --- a/firmware/application/transmitter_model.hpp +++ b/firmware/application/transmitter_model.hpp @@ -57,14 +57,16 @@ public: uint32_t sampling_rate() const; void set_sampling_rate(uint32_t hz); - uint32_t modulation() const; - void set_modulation(int32_t v); + mode_type modulation() const; + void set_modulation(mode_type v); uint32_t baseband_oversampling() const; void set_baseband_oversampling(uint32_t v); void enable(); void disable(); + + void set_baseband_configuration(const BasebandConfiguration config); private: bool rf_amp_ { true }; @@ -72,7 +74,7 @@ private: uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum }; int32_t vga_gain_db_ { 8 }; BasebandConfiguration baseband_configuration { - .mode = 16, + .mode = NONE, .sampling_rate = 2280000, .decimation_factor = 1, }; diff --git a/firmware/application/ui_afskrx.cpp b/firmware/application/ui_afskrx.cpp index 31ac59123..fa6b6eba9 100644 --- a/firmware/application/ui_afskrx.cpp +++ b/firmware/application/ui_afskrx.cpp @@ -48,7 +48,7 @@ AFSKRXView::AFSKRXView( }; receiver_model.set_baseband_configuration({ - .mode = 6, + .mode = RX_AFSK, .sampling_rate = 3072000, .decimation_factor = 4, }); diff --git a/firmware/application/ui_afsksetup.cpp b/firmware/application/ui_afsksetup.cpp index 19f22de40..2176fb962 100644 --- a/firmware/application/ui_afsksetup.cpp +++ b/firmware/application/ui_afsksetup.cpp @@ -46,7 +46,7 @@ void AFSKSetupView::focus() { } void AFSKSetupView::paint(Painter& painter) { - + (void)painter; } void AFSKSetupView::updfreq(rf::Frequency f) { diff --git a/firmware/application/ui_jammer.cpp b/firmware/application/ui_jammer.cpp index b95b5a225..d7782b9fb 100644 --- a/firmware/application/ui_jammer.cpp +++ b/firmware/application/ui_jammer.cpp @@ -50,7 +50,7 @@ JammerView::~JammerView() { } void JammerView::paint(Painter& painter) { - + (void)painter; } void JammerView::updfreq(uint8_t id, rf::Frequency f) { @@ -169,7 +169,7 @@ JammerView::JammerView( .foreground = Color::grey(), }; - transmitter_model.set_modulation(18); + transmitter_model.set_modulation(TX_JAMMER); add_children({ { &text_type, diff --git a/firmware/application/ui_lcr.cpp b/firmware/application/ui_lcr.cpp index 72dda734d..d2d9e64b4 100644 --- a/firmware/application/ui_lcr.cpp +++ b/firmware/application/ui_lcr.cpp @@ -187,7 +187,7 @@ LCRView::LCRView( .foreground = Color::black(), }; - transmitter_model.set_modulation(16); + transmitter_model.set_modulation(TX_LCR); transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); memset(litteral, 0, 5*8); memset(rgsb, 0, 5); @@ -275,9 +275,7 @@ LCRView::LCRView( nav.push(new DebugLCRView { nav, lcrstring, checksum }); }; - button_transmit.on_select = [this,&transmitter_model](Button&){ - uint16_t c; - + button_transmit.on_select = [this,&transmitter_model](Button&){ auto& message_map = context().message_map(); make_frame(); diff --git a/firmware/application/ui_loadmodule.cpp b/firmware/application/ui_loadmodule.cpp index a49ab4636..d5dafdab1 100644 --- a/firmware/application/ui_loadmodule.cpp +++ b/firmware/application/ui_loadmodule.cpp @@ -41,7 +41,7 @@ void LoadModuleView::focus() { } void LoadModuleView::paint(Painter& painter) { - + (void)painter; } void LoadModuleView::on_hide() { @@ -53,7 +53,8 @@ void LoadModuleView::on_show() { auto& message_map = context().message_map(); message_map.register_handler(Message::ID::ReadyForSwitch, [this](Message* const p) { - const auto message = static_cast(p); + (void)p; + // const auto message = static_cast(p); if (m4_load_image()) { text_info.set("Module loaded :)"); _mod_loaded = true; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 74ef82b21..49a9a92f7 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -195,6 +195,7 @@ BMPView::BMPView(NavigationView& nav) { } void BMPView::paint(Painter& painter) { + (void)painter; portapack::display.drawBMP({(240-185)/2, 0}, splash_bmp); } diff --git a/firmware/application/ui_receiver.cpp b/firmware/application/ui_receiver.cpp index 41ba32516..046c43b11 100644 --- a/firmware/application/ui_receiver.cpp +++ b/firmware/application/ui_receiver.cpp @@ -456,7 +456,7 @@ ReceiverView::ReceiverView( options_modulation.set_by_value(receiver_model.modulation()); options_modulation.on_change = [this](size_t n, OptionsField::value_t v) { (void)n; - this->on_modulation_changed(v); + this->on_modulation_changed((mode_type)v); }; /* options_baseband_oversampling.set_by_value(receiver_model.baseband_oversampling()); @@ -625,7 +625,7 @@ void ReceiverView::on_vga_changed(int32_t v_db) { receiver_model.set_vga(v_db); } -void ReceiverView::on_modulation_changed(int32_t modulation) { +void ReceiverView::on_modulation_changed(mode_type modulation) { /* TODO: This is TERRIBLE!!! */ switch(modulation) { case 3: diff --git a/firmware/application/ui_receiver.hpp b/firmware/application/ui_receiver.hpp index 50353b9d6..c5109e896 100644 --- a/firmware/application/ui_receiver.hpp +++ b/firmware/application/ui_receiver.hpp @@ -411,13 +411,12 @@ private: { 19 * 8, 1 * 16 }, 4, { - // TODO: Put ordinals in here... - { " AM ", 0 }, - { "NFM ", 1 }, - { "WFM ", 2 }, - { "AIS ", 3 }, - { "TPMS", 5 }, - { "SPEC", 4 }, + { " AM ", RX_NBAM_AUDIO }, + { "NFM ", RX_NBFM_AUDIO }, + { "WFM ", RX_WBFM_AUDIO }, + { "AIS ", RX_AIS }, + { "TPMS", RX_TPMS }, + { "SPEC", RX_WBSPECTRUM }, } }; /* @@ -464,7 +463,7 @@ private: void on_rf_amp_changed(bool v); void on_lna_changed(int32_t v_db); void on_vga_changed(int32_t v_db); - void on_modulation_changed(int32_t modulation); + void on_modulation_changed(mode_type modulation); void on_show_options_frequency(); void on_show_options_rf_gain(); void on_frequency_step_changed(rf::Frequency f); diff --git a/firmware/application/ui_sigfrx.cpp b/firmware/application/ui_sigfrx.cpp new file mode 100644 index 000000000..514e3963f --- /dev/null +++ b/firmware/application/ui_sigfrx.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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_sigfrx.hpp" +#include "ui_receiver.hpp" + +#include "ch.h" +#include "evtimer.h" + +#include "ff.h" +#include "hackrf_gpio.hpp" +#include "portapack.hpp" +#include "radio.hpp" +//#include "fox_bmp.hpp" + +#include "hackrf_hal.hpp" +#include "portapack_shared_memory.hpp" +#include "portapack_persistent_memory.hpp" + +#include +#include + +using namespace hackrf::one; + +namespace ui { + +void SIGFRXView::focus() { + button_exit.focus(); +} + +SIGFRXView::~SIGFRXView() { + receiver_model.disable(); +} + +void SIGFRXView::paint(Painter& painter) { + uint8_t i, xp; + + //portapack::display.drawBMP({0, 302-160}, fox_bmp); + portapack::display.fill_rectangle({0,16,240,160-16}, ui::Color::white()); + for (i = 0; i < 6; i++) { + xp = sigfrx_marks[i*3]; + painter.draw_string({ (ui::Coord)sigfrx_marks[(i*3)+1], 144-20 }, style_white, to_string_dec_uint(sigfrx_marks[(i*3)+2]) ); + portapack::display.draw_line({xp, 144-4}, {xp, 144}, ui::Color::black()); + } +} + +void SIGFRXView::on_channel_spectrum(const ChannelSpectrum& spectrum) { + portapack::display.fill_rectangle({0, 144, 240, 4},ui::Color::white()); + + uint8_t xmax = 0, imax = 0; + size_t i; + + for (i=0; i<120; i++) { + if (spectrum.db[i] > xmax) { + xmax = spectrum.db[i]; + imax = i; + } + } + for (i=136; i<256; i++) { + if (spectrum.db[i-16] > xmax) { + xmax = spectrum.db[i-16]; + imax = i-16; + } + } + + if ((imax >= last_channel-2) && (imax <= last_channel+2)) { + if (detect_counter >= 5) { + // Latched ! + } else { + detect_counter++; + } + } else { + if (detect_counter >= 5) text_channel.set("... "); + detect_counter = 0; + } + + last_channel = imax; + + portapack::display.fill_rectangle({(ui::Coord)(imax-2), 144, 4, 4}, ui::Color::red()); +} + +void SIGFRXView::on_show() { + context().message_map().register_handler(Message::ID::ChannelSpectrum, + [this](const Message* const p) { + this->on_channel_spectrum(reinterpret_cast(p)->spectrum); + } + ); +} + +SIGFRXView::SIGFRXView( + NavigationView& nav, + ReceiverModel& receiver_model +) : receiver_model(receiver_model) +{ + receiver_model.set_baseband_configuration({ + .mode = RX_SIGFOX, + .sampling_rate = 3072000, + .decimation_factor = 4, + }); + receiver_model.set_baseband_bandwidth(1750000); + + receiver_model.set_tuning_frequency(868110000); + + receiver_model.set_lna(0); + receiver_model.set_vga(0); + + add_children({ { + &text_type, + &text_channel, + &text_data, + &button_exit + } }); + + text_type.set_style(&style_white); + text_channel.set_style(&style_white); + text_data.set_style(&style_white); + + button_exit.on_select = [&nav](Button&){ + nav.pop(); + }; + + receiver_model.enable(); + +} + +} /* namespace ui */ diff --git a/firmware/application/ui_sigfrx.hpp b/firmware/application/ui_sigfrx.hpp new file mode 100644 index 000000000..aebe474ce --- /dev/null +++ b/firmware/application/ui_sigfrx.hpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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 "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" +#include "receiver_model.hpp" + +namespace ui { + +class SIGFRXView : public View { +public: + SIGFRXView(NavigationView& nav, ReceiverModel& receiver_model); + ~SIGFRXView(); + void on_channel_spectrum(const ChannelSpectrum& spectrum); + + void on_show() override; + void focus() override; + void paint(Painter& painter) override; + +private: + ReceiverModel& receiver_model; + + uint8_t last_channel; + uint8_t detect_counter = 0; + + const Style style_white { + .font = font::fixed_8x16, + .background = Color::white(), + .foreground = Color::black() + }; + + const uint16_t sigfrx_marks[18] = { + 10, 8, 0, + 60, 52, 90, + 119, 95, 180, + 121, 122, 220, + 179, 171, 310, + 230, 214, 400 }; + + Text text_type { + { 1 * 8, 1 * 16, 28 * 8, 16 }, + "SIGFOX interceptor. Yap !" + }; + + Text text_channel { + { 1 * 8, 3 * 16, 28 * 8, 16 }, + "PL: " + }; + Text text_data { + { 1 * 8, 4 * 16, 28 * 8, 16 }, + "??: " + }; + + Button button_exit { + { 22 * 8, 160 - 32, 56, 32 }, + "Exit" + }; +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_whistle.cpp b/firmware/application/ui_whistle.cpp index b9c6d7658..74f31096f 100644 --- a/firmware/application/ui_whistle.cpp +++ b/firmware/application/ui_whistle.cpp @@ -50,7 +50,7 @@ WhistleView::~WhistleView() { } void WhistleView::paint(Painter& painter) { - + (void)painter; } void WhistleView::whistle_th(void *arg) { @@ -72,7 +72,7 @@ WhistleView::WhistleView( msg_t mbox_buffer[3]; chMBInit(&mbox, mbox_buffer, 3); - transmitter_model.set_modulation(17); + transmitter_model.set_modulation(TX_TONE); transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); add_children({ { diff --git a/firmware/application/ui_xylos.cpp b/firmware/application/ui_xylos.cpp index acf0f9426..1083b615d 100644 --- a/firmware/application/ui_xylos.cpp +++ b/firmware/application/ui_xylos.cpp @@ -49,7 +49,7 @@ XylosView::~XylosView() { } void XylosView::paint(Painter& painter) { - + (void)painter; } void XylosView::upd_message() { @@ -96,7 +96,37 @@ void XylosView::upd_message() { ccirmessage[20] = 0; + // Display as text text_debug.set(ccirmessage); + + // ASCII to baseband frequency LUT index + for (c=0; c<20; c++) { + if (ccirmessage[c] > '9') + ccirmessage[c] -= 0x37; + else + ccirmessage[c] -= 0x30; + } +} + +void XylosView::journuit() { + uint8_t sr; + + chThdSleepMilliseconds(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); + + upd_message(); + + portapack::audio_codec.set_headphone_volume(volume_t::decibel(90 - 99) + wolfson::wm8731::headphone_gain_range.max); + shared_memory.xylos_transmit_done = false; + memcpy(shared_memory.xylosdata, ccirmessage, 21); + transmitter_model.enable(); } XylosView::XylosView( @@ -116,7 +146,13 @@ XylosView::XylosView( .foreground = Color::black(), }; - transmitter_model.set_modulation(19); + transmitter_model.set_baseband_configuration({ + .mode = TX_XYLOS, + .sampling_rate = 1536000, + .decimation_factor = 1, + }); + + transmitter_model.set_modulation(TX_XYLOS); // Useless ? add_children({ { &text_title, @@ -141,6 +177,7 @@ XylosView::XylosView( &text_progress, &text_debug, &button_transmit, + &checkbox_cligno, &button_exit } }); @@ -170,9 +207,17 @@ XylosView::XylosView( XylosView::upd_message(); }; checkbox_wcsubfamily.on_select = [this](Checkbox&) { + if (checkbox_wcsubfamily.value() == true) + subfamily_code.hidden(true); + else + subfamily_code.hidden(false); XylosView::upd_message(); }; checkbox_wcid.on_select = [this](Checkbox&) { + if (checkbox_wcid.value() == true) + receiver_code.hidden(true); + else + receiver_code.hidden(false); XylosView::upd_message(); }; options_ra.on_change = [this](size_t n, OptionsField::value_t v) { @@ -207,14 +252,19 @@ XylosView::XylosView( char progress[21]; const auto message = static_cast(p); if (message->n == 25) { + portapack::audio_codec.set_headphone_volume(volume_t::decibel(0 - 99) + wolfson::wm8731::headphone_gain_range.max); transmitter_model.disable(); for (c=0;c<20;c++) progress[c] = ' '; progress[20] = 0; text_progress.set(progress); - txing = false; - button_transmit.set_style(&style_val); - button_transmit.set_text("START"); + if (checkbox_cligno.value() == false) { + txing = false; + button_transmit.set_style(&style_val); + button_transmit.set_text("START"); + } else { + journuit(); + } } else { for (c=0;cn;c++) progress[c] = ' '; @@ -227,9 +277,11 @@ XylosView::XylosView( shared_memory.xylos_transmit_done = false; memcpy(shared_memory.xylosdata, ccirmessage, 21); + + transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); - transmitter_model.set_tuning_frequency(87700000); //xylos_freqs[options_freq.selected_index()]); - + portapack::audio_codec.set_headphone_volume(volume_t::decibel(90 - 99) + wolfson::wm8731::headphone_gain_range.max); + txing = true; button_transmit.set_style(&style_cancel); button_transmit.set_text("Wait"); diff --git a/firmware/application/ui_xylos.hpp b/firmware/application/ui_xylos.hpp index cf3b2640a..93b560c4d 100644 --- a/firmware/application/ui_xylos.hpp +++ b/firmware/application/ui_xylos.hpp @@ -38,6 +38,7 @@ class XylosView : public View { public: XylosView(NavigationView& nav, TransmitterModel& transmitter_model); ~XylosView(); + void journuit(); void upd_message(); void focus() override; @@ -45,7 +46,7 @@ public: private: bool txing = false; - const rf::Frequency xylos_freqs[6] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000 }; + const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 87000000 }; char ccirmessage[21]; TransmitterModel& transmitter_model; @@ -117,14 +118,15 @@ private: }; OptionsField options_freq { { 16 * 8, 9 * 16 }, - 6, + 7, { { "31.3250", 0 }, { "31.3875", 1 }, { "31.4375", 2 }, { "31.4750", 3 }, { "31.6875", 4 }, - { "31.9750", 5 } + { "31.9750", 5 }, + { "TEST 87", 6 } } }; @@ -182,6 +184,11 @@ private: "START" }; + Checkbox checkbox_cligno { + { 96, 16 * 16 + 4}, + "J/N" + }; + Button button_exit { { 21 * 8, 16 * 16, 64, 32 }, "Exit" diff --git a/firmware/baseband-tx.bin b/firmware/baseband-tx.bin index 96a451930..cd98095ec 100644 Binary files a/firmware/baseband-tx.bin and b/firmware/baseband-tx.bin differ diff --git a/firmware/baseband-tx/audio_dma.cpp b/firmware/baseband-tx/audio_dma.cpp index 6fa6439bc..57ff5bc40 100644 --- a/firmware/baseband-tx/audio_dma.cpp +++ b/firmware/baseband-tx/audio_dma.cpp @@ -121,7 +121,7 @@ constexpr gpdma::channel::Config config_rx() { /* TODO: Clean up terminology around "buffer", "transfer", "samples" */ -constexpr size_t buffer_samples_log2n = 7; +constexpr size_t buffer_samples_log2n = 8; // Bumped to 8, to allow filling at 750Hz constexpr size_t buffer_samples = (1 << buffer_samples_log2n); constexpr size_t transfers_per_buffer_log2n = 2; constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n); diff --git a/firmware/baseband-tx/main.cpp b/firmware/baseband-tx/main.cpp index 11748f7a7..30ce1c29d 100755 --- a/firmware/baseband-tx/main.cpp +++ b/firmware/baseband-tx/main.cpp @@ -38,6 +38,8 @@ #include "touch_dma.hpp" +#include "modules.h" + #include "dsp_decimate.hpp" #include "dsp_demodulate.hpp" #include "dsp_fft.hpp" @@ -468,6 +470,23 @@ private: const auto baseband_buffer = new std::array(); + +char ram_loop[32]; +typedef int (*fn_ptr)(void); +fn_ptr loop_ptr; + +void ram_loop_fn(void) { + while(1) {} +} + +void wait_for_switch(void) { + memcpy(&ram_loop[0], reinterpret_cast(&ram_loop_fn), 32); + loop_ptr = reinterpret_cast(&ram_loop[0]); + ReadyForSwitchMessage message; + shared_memory.application_queue.push(message); + (*loop_ptr)(); + return; +} int main(void) { init(); @@ -494,30 +513,33 @@ int main(void) { delete old_p; switch(message->configuration.mode) { - case 15: + case TX_RDS: direction = baseband::Direction::Transmit; baseband_thread.baseband_processor = new RDSProcessor(); break; - case 16: + case TX_LCR: direction = baseband::Direction::Transmit; baseband_thread.baseband_processor = new LCRFSKProcessor(); break; - case 17: + case TX_TONE: direction = baseband::Direction::Transmit; baseband_thread.baseband_processor = new ToneProcessor(); break; - case 18: + case TX_JAMMER: direction = baseband::Direction::Transmit; baseband_thread.baseband_processor = new JammerProcessor(); break; - case 19: + case TX_XYLOS: direction = baseband::Direction::Transmit; baseband_thread.baseband_processor = new XylosProcessor(); break; + + case 0xFF: + wait_for_switch(); default: break; diff --git a/firmware/baseband-tx/proc_xylos.cpp b/firmware/baseband-tx/proc_xylos.cpp index 59afcffa4..b97089d30 100644 --- a/firmware/baseband-tx/proc_xylos.cpp +++ b/firmware/baseband-tx/proc_xylos.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -27,27 +28,29 @@ void XylosProcessor::execute(buffer_c8_t buffer) { + // This is called at 1536000/2048 = 750Hz + + ai = 0; + for (size_t i = 0; i= 9) { s = 0; if (sample_count >= CCIR_TONELENGTH) { if (shared_memory.xylos_transmit_done == false) { - message.n = byte_pos; // Progress + message.n = byte_pos; // Inform UI about progress (just as eye candy) shared_memory.application_queue.push(message); digit = shared_memory.xylosdata[byte_pos++]; } if (!digit) { - message.n = 25; // Done code + message.n = 25; // End of message code shared_memory.xylos_transmit_done = true; shared_memory.application_queue.push(message); digit = 0; } - - if (digit > '9') digit -= 7; - digit -= 0x30; sample_count = 0; } else { @@ -59,10 +62,18 @@ void XylosProcessor::execute(buffer_c8_t buffer) { s++; } - sample = (sine_table_f32[(aphase & 0x03FF0000)>>18]*255); + sample = (sine_table_f32[(aphase & 0x03FF0000)>>18]*255); + + // Audio preview sample generation: 1536000/48000 = 32 + if (as >= 31) { + as = 0; + preview_audio_buffer.p[ai++] = sample * 128; + } else { + as++; + } //FM - frq = sample * 160; // 20kHz wide (?) + frq = sample * 300; // ~10kHz wide phase = (phase + frq); sphase = phase + (256<<16); @@ -72,4 +83,6 @@ void XylosProcessor::execute(buffer_c8_t buffer) { buffer.p[i] = {(int8_t)re,(int8_t)im}; } + + fill_audio_buffer(preview_audio_buffer); } diff --git a/firmware/baseband-tx/proc_xylos.hpp b/firmware/baseband-tx/proc_xylos.hpp index a7a4a78d8..a9e2458dc 100644 --- a/firmware/baseband-tx/proc_xylos.hpp +++ b/firmware/baseband-tx/proc_xylos.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -24,35 +25,42 @@ #include "baseband_processor.hpp" -#define CCIR_TONELENGTH 22800 -#define PHASEV 294.34 +#define CCIR_TONELENGTH 15360-1 // 1536000/10/10 +#define PHASEV 436.91 // (65536*1024)/1536000*10 class XylosProcessor : public BasebandProcessor { public: void execute(buffer_c8_t buffer) override; private: + int16_t audio_data[64]; + + const buffer_s16_t preview_audio_buffer { + audio_data, + sizeof(int16_t)*64 + }; + uint32_t ccir_phases[16] = { - 1981*PHASEV, - 1124*PHASEV, - 1197*PHASEV, - 1275*PHASEV, - 1358*PHASEV, - 1446*PHASEV, - 1540*PHASEV, - 1640*PHASEV, - 1747*PHASEV, - 1860*PHASEV, - 2400*PHASEV, - 930*PHASEV, - 2247*PHASEV, - 991*PHASEV, - 2110*PHASEV, - 1055*PHASEV + (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) }; int8_t re, im; - uint8_t s; + uint8_t s, as = 0, ai; uint8_t byte_pos = 0; uint8_t digit = 0; uint32_t sample_count = CCIR_TONELENGTH; diff --git a/firmware/baseband.bin b/firmware/baseband.bin index d5656041c..99a0ae2d3 100644 Binary files a/firmware/baseband.bin and b/firmware/baseband.bin differ diff --git a/firmware/baseband/main.cpp b/firmware/baseband/main.cpp index 701efba0c..bdf520b56 100755 --- a/firmware/baseband/main.cpp +++ b/firmware/baseband/main.cpp @@ -41,6 +41,8 @@ #include "touch_dma.hpp" +#include "modules.h" + #include "dsp_decimate.hpp" #include "dsp_demodulate.hpp" #include "dsp_fft.hpp" @@ -57,9 +59,9 @@ #include "proc_am_audio.hpp" #include "proc_nfm_audio.hpp" #include "proc_wfm_audio.hpp" -//#include "proc_ais.hpp" +#include "proc_ais.hpp" #include "proc_wideband_spectrum.hpp" -//#include "proc_tpms.hpp" +#include "proc_tpms.hpp" #include "proc_afskrx.hpp" #include "proc_sigfrx.hpp" @@ -390,46 +392,46 @@ int main(void) { delete old_p; switch(message->configuration.mode) { - case 0: + case RX_NBAM_AUDIO: direction = baseband::Direction::Receive; baseband_thread.baseband_processor = new NarrowbandAMAudio(); break; - case 1: + case RX_NBFM_AUDIO: direction = baseband::Direction::Receive; baseband_thread.baseband_processor = new NarrowbandFMAudio(); break; - case 2: + case RX_WBFM_AUDIO: baseband_thread.baseband_processor = new WidebandFMAudio(); break; - /*case 3: + case RX_AIS: direction = baseband::Direction::Receive; baseband_thread.baseband_processor = new AISProcessor(); - break;*/ + break; - case 4: + case RX_WBSPECTRUM: direction = baseband::Direction::Receive; baseband_thread.baseband_processor = new WidebandSpectrum(); break; - /*case 5: + case RX_TPMS: direction = baseband::Direction::Receive; baseband_thread.baseband_processor = new TPMSProcessor(); - break;*/ + break; - case 6: + case RX_AFSK: direction = baseband::Direction::Receive; baseband_thread.baseband_processor = new AFSKRXProcessor(); break; - case 7: + case RX_SIGFOX: direction = baseband::Direction::Receive; baseband_thread.baseband_processor = new SIGFRXProcessor(); break; - case 0xFF: + case SWITCH: wait_for_switch(); default: diff --git a/firmware/baseband/proc_sigfrx.cpp b/firmware/baseband/proc_sigfrx.cpp new file mode 100644 index 000000000..c6ca3a8ef --- /dev/null +++ b/firmware/baseband/proc_sigfrx.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * + * 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 "proc_sigfrx.hpp" + +#include +#include + +void SIGFRXProcessor::execute(buffer_c8_t buffer) { + /* Called every 2048/3072000 second -- 1500Hz. */ + + auto decimator_out = decimator.execute(buffer); + + const buffer_c16_t work_baseband_buffer { + (complex16_t*)decimator_out.p, + sizeof(*decimator_out.p) * decimator_out.count + }; + + /* 192kHz complex[64] + * -> 96kHz int16_t[32] */ + //auto channel = channel_filter.execute(decimator_out, work_baseband_buffer); + + // TODO: Feed channel_stats post-decimation data? + feed_channel_spectrum( + decimator_out, + 41000, //decimator_out.sampling_rate * channel_filter_taps.pass_frequency_normalized, + 70000 //decimator_out.sampling_rate * channel_filter_taps.stop_frequency_normalized + ); + + /*const buffer_s16_t work_audio_buffer { + (int16_t*)decimator_out.p, + sizeof(*decimator_out.p) * decimator_out.count + }; + * + auto audio = demod.execute(channel, work_audio_buffer); + + static uint64_t audio_present_history = 0; + const auto audio_present_now = squelch.execute(audio); + audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0); + const bool audio_present = (audio_present_history != 0); + + if( !audio_present ) { + // Zero audio buffer. + for(size_t i=0; i& channel_filter_taps = taps_64_lp_410_700_tfilter; //taps_64_lp_104_140_tfilter + //dsp::decimate::FIRAndDecimateComplex channel_filter; + dsp::demodulate::FM demod { 48000, 7500 }; + + IIRBiquadFilter audio_hpf { audio_hpf_config }; + FMSquelch squelch; +}; + +#endif diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index bc4af7baa..77181b94f 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -159,13 +159,33 @@ public: AudioStatistics statistics; }; +typedef enum { + RX_NBAM_AUDIO = 0, + RX_NBFM_AUDIO, + RX_WBFM_AUDIO, + RX_AIS, + RX_WBSPECTRUM, + RX_TPMS, + RX_AFSK, + RX_SIGFOX, + + TX_RDS, + TX_LCR, + TX_TONE, + TX_JAMMER, + TX_XYLOS, + + NONE, + SWITCH = 0xFF +} mode_type; + struct BasebandConfiguration { - int32_t mode; + mode_type mode; uint32_t sampling_rate; size_t decimation_factor; constexpr BasebandConfiguration( - int32_t mode = -1, + mode_type mode = NONE, uint32_t sampling_rate = 0, size_t decimation_factor = 1 ) : mode { mode }, diff --git a/firmware/common/modules.h b/firmware/common/modules.h new file mode 100644 index 000000000..26dd39776 --- /dev/null +++ b/firmware/common/modules.h @@ -0,0 +1,2 @@ +const char md5_baseband[16] = {0x20,0xb7,0x1a,0x68,0x28,0xda,0xc9,0xb8,0x01,0xb0,0xbd,0x68,0x0d,0xd5,0xd6,0xa7,}; +const char md5_baseband_tx[16] = {0xe5,0x29,0xb9,0xf0,0x81,0x50,0x45,0x69,0x24,0xaf,0xdd,0x4e,0xdb,0xaf,0xd8,0x97,}; diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index bd6b5d245..53acde85f 100644 Binary files a/firmware/portapack-h1-firmware.bin and b/firmware/portapack-h1-firmware.bin differ diff --git a/firmware/tools/make_baseband_file.py b/firmware/tools/make_baseband_file.py index 537bf8983..078db063b 100755 --- a/firmware/tools/make_baseband_file.py +++ b/firmware/tools/make_baseband_file.py @@ -1,9 +1,7 @@ #!/usr/bin/env python # -# Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. -# -# This file is part of PortaPack. +# Copyright (C) 2016 Furrtek # # 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 @@ -89,4 +87,4 @@ for args in sys.argv: md5sum += '0x' + format(byte, '02x') + ',' h_data += 'const char md5_' + args.replace('-','_') + '[16] = {' + md5sum + '};\n' -write_file(h_data, 'application/modules.h') +write_file(h_data, 'common/modules.h')