diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..75e81adb --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "hackrf"] + path = hackrf + url = https://github.com/jboone/hackrf.git diff --git a/.travis.yml b/.travis.yml index 752fe767..83900662 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,16 @@ matrix: cache: apt dist: xenial +env: + global: + - PROJECT_NAME=PortaPack-HAVOC + - SHORT_COMMIT_HASH=`git rev-parse --short HEAD` + - VERSION_STRING=nightly-$SHORT_COMMIT_HASH + - BUILD_DATE="`date +%Y-%m-%d`" + - BUILD_NAME="$PROJECT_NAME-$BUILD_DATE-$SHORT_COMMIT_HASH" + - ARTEFACT_BASE=$TRAVIS_BUILD_DIR/artefacts/ + - ARTEFACT_PATH=$ARTEFACT_BASE/$BUILD_NAME + notifications: irc: channels: @@ -16,7 +26,7 @@ notifications: - "Change view : %{compare_url}" - "Build details : %{build_url}" # TODO: The "build_number.1" in this URL is almost certainly wrong, but correct value not available from Travis? - - "Firmware download : https://portapack-h1-builds.s3.amazonaws.com/%{repository_slug}/%{build_number}/%{build_number}.1/build/firmware/portapack-h1-firmware-%{commit}.tar.bz2" + - "Firmware download : https://jboone.github.io/portapack-havoc-nightly/" before_install: - sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa -y @@ -25,17 +35,39 @@ before_install: script: # TODO: Introduce top-level Makefile, this is lame. + - sed -e "s/\#set(VERSION.*/set(VERSION \"$VERSION_STRING\")/" -i".bak" CMakeLists.txt - mkdir build/ - pushd build/ - cmake .. - - make release + - make firmware - popd +after_success: + - mkdir -p $ARTEFACT_PATH + # Copy firmware to firmware-bin directory + - cd $TRAVIS_BUILD_DIR/build + - cp firmware/portapack-h1-havoc.bin $ARTEFACT_PATH/ + - cp hackrf/firmware/hackrf_usb/hackrf_usb.dfu $ARTEFACT_PATH/ + - cd $TRAVIS_BUILD_DIR + - cp LICENSE $ARTEFACT_PATH/ + # Build the archive + - cd $ARTEFACT_BASE + - tar -cJvf $ARTEFACT_BASE/$BUILD_NAME.tar.xz $BUILD_NAME + - md5sum --binary $BUILD_NAME.tar.xz >MD5SUMS + - sha256sum --binary $BUILD_NAME.tar.xz >SHA256SUMS + addons: apt: packages: + - coreutils + - tar + - sed + - cmake - dfu-util - artifacts: - paths: - - $(ls build/firmware/portapack-h1-havoc-*.tar.bz2 | tr "\n" ":") - - $(ls build/firmware/portapack-h1-havoc-*.zip | tr "\n" ":") + +deploy: + provider: script + skip-cleanup: true + script: bash $TRAVIS_BUILD_DIR/tools/deploy-nightly.sh + on: + branch: master diff --git a/CMakeLists.txt b/CMakeLists.txt index ac13907e..cf8b5706 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,21 +25,37 @@ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/firmware/toolchain-arm-cortex project(portapack-h1) -execute_process( - COMMAND git log -n 1 --format=%h - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} - RESULT_VARIABLE GIT_REVISION_FOUND - ERROR_QUIET - OUTPUT_VARIABLE GIT_REVISION - OUTPUT_STRIP_TRAILING_WHITESPACE -) -if (GIT_REVISION_FOUND) - set(VERSION "unknown") -else (GIT_REVISION_FOUND) - set(VERSION ${GIT_REVISION}) -endif (GIT_REVISION_FOUND) +#set(VERSION "") +if (NOT DEFINED VERSION) + execute_process( + COMMAND git log -n 1 --format=%h + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + RESULT_VARIABLE GIT_VERSION_FOUND + ERROR_QUIET + OUTPUT_VARIABLE GIT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (GIT_VERSION_FOUND) + set(VERSION "unknown") + else (GIT_VERSION_FOUND) + set(VERSION "local-${GIT_VERSION}") + endif (GIT_VERSION_FOUND) +endif() set(LICENSE_PATH ${CMAKE_CURRENT_LIST_DIR}/LICENSE) set(HARDWARE_PATH ${CMAKE_CURRENT_LIST_DIR}/hardware) +add_subdirectory(hackrf/firmware/hackrf_usb) + +set(HACKRF_FIRMWARE_DFU_FILENAME hackrf_usb.dfu) +set(HACKRF_FIRMWARE_BIN_FILENAME hackrf_usb_ram.bin) +set(HACKRF_CPLD_XSVF_FILENAME default.xsvf) + +set(HACKRF_PATH ${CMAKE_CURRENT_LIST_DIR}/hackrf) +set(HACKRF_CPLD_TOOL ${HACKRF_PATH}/firmware/tools/cpld_bitstream.py) +set(HACKRF_CPLD_XSVF_PATH ${HACKRF_PATH}/firmware/cpld/sgpio_if/${HACKRF_CPLD_XSVF_FILENAME}) + +set(HACKRF_FIRMWARE_DFU_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_DFU_FILENAME}) +set(HACKRF_FIRMWARE_BIN_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_BIN_FILENAME}) + add_subdirectory(firmware) diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index bcfd9ed2..fc36b090 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -26,37 +26,12 @@ set(CHIBIOS ${PROJECT_SOURCE_DIR}/chibios) set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack) set(EXTRACT_CPLD_DATA ${PROJECT_SOURCE_DIR}/tools/extract_cpld_data.py) -set(STRIP_DFU ${PROJECT_SOURCE_DIR}/tools/strip_dfu.py) set(MAKE_SPI_IMAGE ${PROJECT_SOURCE_DIR}/tools/make_spi_image.py) set(MAKE_IMAGE_CHUNK ${PROJECT_SOURCE_DIR}/tools/make_image_chunk.py) set(FIRMWARE_NAME portapack-h1-havoc) set(FIRMWARE_FILENAME ${FIRMWARE_NAME}.bin) -include(ExternalProject) -find_program(MAKE_EXE NAMES gmake nmake make) -ExternalProject_Add(hackrf - GIT_REPOSITORY https://github.com/jboone/hackrf.git - # SOURCE_SUBDIR firmware - # SOURCE_SUBDIR isn't available in CMake 3.5 (Ubuntu 16.04 LTS), so the following is a work-around: - CONFIGURE_COMMAND ${CMAKE_COMMAND} "-GUnix Makefiles" ../hackrf/firmware - BUILD_COMMAND ${MAKE_EXE} hackrf_usb.dfu - INSTALL_COMMAND "" -) -ExternalProject_Get_Property(hackrf SOURCE_DIR) -ExternalProject_Get_Property(hackrf BINARY_DIR) -set(hackrf_SOURCE_DIR ${SOURCE_DIR}) -set(hackrf_BINARY_DIR ${BINARY_DIR}) - -set(HACKRF_FIRMWARE_DFU_FILENAME hackrf_usb.dfu) -set(HACKRF_FIRMWARE_BIN_FILENAME hackrf_usb.bin) - -set(HACKRF_FIRMWARE_DFU_IMAGE ${hackrf_BINARY_DIR}/hackrf_usb/${HACKRF_FIRMWARE_DFU_FILENAME}) -set(HACKRF_FIRMWARE_BIN_IMAGE ${hackrf_BINARY_DIR}/hackrf_usb/${HACKRF_FIRMWARE_BIN_FILENAME}) -set(HACKRF_CPLD_TOOL ${hackrf_SOURCE_DIR}/firmware/tools/cpld_bitstream.py) -set(HACKRF_CPLD_XSVF_FILENAME default.xsvf) -set(HACKRF_CPLD_XSVF_PATH ${hackrf_SOURCE_DIR}/firmware/cpld/sgpio_if/${HACKRF_CPLD_XSVF_FILENAME}) - add_subdirectory(application) add_subdirectory(baseband) @@ -70,8 +45,8 @@ add_custom_command( ) add_custom_target( - firmware - DEPENDS ${FIRMWARE_FILENAME} + firmware ALL + DEPENDS ${FIRMWARE_FILENAME} ${HACKRF_FIRMWARE_DFU_FILENAME} ) add_custom_target( @@ -79,22 +54,29 @@ add_custom_target( COMMAND dfu-util --device 1fc9:000c --download ${HACKRF_FIRMWARE_DFU_IMAGE} COMMAND sleep 3s COMMAND hackrf_spiflash -w ${FIRMWARE_FILENAME} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FIRMWARE_FILENAME} + DEPENDS ${FIRMWARE_FILENAME} ) # TODO: Bad hack to fix location of LICENSE file for tar. add_custom_command( - OUTPUT ${FIRMWARE_NAME}-${GIT_REVISION}.tar.bz2 ${FIRMWARE_NAME}-${GIT_REVISION}.zip + OUTPUT ${FIRMWARE_NAME}-${VERSION}.tar.bz2 ${FIRMWARE_NAME}-${VERSION}.zip COMMAND cp ${LICENSE_PATH} LICENSE COMMAND cp ${HACKRF_FIRMWARE_DFU_IMAGE} ${HACKRF_FIRMWARE_DFU_FILENAME} - COMMAND tar -c -j -f ${FIRMWARE_NAME}-${GIT_REVISION}.tar.bz2 ${FIRMWARE_FILENAME} ${HACKRF_FIRMWARE_DFU_FILENAME} LICENSE - COMMAND zip -9 -q ${FIRMWARE_NAME}-${GIT_REVISION}.zip ${FIRMWARE_FILENAME} ${HACKRF_FIRMWARE_DFU_FILENAME} LICENSE + COMMAND tar -c -j -f ${FIRMWARE_NAME}-${VERSION}.tar.bz2 ${FIRMWARE_FILENAME} ${HACKRF_FIRMWARE_DFU_FILENAME} LICENSE + COMMAND zip -9 -q ${FIRMWARE_NAME}-${VERSION}.zip ${FIRMWARE_FILENAME} ${HACKRF_FIRMWARE_DFU_FILENAME} LICENSE COMMAND rm -f LICENSE ${HACKRF_FIRMWARE_DFU_FILENAME} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FIRMWARE_FILENAME} ${LICENSE_PATH} ${HACKRF_FIRMWARE_DFU_IMAGE} + DEPENDS ${FIRMWARE_FILENAME} ${LICENSE_PATH} ${HACKRF_FIRMWARE_DFU_FILENAME} VERBATIM ) +add_custom_command( + OUTPUT MD5SUMS SHA256SUMS + COMMAND md5sum --binary ${FIRMWARE_NAME}-${VERSION}.tar.bz2 ${FIRMWARE_NAME}-${VERSION}.zip >MD5SUMS + COMMAND sha256sum --binary ${FIRMWARE_NAME}-${VERSION}.tar.bz2 ${FIRMWARE_NAME}-${VERSION}.zip >SHA256SUMS + DEPENDS ${FIRMWARE_NAME}-${VERSION}.tar.bz2 ${FIRMWARE_NAME}-${VERSION}.zip +) + add_custom_target( release - DEPENDS ${FIRMWARE_NAME}-${GIT_REVISION}.tar.bz2 ${FIRMWARE_NAME}-${GIT_REVISION}.zip + DEPENDS MD5SUMS SHA256SUMS ) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index a2c74450..91fec2fa 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -206,6 +206,7 @@ set(CPPSRC ui/ui_font_fixed_8x16.cpp ui/ui_geomap.cpp ui/ui_menu.cpp + ui/ui_btngrid.cpp ui/ui_receiver.cpp ui/ui_rssi.cpp ui/ui_spectrum.cpp @@ -346,8 +347,7 @@ set(CPPWARN "-Wall -Wextra -Wno-psabi") # List all default C defines here, like -D_DEBUG=1 # TODO: Switch -DCRT0_INIT_DATA depending on load from RAM or SPIFI? # NOTE: _RANDOM_TCC to kill a GCC 4.9.3 error with std::max argument types - -set(DDEFS -DLPC43XX -DLPC43XX_M0 -D__NEWLIB__ -DHACKRF_ONE -DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0 -DGIT_REVISION=\"${GIT_REVISION}\") +set(DDEFS "-DLPC43XX -DLPC43XX_M0 -D__NEWLIB__ -DHACKRF_ONE -DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0 -D'VERSION_STRING=\"${VERSION}\"'") # List all default ASM defines here, like -D_DEBUG=1 set(DADEFS) @@ -408,7 +408,7 @@ add_custom_command( add_custom_command( OUTPUT ${HACKRF_CPLD_DATA_CPP} COMMAND ${HACKRF_CPLD_TOOL} --xsvf ${HACKRF_CPLD_XSVF_PATH} --portapack-data ${HACKRF_CPLD_DATA_CPP} - DEPENDS ${HACKRF_CPLD_TOOL} ${HACKRF_CPLD_XSVF_PATH} hackrf + DEPENDS ${HACKRF_CPLD_TOOL} ${HACKRF_CPLD_XSVF_PATH} ) add_executable(${PROJECT_NAME}.elf ${CSRC} ${CPPSRC} ${ASMSRC}) diff --git a/firmware/application/apps/ui_about.hpp b/firmware/application/apps/ui_about.hpp index fd8a1cbc..02987f7a 100644 --- a/firmware/application/apps/ui_about.hpp +++ b/firmware/application/apps/ui_about.hpp @@ -75,7 +75,7 @@ private: const credits_t credits[25] = { // 012345678901234567890123456789 { 60, "PortaPack|HAVOC", 0 }, - { 7 * 8, "Git hash " GIT_REVISION, 16 }, + { 4 * 8, "Version " VERSION_STRING, 16 }, { 11 * 8, "Gurus J. Boone", 0 }, { 18 * 8, "M. Ossmann", 16 }, { 11 * 8, "HAVOC Furrtek", 16 }, diff --git a/firmware/application/apps/ui_about_demo.hpp b/firmware/application/apps/ui_about_demo.hpp index 080c6195..1292b789 100644 --- a/firmware/application/apps/ui_about_demo.hpp +++ b/firmware/application/apps/ui_about_demo.hpp @@ -131,7 +131,7 @@ private: Text text_firmware { { 0, 236, 240, 16 }, - "Git Commit Hash " GIT_REVISION, + "Version " VERSION_STRING, }; Text text_cpld_hackrf { diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index 1813eb81..9d14f7a7 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -29,6 +29,8 @@ using namespace portapack; namespace ui { +static int32_t last_category_id { 0 }; + FreqManBaseView::FreqManBaseView( NavigationView& nav ) : nav_ (nav) @@ -80,7 +82,7 @@ void FreqManBaseView::populate_categories() { }); options_category.set_options(categories); - options_category.set_selected_index(0); + options_category.set_selected_index(last_category_id); options_category.on_change = [this](size_t category_id, int32_t) { if (on_change_category) @@ -92,7 +94,7 @@ void FreqManBaseView::change_category(int32_t category_id) { if (!file_list.size()) return; - current_category_id = category_id; + last_category_id = current_category_id = category_id; if (!load_freqman_file(file_list[categories[current_category_id].second], database)) error_ = ERROR_ACCESS; @@ -219,7 +221,7 @@ FrequencyLoadView::FrequencyLoadView( nav.pop(); }; - change_category(0); + change_category(last_category_id); refresh_list(); on_select_frequency = [&nav, this]() { @@ -308,7 +310,7 @@ FrequencyManagerView::FrequencyManagerView( nav.pop(); }; - change_category(0); + change_category(last_category_id); refresh_list(); on_select_frequency = [this]() { diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index 5f854ef3..02b36370 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -78,7 +78,9 @@ void ScannerThread::run() { } void ScannerView::handle_retune(uint32_t i) { - text_cycle.set(to_string_dec_uint(i) + "/" + to_string_dec_uint(frequency_list.size())); + text_cycle.set( to_string_dec_uint(i) + "/" + + to_string_dec_uint(frequency_list.size()) + " : " + + to_string_dec_uint(frequency_list[i]) ); } void ScannerView::focus() { @@ -101,20 +103,46 @@ ScannerView::ScannerView( &field_vga, &field_rf_amp, &field_volume, + &field_bw, &field_squelch, + &field_wait, //&record_view, &text_cycle, //&waterfall, }); - - // DEBUG - frequency_list.push_back(466025000); - frequency_list.push_back(466050000); - frequency_list.push_back(466075000); - frequency_list.push_back(466175000); - frequency_list.push_back(466206250); - frequency_list.push_back(466231250); - + + std::string scanner_file = "SCANNER"; + if (load_freqman_file(scanner_file, database)) { + for(auto& entry : database) { + // FIXME + if (entry.type == RANGE) { + for (uint32_t i=entry.frequency_a; i < entry.frequency_b; i+= 1000000) { + frequency_list.push_back(i); + } + } else { + frequency_list.push_back(entry.frequency_a); + } + } + } else { + // DEBUG + frequency_list.push_back(466025000); + frequency_list.push_back(466050000); + frequency_list.push_back(466075000); + frequency_list.push_back(466175000); + frequency_list.push_back(466206250); + frequency_list.push_back(466231250); + } + + field_bw.set_selected_index(2); + field_bw.on_change = [this](size_t n, OptionsField::value_t) { + receiver_model.set_nbfm_configuration(n); + }; + + field_wait.on_change = [this](int32_t v) { + wait = v; + }; + field_wait.set_value(5); + field_squelch.on_change = [this](int32_t v) { squelch = v; }; @@ -134,7 +162,7 @@ ScannerView::ScannerView( receiver_model.set_baseband_bandwidth(1750000); receiver_model.enable(); receiver_model.set_squelch_level(0); - receiver_model.set_nbfm_configuration(2); // 16k + receiver_model.set_nbfm_configuration(field_bw.selected_index()); audio::output::unmute(); // TODO: Scanning thread here @@ -144,11 +172,11 @@ ScannerView::ScannerView( void ScannerView::on_statistics_update(const ChannelStatistics& statistics) { int32_t max_db = statistics.max_db; - if (timer < 6) + if (timer <= wait) timer++; if (max_db < -squelch) { - if (timer == 5) { + if (timer == wait) { //audio::output::stop(); scan_thread->set_scanning(true); } diff --git a/firmware/application/apps/ui_scanner.hpp b/firmware/application/apps/ui_scanner.hpp index 67cf7a4a..52e48e29 100644 --- a/firmware/application/apps/ui_scanner.hpp +++ b/firmware/application/apps/ui_scanner.hpp @@ -24,6 +24,7 @@ #include "ui_receiver.hpp" #include "ui_font_fixed_8x16.hpp" +#include "freqman.hpp" namespace ui { @@ -67,10 +68,12 @@ private: std::vector frequency_list { }; int32_t squelch { 0 }; uint32_t timer { 0 }; + uint32_t wait { 0 }; + freqman_db database { }; Labels labels { { { 0 * 8, 0 * 16 }, "LNA: VGA: AMP: VOL:", Color::light_grey() }, - { { 0 * 8, 1 * 16 }, "SQUELCH: /99", Color::light_grey() }, + { { 0 * 8, 1 * 16 }, "BW: SQUELCH: /99 WAIT:", Color::light_grey() }, { { 0 * 8, 3 * 16 }, "Work in progress...", Color::light_grey() } }; @@ -93,15 +96,33 @@ private: 1, ' ', }; - + + OptionsField field_bw { + { 3 * 8, 1 * 16 }, + 3, + { + { "8k5", 0 }, + { "11k", 0 }, + { "16k", 0 }, + } + }; + NumberField field_squelch { - { 8 * 8, 1 * 16 }, + { 15 * 8, 1 * 16 }, 2, { 0, 99 }, 1, ' ', }; - + + NumberField field_wait { + { 26 * 8, 1 * 16 }, + 2, + { 0, 99 }, + 1, + ' ', + }; + Text text_cycle { { 0, 5 * 16, 240, 16 }, "--/--" diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 7cee4f0c..3b5747db 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -471,15 +471,16 @@ void ModInfoView::focus() { SettingsMenuView::SettingsMenuView(NavigationView& nav) { add_items({ - { "Audio", ui::Color::white(), &bitmap_icon_speaker, [&nav](){ nav.push(); } }, - { "Radio", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, - { "UI", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, - //{ "SD card modules", ui::Color::white(), [&nav](){ nav.push(); } }, - { "Date/Time", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, - { "Touch screen", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, - { "Play dead", ui::Color::white(), &bitmap_icon_playdead, [&nav](){ nav.push(); } } + //{ "..", ui::Color::light_grey(), &bitmap_icon_previous, [&nav](){ nav.pop(); } }, + { "Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav](){ nav.push(); } }, + { "Radio", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push(); } }, + { "UI", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push(); } }, + //{ "SD card modules", ui::Color::dark_cyan(), [&nav](){ nav.push(); } }, + { "Date/Time", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push(); } }, + { "Touch screen", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push(); } }, + { "Play dead", ui::Color::dark_cyan(), &bitmap_icon_playdead, [&nav](){ nav.push(); } } }); - on_left = [&nav](){ nav.pop(); }; + set_max_rows(2); // allow wider buttons } } /* namespace ui */ diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 39ab9597..e4084ad3 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -356,7 +356,7 @@ private: }; };*/ -class SettingsMenuView : public MenuView { +class SettingsMenuView : public BtnGridView { public: SettingsMenuView(NavigationView& nav); diff --git a/firmware/application/clock_manager.cpp b/firmware/application/clock_manager.cpp index f1f6eb28..088cf17f 100644 --- a/firmware/application/clock_manager.cpp +++ b/firmware/application/clock_manager.cpp @@ -181,8 +181,8 @@ constexpr ClockControls si5351_clock_control_common { { { ClockControl::ClockCurrentDrive::_2mA, ClockControl::ClockSource::MS_Group, ClockControl::ClockInvert::Invert, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, { ClockControl::ClockCurrentDrive::_2mA, ClockControl::ClockSource::MS_Group, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, { ClockControl::ClockCurrentDrive::_8mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, - { ClockControl::ClockCurrentDrive::_8mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, - { ClockControl::ClockCurrentDrive::_6mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, + { ClockControl::ClockCurrentDrive::_6mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Invert, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, + { ClockControl::ClockCurrentDrive::_4mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, { ClockControl::ClockCurrentDrive::_2mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Fractional, ClockControl::ClockPowerDown::Power_Off }, { ClockControl::ClockCurrentDrive::_2mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off }, } }; diff --git a/firmware/application/ui/ui_alphanum.cpp b/firmware/application/ui/ui_alphanum.cpp index 7b77eb8d..16d2f300 100644 --- a/firmware/application/ui/ui_alphanum.cpp +++ b/firmware/application/ui/ui_alphanum.cpp @@ -54,6 +54,10 @@ AlphanumView::AlphanumView( n = 0; for (auto& button : buttons) { + button.id = n; + button.on_highlight = [this](Button& button) { + focused_button = button.id; + }; button.on_select = button_fn; button.set_parent_rect({ static_cast((n % 5) * (240 / 5)), @@ -120,4 +124,16 @@ void AlphanumView::on_button(Button& button) { update_text(); } +bool AlphanumView::on_encoder(const EncoderEvent delta) { + focused_button += delta; + if (focused_button < 0) { + focused_button = buttons.size() - 1; + } + else if (focused_button >= (int16_t)buttons.size()) { + focused_button = 0; + } + buttons[focused_button].focus(); + return true; +} + } diff --git a/firmware/application/ui/ui_alphanum.hpp b/firmware/application/ui/ui_alphanum.hpp index 08b6e250..1e2e42ac 100644 --- a/firmware/application/ui/ui_alphanum.hpp +++ b/firmware/application/ui/ui_alphanum.hpp @@ -41,6 +41,7 @@ public: AlphanumView& operator=(AlphanumView&&) = delete; void paint(Painter& painter) override; + bool on_encoder(const EncoderEvent delta) override; private: const char * const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ' .<"; @@ -53,6 +54,7 @@ private: { "Digit", keys_digit } }; + int16_t focused_button = 0; uint32_t mode = 0; // Uppercase void set_mode(const uint32_t new_mode); diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp new file mode 100644 index 00000000..0c756af4 --- /dev/null +++ b/firmware/application/ui/ui_btngrid.cpp @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * Copyright (C) 2019 Elia Yehuda (z4ziggy) + * + * 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_btngrid.hpp" +#include "rtc_time.hpp" + +namespace ui { + +/* BtnGridView **************************************************************/ + +BtnGridView::BtnGridView( + Rect new_parent_rect, + bool keep_highlight +) : keep_highlight { keep_highlight } +{ + set_parent_rect(new_parent_rect); + + set_focusable(true); + + signal_token_tick_second = rtc_time::signal_tick_second += [this]() { + this->on_tick_second(); + }; + + add_child(&arrow_more); + arrow_more.set_focusable(false); + arrow_more.set_foreground(Color::black()); +} + +BtnGridView::~BtnGridView() { + rtc_time::signal_tick_second -= signal_token_tick_second; + + for (auto item : menu_item_views) { + delete item; + } +} + +void BtnGridView::set_max_rows(int rows) { + rows_ = rows; +} + +int BtnGridView::rows() { + return rows_; +} + +void BtnGridView::set_parent_rect(const Rect new_parent_rect) { + View::set_parent_rect(new_parent_rect); + + displayed_max = (parent_rect().size().height() / button_h); + arrow_more.set_parent_rect( { 228, (Coord)(displayed_max * button_h), 8, 8 } ); + displayed_max *= rows_; + + // TODO: Clean this up :( + if (menu_item_views.size()) { + + for (auto item : menu_item_views) { + remove_child(item); + delete item; + } + menu_item_views.clear(); + } + + button_w = 240 / rows_; + for (size_t c = 0; c < displayed_max; c++) { + auto item = new NewButton { }; + menu_item_views.push_back(item); + add_child(item); + + item->set_parent_rect({ + (int)(c % rows_) * button_w, + (int)(c / rows_) * button_h, + button_w, button_h + }); + } + + update_items(); +} + +void BtnGridView::on_tick_second() { + if (more && blink) + arrow_more.set_foreground(Color::white()); + else + arrow_more.set_foreground(Color::black()); + + blink = !blink; + + arrow_more.set_dirty(); +} + +void BtnGridView::clear() { + menu_items.clear(); +} + +void BtnGridView::add_items(std::initializer_list new_items) { + for (auto item : new_items) { + menu_items.push_back(item); + } + update_items(); +} + +void BtnGridView::update_items() { + size_t i = 0; + + if ((menu_items.size()) > (displayed_max + offset)) { + more = true; + blink = true; + } else + more = false; + + for (NewButton* item : menu_item_views) { + if (i >= menu_items.size()) break; + + // Assign item data to NewButtons according to offset + item->set_text(menu_items[i + offset].text); + item->set_bitmap(menu_items[i + offset].bitmap); + item->set_color(menu_items[i + offset].color); + item->on_select = menu_items[i + offset].on_select; + item->set_dirty(); + + i++; + } +} + +NewButton* BtnGridView::item_view(size_t index) const { + return menu_item_views[index]; +} + +bool BtnGridView::set_highlighted(int32_t new_value) { + int32_t item_count = (int32_t)menu_items.size(); + + if (new_value < 0) + return false; + + if (new_value >= item_count) + new_value = item_count - 1; + + if (((uint32_t)new_value > offset) && ((new_value - offset) >= displayed_max)) { + // Shift BtnGridView up + highlighted_item = new_value; + offset = new_value - displayed_max + rows_; + update_items(); + } else if ((uint32_t)new_value < offset) { + // Shift BtnGridView down + highlighted_item = new_value; + offset = (new_value / rows_) * rows_; + update_items(); + } else { + // Just update highlight + highlighted_item = new_value; + if (visible()) + item_view(highlighted_item - offset)->focus(); + } + + return true; +} + +uint32_t BtnGridView::highlighted_index() { + return highlighted_item; +} + +void BtnGridView::on_focus() { + item_view(highlighted_item - offset)->focus(); +} + +void BtnGridView::on_blur() { +#if 0 + if (!keep_highlight) + item_view(highlighted_item - offset)->unhighlight(); +#endif +} + +bool BtnGridView::on_key(const KeyEvent key) { + switch(key) { + case KeyEvent::Up: + return set_highlighted(highlighted_item - rows_); + + case KeyEvent::Down: + return set_highlighted(highlighted_item + rows_); + + case KeyEvent::Right: + return set_highlighted(highlighted_item + 1); + + case KeyEvent::Left: + return set_highlighted(highlighted_item - 1); + + case KeyEvent::Select: + if( menu_items[highlighted_item].on_select ) { + menu_items[highlighted_item].on_select(); + } + return true; + + default: + return false; + } +} + +bool BtnGridView::on_encoder(const EncoderEvent event) { + return set_highlighted(highlighted_item + event); +} + +} /* namespace ui */ diff --git a/firmware/application/ui/ui_btngrid.hpp b/firmware/application/ui/ui_btngrid.hpp new file mode 100644 index 00000000..1ce14cca --- /dev/null +++ b/firmware/application/ui/ui_btngrid.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * Copyright (C) 2019 Elia Yehuda (z4ziggy) + * + * 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_BTNGRID_H__ +#define __UI_BTNGRID_H__ + +#include "ui.hpp" +#include "ui_widget.hpp" +#include "ui_painter.hpp" +#include "bitmap.hpp" +#include "signal.hpp" + +#include +#include +#include + +namespace ui { + +struct GridItem { + std::string text; + ui::Color color; + const Bitmap* bitmap; + std::function on_select; + + // TODO: Prevent default-constructed GridItems. +}; + +class BtnGridView : public View { +public: + BtnGridView(Rect new_parent_rect = { 0, 0, 240, 304 }, bool keep_highlight = false); + + ~BtnGridView(); + + void add_items(std::initializer_list new_items); + void set_max_rows(int rows); + int rows(); + void clear(); + + NewButton* item_view(size_t index) const; + + bool set_highlighted(int32_t new_value); + uint32_t highlighted_index(); + + void set_parent_rect(const Rect new_parent_rect) override; + void on_focus() override; + void on_blur() override; + bool on_key(const KeyEvent event) override; + bool on_encoder(const EncoderEvent event) override; + +private: + int rows_ { 3 }; + void update_items(); + void on_tick_second(); + + bool keep_highlight { false }; + + SignalToken signal_token_tick_second { }; + std::vector menu_items { }; + std::vector menu_item_views { }; + + Image arrow_more { + { 228, 320 - 8, 8, 8 }, + &bitmap_more, + Color::white(), + Color::black() + }; + + int button_w = 240 / rows_; + static constexpr int button_h = 48; + bool blink = false; + bool more = false; + size_t displayed_max { 0 }; + size_t highlighted_item { 0 }; + size_t offset { 0 }; +}; + +} /* namespace ui */ + +#endif/*__UI_BTNGRID_H__*/ diff --git a/firmware/application/ui/ui_receiver.cpp b/firmware/application/ui/ui_receiver.cpp index db4d059d..9889bbcb 100644 --- a/firmware/application/ui/ui_receiver.cpp +++ b/firmware/application/ui/ui_receiver.cpp @@ -110,6 +110,18 @@ rf::Frequency FrequencyField::clamp_value(rf::Frequency value) { /* FrequencyKeypadView ***************************************************/ +bool FrequencyKeypadView::on_encoder(const EncoderEvent delta) { + focused_button += delta; + if (focused_button < 0) { + focused_button = buttons.size() - 1; + } + else if (focused_button >= (int16_t)buttons.size()) { + focused_button = 0; + } + buttons[focused_button].focus(); + return true; +} + FrequencyKeypadView::FrequencyKeypadView( NavigationView& nav, const rf::Frequency value @@ -128,6 +140,10 @@ FrequencyKeypadView::FrequencyKeypadView( const std::string label { key_caps[n] }; + button.id = n; + button.on_highlight = [this](Button& button) { + focused_button = button.id; + }; button.on_select = button_fn; button.set_parent_rect({ (n % 3) * button_w, diff --git a/firmware/application/ui/ui_receiver.hpp b/firmware/application/ui/ui_receiver.hpp index 716a3114..6bad8886 100644 --- a/firmware/application/ui/ui_receiver.hpp +++ b/firmware/application/ui/ui_receiver.hpp @@ -185,8 +185,10 @@ public: rf::Frequency value() const; void set_value(const rf::Frequency new_value); + bool on_encoder(const EncoderEvent delta) override; private: + int16_t focused_button = 0; static constexpr int button_w = 240 / 3; static constexpr int button_h = 48; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 504ce9d6..4c574c63 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -342,23 +342,23 @@ void NavigationView::focus() { ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { add_items({ - { "ADS-B: Planes", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.replace(); }, }, - { "ACARS: Planes", ui::Color::yellow(),&bitmap_icon_adsb, [&nav](){ nav.replace(); }, }, - { "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.replace(); } }, - { "AFSK", ui::Color::yellow(),&bitmap_icon_receivers, [&nav](){ nav.replace(); } }, - { "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.replace(); } }, - { "ERT: Utility Meters", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.replace(); } }, - { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.replace(); } }, - { "Radiosondes", ui::Color::yellow(),&bitmap_icon_sonde, [&nav](){ nav.replace(); } }, - { "TPMS: Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.replace(); } }, - { "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.replace(); } }, - { "DMR framing", ui::Color::grey(), &bitmap_icon_dmr, [&nav](){ nav.replace(); } }, - { "SIGFOX", ui::Color::grey(), &bitmap_icon_fox, [&nav](){ nav.replace(); } }, // SIGFRXView - { "LoRa", ui::Color::grey(), &bitmap_icon_lora, [&nav](){ nav.replace(); } }, - { "SSTV", ui::Color::grey(), &bitmap_icon_sstv, [&nav](){ nav.replace(); } }, - { "TETRA framing", ui::Color::grey(), &bitmap_icon_tetra, [&nav](){ nav.replace(); } }, + //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, + { "ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push(); }, }, + { "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push(); }, }, + { "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push(); } }, + { "AFSK", ui::Color::yellow(), &bitmap_icon_receivers, [&nav](){ nav.push(); } }, + { "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push(); } }, + { "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push(); } }, + { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, + { "Radiosnde", ui::Color::yellow(), &bitmap_icon_sonde, [&nav](){ nav.push(); } }, + { "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push(); } }, + { "APRS", ui::Color::dark_grey(), &bitmap_icon_aprs, [&nav](){ nav.push(); } }, + { "DMR", ui::Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push(); } }, + { "SIGFOX", ui::Color::dark_grey(), &bitmap_icon_fox, [&nav](){ nav.push(); } }, // SIGFRXView + { "LoRa", ui::Color::dark_grey(), &bitmap_icon_lora, [&nav](){ nav.push(); } }, + { "SSTV", ui::Color::dark_grey(), &bitmap_icon_sstv, [&nav](){ nav.push(); } }, + { "TETRA", ui::Color::dark_grey(), &bitmap_icon_tetra, [&nav](){ nav.push(); } }, }); - on_left = [&nav](){ nav.pop(); }; set_highlighted(4); // Default selection is "Audio" } @@ -367,43 +367,44 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { add_items({ - { "ADS-B Mode S", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push(); } }, + //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, + { "ADS-B [S]", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push(); } }, { "APRS", ui::Color::orange(), &bitmap_icon_aprs, [&nav](){ nav.push(); } }, { "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push(); } }, { "Jammer", ui::Color::yellow(), &bitmap_icon_jammer, [&nav](){ nav.push(); } }, { "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push(); } }, { "LGE tool", ui::Color::yellow(), &bitmap_icon_lge, [&nav](){ nav.push(); } }, - { "Microphone", ui::Color::green(), &bitmap_icon_microphone, [&nav](){ nav.push(); } }, - { "Morse code", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push(); } }, - { "Burger pagers", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push(); } }, - //{ "Nuoptix DTMF timecode", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push(); } }, - { "OOK encoders", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, + { "Mic", ui::Color::green(), &bitmap_icon_microphone,[&nav](){ nav.push(); } }, + { "Morse", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push(); } }, + { "BurgerPgr", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push(); } }, + //{ "Nuoptix DTMF", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push(); } }, + { "OOK", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, { "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push(); } }, - { "Soundboard", ui::Color::green(), &bitmap_icon_soundboard, [&nav](){ nav.push(); } }, + { "Soundbrd", ui::Color::green(), &bitmap_icon_soundboard,[&nav](){ nav.push(); } }, { "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push(); } }, - { "TEDI/LCR AFSK", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push(); } }, - { "TouchTunes remote", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, - { "Custom remote", ui::Color::grey(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, + { "TEDI/LCR", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push(); } }, + { "TouchTune", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, + { "Remote", ui::Color::dark_grey(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, }); - on_left = [&nav](){ nav.pop(); }; } /* UtilitiesMenuView *****************************************************/ 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(); } }, + //{ "Test app", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push(); } }, + //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, + { "Freq manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push(); } }, { "File manager", ui::Color::yellow(), &bitmap_icon_file, [&nav](){ nav.push(); } }, - { "Notepad", ui::Color::grey(), &bitmap_icon_notepad, [&nav](){ nav.push(); } }, - { "Signal generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push(); } }, - //{ "Tone search", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, - { "Wave file viewer", ui::Color::blue(), nullptr, [&nav](){ nav.push(); } }, - { "Whip antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push(); } }, + { "Notepad", ui::Color::dark_grey(), &bitmap_icon_notepad, [&nav](){ nav.push(); } }, + { "Signal gen", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push(); } }, + //{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push(); } }, + { "Wave viewer", ui::Color::blue(), nullptr, [&nav](){ nav.push(); } }, + { "Antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push(); } }, { "Wipe SD card", ui::Color::red(), nullptr, [&nav](){ nav.push(); } }, }); - on_left = [&nav](){ nav.pop(); }; + set_max_rows(2); // allow wider buttons } /* SystemMenuView ********************************************************/ @@ -421,17 +422,17 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) { SystemMenuView::SystemMenuView(NavigationView& nav) { add_items({ { "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push(); } }, - { "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push(); } }, - { "Transmitters", ui::Color::green(), &bitmap_icon_transmit, [&nav](){ nav.push(); } }, + { "Receivers", ui::Color::dark_cyan(), &bitmap_icon_receivers, [&nav](){ nav.push(); } }, + { "Transmit", ui::Color::green(), &bitmap_icon_transmit, [&nav](){ nav.push(); } }, { "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push(); } }, { "Replay", ui::Color::purple(), &bitmap_icon_replay, [&nav](){ nav.push(); } }, - { "Search/Close call", ui::Color::yellow(), &bitmap_icon_closecall, [&nav](){ nav.push(); } }, - { "Scanner", ui::Color::grey(), &bitmap_icon_scanner, [&nav](){ nav.push(); } }, + { "Calls", ui::Color::yellow(), &bitmap_icon_closecall, [&nav](){ nav.push(); } }, + { "Scanner", ui::Color::orange(), &bitmap_icon_scanner, [&nav](){ nav.push(); } }, { "Utilities", ui::Color::light_grey(), &bitmap_icon_utilities, [&nav](){ nav.push(); } }, - { "Settings", ui::Color::white(), &bitmap_icon_setup, [&nav](){ nav.push(); } }, - //{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, - { "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } }, - { "About", ui::Color::white(), nullptr, [&nav](){ nav.push(); } } + { "Settings", ui::Color::cyan(), &bitmap_icon_setup, [&nav](){ nav.push(); } }, + //{ "Debug", ui::Color::cyan(), nullptr, [&nav](){ nav.push(); } }, + { "HackRF", ui::Color::cyan(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } }, + { "About", ui::Color::cyan(), nullptr, [&nav](){ nav.push(); } } }); set_highlighted(1); // Startup selection is "Receivers" diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index b9c35d5b..e84f3b0b 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -27,6 +27,7 @@ #include "ui_widget.hpp" #include "ui_focus.hpp" #include "ui_menu.hpp" +#include "ui_btngrid.hpp" #include "ui_rssi.hpp" #include "ui_channel.hpp" @@ -198,8 +199,8 @@ public: private: Text text_info { - { 76, 284, 20 * 8, 16 }, - "GIT " GIT_REVISION + { 4*8, 284, 20 * 8, 16 }, + "Version " VERSION_STRING }; Button button_done { @@ -208,25 +209,25 @@ private: }; }; -class ReceiversMenuView : public MenuView { +class ReceiversMenuView : public BtnGridView { public: ReceiversMenuView(NavigationView& nav); std::string title() const override { return "Receivers"; }; }; -class TransmittersMenuView : public MenuView { +class TransmittersMenuView : public BtnGridView { public: TransmittersMenuView(NavigationView& nav); std::string title() const override { return "Transmitters"; }; }; -class UtilitiesMenuView : public MenuView { +class UtilitiesMenuView : public BtnGridView { public: UtilitiesMenuView(NavigationView& nav); std::string title() const override { return "Utilities"; }; }; -class SystemMenuView : public MenuView { +class SystemMenuView : public BtnGridView { public: SystemMenuView(NavigationView& nav); private: diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index a31bd07e..fd70a03a 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -201,7 +201,7 @@ set(CPPWARN "-Wall -Wextra") # List all default C defines here, like -D_DEBUG=1 # TODO: Switch -DCRT0_INIT_DATA depending on load from RAM or SPIFI? # NOTE: _RANDOM_TCC to kill a GCC 4.9.3 error with std::max argument types -set(DDEFS -DLPC43XX -DLPC43XX_M4 -D__NEWLIB__ -DHACKRF_ONE -DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0 -DGIT_REVISION=\"${GIT_REVISION}\") +set(DDEFS "-DLPC43XX -DLPC43XX_M4 -D__NEWLIB__ -DHACKRF_ONE -DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0 -D'VERSION_STRING=\"${VERSION}\"'") # List all default ASM defines here, like -D_DEBUG=1 set(DADEFS) @@ -469,10 +469,9 @@ DeclareTargets(PWFM wfm_audio) ### HackRF "factory" firmware add_custom_command( - OUTPUT hackrf.bin hackrf.img - COMMAND ${STRIP_DFU} ${HACKRF_FIRMWARE_DFU_IMAGE} hackrf.bin - COMMAND ${MAKE_IMAGE_CHUNK} hackrf.bin HRF1 hackrf.img 98304 - DEPENDS hackrf ${STRIP_DFU} ${MAKE_IMAGE_CHUNK} + OUTPUT hackrf.img + COMMAND ${MAKE_IMAGE_CHUNK} ${HACKRF_FIRMWARE_BIN_IMAGE} HRF1 hackrf.img 98304 + DEPENDS ${HACKRF_FIRMWARE_BIN_FILENAME} ${MAKE_IMAGE_CHUNK} VERBATIM ) diff --git a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp index fbfe664b..43d297b4 100755 --- a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp +++ b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp @@ -170,7 +170,7 @@ const PALConfig pal_default_config = { | (1 << 9) // P7_1: PortaPack GPIO3_9(IO) | (1 << 8) // P7_0: PortaPack GPIO3_8(IO) | (1 << 7) // P6_11: VREGMODE - | (1 << 6) // P6_10: EN1V8, 10K PD + | (0 << 6) // P6_10: EN1V8, 10K PD | (1 << 5) // P6_9: !TX_AMP_PWR, 10K PU | (1 << 4) // P6_5: HackRF CPLD.TMS(I) (output only when needed, pull-up internal to CPLD when 1V8 present) | (1 << 3) // P6_4: MIXER_SDATA @@ -478,8 +478,8 @@ void vaa_power_on(void) { /* Combination of pulse duration and duty cycle was arrived at empirically, to keep supply glitching * to +/- 0.15V. */ - const uint32_t cycle_period = 128; - const uint32_t enable_period = 10; + const uint32_t cycle_period = 256; + uint32_t enable_period = 2; LPC_MCPWM->TC2 = 0; LPC_MCPWM->MAT2 = cycle_period - enable_period; LPC_MCPWM->LIM2 = cycle_period; @@ -493,7 +493,11 @@ void vaa_power_on(void) { /* Wait until VAA rises to approximately 90% of final voltage. */ /* Timing assumes we're running immediately after the bootloader: 96 MHz from IRC+PLL1 */ - { volatile uint32_t delay = 12000; while(delay--); } + while(enable_period < cycle_period) { + { volatile uint32_t delay = 2000; while(delay--); } + enable_period <<= 1; + LPC_MCPWM->MAT2 = cycle_period - enable_period; + } /* Hold !VAA_ENABLE active using a GPIO, so we can reclaim and shut down the MOTOCONPWM peripheral. */ LPC_GPIO->CLR[2] = (1 << 9); // !VAA_ENABLE @@ -635,9 +639,11 @@ extern "C" void __late_init(void) { */ extern "C" void boardInit(void) { vaa_power_on(); + LPC_GPIO->W3[6] = 1; } extern "C" void _default_exit(void) { + LPC_GPIO->W3[6] = 0; vaa_power_off(); chSysDisable(); diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 02b9bc02..5e2d7db8 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -918,6 +918,132 @@ bool Button::on_touch(const TouchEvent event) { #endif } +/* NewButton ****************************************************************/ + +NewButton::NewButton( + Rect parent_rect, + std::string text, + const Bitmap* bitmap +) : Widget { parent_rect }, + text_ { text }, + bitmap_ (bitmap) +{ + set_focusable(true); +} + +void NewButton::set_text(const std::string value) { + text_ = value; + set_dirty(); +} + +std::string NewButton::text() const { + return text_; +} + +void NewButton::set_bitmap(const Bitmap* bitmap) { + bitmap_ = bitmap; + set_dirty(); +} + +const Bitmap* NewButton::bitmap() { + return bitmap_; +} + +void NewButton::set_color(Color color) { + color_ = color; + set_dirty(); +} + +ui::Color NewButton::color() { + return color_; +} + +void NewButton::paint(Painter& painter) { + + if (!bitmap_ && text_.empty()) + return; + + Color bg, fg; + const auto r = screen_rect(); + + if (has_focus() || highlighted()) { + bg = style().foreground; + fg = Color::black(); + } else { + bg = Color::grey(); + fg = style().foreground; + } + + const Style paint_style = { style().font, bg, fg }; + + painter.draw_rectangle({r.location(), {r.size().width(), 1}}, Color::light_grey()); + painter.draw_rectangle({r.location().x(), r.location().y() + r.size().height() - 1, r.size().width(), 1}, Color::dark_grey()); + painter.draw_rectangle({r.location().x() + r.size().width() - 1, r.location().y(), 1, r.size().height()}, Color::dark_grey()); + + painter.fill_rectangle( + { r.location().x(), r.location().y() + 1, r.size().width() - 1, r.size().height() - 2 }, + paint_style.background + ); + + int y = r.location().y(); + if (bitmap_) { + painter.draw_bitmap( + {r.location().x() + (r.size().width() / 2) - 8, r.location().y() + 6}, + *bitmap_, + color_, //Color::green(), //fg, + bg + ); + y += 10; + } + const auto label_r = paint_style.font.size_of(text_); + painter.draw_string( + { r.location().x() + (r.size().width() - label_r.width()) / 2, y + (r.size().height() - label_r.height()) / 2 }, + paint_style, + text_ + ); +} + +void NewButton::on_focus() { + if( on_highlight ) + on_highlight(*this); +} + +bool NewButton::on_key(const KeyEvent key) { + if( key == KeyEvent::Select ) { + if( on_select ) { + on_select(); + return true; + } + } else { + if( on_dir ) { + return on_dir(*this, key); + } + } + + return false; +} + +bool NewButton::on_touch(const TouchEvent event) { + switch(event.type) { + case TouchEvent::Type::Start: + set_highlighted(true); + set_dirty(); + return true; + + + case TouchEvent::Type::End: + set_highlighted(false); + set_dirty(); + if( on_select ) { + on_select(); + } + return true; + + default: + return false; + } +} + /* Image *****************************************************************/ Image::Image( diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index db3bdda4..e4b8533b 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -394,6 +394,40 @@ private: std::string text_; }; +class NewButton : public Widget { +public: + std::function on_select { }; + //std::function on_select { }; + std::function on_dir { }; + std::function on_highlight { }; + + NewButton(const NewButton&) = delete; + NewButton& operator=(const NewButton&) = delete; + NewButton(Rect parent_rect, std::string text, const Bitmap* bitmap); + NewButton( + ) : NewButton { { }, { }, { } } + { + } + + void set_bitmap(const Bitmap* bitmap); + void set_text(const std::string value); + void set_color(Color value); + std::string text() const; + const Bitmap* bitmap(); + ui::Color color(); + + void on_focus() override; + bool on_key(const KeyEvent key) override; + bool on_touch(const TouchEvent event) override; + + void paint(Painter& painter) override; + +private: + std::string text_; + Color color_ = Color::dark_cyan(); + const Bitmap* bitmap_; +}; + class Image : public Widget { public: Image(); diff --git a/firmware/tools/strip_dfu.py b/firmware/tools/strip_dfu.py deleted file mode 100755 index d3a9d8eb..00000000 --- a/firmware/tools/strip_dfu.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import sys - -usage_message = """ -PortaPack DFU header stripper - -Usage: -""" - -def read_image(path): - f = open(path, 'rb') - data = f.read() - f.close() - return data - -def read_image_from_dfu(path): - data = read_image(path) - # Strip DFU header from file to get binary image. - return data[16:] - -def write_image(data, path): - f = open(path, 'wb') - f.write(data) - f.close() - -if len(sys.argv) != 3: - print(usage_message) - sys.exit(-1) - -dfu_image = read_image_from_dfu(sys.argv[1]) -output_path = sys.argv[2] - -write_image(dfu_image, output_path) diff --git a/hackrf b/hackrf new file mode 160000 index 00000000..923f9fe6 --- /dev/null +++ b/hackrf @@ -0,0 +1 @@ +Subproject commit 923f9fe617c9dcf00c97c18f5aa79e51720b9e59 diff --git a/sdcard/FREQMAN/SCANNER.TXT b/sdcard/FREQMAN/SCANNER.TXT new file mode 100644 index 00000000..f34f2936 --- /dev/null +++ b/sdcard/FREQMAN/SCANNER.TXT @@ -0,0 +1,50 @@ +f=118000000 +f=119100000 +f=121100000 +f=122300000 +f=122400000 +f=131900000 +f=133250000 +f=144330000 +f=145025000 +f=145310000 +f=145375000 +f=145625000 +f=145700000 +f=145725000 +f=145750000 +f=146395000 +f=152250000 +f=154510000 +f=155210000 +f=156295000 +f=156700000 +f=158410000 +f=161550000 +f=161650000 +f=161700000 +f=163812500 +f=170900000 +f=172437500 +f=172725000 +f=173012500 +f=173325000 +f=173350000 +f=430625000 +f=430650000 +f=430725000 +f=430762500 +f=431200000 +f=431200000 +f=431500000 +f=431600000 +f=431825000 +f=438225000 +f=438250000 +f=438325000 +f=438362500 +f=438800000 +f=438800000 +f=439100000 +f=439200000 +f=439425000 diff --git a/tools/deploy-nightly.sh b/tools/deploy-nightly.sh new file mode 100644 index 00000000..d0c1672a --- /dev/null +++ b/tools/deploy-nightly.sh @@ -0,0 +1,57 @@ +#!/bin/bash +PUBLICATION_BRANCH=master +# set -x +cd $HOME +# Checkout the branch +git clone --branch=$PUBLICATION_BRANCH https://${GITHUB_TOKEN}@github.com/${ARTEFACT_REPO}.git publish +cd publish +# Update pages +BUILD_PATH=$BUILD_DATE-$SHORT_COMMIT_HASH +mkdir $BUILD_PATH +cp $ARTEFACT_BASE/$BUILD_NAME.tar.xz $BUILD_PATH/ +cp $ARTEFACT_BASE/MD5SUMS $BUILD_PATH/ +cp $ARTEFACT_BASE/SHA256SUMS $BUILD_PATH/ +# Write index page +cd $TRAVIS_BUILD_DIR +COMMITS=`git log --oneline | awk '{print $1}'` +cd $HOME/publish +echo " + + + + $PROJECT_NAME Builds + + +

$PROJECT_NAME Builds

+ +" > index.html + +for commit in $COMMITS; do + FILEPATH=`find . -maxdepth 2 -name "*-$commit.tar.xz"` + if [ "$FILEPATH" != "" ]; then + FILEDIR=`dirname "${FILEPATH}"` + FILENAME=`basename "${FILEPATH}"` + FILEPATH=${FILEPATH:2} + # pushd "${FILEDIR}" + # HASH_MD5=`md5sum --binary ${FILENAME}` + # HASH_SHA256=`sha256sum --binary ${FILENAME}` + # popd + echo "" >> index.html + fi + +done + +echo " +
$FILENAMEMD5SUMSSHA256SUMS
+ +" >> index.html + +# Commit and push latest version +git add $BUILD_PATH/$BUILD_NAME.tar.xz $BUILD_PATH/MD5SUMS $BUILD_PATH/SHA256SUMS index.html +git config user.name "Travis" +git config user.email "travis@travis-ci.org" +git commit -m "Build products for $SHORT_COMMIT_HASH, built on $TRAVIS_OS_NAME, log: $TRAVIS_BUILD_WEB_URL" +if [ "$?" != "0" ]; then + echo "Looks like the commit failed" +fi +git push -fq origin $PUBLICATION_BRANCH \ No newline at end of file