diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 63f4f969..d53b8c22 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -209,6 +209,7 @@ set(CPPSRC ui_spectrum.cpp ui_sstvtx.cpp ui_tabview.cpp + ui_test.cpp ui_textentry.cpp ui_touch_calibration.cpp ui_touchtunes.cpp @@ -229,6 +230,7 @@ set(CPPSRC ${COMMON}/adsb_frame.cpp ${COMMON}/adsb.cpp ${COMMON}/sonde_packet.cpp + ${COMMON}/test_packet.cpp ais_app.cpp tpms_app.cpp pocsag_app.cpp diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 0d2ca15c..83217bc3 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -59,7 +59,24 @@ Continuous (Fox-oring) 60s transmit, 240s space (Classic 1/5 min) 60s transmit, 360s space (Classic 1/7 min) */ +<<<<<<< ./firmware/application/main_LOCAL_5232.cpp +||||||| ./firmware/application/main_BASE_5232.cpp +//TODO: Use TransmitterView in TEDI/LCR, Numbers, ... +======= +//TODO: Use TransmitterView in TEDI/LCR, Numbers, ... +//TODO: Use TransmitterView in TEDI/LCR, Numbers, ... +>>>>>>> ./firmware/application/main_REMOTE_5232.cpp //TODO: FreqMan: Remove and rename categories +<<<<<<< ./firmware/application/main_LOCAL_5232.cpp +||||||| ./firmware/application/main_BASE_5232.cpp +//TODO: Wav visualizer +//TODO: File browser view ? +======= +//TODO: Wav visualizer +//TODO: File browser view ? +//TODO: Wav visualizer +//TODO: File browser view ? +>>>>>>> ./firmware/application/main_REMOTE_5232.cpp //TODO: Mousejack ? //TODO: Move frequencykeypad from ui_receiver to ui_widget (used everywhere) //TODO: ADS-B draw trajectory + GPS coordinates + scale, and playback diff --git a/firmware/application/ui_adsb_rx.cpp b/firmware/application/ui_adsb_rx.cpp index 508f2c55..fcb47ea0 100644 --- a/firmware/application/ui_adsb_rx.cpp +++ b/firmware/application/ui_adsb_rx.cpp @@ -161,6 +161,7 @@ ADSBRxDetailsView::ADSBRxDetailsView( geomap_view = nav.push( entry_copy.callsign, entry_copy.pos.altitude, + GeoPos::alt_unit::FEET, entry_copy.pos.latitude, entry_copy.pos.longitude, 0, diff --git a/firmware/application/ui_adsb_tx.cpp b/firmware/application/ui_adsb_tx.cpp index ada4d99c..94da2343 100644 --- a/firmware/application/ui_adsb_tx.cpp +++ b/firmware/application/ui_adsb_tx.cpp @@ -89,6 +89,7 @@ ADSBPositionView::ADSBPositionView( button_set_map.on_select = [this, &nav](Button&) { nav.push( geopos.altitude(), + GeoPos::alt_unit::FEET, geopos.lat(), geopos.lon(), [this](int32_t altitude, float lat, float lon) { diff --git a/firmware/application/ui_adsb_tx.hpp b/firmware/application/ui_adsb_tx.hpp index 927d543f..f68da241 100644 --- a/firmware/application/ui_adsb_tx.hpp +++ b/firmware/application/ui_adsb_tx.hpp @@ -55,7 +55,8 @@ public: private: GeoPos geopos { - { 0, 2 * 16 } + { 0, 2 * 16 }, + GeoPos::FEET }; Button button_set_map { diff --git a/firmware/application/ui_geomap.cpp b/firmware/application/ui_geomap.cpp index a81527c2..724665a0 100644 --- a/firmware/application/ui_geomap.cpp +++ b/firmware/application/ui_geomap.cpp @@ -29,22 +29,29 @@ using namespace portapack; +#include "string_format.hpp" + namespace ui { GeoPos::GeoPos( - const Point pos -) { - set_parent_rect({pos, {30 * 8, 3 * 16}}); + const Point pos, + const alt_unit altitude_unit +) : altitude_unit_(altitude_unit) { + + set_parent_rect({pos, { 30 * 8, 3 * 16 }}); add_children({ &labels_position, &field_altitude, + &text_alt_unit, &field_lat_degrees, &field_lat_minutes, &field_lat_seconds, + &text_lat_decimal, &field_lon_degrees, &field_lon_minutes, - &field_lon_seconds + &field_lon_seconds, + &text_lon_decimal }); // Defaults @@ -53,8 +60,22 @@ GeoPos::GeoPos( set_lon(0); const auto changed_fn = [this](int32_t) { + float lat_value = lat(); + float lon_value = lon(); + double integer_part; + double fractional_part; + + fractional_part = modf(lat_value, &integer_part) * 100000; + if (fractional_part < 0) + fractional_part = -fractional_part; + text_lat_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5)); + fractional_part = modf(lon_value, &integer_part) * 100000; + if (fractional_part < 0) + fractional_part = -fractional_part; + text_lon_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5)); + if (on_change && report_change) - on_change(altitude(), lat(), lon()); + on_change(altitude(), lat_value, lon_value); }; field_altitude.on_change = changed_fn; @@ -64,6 +85,13 @@ GeoPos::GeoPos( field_lon_degrees.on_change = changed_fn; field_lon_minutes.on_change = changed_fn; field_lon_seconds.on_change = changed_fn; + + text_alt_unit.set(altitude_unit_ ? "m" : "ft"); +} + +void GeoPos::set_read_only(bool v) { + for(auto child : children_) + child->set_focusable(!v); } // Stupid hack to avoid an event loop @@ -103,10 +131,6 @@ int32_t GeoPos::altitude() { return field_altitude.value(); }; -void GeoPos::set_read_only(bool v) { - set_focusable(~v); -}; - GeoMap::GeoMap( Rect parent_rect ) : Widget { parent_rect } @@ -117,7 +141,6 @@ GeoMap::GeoMap( void GeoMap::paint(Painter& painter) { Coord line; std::array map_line_buffer; - //Color border; const auto r = screen_rect(); // Ony redraw map if it moved by at least 1 pixel @@ -265,12 +288,14 @@ GeoMapView::GeoMapView( NavigationView& nav, const std::string& tag, int32_t altitude, + GeoPos::alt_unit altitude_unit, float lat, float lon, float angle, const std::function on_close ) : nav_ (nav), altitude_ (altitude), + altitude_unit_ (altitude_unit), lat_ (lat), lon_ (lon), angle_ (angle), @@ -296,11 +321,13 @@ GeoMapView::GeoMapView( GeoMapView::GeoMapView( NavigationView& nav, int32_t altitude, + GeoPos::alt_unit altitude_unit, float lat, float lon, const std::function on_done ) : nav_ (nav), altitude_ (altitude), + altitude_unit_ (altitude_unit), lat_ (lat), lon_ (lon) { diff --git a/firmware/application/ui_geomap.hpp b/firmware/application/ui_geomap.hpp index 4608742c..45a9479b 100644 --- a/firmware/application/ui_geomap.hpp +++ b/firmware/application/ui_geomap.hpp @@ -39,9 +39,14 @@ enum GeoMapMode { class GeoPos : public View { public: + enum alt_unit { + FEET = 0, + METERS + }; + std::function on_change { }; - GeoPos(const Point pos); + GeoPos(const Point pos, const alt_unit altitude_unit); void focus() override; @@ -58,39 +63,52 @@ public: private: bool read_only { false }; bool report_change { true }; + alt_unit altitude_unit_ { }; Labels labels_position { - { { 2 * 8, 0 * 16 }, "Alt: feet", Color::light_grey() }, - { { 2 * 8, 1 * 16 }, "Lat: * ' \"", Color::light_grey() }, // No ° symbol in 8x16 font - { { 2 * 8, 2 * 16 }, "Lon: * ' \"", Color::light_grey() }, + { { 1 * 8, 0 * 16 }, "Alt:", Color::light_grey() }, + { { 1 * 8, 1 * 16 }, "Lat: * ' \"", Color::light_grey() }, // No ° symbol in 8x16 font + { { 1 * 8, 2 * 16 }, "Lon: * ' \"", Color::light_grey() }, }; NumberField field_altitude { - { 7 * 8, 0 * 16 }, + { 6 * 8, 0 * 16 }, 5, { -1000, 50000 }, 250, ' ' }; + Text text_alt_unit { + { 12 * 8, 0 * 16, 2 * 8, 16 }, + "" + }; NumberField field_lat_degrees { - { 7 * 8, 1 * 16 }, 4, { -90, 90 }, 1, ' ' + { 5 * 8, 1 * 16 }, 4, { -90, 90 }, 1, ' ' }; NumberField field_lat_minutes { - { 12 * 8, 1 * 16 }, 2, { 0, 59 }, 1, ' ' + { 10 * 8, 1 * 16 }, 2, { 0, 59 }, 1, ' ' }; NumberField field_lat_seconds { - { 15 * 8, 1 * 16 }, 2, { 0, 59 }, 1, ' ' + { 13 * 8, 1 * 16 }, 2, { 0, 59 }, 1, ' ' + }; + Text text_lat_decimal { + { 17 * 8, 1 * 16, 13 * 8, 1 * 16 }, + "" }; NumberField field_lon_degrees { - { 7 * 8, 2 * 16 }, 4, { -180, 180 }, 1, ' ' + { 5 * 8, 2 * 16 }, 4, { -180, 180 }, 1, ' ' }; NumberField field_lon_minutes { - { 12 * 8, 2 * 16 }, 2, { 0, 59 }, 1, ' ' + { 10 * 8, 2 * 16 }, 2, { 0, 59 }, 1, ' ' }; NumberField field_lon_seconds { - { 15 * 8, 2 * 16 }, 2, { 0, 59 }, 1, ' ' + { 13 * 8, 2 * 16 }, 2, { 0, 59 }, 1, ' ' + }; + Text text_lon_decimal { + { 17 * 8, 2 * 16, 13 * 8, 1 * 16 }, + "" }; }; @@ -133,13 +151,15 @@ public: NavigationView& nav, const std::string& tag, int32_t altitude, + GeoPos::alt_unit altitude_unit, float lat, float lon, float angle, - const std::function on_close + const std::function on_close = nullptr ); GeoMapView(NavigationView& nav, int32_t altitude, + GeoPos::alt_unit altitude_unit, float lat, float lon, const std::function on_done @@ -167,6 +187,7 @@ private: const Dim banner_height = 3 * 16; GeoMapMode mode_ { }; int32_t altitude_ { }; + GeoPos::alt_unit altitude_unit_ { }; float lat_ { }; float lon_ { }; float angle_ { }; @@ -175,7 +196,8 @@ private: bool map_opened { }; GeoPos geopos { - { 0, 0 } + { 0, 0 }, + altitude_unit_ }; GeoMap geomap { diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a31edb48..04cb114d 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -58,6 +58,7 @@ #include "ui_sonde.hpp" #include "ui_soundboard.hpp" #include "ui_sstvtx.hpp" +#include "ui_test.hpp" #include "ui_touchtunes.hpp" #include "ui_view_wav.hpp" #include "ui_whipcalc.hpp" @@ -297,7 +298,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, { "SIGFOX", ui::Color::grey(), &bitmap_icon_fox, [&nav](){ nav.push(); } }, // SIGFRXView { "LoRa", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, - { "Radiosondes", ui::Color::red(), &bitmap_icon_sonde, [&nav](){ nav.push(); } }, + { "Radiosondes", ui::Color::yellow(),&bitmap_icon_sonde, [&nav](){ nav.push(); } }, { "SSTV", ui::Color::grey(), &bitmap_icon_sstv, [&nav](){ nav.push(); } }, { "TPMS: Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push(); } }, }); @@ -335,6 +336,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) { add_items({ + { "Test app", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, { "Frequency manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push(); } }, { "File manager", ui::Color::yellow(), &bitmap_icon_file, [&nav](){ nav.push(); } }, { "Whip antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push(); } }, diff --git a/firmware/application/ui_sonde.cpp b/firmware/application/ui_sonde.cpp index 92720dc0..3854373c 100644 --- a/firmware/application/ui_sonde.cpp +++ b/firmware/application/ui_sonde.cpp @@ -21,20 +21,17 @@ */ #include "ui_sonde.hpp" - #include "baseband_api.hpp" #include "portapack.hpp" using namespace portapack; -//#include "manchester.hpp" - #include "string_format.hpp" -/*void SondeLogger::on_packet(const sonde::Packet& packet) { +void SondeLogger::on_packet(const sonde::Packet& packet) { const auto formatted = packet.symbols_formatted(); - log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors); -}*/ + log_file.write_entry(packet.received_at(), formatted.data); +} namespace ui { @@ -42,16 +39,22 @@ SondeView::SondeView(NavigationView& nav) { baseband::run_image(portapack::spi_flash::image_tag_sonde); add_children({ + &labels, &field_frequency, - &text_debug, &field_rf_amp, &field_lna, &field_vga, - &rssi + &rssi, + &check_log, + &text_signature, + &text_serial, + &text_voltage, + &geopos, + &button_see_map }); - field_frequency.set_value(receiver_model.tuning_frequency()); - field_frequency.set_step(receiver_model.frequency_step()); + field_frequency.set_value(target_frequency_); + field_frequency.set_step(10000); field_frequency.on_change = [this](rf::Frequency f) { set_target_frequency(f); field_frequency.set_value(f); @@ -65,8 +68,14 @@ SondeView::SondeView(NavigationView& nav) { }; }; + geopos.set_read_only(true); + + check_log.on_select = [this](Checkbox&, bool v) { + logging = v; + }; + radio::enable({ - receiver_model.tuning_frequency(), + tuning_frequency(), sampling_rate, baseband_bandwidth, rf::Direction::Receive, @@ -74,13 +83,21 @@ SondeView::SondeView(NavigationView& nav) { static_cast(receiver_model.lna()), static_cast(receiver_model.vga()), }); - - set_target_frequency(402000000); - /*logger = std::make_unique(); - if( logger ) { + button_see_map.on_select = [this, &nav](Button&) { + nav.push( + "", + altitude, + GeoPos::alt_unit::METERS, + latitude, + longitude, + 0); + }; + + logger = std::make_unique(); + if (logger) logger->append(u"sonde.txt"); - }*/ + } SondeView::~SondeView() { @@ -92,19 +109,25 @@ void SondeView::focus() { field_vga.focus(); } -void SondeView::on_packet(const baseband::Packet& packet) { - std::string bin_string; +void SondeView::on_packet(const sonde::Packet& packet) { + //const auto hex_formatted = packet.symbols_formatted(); - for (size_t i = 0; i < 30; i++) { - bin_string += to_string_dec_uint(packet[i]); + text_signature.set(packet.signature()); + text_serial.set(packet.serial_number()); + text_voltage.set(unit_auto_scale(packet.battery_voltage(), 2, 3) + "V"); + + altitude = packet.GPS_altitude(); + latitude = packet.GPS_latitude(); + longitude = packet.GPS_longitude(); + + geopos.set_altitude(altitude); + geopos.set_lat(latitude); + geopos.set_lon(longitude); + + if (logger && logging) { + logger->on_packet(packet); } - text_debug.set(bin_string); - - /*if( logger ) { - logger->on_packet(packet); - }*/ - /*if( packet.crc_ok() ) { }*/ } diff --git a/firmware/application/ui_sonde.hpp b/firmware/application/ui_sonde.hpp index b00b6336..f31ac823 100644 --- a/firmware/application/ui_sonde.hpp +++ b/firmware/application/ui_sonde.hpp @@ -26,7 +26,7 @@ #include "ui_navigation.hpp" #include "ui_receiver.hpp" #include "ui_rssi.hpp" -#include "ui_channel.hpp" +#include "ui_geomap.hpp" #include "event_m0.hpp" @@ -34,12 +34,10 @@ #include "sonde_packet.hpp" -#include "recent_entries.hpp" - #include #include -/*class SondeLogger { +class SondeLogger { public: Optional append(const std::filesystem::path& filename) { return log_file.append(filename); @@ -49,7 +47,7 @@ public: private: LogFile log_file { }; -};*/ +}; namespace ui { @@ -66,8 +64,18 @@ public: std::string title() const override { return "Radiosonde RX"; }; private: - //std::unique_ptr logger { }; - uint32_t target_frequency_ { }; + std::unique_ptr logger { }; + uint32_t target_frequency_ { 402000000 }; + bool logging { false }; + int32_t altitude { 0 }; + float latitude { 0 }; + float longitude { 0 }; + + Labels labels { + { { 0 * 8, 2 * 16 }, "Signature:", Color::light_grey() }, + { { 3 * 8, 3 * 16 }, "Serial:", Color::light_grey() }, + { { 4 * 8, 4 * 16 }, "Vbatt:", Color::light_grey() } + }; FrequencyField field_frequency { { 0 * 8, 0 * 8 }, @@ -88,23 +96,45 @@ private: { 21 * 8, 0, 6 * 8, 4 }, }; - Text text_debug { - { 0, 32, 240, 16 }, - "Waiting for frame..." + Checkbox check_log { + { 22 * 8, 2 * 16 + 12 }, + 3, + "Log" + }; + + Text text_signature { + { 10 * 8, 2 * 16, 10 * 8, 16 }, + "..." + }; + Text text_serial { + { 10 * 8, 3 * 16, 11 * 8, 16 }, + "..." + }; + Text text_voltage { + { 10 * 8, 4 * 16, 10 * 8, 16 }, + "..." + }; + + GeoPos geopos { + { 0, 6 * 16 }, + GeoPos::alt_unit::METERS + }; + + Button button_see_map { + { 8 * 8, 10 * 16, 14 * 8, 3 * 16 }, + "See on map" }; MessageHandlerRegistration message_handler_packet { Message::ID::SondePacket, [this](Message* const p) { const auto message = static_cast(p); - //const sonde::Packet packet { message->type, message->packet }; - //this->on_packet(packet); - this->on_packet(message->packet); + const sonde::Packet packet { message->packet, message->type }; + this->on_packet(packet); } }; - //void on_packet(const sonde::Packet& packet); - void on_packet(const baseband::Packet& packet); + void on_packet(const sonde::Packet& packet); void set_target_frequency(const uint32_t new_value); uint32_t tuning_frequency() const; }; diff --git a/firmware/application/ui_test.cpp b/firmware/application/ui_test.cpp new file mode 100644 index 00000000..6268a1db --- /dev/null +++ b/firmware/application/ui_test.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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_test.hpp" +#include "baseband_api.hpp" + +#include "portapack.hpp" +using namespace portapack; + +#include "string_format.hpp" + +namespace ui { + +TestView::TestView(NavigationView& nav) { + baseband::run_image(portapack::spi_flash::image_tag_test); + + add_children({ + &labels, + &field_frequency, + &field_rf_amp, + &field_lna, + &field_vga, + &rssi, + &text_debug_a, + &text_debug_b + }); + + field_frequency.set_value(target_frequency_); + field_frequency.set_step(10000); + field_frequency.on_change = [this](rf::Frequency f) { + set_target_frequency(f); + field_frequency.set_value(f); + }; + field_frequency.on_edit = [this, &nav]() { + // TODO: Provide separate modal method/scheme? + auto new_view = nav.push(receiver_model.tuning_frequency()); + new_view->on_changed = [this](rf::Frequency f) { + set_target_frequency(f); + field_frequency.set_value(f); + }; + }; + + radio::enable({ + tuning_frequency(), + sampling_rate, + baseband_bandwidth, + rf::Direction::Receive, + receiver_model.rf_amp(), + static_cast(receiver_model.lna()), + static_cast(receiver_model.vga()), + }); +} + +TestView::~TestView() { + radio::disable(); + baseband::shutdown(); +} + +void TestView::focus() { + field_vga.focus(); +} + +void TestView::on_packet(const testapp::Packet& packet) { + const auto hex_formatted = packet.symbols_formatted(); + auto v = packet.value(); + + packet_count++; + uint32_t diff = ((v - 1) - prev_v); + if (diff < 20) + packets_lost += diff; + prev_v = v; + + text_debug_a.set(hex_formatted.data.substr(0, 30)); + + text_debug_b.set(to_string_dec_uint((packets_lost * 1000) / packet_count) + " per 1000"); + + display.draw_pixel(Point(cur_x, 4 * 16 + (256 - packet.alt())), Color::white()); + + cur_x++; + if (cur_x >= 240) { + display.fill_rectangle(Rect(0, 4 * 16, 240, 256), Color::black()); + cur_x = 0; + } + + //radio::disable(); + + /*text_serial.set(packet.serial_number()); + text_voltage.set(unit_auto_scale(packet.battery_voltage(), 2, 3) + "V"); + + altitude = packet.GPS_altitude(); + latitude = packet.GPS_latitude(); + longitude = packet.GPS_longitude();*/ +} + +void TestView::set_target_frequency(const uint32_t new_value) { + target_frequency_ = new_value; + radio::set_tuning_frequency(tuning_frequency()); +} + +uint32_t TestView::tuning_frequency() const { + return target_frequency_ - (sampling_rate / 4); +} + +} /* namespace ui */ diff --git a/firmware/application/ui_test.hpp b/firmware/application/ui_test.hpp new file mode 100644 index 00000000..58bddc82 --- /dev/null +++ b/firmware/application/ui_test.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UI_TEST_H__ +#define __UI_TEST_H__ + +#include "ui_navigation.hpp" +#include "ui_receiver.hpp" +#include "ui_rssi.hpp" + +#include "event_m0.hpp" + +#include "test_packet.hpp" + +#include +#include + +namespace ui { + +class TestView : public View { +public: + static constexpr uint32_t sampling_rate = 2457600; + static constexpr uint32_t baseband_bandwidth = 1750000; + + TestView(NavigationView& nav); + ~TestView(); + + void focus() override; + + std::string title() const override { return "Test app"; }; + +private: + uint32_t target_frequency_ { 439255000 }; + Coord cur_x { 0 }; + uint32_t packet_count { 0 }; + uint32_t packets_lost { 0 }; + uint32_t prev_v { 0 }; + + Labels labels { + { { 0 * 8, 1 * 16 }, "Data:", Color::light_grey() } + }; + + FrequencyField field_frequency { + { 0 * 8, 0 * 8 }, + }; + RFAmpField field_rf_amp { + { 13 * 8, 0 * 16 } + }; + + LNAGainField field_lna { + { 15 * 8, 0 * 16 } + }; + + VGAGainField field_vga { + { 18 * 8, 0 * 16 } + }; + + RSSI rssi { + { 21 * 8, 0, 6 * 8, 4 }, + }; + + Text text_debug_a { + { 0 * 8, 2 * 16, 30 * 8, 16 }, + "..." + }; + Text text_debug_b { + { 0 * 8, 3 * 16, 30 * 8, 16 }, + "..." + }; + + MessageHandlerRegistration message_handler_packet { + Message::ID::TestAppPacket, + [this](Message* const p) { + const auto message = static_cast(p); + const testapp::Packet packet { message->packet }; + this->on_packet(packet); + } + }; + + void on_packet(const testapp::Packet& packet); + void set_target_frequency(const uint32_t new_value); + uint32_t tuning_frequency() const; +}; + +} /* namespace ui */ + +#endif/*__UI_TEST_H__*/ diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 206e1bb7..7346f89f 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -422,6 +422,13 @@ set(MODE_CPPSRC ) DeclareTargets(PSTX sstvtx) +### Test + +set(MODE_CPPSRC + proc_test.cpp +) +DeclareTargets(PTST test) + ### Tones set(MODE_CPPSRC diff --git a/firmware/baseband/proc_sonde.cpp b/firmware/baseband/proc_sonde.cpp index 9743beb6..35e8791e 100644 --- a/firmware/baseband/proc_sonde.cpp +++ b/firmware/baseband/proc_sonde.cpp @@ -23,7 +23,6 @@ #include "proc_sonde.hpp" #include "dsp_fir_taps.hpp" -//#include "portapack_shared_memory.hpp" #include "event_m4.hpp" diff --git a/firmware/baseband/proc_sonde.hpp b/firmware/baseband/proc_sonde.hpp index e5dba34e..9f6cca05 100644 --- a/firmware/baseband/proc_sonde.hpp +++ b/firmware/baseband/proc_sonde.hpp @@ -28,8 +28,8 @@ * Since the applied shift in ui_sonde.cpp is -fs/4 = -2457600/4 = -614400Hz to avoid the DC spike, the FSK signal ends up being * shifted by 614400 / 8 / 8 = 9600Hz. So decim_1_out should look like this: * - * _______________|__/'\__________ - * -C A B C + * _______________|______/'\______ + * -C A B C * * A is the DC spike at 0Hz * B is the FSK signal shifted right at 9600Hz @@ -40,7 +40,7 @@ * ______________/'\______________ * -C D C * - * A should have been filtered off ? + * Anything unwanted (like A) should have been filtered off * D is B around 0Hz now * * Then the clock_recovery function should be happy :) @@ -113,18 +113,17 @@ private: dsp::decimate::FIRC16xR16x32Decim8 decim_1 { }; dsp::matched_filter::MatchedFilter mf { baseband::ais::square_taps_38k4_1t_p, 2 }; - // AIS: 19200, 9600 clock_recovery::ClockRecovery clock_recovery_fsk_4800 { - 19200, 4800, { 0.0555f }, + 19200, 9600, { 0.0555f }, [this](const float raw_symbol) { const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0; this->packet_builder_fsk_4800_M10.execute(sliced_symbol); } }; PacketBuilder packet_builder_fsk_4800_M10 { - { 0b11001100110011001010011001001100, 32, 1 }, + { 0b00110011001100110101100110110011, 32, 1 }, { }, - { 50 }, // { 102 * 8 }, + { 88 * 2 * 8 }, [this](const baseband::Packet& packet) { const SondePacketMessage message { sonde::Packet::Type::M10, packet }; shared_memory.application_queue.push(message); diff --git a/firmware/baseband/proc_test.cpp b/firmware/baseband/proc_test.cpp new file mode 100644 index 00000000..d31da2ac --- /dev/null +++ b/firmware/baseband/proc_test.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 "proc_test.hpp" + +#include "dsp_fir_taps.hpp" + +#include "event_m4.hpp" + +TestProcessor::TestProcessor() { + decim_0.configure(taps_11k0_decim_0.taps, 33554432); + decim_1.configure(taps_11k0_decim_1.taps, 131072); +} + +void TestProcessor::execute(const buffer_c8_t& buffer) { + /* 2.4576MHz, 2048 samples */ + + const auto decim_0_out = decim_0.execute(buffer, dst_buffer); + const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); + const auto decimator_out = decim_1_out; + + /* 38.4kHz, 32 samples */ + feed_channel_stats(decimator_out); + + for(size_t i=0; i() }; + event_dispatcher.run(); + return 0; +} diff --git a/firmware/baseband/proc_test.hpp b/firmware/baseband/proc_test.hpp new file mode 100644 index 00000000..dcdcd4a9 --- /dev/null +++ b/firmware/baseband/proc_test.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PROC_TEST_H__ +#define __PROC_TEST_H__ + +#include "baseband_processor.hpp" +#include "baseband_thread.hpp" +#include "rssi_thread.hpp" +#include "proc_ais.hpp" + +#include "channel_decimator.hpp" +#include "matched_filter.hpp" + +#include "clock_recovery.hpp" +#include "symbol_coding.hpp" +#include "packet_builder.hpp" +#include "baseband_packet.hpp" + +#include "message.hpp" +#include "portapack_shared_memory.hpp" + +#include +#include +#include + +class TestProcessor : public BasebandProcessor { +public: + TestProcessor(); + + void execute(const buffer_c8_t& buffer) override; + +private: + static constexpr size_t baseband_fs = 2457600; + + BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive }; + RSSIThread rssi_thread { NORMALPRIO + 10 }; + + std::array dst { }; + const buffer_c16_t dst_buffer { + dst.data(), + dst.size() + }; + + dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { }; + dsp::decimate::FIRC16xR16x32Decim8 decim_1 { }; + dsp::matched_filter::MatchedFilter mf { baseband::ais::square_taps_38k4_1t_p, 2 }; + + clock_recovery::ClockRecovery clock_recovery_fsk_9600 { + 19200, 9600, { 0.00555f }, + [this](const float raw_symbol) { + const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0; + this->packet_builder_fsk_9600_CC1101.execute(sliced_symbol); + } + }; + PacketBuilder packet_builder_fsk_9600_CC1101 { + { 0b01010110010110100101101001101010, 32, 1 }, // Manchester 0x1337 + { }, + { 10 * 8 }, + [this](const baseband::Packet& packet) { + const TestAppPacketMessage message { packet }; + shared_memory.application_queue.push(message); + } + }; +}; + +#endif/*__PROC_TEST_H__*/ diff --git a/firmware/common/manchester.cpp b/firmware/common/manchester.cpp index 8c02ad20..bc14c0c1 100644 --- a/firmware/common/manchester.cpp +++ b/firmware/common/manchester.cpp @@ -23,6 +23,10 @@ #include "string_format.hpp" +size_t ManchesterBase::symbols_count() const { + return packet.size() / 2; +} + DecodedSymbol ManchesterDecoder::operator[](const size_t index) const { const size_t encoded_index = index * 2; if( (encoded_index + 1) < packet.size() ) { @@ -34,12 +38,19 @@ DecodedSymbol ManchesterDecoder::operator[](const size_t index) const { } } -size_t ManchesterDecoder::symbols_count() const { - return packet.size() / 2; +DecodedSymbol BiphaseMDecoder::operator[](const size_t index) const { + const size_t encoded_index = index * 2; + if( (encoded_index + 1) < packet.size() ) { + const auto value = packet[encoded_index + 0] != packet[encoded_index + 1]; + const uint_fast8_t error = encoded_index ? (packet[encoded_index - 1] == packet[encoded_index + 0]) : 0; + return { value, error }; + } else { + return { 0, 1 }; + } } FormattedSymbols format_symbols( - const ManchesterDecoder& decoder + const ManchesterBase& decoder ) { const size_t payload_length_decoded = decoder.symbols_count(); const size_t payload_length_hex_characters = (payload_length_decoded + 3) / 4; diff --git a/firmware/common/manchester.hpp b/firmware/common/manchester.hpp index ca2f1e43..91bd1f19 100644 --- a/firmware/common/manchester.hpp +++ b/firmware/common/manchester.hpp @@ -34,25 +34,39 @@ struct DecodedSymbol { uint_fast8_t error; }; -class ManchesterDecoder { +class ManchesterBase { public: - constexpr ManchesterDecoder( + constexpr ManchesterBase( const baseband::Packet& packet, const size_t sense = 0 ) : packet { packet }, sense { sense } { } + + virtual DecodedSymbol operator[](const size_t index) const = 0; - DecodedSymbol operator[](const size_t index) const; - - size_t symbols_count() const; - -private: + virtual size_t symbols_count() const; + + virtual ~ManchesterBase() { }; + +protected: const baseband::Packet& packet; const size_t sense; }; +class ManchesterDecoder : public ManchesterBase { +public: + using ManchesterBase::ManchesterBase; + DecodedSymbol operator[](const size_t index) const; +}; + +class BiphaseMDecoder : public ManchesterBase { +public: + using ManchesterBase::ManchesterBase; + DecodedSymbol operator[](const size_t index) const; +}; + template T operator|(const T& l, const DecodedSymbol& r) { return l | r.value; @@ -64,7 +78,7 @@ struct FormattedSymbols { }; FormattedSymbols format_symbols( - const ManchesterDecoder& decoder + const ManchesterBase& decoder ); void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense = 0); diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index ab23d14d..3fb4e898 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -97,6 +97,7 @@ public: POCSAGPacket = 50, ADSBFrame = 51, AFSKData = 52, + TestAppPacket = 53, RequestSignal = 60, FIFOData = 61, @@ -390,6 +391,18 @@ public: baseband::Packet packet; }; +class TestAppPacketMessage : public Message { +public: + constexpr TestAppPacketMessage( + const baseband::Packet& packet + ) : Message { ID::TestAppPacket }, + packet { packet } + { + } + + baseband::Packet packet; +}; + class UpdateSpectrumMessage : public Message { public: constexpr UpdateSpectrumMessage( diff --git a/firmware/common/sonde_packet.cpp b/firmware/common/sonde_packet.cpp index d4e1f097..5eba330c 100644 --- a/firmware/common/sonde_packet.cpp +++ b/firmware/common/sonde_packet.cpp @@ -21,8 +21,7 @@ */ #include "sonde_packet.hpp" - -//#include "crc.hpp" +#include "string_format.hpp" namespace sonde { @@ -42,15 +41,49 @@ Packet::Type Packet::type() const { return type_; } -SN Packet::serial_number() const { +uint32_t Packet::GPS_altitude() const { + return (reader_.read(22 * 8, 32) / 1000) - 48; +} + +float Packet::GPS_latitude() const { + return reader_.read(14 * 8, 32) / ((1ULL << 32) / 360.0); +} + +float Packet::GPS_longitude() const { + return reader_.read(18 * 8, 32) / ((1ULL << 32) / 360.0); +} + +uint32_t Packet::battery_voltage() const { + return (reader_.read(69 * 8, 8) + (reader_.read(70 * 8, 8) << 8)) * 1000 / 150; +} + +std::string Packet::signature() const { + const auto header = reader_.read(0, 24); + + if (header == 0x649F20) + return "M10"; + else if ((header == 0x648F20) || (header == 0x648F23)) + return "M2K2"; + else + return "0x" + symbols_formatted().data.substr(0, 6); +} + +std::string Packet::serial_number() const { if (type() == Type::M10) { // See https://github.com/rs1729/RS/blob/master/m10/m10x.c line 606 - return (reader_.read(2 * 8, 8) << 20) | - (reader_.read(0, 4) << 16) | - (reader_.read(4 * 8, 3) << 13) | - (reader_.read(4 * 8 + 3, 5) << 8) | - reader_.read(3 * 8, 8); + // Starting at byte #93: 00000000 11111111 22222222 33333333 44444444 + // CCCC AAAABBBB + // 44444444 33333333 + // DDDEEEEE EEEEEEEE + + return to_string_hex(reader_.read(93 * 8 + 16, 4), 1) + + to_string_dec_uint(reader_.read(93 * 8 + 20, 4), 2, '0') + " " + + to_string_hex(reader_.read(93 * 8 + 4, 4), 1) + " " + + to_string_dec_uint(reader_.read(93 * 8 + 24, 3), 1) + + to_string_dec_uint(reader_.read(93 * 8 + 27, 13), 4, '0'); + } + return 0; } diff --git a/firmware/common/sonde_packet.hpp b/firmware/common/sonde_packet.hpp index 73612a0f..d9658a54 100644 --- a/firmware/common/sonde_packet.hpp +++ b/firmware/common/sonde_packet.hpp @@ -32,8 +32,6 @@ namespace sonde { -using SN = uint64_t; - class Packet { public: enum class Type : uint32_t { @@ -42,8 +40,8 @@ public: }; Packet( - const Type type, - const baseband::Packet& packet + const baseband::Packet& packet, + const Type type ) : packet_ { packet }, decoder_ { packet_ }, reader_ { decoder_ }, @@ -58,17 +56,22 @@ public: Timestamp received_at() const; Type type() const; - SN serial_number() const; + std::string serial_number() const; + uint32_t GPS_altitude() const; + float GPS_latitude() const; + float GPS_longitude() const; + std::string signature() const; + uint32_t battery_voltage() const; FormattedSymbols symbols_formatted() const; bool crc_ok() const; private: - using Reader = FieldReader; + using Reader = FieldReader; const baseband::Packet packet_; - const ManchesterDecoder decoder_; + const BiphaseMDecoder decoder_; const Reader reader_; const Type type_; diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 036b3fd1..51ea0679 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -75,6 +75,7 @@ constexpr image_tag_t image_tag_sonde { 'P', 'S', 'O', 'N' }; constexpr image_tag_t image_tag_tpms { 'P', 'T', 'P', 'M' }; constexpr image_tag_t image_tag_wfm_audio { 'P', 'W', 'F', 'M' }; constexpr image_tag_t image_tag_wideband_spectrum { 'P', 'S', 'P', 'E' }; +constexpr image_tag_t image_tag_test { 'P', 'T', 'S', 'T' }; constexpr image_tag_t image_tag_adsb_tx { 'P', 'A', 'D', 'T' }; constexpr image_tag_t image_tag_afsk { 'P', 'A', 'F', 'T' }; diff --git a/firmware/common/test_packet.cpp b/firmware/common/test_packet.cpp new file mode 100644 index 00000000..86c2fb8a --- /dev/null +++ b/firmware/common/test_packet.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 "test_packet.hpp" +#include "string_format.hpp" + +namespace testapp { + +size_t Packet::length() const { + return decoder_.symbols_count(); +} + +bool Packet::is_valid() const { + return true; +} + +Timestamp Packet::received_at() const { + return packet_.timestamp(); +} + +FormattedSymbols Packet::symbols_formatted() const { + return format_symbols(decoder_); +} + +uint32_t Packet::value() const { + return reader_.read(3 * 8, 8); +} + +uint32_t Packet::alt() const { + return reader_.read(1 * 8, 12) - 0xC00; +} + +} /* namespace testapp */ diff --git a/firmware/common/test_packet.hpp b/firmware/common/test_packet.hpp new file mode 100644 index 00000000..d4b23d7d --- /dev/null +++ b/firmware/common/test_packet.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __TEST_PACKET_H__ +#define __TEST_PACKET_H__ + +#include +#include + +#include "field_reader.hpp" +#include "baseband_packet.hpp" +#include "manchester.hpp" + +namespace testapp { + +class Packet { +public: + Packet( + const baseband::Packet& packet + ) : packet_ { packet }, + decoder_ { packet_ }, + reader_ { decoder_ } + { + } + + size_t length() const; + + bool is_valid() const; + + Timestamp received_at() const; + + uint32_t value() const; + uint32_t alt() const; + /*std::string serial_number() const; + uint32_t GPS_altitude() const; + float GPS_latitude() const; + float GPS_longitude() const; + std::string signature() const; + uint32_t battery_voltage() const;*/ + + FormattedSymbols symbols_formatted() const; + + //bool crc_ok() const; + +private: + using Reader = FieldReader; + + const baseband::Packet packet_; + const ManchesterDecoder decoder_; + const Reader reader_; +}; + +} /* namespace testapp */ + +#endif/*__TEST_PACKET_H__*/ diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index fc5a836c..7a04171e 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ