diff --git a/firmware/application/Makefile b/firmware/application/Makefile index aeb55a32..9dcb4d34 100755 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -160,10 +160,12 @@ CPPSRC = main.cpp \ ui_font_fixed_8x16.cpp \ ui_setup.cpp \ ui_debug.cpp \ + ui_rds.cpp \ ui_console.cpp \ ui_receiver.cpp \ ui_spectrum.cpp \ receiver_model.cpp \ + transmitter_model.cpp \ spectrum_color_lut.cpp \ ../common/utility.cpp \ ../common/debug.cpp \ diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index 9f4c361c..4912d62d 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -65,6 +65,10 @@ ReceiverModel receiver_model { clock_manager }; +TransmitterModel transmitter_model { + clock_manager +}; + class Power { public: void init() { diff --git a/firmware/application/portapack.hpp b/firmware/application/portapack.hpp index 939442de..38593afc 100644 --- a/firmware/application/portapack.hpp +++ b/firmware/application/portapack.hpp @@ -22,6 +22,7 @@ #include "portapack_io.hpp" #include "receiver_model.hpp" +#include "transmitter_model.hpp" #include "spi_pp.hpp" #include "wm8731.hpp" @@ -41,6 +42,7 @@ extern SPI ssp1; extern wolfson::wm8731::WM8731 audio_codec; extern ReceiverModel receiver_model; +extern TransmitterModel transmitter_model; void init(); void shutdown(); diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index f54ae86e..d5f881ee 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -101,7 +101,7 @@ uint32_t ReceiverModel::modulation() const { return baseband_configuration.mode; } -void ReceiverModel::set_modulation(uint32_t v) { +void ReceiverModel::set_modulation(int32_t v) { baseband_configuration.mode = v; update_modulation(); } diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index a6af119c..969ef361 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -64,7 +64,7 @@ public: void set_sampling_rate(uint32_t hz); uint32_t modulation() const; - void set_modulation(uint32_t v); + void set_modulation(int32_t v); volume_t headphone_volume() const; void set_headphone_volume(volume_t v); @@ -82,7 +82,7 @@ private: uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum }; int32_t vga_gain_db_ { 32 }; BasebandConfiguration baseband_configuration { - .mode = 1, /* TODO: Enum! */ + .mode = 1, .sampling_rate = 3072000, .decimation_factor = 4, }; diff --git a/firmware/application/touch.cpp b/firmware/application/touch.cpp index 72f6d457..a32f5b17 100644 --- a/firmware/application/touch.cpp +++ b/firmware/application/touch.cpp @@ -22,6 +22,9 @@ #include "touch.hpp" namespace touch { + +float Manager::cmx; +float Manager::cmy; struct Metrics { const float x; @@ -66,6 +69,13 @@ static Metrics calculate_metrics(const Frame frame) { }; } +ui::Point Manager::raw_point() const { + return { + static_cast(cmx), + static_cast(cmy) + }; +} + void Manager::feed(const Frame frame) { // touch_debounce.feed(touch_raw); const auto touch_raw = frame.touch; @@ -81,6 +91,9 @@ void Manager::feed(const Frame frame) { // TODO: Add touch pressure hysteresis? touch_pressure = (metrics.r < r_touch_threshold); if( touch_pressure ) { + cmx = metrics.x*100; + cmy = metrics.y*100; + const float x = width_pixels * (metrics.x - calib_x_low) / calib_x_range; filter_x.feed(x); const float y = height_pixels * (calib_y_high - metrics.y) / calib_y_range; diff --git a/firmware/application/touch.hpp b/firmware/application/touch.hpp index ec0491fe..c56460c9 100644 --- a/firmware/application/touch.hpp +++ b/firmware/application/touch.hpp @@ -172,6 +172,9 @@ private: NoTouch, TouchDetected, }; + + static float cmx; + static float cmy; static constexpr uint32_t width_pixels = 240; static constexpr uint32_t height_pixels = 320; @@ -180,12 +183,12 @@ private: static constexpr size_t touch_count_threshold { 4 }; static constexpr uint32_t touch_stable_bound { 4 }; - static constexpr float calib_x_low = 0.07f; - static constexpr float calib_x_high = 0.94f; + static constexpr float calib_x_low = 0.15f; + static constexpr float calib_x_high = 0.93f; static constexpr float calib_x_range = calib_x_high - calib_x_low; - static constexpr float calib_y_low = 0.04f; - static constexpr float calib_y_high = 0.91f; + static constexpr float calib_y_low = 0.05f; + static constexpr float calib_y_high = 0.84f; static constexpr float calib_y_range = calib_y_high - calib_y_low; // Ensure filter length is equal or less than touch_count_threshold, @@ -209,6 +212,8 @@ private: }; } + ui::Point raw_point() const ; + void touch_started() { fire_event(ui::TouchEvent::Type::Start); } @@ -223,7 +228,7 @@ private: void fire_event(ui::TouchEvent::Type type) { if( on_event ) { - on_event({ filtered_point(), type }); + on_event({ filtered_point(), type, raw_point() }); } } }; diff --git a/firmware/application/ui_debug.cpp b/firmware/application/ui_debug.cpp index a8ba25ef..56b02407 100644 --- a/firmware/application/ui_debug.cpp +++ b/firmware/application/ui_debug.cpp @@ -23,12 +23,19 @@ #include "ch.h" +#include "ff.h" +#include "led.hpp" +#include "hackrf_gpio.hpp" +#include "portapack.hpp" + #include "radio.hpp" #include "hackrf_hal.hpp" using namespace hackrf::one; namespace ui { + +FRESULT fr; /* FatFs function common result code */ /* BasebandStatsView *****************************************************/ @@ -154,11 +161,79 @@ void DebugRFFC5072View::focus() { button_done.focus(); } +void DebugSDView::paint(Painter& painter) { + const Point offset = { + static_cast(32), + static_cast(32) + }; + + const auto text = to_string_hex(fr, 2); + painter.draw_string( + screen_pos() + offset, + style(), + text + ); +} + +DebugSDView::DebugSDView(NavigationView& nav) { + add_children({ { + &text_title, + &button_makefile, + &button_done + } }); + + button_makefile.on_select = [this](Button&){ + FATFS fs; /* Work area (file system object) for logical drives */ + FIL fdst; /* File objects */ + int16_t buffer[512]; /* File copy buffer */ + UINT bw; /* File read/write count */ + + sdcConnect(&SDCD1); + + fr = f_mount(&fs, "", 1); + + fr = f_open(&fdst, "TST.SND", FA_OPEN_EXISTING | FA_READ); + + if (!fr) led_rx.on(); + + /*fr = f_read(&fdst, buffer, 512*2, &bw); + + Coord oy,ny; + + oy = 128; + + for (int c=0;c<512;c++) { + ny = 128+32-(buffer[c]>>10); + portapack::display.draw_line({static_cast(c/3),oy},{static_cast((c+1)/3),ny},{255,127,0}); + oy = ny; + }*/ + + /* + //if (fr) return; + + fr = f_write(&fdst, buffer, br, &bw); + //if (fr || bw < br) return;*/ + + //set_dirty(); + + f_close(&fdst); + + f_mount(NULL, "", 0); + + }; + + button_done.on_select = [&nav](Button&){ nav.pop(); }; +} + +void DebugSDView::focus() { + button_done.focus(); +} + DebugMenuView::DebugMenuView(NavigationView& nav) { add_items<7>({ { { "Memory", [&nav](){ nav.push(new DebugMemoryView { nav }); } }, { "Radio State", [&nav](){ nav.push(new NotImplementedView { nav }); } }, - { "SD Card", [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "SD Card", [&nav](){ nav.push(new DebugSDView { nav }); } }, { "RFFC5072", [&nav](){ nav.push(new DebugRFFC5072View { nav }); } }, { "MAX2837", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "Si5351C", [&nav](){ nav.push(new NotImplementedView { nav }); } }, diff --git a/firmware/application/ui_debug.hpp b/firmware/application/ui_debug.hpp index 3f92fa6d..ec976313 100644 --- a/firmware/application/ui_debug.hpp +++ b/firmware/application/ui_debug.hpp @@ -163,6 +163,31 @@ private: }; }; +class DebugSDView : public View { +public: + DebugSDView(NavigationView& nav); + + void focus() override; + + void paint(Painter& painter) override; + +private: + Text text_title { + { 32, 16, 128, 16 }, + "SD card debug", + }; + + Button button_makefile { + { 72, 192, 96, 24 }, + "Play file" + }; + + Button button_done { + { 72, 240, 96, 24 }, + "Done" + }; +}; + class DebugMenuView : public MenuView { public: DebugMenuView(NavigationView& nav); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 8b730049..086f539d 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -22,10 +22,12 @@ #include "ui_navigation.hpp" #include "receiver_model.hpp" +#include "transmitter_model.hpp" #include "ui_setup.hpp" #include "ui_debug.hpp" #include "ui_receiver.hpp" +#include "ui_rds.hpp" #include "portapack.hpp" #include "m4_startup.hpp" @@ -95,10 +97,11 @@ void NavigationView::focus() { /* SystemMenuView ********************************************************/ SystemMenuView::SystemMenuView(NavigationView& nav) { - add_items<7>({ { + add_items<8>({ { { "Receiver", [&nav](){ nav.push(new ReceiverView { nav, receiver_model }); } }, { "Capture", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "Analyze", [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "RDS toolbox",[&nav](){ nav.push(new RDSView { nav, transmitter_model }); } }, { "Setup", [&nav](){ nav.push(new SetupMenuView { nav }); } }, { "About", [&nav](){ nav.push(new AboutView { nav }); } }, { "Debug", [&nav](){ nav.push(new DebugMenuView { nav }); } }, diff --git a/firmware/application/ui_receiver.cpp b/firmware/application/ui_receiver.cpp index 80b7b96f..a1c455b1 100644 --- a/firmware/application/ui_receiver.cpp +++ b/firmware/application/ui_receiver.cpp @@ -524,7 +524,7 @@ void ReceiverView::on_vga_changed(int32_t v_db) { } void ReceiverView::on_modulation_changed(int32_t modulation) { - if( modulation == 3 ) { + if( modulation == 4 ) { /* TODO: This is TERRIBLE!!! */ receiver_model.set_sampling_rate(2457600); } else { diff --git a/firmware/application/ui_setup.cpp b/firmware/application/ui_setup.cpp index fd7aa4db..08b29272 100644 --- a/firmware/application/ui_setup.cpp +++ b/firmware/application/ui_setup.cpp @@ -20,9 +20,13 @@ */ #include "ui_setup.hpp" +#include "touch.hpp" #include "portapack_persistent_memory.hpp" #include "lpc43xx_cpp.hpp" + +#include + using namespace lpc43xx; namespace ui { @@ -157,11 +161,34 @@ void AboutView::focus() { button_ok.focus(); } +SetTouchCalibView::SetTouchCalibView(NavigationView& nav) { + add_children({{ + &text_title, + &text_debugx, + &text_debugy, + &button_ok + }}); + + button_ok.on_select = [&nav](Button&){ nav.pop(); }; +} + +void SetTouchCalibView::focus() { + button_ok.focus(); +} + +bool SetTouchCalibView::on_touch(const TouchEvent event) { + if (event.type == ui::TouchEvent::Type::Start) { + text_debugx.set(to_string_dec_uint(round(event.rawpoint.x), 4)); + text_debugy.set(to_string_dec_uint(round(event.rawpoint.y), 4)); + } + return true; +} + SetupMenuView::SetupMenuView(NavigationView& nav) { add_items<3>({ { { "Date/Time", [&nav](){ nav.push(new SetDateTimeView { nav }); } }, { "Frequency Correction", [&nav](){ nav.push(new SetFrequencyCorrectionView { nav }); } }, - { "Touch", [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "Touch", [&nav](){ nav.push(new SetTouchCalibView { nav }); } }, } }); on_left = [&nav](){ nav.pop(); }; } diff --git a/firmware/application/ui_setup.hpp b/firmware/application/ui_setup.hpp index b2f975bd..fd8370f7 100644 --- a/firmware/application/ui_setup.hpp +++ b/firmware/application/ui_setup.hpp @@ -209,6 +209,34 @@ private: }; }; +class SetTouchCalibView : public View { +public: + SetTouchCalibView(NavigationView& nav); + void focus() override; + bool on_touch(const TouchEvent event) override; +private: + + Text text_title { + { 64, 32, 40, 16 }, + "UL,UR,DL,DR !", + }; + + Text text_debugx { + { 64, 64, 40, 16 }, + "X", + }; + + Text text_debugy { + { 64, 80, 40, 16 }, + "Y", + }; + + Button button_ok { + { 72, 192, 96, 24 }, + "OK" + }; +}; + class SetupMenuView : public MenuView { public: SetupMenuView(NavigationView& nav); diff --git a/firmware/baseband/baseband_dma.cpp b/firmware/baseband/baseband_dma.cpp index 88bc443e..b6c50cde 100644 --- a/firmware/baseband/baseband_dma.cpp +++ b/firmware/baseband/baseband_dma.cpp @@ -20,6 +20,7 @@ */ #include "baseband_dma.hpp" +#include "portapack_shared_memory.hpp" #include #include @@ -34,6 +35,8 @@ using namespace lpc43xx; namespace baseband { namespace dma { + + int quitt = 0; constexpr uint32_t gpdma_ahb_master_sgpio = 0; constexpr uint32_t gpdma_ahb_master_memory = 1; @@ -105,8 +108,14 @@ static Semaphore semaphore; static volatile const gpdma::channel::LLI* next_lli = nullptr; -static void transfer_complete() { +void test() { + quitt = 1; + chSemSignalI(&semaphore); +} + +void transfer_complete() { next_lli = gpdma_channel_sgpio.next_lli(); + quitt = 0; /* TODO: Is Mailbox the proper synchronization mechanism for this? */ //chMBPostI(&mailbox, 0); chSemSignalI(&semaphore); @@ -162,6 +171,7 @@ baseband::buffer_t wait_for_rx_buffer() { //msg_t msg; //const auto status = chMBFetch(&mailbox, &msg, TIME_INFINITE); const auto status = chSemWait(&semaphore); + if (quitt) return { nullptr, 0 }; if( status == RDY_OK ) { const auto next = next_lli; if( next ) { @@ -176,5 +186,23 @@ baseband::buffer_t wait_for_rx_buffer() { } } +baseband::buffer_t wait_for_tx_buffer() { + //msg_t msg; + //const auto status = chMBFetch(&mailbox, &msg, TIME_INFINITE); + const auto status = chSemWait(&semaphore); + if( status == RDY_OK ) { + const auto next = next_lli; + if( next ) { + const size_t next_index = next - &lli_loop[0]; + const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask; + return { reinterpret_cast(lli_loop[free_index].srcaddr), transfer_samples }; + } else { + return { nullptr, 0 }; + } + } else { + return { nullptr, 0 }; + } +} + } /* namespace dma */ } /* namespace baseband */ diff --git a/firmware/baseband/baseband_dma.hpp b/firmware/baseband/baseband_dma.hpp index cc41a751..683fc08f 100644 --- a/firmware/baseband/baseband_dma.hpp +++ b/firmware/baseband/baseband_dma.hpp @@ -39,12 +39,15 @@ void configure( const baseband::Direction direction ); +void test(); + void enable(const baseband::Direction direction); bool is_enabled(); void disable(); baseband::buffer_t wait_for_rx_buffer(); +baseband::buffer_t wait_for_tx_buffer(); } /* namespace dma */ } /* namespace baseband */ diff --git a/firmware/baseband/main.cpp b/firmware/baseband/main.cpp index eb048ace..4253b003 100755 --- a/firmware/baseband/main.cpp +++ b/firmware/baseband/main.cpp @@ -26,9 +26,9 @@ #include "portapack_shared_memory.hpp" #include "portapack_dma.hpp" - #include "gpdma.hpp" +#include "baseband.hpp" #include "baseband_dma.hpp" #include "event_m4.hpp" @@ -70,6 +70,7 @@ #include #include #include +#include constexpr auto baseband_thread_priority = NORMALPRIO + 20; constexpr auto rssi_thread_priority = NORMALPRIO + 10; @@ -254,7 +255,7 @@ protected: } void fill_audio_buffer(const buffer_s16_t audio) { - auto audio_buffer = audio::dma::tx_empty_buffer();; + auto audio_buffer = audio::dma::tx_empty_buffer(); for(size_t i=0; i= 9) { + s = 0; + if(sample_count >= SAMPLES_PER_BIT) { + cur_bit = (shared_memory.rdsdata[(bit_pos / 26) & 15]>>(25-(bit_pos % 26))) & 1; + prev_output = cur_output; + cur_output = prev_output ^ cur_bit; + + inverting = (cur_output == 1); + + float *src = waveform_biphase; + int idx = in_sample_index; + + for(int j=0; j= SAMPLE_BUFFER_SIZE) idx = 0; + } + + in_sample_index += SAMPLES_PER_BIT; + if (in_sample_index >= SAMPLE_BUFFER_SIZE) in_sample_index -= SAMPLE_BUFFER_SIZE; + + bit_pos++; + sample_count = 0; + } + + sample = sample_buffer[out_sample_index]; + sample_buffer[out_sample_index] = 0; + out_sample_index++; + if (out_sample_index >= SAMPLE_BUFFER_SIZE) out_sample_index = 0; + + switch(mphase) { + case 0: + case 2: sample = 0; break; + case 1: break; + case 3: sample = -sample; break; + } + mphase++; + if (mphase >= 4) mphase = 0; + //sample *= 16; + + sample_count++; + } else { + s++; + } + + frq = sample * 586 * 33; // / 8; + + phase = (phase + frq); + sphase = phase + (256<<16); + + re = sintab[(sphase & 0x03FF0000)>>16]; + im = sintab[(phase & 0x03FF0000)>>16]; + + buffer.p[i] = {(int8_t)re,(int8_t)im}; + } + } + +private: + int bit_pos; + float sample_buffer[SAMPLE_BUFFER_SIZE] = {0}; + float val; + int prev_output = 0; + int cur_output = 0; + int cur_bit = 0; + int sample_count = SAMPLES_PER_BIT; + int inverting = 0; + int phase; + + int in_sample_index = 0; + float sample; + int out_sample_index = SAMPLE_BUFFER_SIZE-1; + int8_t s; + uint32_t sphase, mphase; + int32_t sig, frq, frq_im, rdsc; + int32_t k; +}; + static BasebandProcessor* baseband_processor { nullptr }; static BasebandConfiguration baseband_configuration; +static baseband::Direction direction = baseband::Direction::Transmit; + static WORKING_AREA(baseband_thread_wa, 8192); +/*static __attribute__((noreturn)) msg_t basebandrx_fn(void *arg) { + (void)arg; + chRegSetThreadName("baseband"); + + BasebandStatsCollector stats; + BasebandStatisticsMessage message; + + while(true) { + + } +}*/ + static __attribute__((noreturn)) msg_t baseband_fn(void *arg) { (void)arg; chRegSetThreadName("baseband"); BasebandStatsCollector stats; BasebandStatisticsMessage message; - + while(true) { - // TODO: Place correct sampling rate into buffer returned here: - const auto buffer_tmp = baseband::dma::wait_for_rx_buffer(); - const buffer_c8_t buffer { - buffer_tmp.p, buffer_tmp.count, baseband_configuration.sampling_rate - }; + if (direction == baseband::Direction::Transmit) { + + const auto buffer_tmp = baseband::dma::wait_for_tx_buffer(); + + const buffer_c8_t buffer { + buffer_tmp.p, buffer_tmp.count, baseband_configuration.sampling_rate + }; - if( baseband_processor ) { - baseband_processor->execute(buffer); - } - - stats.process(buffer, - [&message](const BasebandStatistics statistics) { - if( message.is_free() ) { - message.statistics = statistics; - shared_memory.application_queue.push(&message); - } + if( baseband_processor ) { + baseband_processor->execute(buffer); } - ); + + stats.process(buffer, + [&message](const BasebandStatistics statistics) { + if( message.is_free() ) { + message.statistics = statistics; + shared_memory.application_queue.push(&message); + } + } + ); + } else if (direction == baseband::Direction::Receive) { + // TODO: Place correct sampling rate into buffer returned here: + const auto buffer_tmp = baseband::dma::wait_for_rx_buffer(); + + const buffer_c8_t buffer { + buffer_tmp.p, buffer_tmp.count, baseband_configuration.sampling_rate + }; + + if( baseband_processor ) { + baseband_processor->execute(buffer); + } + + stats.process(buffer, + [&message](const BasebandStatistics statistics) { + if( message.is_free() ) { + message.statistics = statistics; + shared_memory.application_queue.push(&message); + } + } + ); + } } } @@ -690,7 +827,7 @@ static void init() { baseband_thread_priority, baseband_fn, nullptr ); - + chThdCreateStatic(rssi_thread_wa, sizeof(rssi_thread_wa), rssi_thread_priority, rssi_fn, nullptr @@ -784,7 +921,7 @@ CH_IRQ_HANDLER(MAPP_IRQHandler) { } -static constexpr auto direction = baseband::Direction::Receive; +std::array baseband_buffer; int main(void) { init(); @@ -794,6 +931,8 @@ int main(void) { EventDispatcher event_dispatcher; auto& message_handlers = event_dispatcher.message_handlers(); + + //const auto baseband_buffer = new std::array(); message_handlers[Message::ID::BasebandConfiguration] = [&message_handlers](const Message* const p) { auto message = reinterpret_cast(p); @@ -805,21 +944,30 @@ int main(void) { delete old_p; switch(message->configuration.mode) { - case 0: + case 1: + direction = baseband::Direction::Receive; baseband_processor = new NarrowbandAMAudio(); break; - case 1: + case 2: + direction = baseband::Direction::Receive; baseband_processor = new NarrowbandFMAudio(); break; - case 2: + case 3: + direction = baseband::Direction::Receive; baseband_processor = new WidebandFMAudio(); break; - case 3: + case 4: + direction = baseband::Direction::Receive; baseband_processor = new FSKProcessor(message_handlers); break; + + case 15: + direction = baseband::Direction::Transmit; + baseband_processor = new RDSProcessor(); + break; default: break; @@ -835,26 +983,29 @@ int main(void) { rf::rssi::stop(); } } + + baseband::dma::configure( + baseband_buffer.data(), + direction + ); baseband_configuration = message->configuration; }; /* TODO: Ensure DMAs are configured to point at first LLI in chain. */ - if( direction == baseband::Direction::Receive ) { + //if( direction == baseband::Direction::Receive ) { rf::rssi::dma::allocate(4, 400); - } + //} touch::dma::allocate(); touch::dma::enable(); - const auto baseband_buffer = - new std::array(); baseband::dma::configure( - baseband_buffer->data(), + baseband_buffer.data(), direction ); - //baseband::dma::allocate(4, 2048); + //baseband::dma::allocate(4, 2048);d while(true) { const auto events = event_dispatcher.wait(); diff --git a/firmware/common/baseband.hpp b/firmware/common/baseband.hpp index 50ce8da7..6bd9c85f 100644 --- a/firmware/common/baseband.hpp +++ b/firmware/common/baseband.hpp @@ -36,6 +36,7 @@ enum class Direction { }; buffer_t wait_for_rx_buffer(); +buffer_t wait_for_tx_buffer(); } /* namespace baseband */ diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index 96b3da0d..a470d417 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -28,6 +28,8 @@ using namespace portapack; #include "ch.h" +#include + namespace lcd { namespace { @@ -239,6 +241,25 @@ void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) { } } +void ILI9341::draw_line(const ui::Point start, const ui::Point end, const ui::Color color) { + int x0 = start.x; + int y0 = start.y; + int x1 = end.x; + int y1 = end.y; + + int dx = std::abs(x1-x0), sx = x0dy ? dx : -dy)/2, e2; + + for(;;){ + draw_pixel({static_cast(x0), static_cast(y0)}, color); + if (x0==x1 && y0==y1) break; + e2 = err; + if (e2 >-dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } +} + void ILI9341::fill_circle( const ui::Point center, const ui::Dim radius, diff --git a/firmware/common/lcd_ili9341.hpp b/firmware/common/lcd_ili9341.hpp index 2a0d6cd6..415dbd53 100644 --- a/firmware/common/lcd_ili9341.hpp +++ b/firmware/common/lcd_ili9341.hpp @@ -45,6 +45,7 @@ public: void shutdown(); void fill_rectangle(ui::Rect r, const ui::Color c); + void draw_line(const ui::Point start, const ui::Point end, const ui::Color color); void fill_circle( const ui::Point center, const ui::Dim radius, diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 5a39927f..2910f80e 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -164,6 +164,15 @@ public: AudioStatistics statistics; }; +/*enum bbmode { + RxNBAM = 1, + RxNBFM = 2, + RxWBFM = 3, + RxFSK = 4, + TxRDS = 15, + BBOff = 255 +};*/ + struct BasebandConfiguration { int32_t mode; uint32_t sampling_rate; diff --git a/firmware/common/portapack_shared_memory.hpp b/firmware/common/portapack_shared_memory.hpp index c4ae6aab..f222e5cd 100644 --- a/firmware/common/portapack_shared_memory.hpp +++ b/firmware/common/portapack_shared_memory.hpp @@ -38,6 +38,10 @@ struct SharedMemory { // TODO: M0 should directly configure and control DMA channel that is // acquiring ADC samples. TouchADCFrame touch_adc_frame; + + int test; + + uint32_t rdsdata[16]; }; extern SharedMemory& shared_memory; diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index 554b1f36..dc738aec 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -282,6 +282,7 @@ struct TouchEvent { Point point; Type type; + Point rawpoint; }; } /* namespace ui */ diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 866735ba..83b7e705 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -356,14 +356,23 @@ void Button::set_text(const std::string value) { set_dirty(); } +void Button::set_style(const Style* new_style) { + if( new_style != style_ ) { + style_ = new_style; + set_dirty(); + } +} + std::string Button::text() const { return text_; } void Button::paint(Painter& painter) { const auto r = screen_rect(); + + if (style_ == nullptr) style_ = &style(); - const auto paint_style = (has_focus() || flags.highlighted) ? style().invert() : style(); + const auto paint_style = (has_focus() || flags.highlighted) ? style_->invert() : *(style_); painter.draw_rectangle(r, style().foreground); diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 797083cf..c5293cdb 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -228,6 +228,7 @@ public: } void set_text(const std::string value); + void set_style(const Style* new_style); std::string text() const; void paint(Painter& painter) override; @@ -237,6 +238,7 @@ public: private: std::string text_; + const Style* style_ { nullptr }; }; class OptionsField : public Widget {