diff --git a/firmware/application/Makefile b/firmware/application/Makefile index cb5693f6..f896b1f7 100755 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -156,6 +156,7 @@ CPPSRC = main.cpp \ ui_focus.cpp \ ui_navigation.cpp \ ui_menu.cpp \ + ui_about.cpp \ ui_rssi.cpp \ ui_channel.cpp \ ui_audio.cpp \ diff --git a/firmware/application/m4_startup.cpp b/firmware/application/m4_startup.cpp index 0e493f1b..69345414 100644 --- a/firmware/application/m4_startup.cpp +++ b/firmware/application/m4_startup.cpp @@ -52,7 +52,8 @@ void m4_init(const portapack::spi_flash::region_t from, const portapack::memory: } int m4_load_image(void) { - uint32_t mod_size; + const char magic[6] = {'P', 'P', 'M', ' ', 0x01, 0x00}; + //uint32_t mod_size; UINT bw; uint8_t i; uint16_t cnt; @@ -62,28 +63,36 @@ int m4_load_image(void) { DIR rootdir; FRESULT res; - // Scan SD card root directory for files with the right md5 fingerprint at the right location + // Scan SD card root directory for files with the right MD5 fingerprint at the right location f_opendir(&rootdir, "/"); for (;;) { res = f_readdir(&rootdir, &modinfo); - if (res != FR_OK || modinfo.fname[0] == 0) break; - if (!(modinfo.fattrib & AM_DIR)) { + if (res != FR_OK || modinfo.fname[0] == 0) break; // Reached last file, abort + // Only care about files with .bin extension + if ((!(modinfo.fattrib & AM_DIR)) && (modinfo.fname[9] == 'B') && (modinfo.fname[10] == 'I') && (modinfo.fname[11] == 'N')) { f_open(&modfile, modinfo.fname, FA_OPEN_EXISTING | FA_READ); - f_lseek(&modfile, 26); - f_read(&modfile, &md5sum, 16, &bw); - for (i = 0; i < 16; i++) { - if (md5sum[i] != modhash[i]) break; + // Magic bytes and version check + f_read(&modfile, &md5sum, 6, &bw); + for (i = 0; i < 6; i++) { + if (md5sum[i] != magic[i]) break; } - if (i == 16) { - f_lseek(&modfile, 6); - f_read(&modfile, &mod_size, 4, &bw); - f_lseek(&modfile, 256); - // For some reason, f_read > 512 bytes at once crashes everything... :/ - for (cnt=0;cnt<256;cnt++) - f_read(&modfile, reinterpret_cast(portapack::memory::map::m4_code.base()+(cnt*256)), 256, &bw); - f_close(&modfile); - LPC_RGU->RESET_CTRL[0] = (1 << 13); - return 1; + if (i == 6) { + f_lseek(&modfile, 26); + f_read(&modfile, &md5sum, 16, &bw); + for (i = 0; i < 16; i++) { + if (md5sum[i] != modhash[i]) break; + } + if (i == 16) { + //f_lseek(&modfile, 6); + //f_read(&modfile, &mod_size, 4, &bw); + f_lseek(&modfile, 256); + // For some reason, f_read > 512 bytes at once crashes everything... :/ + for (cnt=0;cnt<256;cnt++) + f_read(&modfile, reinterpret_cast(portapack::memory::map::m4_code.base()+(cnt*256)), 256, &bw); + f_close(&modfile); + LPC_RGU->RESET_CTRL[0] = (1 << 13); + return 1; + } } f_close(&modfile); } @@ -95,7 +104,7 @@ int m4_load_image(void) { void m4_switch(const char * hash) { modhash = const_cast(hash); - // Ask M4 to enter loop in RAM + // Ask M4 to enter wait loop in RAM BasebandConfiguration baseband_switch { .mode = SWITCH, .sampling_rate = 0, diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index ab6d387f..37e65745 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -19,11 +19,13 @@ * Boston, MA 02110-1301, USA. */ -//TODO: Enum modulation modes (baseband) +//TODO: Playdead amnesia and login +//TODO: Touch screen calibration +//TODO: Display module info (name, desc) somewhere +//TODO: Show MD5 mismatches for modules not found, etc... //TODO: More gfx, cute icons :) //TODO: check jammer bandwidths //TODO: GSM channel detector -//TODO: wait_for_switch() in baseband-tx ! //TODO: AFSK receiver //TODO: SIGFOX RX/TX //TODO: Reset baseband if module not found (instead of lockup in RAM loop) @@ -32,7 +34,6 @@ //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) //TODO: Bodet :) //TODO: Whistler //TODO: Setup: Play dead by default ? Enable/disable ? @@ -51,7 +52,10 @@ using namespace lpc43xx; #include "portapack.hpp" +#include "portapack_io.hpp" #include "portapack_shared_memory.hpp" +#include "portapack_persistent_memory.hpp" +using namespace portapack; #include "cpld_update.hpp" @@ -160,7 +164,17 @@ private: } void handle_rtc_tick() { + uint16_t bloff_time; const auto sd_card_present_now = sdc_lld_is_card_inserted(&SDCD1); + + bloff_time = portapack::persistent_memory::ui_config_bloff(); + if (bloff_time) { + if (portapack::bl_tick_counter >= bloff_time) + io.lcd_backlight(0); + else + portapack::bl_tick_counter++; + } + if( sd_card_present_now != sd_card_present ) { sd_card_present = sd_card_present_now; @@ -234,6 +248,10 @@ private: void handle_switches() { const auto switches_state = get_switches_state(); + + io.lcd_backlight(1); + portapack::bl_tick_counter = 0; + for(size_t i=0; i(encoder_now - encoder_last); + + io.lcd_backlight(1); + portapack::bl_tick_counter = 0; + encoder_last = encoder_now; const auto event = static_cast(delta); event_bubble_encoder(event); diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index 99d23e44..73c905cf 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -70,6 +70,8 @@ TransmitterModel transmitter_model { clock_manager }; +uint8_t bl_tick_counter = 0; + class Power { public: void init() { diff --git a/firmware/application/portapack.hpp b/firmware/application/portapack.hpp index 38593afc..676b86b2 100644 --- a/firmware/application/portapack.hpp +++ b/firmware/application/portapack.hpp @@ -44,6 +44,8 @@ extern wolfson::wm8731::WM8731 audio_codec; extern ReceiverModel receiver_model; extern TransmitterModel transmitter_model; +extern uint8_t bl_tick_counter; + void init(); void shutdown(); diff --git a/firmware/application/ui_about.cpp b/firmware/application/ui_about.cpp new file mode 100644 index 00000000..9d637c09 --- /dev/null +++ b/firmware/application/ui_about.cpp @@ -0,0 +1,71 @@ +/* + * 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_about.hpp" +#include "touch.hpp" + +#include "portapack_persistent_memory.hpp" +#include "lpc43xx_cpp.hpp" + +#include +#include + +using namespace lpc43xx; +using namespace portapack; + +namespace ui { + +/*static AboutView::update() { + uint8_t c; + uint16_t raster_color; + + for (c=0; c<=200; c++) { + raster_color = copper_buffer[c]; + if (raster_color) painter.fill_rectangle({ { 0, (c+32) }, { 240, 1 } }, { (raster_color >> 4) & 0xF0, raster_color & 0xF0, (raster_color << 4) & 0xF0 }); + } + + for (c=0; c<=200; c++) + copper_buffer[c] = 0; + + for (c=0; c<=200; c++) { + copper_buffer[c] = (c | (c << 4)) + phase; + } + + phase++; +}*/ + +AboutView::AboutView(NavigationView& nav) { + add_children({ { + &text_title, + &text_firmware, + &text_cpld_hackrf, + &text_cpld_portapack, + &button_ok, + } }); + + button_ok.on_select = [this,&nav](Button&){ nav.pop(); }; +} + +void AboutView::focus() { + button_ok.focus(); +} + +} /* namespace ui */ diff --git a/firmware/application/ui_about.hpp b/firmware/application/ui_about.hpp new file mode 100644 index 00000000..24927217 --- /dev/null +++ b/firmware/application/ui_about.hpp @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef __UI_ABOUT_H__ +#define __UI_ABOUT_H__ + +#include "ui_widget.hpp" +#include "ui_menu.hpp" +#include "ui_navigation.hpp" + +#include + +namespace ui { + +class AboutView : public View { +public: + AboutView(NavigationView& nav); + void focus() override; + +private: + /*bool drawn; + uint16_t phase = 0; + uint16_t copper_buffer[256]; + void update(void);*/ + + Text text_title { + { 100, 96, 40, 16 }, + "About", + }; + + Text text_firmware { + { 0, 128, 240, 16 }, + "Git Commit hash " GIT_REVISION, + }; + + Text text_cpld_hackrf { + { 0, 144, 240, 16 }, + "HackRF CPLD CRC 0x????????", + }; + + Text text_cpld_portapack { + { 0, 160, 240, 16 }, + "PortaPack CPLD CRC 0x????????", + }; + + Button button_ok { + { 72, 192, 96, 24 }, + "OK" + }; +}; + +} /* namespace ui */ + +#endif/*__UI_ABOUT_H__*/ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 35021536..73b3dccb 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -28,6 +28,7 @@ #include "splash.hpp" +#include "ui_about.hpp" #include "ui_setup.hpp" #include "ui_debug.hpp" #include "ui_receiver.hpp" @@ -169,7 +170,10 @@ SystemView::SystemView( //else // navigation_view.push(new BMPView { navigation_view }); + if (portapack::persistent_memory::ui_config() & 1) navigation_view.push(new BMPView { navigation_view }); + else + navigation_view.push(new SystemMenuView { navigation_view }); } Context& SystemView::context() const { diff --git a/firmware/application/ui_setup.cpp b/firmware/application/ui_setup.cpp index bddb04f8..91cd1fb3 100644 --- a/firmware/application/ui_setup.cpp +++ b/firmware/application/ui_setup.cpp @@ -147,22 +147,6 @@ SetFrequencyCorrectionModel SetFrequencyCorrectionView::form_collect() { }; } -AboutView::AboutView(NavigationView& nav) { - add_children({ { - &text_title, - &text_firmware, - &text_cpld_hackrf, - &text_cpld_portapack, - &button_ok, - } }); - - button_ok.on_select = [&nav](Button&){ nav.pop(); }; -} - -void AboutView::focus() { - button_ok.focus(); -} - SetTouchCalibView::SetTouchCalibView(NavigationView& nav) { add_children({{ &text_title, @@ -230,12 +214,45 @@ void SetPlayDeadView::focus() { button_enter.focus(); } +SetUIView::SetUIView(NavigationView& nav) { + uint32_t ui_config; + + add_children({{ + &checkbox_showsplash, + &checkbox_bloff, + &options_bloff, + &button_ok + }}); + + ui_config = portapack::persistent_memory::ui_config(); + + if (ui_config & 1) checkbox_showsplash.set_value(true); + if (ui_config & 2) checkbox_bloff.set_value(true); + options_bloff.set_selected_index((ui_config >> 5) & 7); + + button_ok.on_select = [&nav,this](Button&){ + uint32_t ui_config = 0; + if (checkbox_showsplash.value() == true) ui_config |= 1; + if (checkbox_bloff.value() == true) ui_config |= 2; + + ui_config |= (options_bloff.selected_index() << 5); + + portapack::persistent_memory::set_ui_config(ui_config); + nav.pop(); + }; +} + +void SetUIView::focus() { + button_ok.focus(); +} + SetupMenuView::SetupMenuView(NavigationView& nav) { - add_items<4>({ { + add_items<5>({ { { "Date/Time", ui::Color::white(), [&nav](){ nav.push(new SetDateTimeView { nav }); } }, { "Frequency correction", ui::Color::white(), [&nav](){ nav.push(new SetFrequencyCorrectionView { nav }); } }, - { "Touch", ui::Color::white(), [&nav](){ nav.push(new SetTouchCalibView { nav }); } }, - { "Play dead", ui::Color::white(), [&nav](){ nav.push(new SetPlayDeadView { nav }); } }, + { "Touch screen", ui::Color::white(), [&nav](){ nav.push(new SetTouchCalibView { nav }); } }, + { "Play dead", ui::Color::red(), [&nav](){ nav.push(new SetPlayDeadView { nav }); } }, + { "UI", ui::Color::white(), [&nav](){ nav.push(new SetUIView { nav }); } }, } }); on_left = [&nav](){ nav.pop(); }; } diff --git a/firmware/application/ui_setup.hpp b/firmware/application/ui_setup.hpp index 4c482824..b5647b8c 100644 --- a/firmware/application/ui_setup.hpp +++ b/firmware/application/ui_setup.hpp @@ -176,44 +176,12 @@ private: SetFrequencyCorrectionModel form_collect(); }; -class AboutView : public View { -public: - AboutView(NavigationView& nav); - - void focus() override; - -private: - Text text_title { - { 100, 96, 40, 16 }, - "About", - }; - - Text text_firmware { - { 0, 128, 240, 16 }, - "Git Commit Hash " GIT_REVISION, - }; - - Text text_cpld_hackrf { - { 0, 144, 240, 16 }, - "HackRF CPLD CRC 0x????????", - }; - - Text text_cpld_portapack { - { 0, 160, 240, 16 }, - "PortaPack CPLD CRC 0x????????", - }; - - Button button_ok { - { 72, 192, 96, 24 }, - "OK" - }; -}; - class SetTouchCalibView : public View { public: SetTouchCalibView(NavigationView& nav); void focus() override; bool on_touch(const TouchEvent event) override; + private: Text text_title { @@ -237,6 +205,40 @@ private: }; }; +class SetUIView : public View { +public: + SetUIView(NavigationView& nav); + void focus() override; + +private: + Checkbox checkbox_showsplash { + { 3 * 8, 2 * 16}, + "Show splash" + }; + + Checkbox checkbox_bloff { + { 3 * 8, 4 * 16}, + "Backlight off after:" + }; + + OptionsField options_bloff { + { 10 * 8, 5 * 16 + 4 }, + 5, + { + { "5 seconds ", 0 }, + { "15 seconds", 1 }, + { "1 minute ", 2 }, + { "5 minutes ", 3 }, + { "10 minutes", 4 } + } + }; + + Button button_ok { + { 4 * 8, 272, 64, 24 }, + "Ok" + }; +}; + class SetPlayDeadView : public View { public: SetPlayDeadView(NavigationView& nav); diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 554894c1..772538fc 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -84,6 +84,8 @@ struct data_t { // Play dead unlock uint32_t playing_dead; uint32_t playdead_sequence; + + int32_t ui_config; }; static_assert(sizeof(data_t) <= 0x100, "Persistent memory structure too large for VBAT-maintained region"); @@ -168,5 +170,34 @@ void set_playdead_sequence(const uint32_t new_value) { data->playdead_sequence = new_value; } +uint32_t ui_config() { + uint8_t bloff_value; + + // Cap value + bloff_value = (data->ui_config >> 5) & 7; + if (bloff_value > 4) bloff_value = 1; + + data->ui_config = (data->ui_config & 0x1F) | (bloff_value << 5); + + return data->ui_config; +} + +uint16_t ui_config_bloff() { + uint8_t bloff_value; + uint16_t bloff_seconds[5] = { 5, 15, 60, 300, 600 }; + + if (!(data->ui_config & 2)) return 0; + + // Cap value + bloff_value = (data->ui_config >> 5) & 7; + if (bloff_value > 4) bloff_value = 1; + + return bloff_seconds[bloff_value]; +} + +void set_ui_config(const uint32_t new_value) { + data->ui_config = new_value; +} + } /* namespace persistent_memory */ } /* namespace portapack */ diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 8b8da966..294d9ebe 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -58,6 +58,10 @@ void set_playing_dead(const uint32_t new_value); uint32_t playdead_sequence(); void set_playdead_sequence(const uint32_t new_value); +uint32_t ui_config(); +void set_ui_config(const uint32_t new_value); +uint16_t ui_config_bloff(); + } /* namespace persistent_memory */ } /* namespace portapack */ diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index 69c06fdf..0b14b807 100644 Binary files a/firmware/portapack-h1-firmware.bin and b/firmware/portapack-h1-firmware.bin differ