From 6bcb7dc1b15e2b61fe729d80224a46b7274946fd Mon Sep 17 00:00:00 2001 From: furrtek Date: Fri, 9 Dec 2016 18:21:47 +0100 Subject: [PATCH] # This is a combination of 2 commits. # The first commit's message is: Updated RDS transmitter: flags, PI and date/time Merging baseband audio tone generators Merging DTMF baseband with "tones" baseband Added stealth transmit mode App flash section bumped to 512k RX and TX LEDs are now used Play dead should work again, added login option Morse frame gen. for letters and fox hunt codes Merged EPAR with Xylos Made EPAR use encoders for frame gen. Moved OOK encoders data in encoders.hpp Simplified about screen, ui_about_demo.* files are still there BHT city DB, keywords removed BHT cities DB, keywords removed Update README.md RDS radiotext and time group generators # This is the 2nd commit message: Update README.md --- firmware/Makefile | 23 +- firmware/application/CMakeLists.txt | 7 +- firmware/application/Makefile | 660 +++++++++++++++++- firmware/application/baseband_api.cpp | 16 +- firmware/application/baseband_api.hpp | 5 +- firmware/application/bitmap.hpp | 64 +- firmware/application/demofont.hpp | 2 +- firmware/application/encoders.hpp | 221 ++++++ firmware/application/event_m0.cpp | 13 +- firmware/application/event_m0.hpp | 5 +- firmware/application/main.cpp | 36 +- firmware/application/rds.cpp | 20 +- firmware/application/rds.hpp | 8 + firmware/application/receiver_model.cpp | 4 + firmware/application/transmitter_model.cpp | 20 + firmware/application/transmitter_model.hpp | 4 + firmware/application/ui_about.cpp | 439 +++--------- firmware/application/ui_about.hpp | 150 ++-- firmware/application/ui_about_demo.cpp | 418 +++++++++++ firmware/application/ui_about_demo.hpp | 174 +++++ firmware/application/ui_adsbtx.cpp | 2 +- firmware/application/ui_adsbtx.hpp | 2 +- firmware/application/ui_alphanum.cpp | 97 ++- firmware/application/ui_alphanum.hpp | 32 +- firmware/application/ui_audio.hpp | 2 - firmware/application/ui_bht_tx.cpp | 409 +++++++++++ firmware/application/ui_bht_tx.hpp | 429 ++++++++++++ firmware/application/ui_closecall.cpp | 4 - firmware/application/ui_closecall.hpp | 2 - firmware/application/ui_debug.hpp | 30 - firmware/application/ui_encoders.cpp | 4 +- firmware/application/ui_encoders.hpp | 192 +---- firmware/application/ui_epar.cpp | 235 ------- firmware/application/ui_epar.hpp | 155 ---- firmware/application/ui_freqman.cpp | 27 +- firmware/application/ui_freqman.hpp | 34 + firmware/application/ui_handwrite.cpp | 48 +- firmware/application/ui_handwrite.hpp | 24 +- firmware/application/ui_jammer.cpp | 2 +- firmware/application/ui_lcr.cpp | 2 +- firmware/application/ui_lcr.hpp | 2 +- firmware/application/ui_menu.cpp | 19 +- firmware/application/ui_menu.hpp | 1 + firmware/application/ui_morse.cpp | 143 ++++ firmware/application/ui_morse.hpp | 198 ++++++ firmware/application/ui_navigation.cpp | 160 +++-- firmware/application/ui_navigation.hpp | 38 +- firmware/application/ui_nuoptix.cpp | 78 ++- firmware/application/ui_nuoptix.hpp | 52 +- firmware/application/ui_rds.cpp | 80 ++- firmware/application/ui_rds.hpp | 110 ++- firmware/application/ui_receiver.cpp | 4 + firmware/application/ui_receiver.hpp | 8 +- .../application/ui_sd_card_status_view.cpp | 1 + .../application/ui_sd_card_status_view.hpp | 1 + firmware/application/ui_setup.cpp | 44 +- firmware/application/ui_setup.hpp | 23 +- firmware/application/ui_soundboard.cpp | 1 + firmware/application/ui_soundboard.hpp | 2 +- firmware/application/ui_textentry.cpp | 2 +- firmware/application/ui_textentry.hpp | 2 +- firmware/application/ui_whistle.cpp | 31 +- firmware/application/ui_whistle.hpp | 9 +- firmware/application/ui_xylos.cpp | 431 ------------ firmware/application/ui_xylos.hpp | 387 ---------- firmware/application/ymdata.hpp | 2 +- firmware/baseband/CMakeLists.txt | 13 +- firmware/baseband/audio_output.cpp | 35 +- firmware/baseband/audio_output.hpp | 6 + firmware/baseband/baseband_ads.img | Bin 9060 -> 9060 bytes firmware/baseband/baseband_tones.img | Bin 0 -> 11572 bytes firmware/baseband/proc_adsbtx.cpp | 2 +- firmware/baseband/proc_afsk.cpp | 12 +- firmware/baseband/proc_dtmf_tx.cpp | 10 +- firmware/baseband/proc_jammer.cpp | 2 +- firmware/baseband/proc_ook.cpp | 14 +- firmware/baseband/proc_ook.hpp | 2 +- firmware/baseband/proc_rds.cpp | 2 +- firmware/baseband/proc_tones.cpp | 152 ++++ .../{proc_xylos.hpp => proc_tones.hpp} | 65 +- firmware/baseband/proc_xylos.cpp | 122 ---- firmware/bootstrap/bootstrap.bin | Bin 228 -> 220 bytes .../GCC/ARMCMx/LPC43xx_M0/ld/LPC43xx_M0.ld | 2 +- firmware/common/message.hpp | 31 +- .../common/portapack_persistent_memory.cpp | 10 +- .../common/portapack_persistent_memory.hpp | 3 + firmware/common/portapack_shared_memory.hpp | 20 +- firmware/common/spi_image.hpp | 4 +- firmware/common/ui_widget.cpp | 34 +- firmware/common/ui_widget.hpp | 11 +- firmware/portapack-h1-havoc.bin | Bin 795620 -> 794864 bytes 91 files changed, 3867 insertions(+), 2535 deletions(-) create mode 100644 firmware/application/encoders.hpp create mode 100644 firmware/application/ui_about_demo.cpp create mode 100644 firmware/application/ui_about_demo.hpp create mode 100644 firmware/application/ui_bht_tx.cpp create mode 100644 firmware/application/ui_bht_tx.hpp delete mode 100644 firmware/application/ui_epar.cpp delete mode 100644 firmware/application/ui_epar.hpp create mode 100644 firmware/application/ui_morse.cpp create mode 100644 firmware/application/ui_morse.hpp delete mode 100644 firmware/application/ui_xylos.cpp delete mode 100644 firmware/application/ui_xylos.hpp create mode 100644 firmware/baseband/baseband_tones.img create mode 100644 firmware/baseband/proc_tones.cpp rename firmware/baseband/{proc_xylos.hpp => proc_tones.hpp} (51%) delete mode 100644 firmware/baseband/proc_xylos.cpp diff --git a/firmware/Makefile b/firmware/Makefile index f1c541360..00840846b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,26 +1,35 @@ # CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 2.8 +# Generated by "Unix Makefiles" Generator, CMake Version 3.5 # Default target executed when no arguments are given to make. default_target: all + .PHONY : default_target +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + #============================================================================= # Special targets provided by cmake. # Disable implicit rules so canonical targets will work. .SUFFIXES: + # Remove some rules from gmake that .SUFFIXES does not remove. SUFFIXES = .SUFFIXES: .hpux_make_needs_suffix_list + # Suppress display of executed commands. $(VERBOSE).SILENT: + # A target that is always out of date. cmake_force: + .PHONY : cmake_force #============================================================================= @@ -49,12 +58,13 @@ CMAKE_BINARY_DIR = /home/furrtek/portapack-hackrf # Special rule for the target edit_cache edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..." - /usr/bin/cmake -i . + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. .PHONY : edit_cache # Special rule for the target edit_cache edit_cache/fast: edit_cache + .PHONY : edit_cache/fast # Special rule for the target rebuild_cache @@ -65,6 +75,7 @@ rebuild_cache: # Special rule for the target rebuild_cache rebuild_cache/fast: rebuild_cache + .PHONY : rebuild_cache/fast # The main all target @@ -81,6 +92,7 @@ clean: # The main clean target clean/fast: clean + .PHONY : clean/fast # Prepare targets for installation. @@ -105,6 +117,7 @@ firmware/CMakeFiles/firmware.dir/rule: # Convenience name for target. firmware: firmware/CMakeFiles/firmware.dir/rule + .PHONY : firmware # fast build rule for target. @@ -119,6 +132,7 @@ firmware/CMakeFiles/program.dir/rule: # Convenience name for target. program: firmware/CMakeFiles/program.dir/rule + .PHONY : program # fast build rule for target. @@ -133,6 +147,7 @@ firmware/CMakeFiles/release.dir/rule: # Convenience name for target. release: firmware/CMakeFiles/release.dir/rule + .PHONY : release # fast build rule for target. @@ -149,8 +164,8 @@ help: @echo "... edit_cache" @echo "... firmware" @echo "... program" - @echo "... rebuild_cache" @echo "... release" + @echo "... rebuild_cache" .PHONY : help diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index baa0072e9..f2198d334 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. +# Copyright (C) 2016 Furrtek # # This file is part of PortaPack. # @@ -152,7 +153,9 @@ set(CPPSRC ui_alphanum.cpp ui_audio.cpp ui_baseband_stats_view.cpp + ui_bht_tx.cpp ui_channel.cpp + ui_closecall.cpp ui_debug.cpp ui_encoders.cpp ui_font_fixed_8x16.cpp @@ -161,6 +164,7 @@ set(CPPSRC ui_jammer.cpp ui_lcr.cpp ui_menu.cpp + ui_morse.cpp ui_navigation.cpp ui_numbers.cpp ui_nuoptix.cpp @@ -176,8 +180,7 @@ set(CPPSRC ui_textentry.cpp ui_touch_calibration.cpp ui_whipcalc.cpp - ui_xylos.cpp - ui_closecall.cpp + ui_whistle.cpp # ui_loadmodule.cpp recent_entries.cpp receiver_model.cpp diff --git a/firmware/application/Makefile b/firmware/application/Makefile index 1be1dcc29..bd462e287 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -1,26 +1,35 @@ # CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 2.8 +# Generated by "Unix Makefiles" Generator, CMake Version 3.5 # Default target executed when no arguments are given to make. default_target: all + .PHONY : default_target +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + #============================================================================= # Special targets provided by cmake. # Disable implicit rules so canonical targets will work. .SUFFIXES: + # Remove some rules from gmake that .SUFFIXES does not remove. SUFFIXES = .SUFFIXES: .hpux_make_needs_suffix_list + # Suppress display of executed commands. $(VERBOSE).SILENT: + # A target that is always out of date. cmake_force: + .PHONY : cmake_force #============================================================================= @@ -49,12 +58,13 @@ CMAKE_BINARY_DIR = /home/furrtek/portapack-hackrf # Special rule for the target edit_cache edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..." - /usr/bin/cmake -i . + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. .PHONY : edit_cache # Special rule for the target edit_cache edit_cache/fast: edit_cache + .PHONY : edit_cache/fast # Special rule for the target rebuild_cache @@ -65,6 +75,7 @@ rebuild_cache: # Special rule for the target rebuild_cache rebuild_cache/fast: rebuild_cache + .PHONY : rebuild_cache/fast # The main all target @@ -81,6 +92,7 @@ clean: # The main clean target clean/fast: clean + .PHONY : clean/fast # Prepare targets for installation. @@ -105,6 +117,7 @@ firmware/application/CMakeFiles/application.dir/rule: # Convenience name for target. application: firmware/application/CMakeFiles/application.dir/rule + .PHONY : application # fast build rule for target. @@ -119,6 +132,7 @@ firmware/application/CMakeFiles/application.elf.dir/rule: # Convenience name for target. application.elf: firmware/application/CMakeFiles/application.elf.dir/rule + .PHONY : application.elf # fast build rule for target. @@ -127,6 +141,7 @@ application.elf/fast: .PHONY : application.elf/fast __/chibios-portapack/boards/GSG_HACKRF_ONE/board.obj: __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.obj + .PHONY : __/chibios-portapack/boards/GSG_HACKRF_ONE/board.obj # target to build an object file @@ -135,6 +150,7 @@ __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.obj: .PHONY : __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.obj __/chibios-portapack/boards/GSG_HACKRF_ONE/board.i: __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.i + .PHONY : __/chibios-portapack/boards/GSG_HACKRF_ONE/board.i # target to preprocess a source file @@ -143,6 +159,7 @@ __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.i: .PHONY : __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.i __/chibios-portapack/boards/GSG_HACKRF_ONE/board.s: __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.s + .PHONY : __/chibios-portapack/boards/GSG_HACKRF_ONE/board.s # target to generate assembly for a file @@ -151,6 +168,7 @@ __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.s: .PHONY : __/chibios-portapack/boards/GSG_HACKRF_ONE/board.c.s __/chibios-portapack/ext/fatfs/src/ff.obj: __/chibios-portapack/ext/fatfs/src/ff.c.obj + .PHONY : __/chibios-portapack/ext/fatfs/src/ff.obj # target to build an object file @@ -159,6 +177,7 @@ __/chibios-portapack/ext/fatfs/src/ff.c.obj: .PHONY : __/chibios-portapack/ext/fatfs/src/ff.c.obj __/chibios-portapack/ext/fatfs/src/ff.i: __/chibios-portapack/ext/fatfs/src/ff.c.i + .PHONY : __/chibios-portapack/ext/fatfs/src/ff.i # target to preprocess a source file @@ -167,6 +186,7 @@ __/chibios-portapack/ext/fatfs/src/ff.c.i: .PHONY : __/chibios-portapack/ext/fatfs/src/ff.c.i __/chibios-portapack/ext/fatfs/src/ff.s: __/chibios-portapack/ext/fatfs/src/ff.c.s + .PHONY : __/chibios-portapack/ext/fatfs/src/ff.s # target to generate assembly for a file @@ -175,6 +195,7 @@ __/chibios-portapack/ext/fatfs/src/ff.c.s: .PHONY : __/chibios-portapack/ext/fatfs/src/ff.c.s __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.obj # target to build an object file @@ -183,6 +204,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.i # target to preprocess a source file @@ -191,6 +213,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.s # target to generate assembly for a file @@ -199,6 +222,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.c.s __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.obj # target to build an object file @@ -207,6 +231,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.i # target to preprocess a source file @@ -215,6 +240,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.s # target to generate assembly for a file @@ -223,6 +249,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/i2c_lld.c.s __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.obj # target to build an object file @@ -231,6 +258,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.i # target to preprocess a source file @@ -239,6 +267,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.s # target to generate assembly for a file @@ -247,6 +276,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.c.s __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.obj # target to build an object file @@ -255,6 +285,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.i # target to preprocess a source file @@ -263,6 +294,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.s # target to generate assembly for a file @@ -271,6 +303,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/rtc_lld.c.s __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.obj # target to build an object file @@ -279,6 +312,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.i # target to preprocess a source file @@ -287,6 +321,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.s # target to generate assembly for a file @@ -295,6 +330,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/sdc_lld.c.s __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.obj # target to build an object file @@ -303,6 +339,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.i # target to preprocess a source file @@ -311,6 +348,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.s # target to generate assembly for a file @@ -319,6 +357,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/serial_lld.c.s __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.obj # target to build an object file @@ -327,6 +366,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.i # target to preprocess a source file @@ -335,6 +375,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.s # target to generate assembly for a file @@ -343,6 +384,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx/spi_lld.c.s __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.obj: __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.obj + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.obj # target to build an object file @@ -351,6 +393,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.obj: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.obj __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.i: __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.i + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.i # target to preprocess a source file @@ -359,6 +402,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.i: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.i __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.s: __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.s + .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.s # target to generate assembly for a file @@ -367,6 +411,7 @@ __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.s: .PHONY : __/chibios-portapack/os/hal/platforms/LPC43xx_M0/hal_lld.c.s __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.obj: __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.obj + .PHONY : __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.obj # target to build an object file @@ -375,6 +420,7 @@ __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.obj: .PHONY : __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.obj __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.i: __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.i + .PHONY : __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.i # target to preprocess a source file @@ -383,6 +429,7 @@ __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.i: .PHONY : __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.i __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.s: __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.s + .PHONY : __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.s # target to generate assembly for a file @@ -391,6 +438,7 @@ __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.s: .PHONY : __/chibios-portapack/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c.s __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.obj: __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.obj + .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.obj # target to build an object file @@ -399,6 +447,7 @@ __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.obj: .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.obj __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.i: __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.i + .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.i # target to preprocess a source file @@ -407,6 +456,7 @@ __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.i: .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.i __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.s: __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.s + .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.s # target to generate assembly for a file @@ -415,6 +465,7 @@ __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.s: .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c.s __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.obj: __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.obj + .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.obj # target to build an object file @@ -423,6 +474,7 @@ __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.obj: .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.obj __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.i: __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.i + .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.i # target to preprocess a source file @@ -431,6 +483,7 @@ __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.i: .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.i __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.s: __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.s + .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.s # target to generate assembly for a file @@ -439,6 +492,7 @@ __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.s: .PHONY : __/chibios-portapack/os/various/fatfs_bindings/fatfs_syscall.c.s __/chibios/os/hal/src/adc.obj: __/chibios/os/hal/src/adc.c.obj + .PHONY : __/chibios/os/hal/src/adc.obj # target to build an object file @@ -447,6 +501,7 @@ __/chibios/os/hal/src/adc.c.obj: .PHONY : __/chibios/os/hal/src/adc.c.obj __/chibios/os/hal/src/adc.i: __/chibios/os/hal/src/adc.c.i + .PHONY : __/chibios/os/hal/src/adc.i # target to preprocess a source file @@ -455,6 +510,7 @@ __/chibios/os/hal/src/adc.c.i: .PHONY : __/chibios/os/hal/src/adc.c.i __/chibios/os/hal/src/adc.s: __/chibios/os/hal/src/adc.c.s + .PHONY : __/chibios/os/hal/src/adc.s # target to generate assembly for a file @@ -463,6 +519,7 @@ __/chibios/os/hal/src/adc.c.s: .PHONY : __/chibios/os/hal/src/adc.c.s __/chibios/os/hal/src/can.obj: __/chibios/os/hal/src/can.c.obj + .PHONY : __/chibios/os/hal/src/can.obj # target to build an object file @@ -471,6 +528,7 @@ __/chibios/os/hal/src/can.c.obj: .PHONY : __/chibios/os/hal/src/can.c.obj __/chibios/os/hal/src/can.i: __/chibios/os/hal/src/can.c.i + .PHONY : __/chibios/os/hal/src/can.i # target to preprocess a source file @@ -479,6 +537,7 @@ __/chibios/os/hal/src/can.c.i: .PHONY : __/chibios/os/hal/src/can.c.i __/chibios/os/hal/src/can.s: __/chibios/os/hal/src/can.c.s + .PHONY : __/chibios/os/hal/src/can.s # target to generate assembly for a file @@ -487,6 +546,7 @@ __/chibios/os/hal/src/can.c.s: .PHONY : __/chibios/os/hal/src/can.c.s __/chibios/os/hal/src/ext.obj: __/chibios/os/hal/src/ext.c.obj + .PHONY : __/chibios/os/hal/src/ext.obj # target to build an object file @@ -495,6 +555,7 @@ __/chibios/os/hal/src/ext.c.obj: .PHONY : __/chibios/os/hal/src/ext.c.obj __/chibios/os/hal/src/ext.i: __/chibios/os/hal/src/ext.c.i + .PHONY : __/chibios/os/hal/src/ext.i # target to preprocess a source file @@ -503,6 +564,7 @@ __/chibios/os/hal/src/ext.c.i: .PHONY : __/chibios/os/hal/src/ext.c.i __/chibios/os/hal/src/ext.s: __/chibios/os/hal/src/ext.c.s + .PHONY : __/chibios/os/hal/src/ext.s # target to generate assembly for a file @@ -511,6 +573,7 @@ __/chibios/os/hal/src/ext.c.s: .PHONY : __/chibios/os/hal/src/ext.c.s __/chibios/os/hal/src/gpt.obj: __/chibios/os/hal/src/gpt.c.obj + .PHONY : __/chibios/os/hal/src/gpt.obj # target to build an object file @@ -519,6 +582,7 @@ __/chibios/os/hal/src/gpt.c.obj: .PHONY : __/chibios/os/hal/src/gpt.c.obj __/chibios/os/hal/src/gpt.i: __/chibios/os/hal/src/gpt.c.i + .PHONY : __/chibios/os/hal/src/gpt.i # target to preprocess a source file @@ -527,6 +591,7 @@ __/chibios/os/hal/src/gpt.c.i: .PHONY : __/chibios/os/hal/src/gpt.c.i __/chibios/os/hal/src/gpt.s: __/chibios/os/hal/src/gpt.c.s + .PHONY : __/chibios/os/hal/src/gpt.s # target to generate assembly for a file @@ -535,6 +600,7 @@ __/chibios/os/hal/src/gpt.c.s: .PHONY : __/chibios/os/hal/src/gpt.c.s __/chibios/os/hal/src/hal.obj: __/chibios/os/hal/src/hal.c.obj + .PHONY : __/chibios/os/hal/src/hal.obj # target to build an object file @@ -543,6 +609,7 @@ __/chibios/os/hal/src/hal.c.obj: .PHONY : __/chibios/os/hal/src/hal.c.obj __/chibios/os/hal/src/hal.i: __/chibios/os/hal/src/hal.c.i + .PHONY : __/chibios/os/hal/src/hal.i # target to preprocess a source file @@ -551,6 +618,7 @@ __/chibios/os/hal/src/hal.c.i: .PHONY : __/chibios/os/hal/src/hal.c.i __/chibios/os/hal/src/hal.s: __/chibios/os/hal/src/hal.c.s + .PHONY : __/chibios/os/hal/src/hal.s # target to generate assembly for a file @@ -559,6 +627,7 @@ __/chibios/os/hal/src/hal.c.s: .PHONY : __/chibios/os/hal/src/hal.c.s __/chibios/os/hal/src/i2c.obj: __/chibios/os/hal/src/i2c.c.obj + .PHONY : __/chibios/os/hal/src/i2c.obj # target to build an object file @@ -567,6 +636,7 @@ __/chibios/os/hal/src/i2c.c.obj: .PHONY : __/chibios/os/hal/src/i2c.c.obj __/chibios/os/hal/src/i2c.i: __/chibios/os/hal/src/i2c.c.i + .PHONY : __/chibios/os/hal/src/i2c.i # target to preprocess a source file @@ -575,6 +645,7 @@ __/chibios/os/hal/src/i2c.c.i: .PHONY : __/chibios/os/hal/src/i2c.c.i __/chibios/os/hal/src/i2c.s: __/chibios/os/hal/src/i2c.c.s + .PHONY : __/chibios/os/hal/src/i2c.s # target to generate assembly for a file @@ -583,6 +654,7 @@ __/chibios/os/hal/src/i2c.c.s: .PHONY : __/chibios/os/hal/src/i2c.c.s __/chibios/os/hal/src/icu.obj: __/chibios/os/hal/src/icu.c.obj + .PHONY : __/chibios/os/hal/src/icu.obj # target to build an object file @@ -591,6 +663,7 @@ __/chibios/os/hal/src/icu.c.obj: .PHONY : __/chibios/os/hal/src/icu.c.obj __/chibios/os/hal/src/icu.i: __/chibios/os/hal/src/icu.c.i + .PHONY : __/chibios/os/hal/src/icu.i # target to preprocess a source file @@ -599,6 +672,7 @@ __/chibios/os/hal/src/icu.c.i: .PHONY : __/chibios/os/hal/src/icu.c.i __/chibios/os/hal/src/icu.s: __/chibios/os/hal/src/icu.c.s + .PHONY : __/chibios/os/hal/src/icu.s # target to generate assembly for a file @@ -607,6 +681,7 @@ __/chibios/os/hal/src/icu.c.s: .PHONY : __/chibios/os/hal/src/icu.c.s __/chibios/os/hal/src/mac.obj: __/chibios/os/hal/src/mac.c.obj + .PHONY : __/chibios/os/hal/src/mac.obj # target to build an object file @@ -615,6 +690,7 @@ __/chibios/os/hal/src/mac.c.obj: .PHONY : __/chibios/os/hal/src/mac.c.obj __/chibios/os/hal/src/mac.i: __/chibios/os/hal/src/mac.c.i + .PHONY : __/chibios/os/hal/src/mac.i # target to preprocess a source file @@ -623,6 +699,7 @@ __/chibios/os/hal/src/mac.c.i: .PHONY : __/chibios/os/hal/src/mac.c.i __/chibios/os/hal/src/mac.s: __/chibios/os/hal/src/mac.c.s + .PHONY : __/chibios/os/hal/src/mac.s # target to generate assembly for a file @@ -631,6 +708,7 @@ __/chibios/os/hal/src/mac.c.s: .PHONY : __/chibios/os/hal/src/mac.c.s __/chibios/os/hal/src/mmc_spi.obj: __/chibios/os/hal/src/mmc_spi.c.obj + .PHONY : __/chibios/os/hal/src/mmc_spi.obj # target to build an object file @@ -639,6 +717,7 @@ __/chibios/os/hal/src/mmc_spi.c.obj: .PHONY : __/chibios/os/hal/src/mmc_spi.c.obj __/chibios/os/hal/src/mmc_spi.i: __/chibios/os/hal/src/mmc_spi.c.i + .PHONY : __/chibios/os/hal/src/mmc_spi.i # target to preprocess a source file @@ -647,6 +726,7 @@ __/chibios/os/hal/src/mmc_spi.c.i: .PHONY : __/chibios/os/hal/src/mmc_spi.c.i __/chibios/os/hal/src/mmc_spi.s: __/chibios/os/hal/src/mmc_spi.c.s + .PHONY : __/chibios/os/hal/src/mmc_spi.s # target to generate assembly for a file @@ -655,6 +735,7 @@ __/chibios/os/hal/src/mmc_spi.c.s: .PHONY : __/chibios/os/hal/src/mmc_spi.c.s __/chibios/os/hal/src/mmcsd.obj: __/chibios/os/hal/src/mmcsd.c.obj + .PHONY : __/chibios/os/hal/src/mmcsd.obj # target to build an object file @@ -663,6 +744,7 @@ __/chibios/os/hal/src/mmcsd.c.obj: .PHONY : __/chibios/os/hal/src/mmcsd.c.obj __/chibios/os/hal/src/mmcsd.i: __/chibios/os/hal/src/mmcsd.c.i + .PHONY : __/chibios/os/hal/src/mmcsd.i # target to preprocess a source file @@ -671,6 +753,7 @@ __/chibios/os/hal/src/mmcsd.c.i: .PHONY : __/chibios/os/hal/src/mmcsd.c.i __/chibios/os/hal/src/mmcsd.s: __/chibios/os/hal/src/mmcsd.c.s + .PHONY : __/chibios/os/hal/src/mmcsd.s # target to generate assembly for a file @@ -679,6 +762,7 @@ __/chibios/os/hal/src/mmcsd.c.s: .PHONY : __/chibios/os/hal/src/mmcsd.c.s __/chibios/os/hal/src/pal.obj: __/chibios/os/hal/src/pal.c.obj + .PHONY : __/chibios/os/hal/src/pal.obj # target to build an object file @@ -687,6 +771,7 @@ __/chibios/os/hal/src/pal.c.obj: .PHONY : __/chibios/os/hal/src/pal.c.obj __/chibios/os/hal/src/pal.i: __/chibios/os/hal/src/pal.c.i + .PHONY : __/chibios/os/hal/src/pal.i # target to preprocess a source file @@ -695,6 +780,7 @@ __/chibios/os/hal/src/pal.c.i: .PHONY : __/chibios/os/hal/src/pal.c.i __/chibios/os/hal/src/pal.s: __/chibios/os/hal/src/pal.c.s + .PHONY : __/chibios/os/hal/src/pal.s # target to generate assembly for a file @@ -703,6 +789,7 @@ __/chibios/os/hal/src/pal.c.s: .PHONY : __/chibios/os/hal/src/pal.c.s __/chibios/os/hal/src/pwm.obj: __/chibios/os/hal/src/pwm.c.obj + .PHONY : __/chibios/os/hal/src/pwm.obj # target to build an object file @@ -711,6 +798,7 @@ __/chibios/os/hal/src/pwm.c.obj: .PHONY : __/chibios/os/hal/src/pwm.c.obj __/chibios/os/hal/src/pwm.i: __/chibios/os/hal/src/pwm.c.i + .PHONY : __/chibios/os/hal/src/pwm.i # target to preprocess a source file @@ -719,6 +807,7 @@ __/chibios/os/hal/src/pwm.c.i: .PHONY : __/chibios/os/hal/src/pwm.c.i __/chibios/os/hal/src/pwm.s: __/chibios/os/hal/src/pwm.c.s + .PHONY : __/chibios/os/hal/src/pwm.s # target to generate assembly for a file @@ -727,6 +816,7 @@ __/chibios/os/hal/src/pwm.c.s: .PHONY : __/chibios/os/hal/src/pwm.c.s __/chibios/os/hal/src/rtc.obj: __/chibios/os/hal/src/rtc.c.obj + .PHONY : __/chibios/os/hal/src/rtc.obj # target to build an object file @@ -735,6 +825,7 @@ __/chibios/os/hal/src/rtc.c.obj: .PHONY : __/chibios/os/hal/src/rtc.c.obj __/chibios/os/hal/src/rtc.i: __/chibios/os/hal/src/rtc.c.i + .PHONY : __/chibios/os/hal/src/rtc.i # target to preprocess a source file @@ -743,6 +834,7 @@ __/chibios/os/hal/src/rtc.c.i: .PHONY : __/chibios/os/hal/src/rtc.c.i __/chibios/os/hal/src/rtc.s: __/chibios/os/hal/src/rtc.c.s + .PHONY : __/chibios/os/hal/src/rtc.s # target to generate assembly for a file @@ -751,6 +843,7 @@ __/chibios/os/hal/src/rtc.c.s: .PHONY : __/chibios/os/hal/src/rtc.c.s __/chibios/os/hal/src/sdc.obj: __/chibios/os/hal/src/sdc.c.obj + .PHONY : __/chibios/os/hal/src/sdc.obj # target to build an object file @@ -759,6 +852,7 @@ __/chibios/os/hal/src/sdc.c.obj: .PHONY : __/chibios/os/hal/src/sdc.c.obj __/chibios/os/hal/src/sdc.i: __/chibios/os/hal/src/sdc.c.i + .PHONY : __/chibios/os/hal/src/sdc.i # target to preprocess a source file @@ -767,6 +861,7 @@ __/chibios/os/hal/src/sdc.c.i: .PHONY : __/chibios/os/hal/src/sdc.c.i __/chibios/os/hal/src/sdc.s: __/chibios/os/hal/src/sdc.c.s + .PHONY : __/chibios/os/hal/src/sdc.s # target to generate assembly for a file @@ -775,6 +870,7 @@ __/chibios/os/hal/src/sdc.c.s: .PHONY : __/chibios/os/hal/src/sdc.c.s __/chibios/os/hal/src/serial.obj: __/chibios/os/hal/src/serial.c.obj + .PHONY : __/chibios/os/hal/src/serial.obj # target to build an object file @@ -783,6 +879,7 @@ __/chibios/os/hal/src/serial.c.obj: .PHONY : __/chibios/os/hal/src/serial.c.obj __/chibios/os/hal/src/serial.i: __/chibios/os/hal/src/serial.c.i + .PHONY : __/chibios/os/hal/src/serial.i # target to preprocess a source file @@ -791,6 +888,7 @@ __/chibios/os/hal/src/serial.c.i: .PHONY : __/chibios/os/hal/src/serial.c.i __/chibios/os/hal/src/serial.s: __/chibios/os/hal/src/serial.c.s + .PHONY : __/chibios/os/hal/src/serial.s # target to generate assembly for a file @@ -799,6 +897,7 @@ __/chibios/os/hal/src/serial.c.s: .PHONY : __/chibios/os/hal/src/serial.c.s __/chibios/os/hal/src/serial_usb.obj: __/chibios/os/hal/src/serial_usb.c.obj + .PHONY : __/chibios/os/hal/src/serial_usb.obj # target to build an object file @@ -807,6 +906,7 @@ __/chibios/os/hal/src/serial_usb.c.obj: .PHONY : __/chibios/os/hal/src/serial_usb.c.obj __/chibios/os/hal/src/serial_usb.i: __/chibios/os/hal/src/serial_usb.c.i + .PHONY : __/chibios/os/hal/src/serial_usb.i # target to preprocess a source file @@ -815,6 +915,7 @@ __/chibios/os/hal/src/serial_usb.c.i: .PHONY : __/chibios/os/hal/src/serial_usb.c.i __/chibios/os/hal/src/serial_usb.s: __/chibios/os/hal/src/serial_usb.c.s + .PHONY : __/chibios/os/hal/src/serial_usb.s # target to generate assembly for a file @@ -823,6 +924,7 @@ __/chibios/os/hal/src/serial_usb.c.s: .PHONY : __/chibios/os/hal/src/serial_usb.c.s __/chibios/os/hal/src/spi.obj: __/chibios/os/hal/src/spi.c.obj + .PHONY : __/chibios/os/hal/src/spi.obj # target to build an object file @@ -831,6 +933,7 @@ __/chibios/os/hal/src/spi.c.obj: .PHONY : __/chibios/os/hal/src/spi.c.obj __/chibios/os/hal/src/spi.i: __/chibios/os/hal/src/spi.c.i + .PHONY : __/chibios/os/hal/src/spi.i # target to preprocess a source file @@ -839,6 +942,7 @@ __/chibios/os/hal/src/spi.c.i: .PHONY : __/chibios/os/hal/src/spi.c.i __/chibios/os/hal/src/spi.s: __/chibios/os/hal/src/spi.c.s + .PHONY : __/chibios/os/hal/src/spi.s # target to generate assembly for a file @@ -847,6 +951,7 @@ __/chibios/os/hal/src/spi.c.s: .PHONY : __/chibios/os/hal/src/spi.c.s __/chibios/os/hal/src/tm.obj: __/chibios/os/hal/src/tm.c.obj + .PHONY : __/chibios/os/hal/src/tm.obj # target to build an object file @@ -855,6 +960,7 @@ __/chibios/os/hal/src/tm.c.obj: .PHONY : __/chibios/os/hal/src/tm.c.obj __/chibios/os/hal/src/tm.i: __/chibios/os/hal/src/tm.c.i + .PHONY : __/chibios/os/hal/src/tm.i # target to preprocess a source file @@ -863,6 +969,7 @@ __/chibios/os/hal/src/tm.c.i: .PHONY : __/chibios/os/hal/src/tm.c.i __/chibios/os/hal/src/tm.s: __/chibios/os/hal/src/tm.c.s + .PHONY : __/chibios/os/hal/src/tm.s # target to generate assembly for a file @@ -871,6 +978,7 @@ __/chibios/os/hal/src/tm.c.s: .PHONY : __/chibios/os/hal/src/tm.c.s __/chibios/os/hal/src/uart.obj: __/chibios/os/hal/src/uart.c.obj + .PHONY : __/chibios/os/hal/src/uart.obj # target to build an object file @@ -879,6 +987,7 @@ __/chibios/os/hal/src/uart.c.obj: .PHONY : __/chibios/os/hal/src/uart.c.obj __/chibios/os/hal/src/uart.i: __/chibios/os/hal/src/uart.c.i + .PHONY : __/chibios/os/hal/src/uart.i # target to preprocess a source file @@ -887,6 +996,7 @@ __/chibios/os/hal/src/uart.c.i: .PHONY : __/chibios/os/hal/src/uart.c.i __/chibios/os/hal/src/uart.s: __/chibios/os/hal/src/uart.c.s + .PHONY : __/chibios/os/hal/src/uart.s # target to generate assembly for a file @@ -895,6 +1005,7 @@ __/chibios/os/hal/src/uart.c.s: .PHONY : __/chibios/os/hal/src/uart.c.s __/chibios/os/hal/src/usb.obj: __/chibios/os/hal/src/usb.c.obj + .PHONY : __/chibios/os/hal/src/usb.obj # target to build an object file @@ -903,6 +1014,7 @@ __/chibios/os/hal/src/usb.c.obj: .PHONY : __/chibios/os/hal/src/usb.c.obj __/chibios/os/hal/src/usb.i: __/chibios/os/hal/src/usb.c.i + .PHONY : __/chibios/os/hal/src/usb.i # target to preprocess a source file @@ -911,6 +1023,7 @@ __/chibios/os/hal/src/usb.c.i: .PHONY : __/chibios/os/hal/src/usb.c.i __/chibios/os/hal/src/usb.s: __/chibios/os/hal/src/usb.c.s + .PHONY : __/chibios/os/hal/src/usb.s # target to generate assembly for a file @@ -919,6 +1032,7 @@ __/chibios/os/hal/src/usb.c.s: .PHONY : __/chibios/os/hal/src/usb.c.s __/chibios/os/kernel/src/chcond.obj: __/chibios/os/kernel/src/chcond.c.obj + .PHONY : __/chibios/os/kernel/src/chcond.obj # target to build an object file @@ -927,6 +1041,7 @@ __/chibios/os/kernel/src/chcond.c.obj: .PHONY : __/chibios/os/kernel/src/chcond.c.obj __/chibios/os/kernel/src/chcond.i: __/chibios/os/kernel/src/chcond.c.i + .PHONY : __/chibios/os/kernel/src/chcond.i # target to preprocess a source file @@ -935,6 +1050,7 @@ __/chibios/os/kernel/src/chcond.c.i: .PHONY : __/chibios/os/kernel/src/chcond.c.i __/chibios/os/kernel/src/chcond.s: __/chibios/os/kernel/src/chcond.c.s + .PHONY : __/chibios/os/kernel/src/chcond.s # target to generate assembly for a file @@ -943,6 +1059,7 @@ __/chibios/os/kernel/src/chcond.c.s: .PHONY : __/chibios/os/kernel/src/chcond.c.s __/chibios/os/kernel/src/chdebug.obj: __/chibios/os/kernel/src/chdebug.c.obj + .PHONY : __/chibios/os/kernel/src/chdebug.obj # target to build an object file @@ -951,6 +1068,7 @@ __/chibios/os/kernel/src/chdebug.c.obj: .PHONY : __/chibios/os/kernel/src/chdebug.c.obj __/chibios/os/kernel/src/chdebug.i: __/chibios/os/kernel/src/chdebug.c.i + .PHONY : __/chibios/os/kernel/src/chdebug.i # target to preprocess a source file @@ -959,6 +1077,7 @@ __/chibios/os/kernel/src/chdebug.c.i: .PHONY : __/chibios/os/kernel/src/chdebug.c.i __/chibios/os/kernel/src/chdebug.s: __/chibios/os/kernel/src/chdebug.c.s + .PHONY : __/chibios/os/kernel/src/chdebug.s # target to generate assembly for a file @@ -967,6 +1086,7 @@ __/chibios/os/kernel/src/chdebug.c.s: .PHONY : __/chibios/os/kernel/src/chdebug.c.s __/chibios/os/kernel/src/chdynamic.obj: __/chibios/os/kernel/src/chdynamic.c.obj + .PHONY : __/chibios/os/kernel/src/chdynamic.obj # target to build an object file @@ -975,6 +1095,7 @@ __/chibios/os/kernel/src/chdynamic.c.obj: .PHONY : __/chibios/os/kernel/src/chdynamic.c.obj __/chibios/os/kernel/src/chdynamic.i: __/chibios/os/kernel/src/chdynamic.c.i + .PHONY : __/chibios/os/kernel/src/chdynamic.i # target to preprocess a source file @@ -983,6 +1104,7 @@ __/chibios/os/kernel/src/chdynamic.c.i: .PHONY : __/chibios/os/kernel/src/chdynamic.c.i __/chibios/os/kernel/src/chdynamic.s: __/chibios/os/kernel/src/chdynamic.c.s + .PHONY : __/chibios/os/kernel/src/chdynamic.s # target to generate assembly for a file @@ -991,6 +1113,7 @@ __/chibios/os/kernel/src/chdynamic.c.s: .PHONY : __/chibios/os/kernel/src/chdynamic.c.s __/chibios/os/kernel/src/chevents.obj: __/chibios/os/kernel/src/chevents.c.obj + .PHONY : __/chibios/os/kernel/src/chevents.obj # target to build an object file @@ -999,6 +1122,7 @@ __/chibios/os/kernel/src/chevents.c.obj: .PHONY : __/chibios/os/kernel/src/chevents.c.obj __/chibios/os/kernel/src/chevents.i: __/chibios/os/kernel/src/chevents.c.i + .PHONY : __/chibios/os/kernel/src/chevents.i # target to preprocess a source file @@ -1007,6 +1131,7 @@ __/chibios/os/kernel/src/chevents.c.i: .PHONY : __/chibios/os/kernel/src/chevents.c.i __/chibios/os/kernel/src/chevents.s: __/chibios/os/kernel/src/chevents.c.s + .PHONY : __/chibios/os/kernel/src/chevents.s # target to generate assembly for a file @@ -1015,6 +1140,7 @@ __/chibios/os/kernel/src/chevents.c.s: .PHONY : __/chibios/os/kernel/src/chevents.c.s __/chibios/os/kernel/src/chheap.obj: __/chibios/os/kernel/src/chheap.c.obj + .PHONY : __/chibios/os/kernel/src/chheap.obj # target to build an object file @@ -1023,6 +1149,7 @@ __/chibios/os/kernel/src/chheap.c.obj: .PHONY : __/chibios/os/kernel/src/chheap.c.obj __/chibios/os/kernel/src/chheap.i: __/chibios/os/kernel/src/chheap.c.i + .PHONY : __/chibios/os/kernel/src/chheap.i # target to preprocess a source file @@ -1031,6 +1158,7 @@ __/chibios/os/kernel/src/chheap.c.i: .PHONY : __/chibios/os/kernel/src/chheap.c.i __/chibios/os/kernel/src/chheap.s: __/chibios/os/kernel/src/chheap.c.s + .PHONY : __/chibios/os/kernel/src/chheap.s # target to generate assembly for a file @@ -1039,6 +1167,7 @@ __/chibios/os/kernel/src/chheap.c.s: .PHONY : __/chibios/os/kernel/src/chheap.c.s __/chibios/os/kernel/src/chlists.obj: __/chibios/os/kernel/src/chlists.c.obj + .PHONY : __/chibios/os/kernel/src/chlists.obj # target to build an object file @@ -1047,6 +1176,7 @@ __/chibios/os/kernel/src/chlists.c.obj: .PHONY : __/chibios/os/kernel/src/chlists.c.obj __/chibios/os/kernel/src/chlists.i: __/chibios/os/kernel/src/chlists.c.i + .PHONY : __/chibios/os/kernel/src/chlists.i # target to preprocess a source file @@ -1055,6 +1185,7 @@ __/chibios/os/kernel/src/chlists.c.i: .PHONY : __/chibios/os/kernel/src/chlists.c.i __/chibios/os/kernel/src/chlists.s: __/chibios/os/kernel/src/chlists.c.s + .PHONY : __/chibios/os/kernel/src/chlists.s # target to generate assembly for a file @@ -1063,6 +1194,7 @@ __/chibios/os/kernel/src/chlists.c.s: .PHONY : __/chibios/os/kernel/src/chlists.c.s __/chibios/os/kernel/src/chmboxes.obj: __/chibios/os/kernel/src/chmboxes.c.obj + .PHONY : __/chibios/os/kernel/src/chmboxes.obj # target to build an object file @@ -1071,6 +1203,7 @@ __/chibios/os/kernel/src/chmboxes.c.obj: .PHONY : __/chibios/os/kernel/src/chmboxes.c.obj __/chibios/os/kernel/src/chmboxes.i: __/chibios/os/kernel/src/chmboxes.c.i + .PHONY : __/chibios/os/kernel/src/chmboxes.i # target to preprocess a source file @@ -1079,6 +1212,7 @@ __/chibios/os/kernel/src/chmboxes.c.i: .PHONY : __/chibios/os/kernel/src/chmboxes.c.i __/chibios/os/kernel/src/chmboxes.s: __/chibios/os/kernel/src/chmboxes.c.s + .PHONY : __/chibios/os/kernel/src/chmboxes.s # target to generate assembly for a file @@ -1087,6 +1221,7 @@ __/chibios/os/kernel/src/chmboxes.c.s: .PHONY : __/chibios/os/kernel/src/chmboxes.c.s __/chibios/os/kernel/src/chmemcore.obj: __/chibios/os/kernel/src/chmemcore.c.obj + .PHONY : __/chibios/os/kernel/src/chmemcore.obj # target to build an object file @@ -1095,6 +1230,7 @@ __/chibios/os/kernel/src/chmemcore.c.obj: .PHONY : __/chibios/os/kernel/src/chmemcore.c.obj __/chibios/os/kernel/src/chmemcore.i: __/chibios/os/kernel/src/chmemcore.c.i + .PHONY : __/chibios/os/kernel/src/chmemcore.i # target to preprocess a source file @@ -1103,6 +1239,7 @@ __/chibios/os/kernel/src/chmemcore.c.i: .PHONY : __/chibios/os/kernel/src/chmemcore.c.i __/chibios/os/kernel/src/chmemcore.s: __/chibios/os/kernel/src/chmemcore.c.s + .PHONY : __/chibios/os/kernel/src/chmemcore.s # target to generate assembly for a file @@ -1111,6 +1248,7 @@ __/chibios/os/kernel/src/chmemcore.c.s: .PHONY : __/chibios/os/kernel/src/chmemcore.c.s __/chibios/os/kernel/src/chmempools.obj: __/chibios/os/kernel/src/chmempools.c.obj + .PHONY : __/chibios/os/kernel/src/chmempools.obj # target to build an object file @@ -1119,6 +1257,7 @@ __/chibios/os/kernel/src/chmempools.c.obj: .PHONY : __/chibios/os/kernel/src/chmempools.c.obj __/chibios/os/kernel/src/chmempools.i: __/chibios/os/kernel/src/chmempools.c.i + .PHONY : __/chibios/os/kernel/src/chmempools.i # target to preprocess a source file @@ -1127,6 +1266,7 @@ __/chibios/os/kernel/src/chmempools.c.i: .PHONY : __/chibios/os/kernel/src/chmempools.c.i __/chibios/os/kernel/src/chmempools.s: __/chibios/os/kernel/src/chmempools.c.s + .PHONY : __/chibios/os/kernel/src/chmempools.s # target to generate assembly for a file @@ -1135,6 +1275,7 @@ __/chibios/os/kernel/src/chmempools.c.s: .PHONY : __/chibios/os/kernel/src/chmempools.c.s __/chibios/os/kernel/src/chmsg.obj: __/chibios/os/kernel/src/chmsg.c.obj + .PHONY : __/chibios/os/kernel/src/chmsg.obj # target to build an object file @@ -1143,6 +1284,7 @@ __/chibios/os/kernel/src/chmsg.c.obj: .PHONY : __/chibios/os/kernel/src/chmsg.c.obj __/chibios/os/kernel/src/chmsg.i: __/chibios/os/kernel/src/chmsg.c.i + .PHONY : __/chibios/os/kernel/src/chmsg.i # target to preprocess a source file @@ -1151,6 +1293,7 @@ __/chibios/os/kernel/src/chmsg.c.i: .PHONY : __/chibios/os/kernel/src/chmsg.c.i __/chibios/os/kernel/src/chmsg.s: __/chibios/os/kernel/src/chmsg.c.s + .PHONY : __/chibios/os/kernel/src/chmsg.s # target to generate assembly for a file @@ -1159,6 +1302,7 @@ __/chibios/os/kernel/src/chmsg.c.s: .PHONY : __/chibios/os/kernel/src/chmsg.c.s __/chibios/os/kernel/src/chmtx.obj: __/chibios/os/kernel/src/chmtx.c.obj + .PHONY : __/chibios/os/kernel/src/chmtx.obj # target to build an object file @@ -1167,6 +1311,7 @@ __/chibios/os/kernel/src/chmtx.c.obj: .PHONY : __/chibios/os/kernel/src/chmtx.c.obj __/chibios/os/kernel/src/chmtx.i: __/chibios/os/kernel/src/chmtx.c.i + .PHONY : __/chibios/os/kernel/src/chmtx.i # target to preprocess a source file @@ -1175,6 +1320,7 @@ __/chibios/os/kernel/src/chmtx.c.i: .PHONY : __/chibios/os/kernel/src/chmtx.c.i __/chibios/os/kernel/src/chmtx.s: __/chibios/os/kernel/src/chmtx.c.s + .PHONY : __/chibios/os/kernel/src/chmtx.s # target to generate assembly for a file @@ -1183,6 +1329,7 @@ __/chibios/os/kernel/src/chmtx.c.s: .PHONY : __/chibios/os/kernel/src/chmtx.c.s __/chibios/os/kernel/src/chqueues.obj: __/chibios/os/kernel/src/chqueues.c.obj + .PHONY : __/chibios/os/kernel/src/chqueues.obj # target to build an object file @@ -1191,6 +1338,7 @@ __/chibios/os/kernel/src/chqueues.c.obj: .PHONY : __/chibios/os/kernel/src/chqueues.c.obj __/chibios/os/kernel/src/chqueues.i: __/chibios/os/kernel/src/chqueues.c.i + .PHONY : __/chibios/os/kernel/src/chqueues.i # target to preprocess a source file @@ -1199,6 +1347,7 @@ __/chibios/os/kernel/src/chqueues.c.i: .PHONY : __/chibios/os/kernel/src/chqueues.c.i __/chibios/os/kernel/src/chqueues.s: __/chibios/os/kernel/src/chqueues.c.s + .PHONY : __/chibios/os/kernel/src/chqueues.s # target to generate assembly for a file @@ -1207,6 +1356,7 @@ __/chibios/os/kernel/src/chqueues.c.s: .PHONY : __/chibios/os/kernel/src/chqueues.c.s __/chibios/os/kernel/src/chregistry.obj: __/chibios/os/kernel/src/chregistry.c.obj + .PHONY : __/chibios/os/kernel/src/chregistry.obj # target to build an object file @@ -1215,6 +1365,7 @@ __/chibios/os/kernel/src/chregistry.c.obj: .PHONY : __/chibios/os/kernel/src/chregistry.c.obj __/chibios/os/kernel/src/chregistry.i: __/chibios/os/kernel/src/chregistry.c.i + .PHONY : __/chibios/os/kernel/src/chregistry.i # target to preprocess a source file @@ -1223,6 +1374,7 @@ __/chibios/os/kernel/src/chregistry.c.i: .PHONY : __/chibios/os/kernel/src/chregistry.c.i __/chibios/os/kernel/src/chregistry.s: __/chibios/os/kernel/src/chregistry.c.s + .PHONY : __/chibios/os/kernel/src/chregistry.s # target to generate assembly for a file @@ -1231,6 +1383,7 @@ __/chibios/os/kernel/src/chregistry.c.s: .PHONY : __/chibios/os/kernel/src/chregistry.c.s __/chibios/os/kernel/src/chschd.obj: __/chibios/os/kernel/src/chschd.c.obj + .PHONY : __/chibios/os/kernel/src/chschd.obj # target to build an object file @@ -1239,6 +1392,7 @@ __/chibios/os/kernel/src/chschd.c.obj: .PHONY : __/chibios/os/kernel/src/chschd.c.obj __/chibios/os/kernel/src/chschd.i: __/chibios/os/kernel/src/chschd.c.i + .PHONY : __/chibios/os/kernel/src/chschd.i # target to preprocess a source file @@ -1247,6 +1401,7 @@ __/chibios/os/kernel/src/chschd.c.i: .PHONY : __/chibios/os/kernel/src/chschd.c.i __/chibios/os/kernel/src/chschd.s: __/chibios/os/kernel/src/chschd.c.s + .PHONY : __/chibios/os/kernel/src/chschd.s # target to generate assembly for a file @@ -1255,6 +1410,7 @@ __/chibios/os/kernel/src/chschd.c.s: .PHONY : __/chibios/os/kernel/src/chschd.c.s __/chibios/os/kernel/src/chsem.obj: __/chibios/os/kernel/src/chsem.c.obj + .PHONY : __/chibios/os/kernel/src/chsem.obj # target to build an object file @@ -1263,6 +1419,7 @@ __/chibios/os/kernel/src/chsem.c.obj: .PHONY : __/chibios/os/kernel/src/chsem.c.obj __/chibios/os/kernel/src/chsem.i: __/chibios/os/kernel/src/chsem.c.i + .PHONY : __/chibios/os/kernel/src/chsem.i # target to preprocess a source file @@ -1271,6 +1428,7 @@ __/chibios/os/kernel/src/chsem.c.i: .PHONY : __/chibios/os/kernel/src/chsem.c.i __/chibios/os/kernel/src/chsem.s: __/chibios/os/kernel/src/chsem.c.s + .PHONY : __/chibios/os/kernel/src/chsem.s # target to generate assembly for a file @@ -1279,6 +1437,7 @@ __/chibios/os/kernel/src/chsem.c.s: .PHONY : __/chibios/os/kernel/src/chsem.c.s __/chibios/os/kernel/src/chsys.obj: __/chibios/os/kernel/src/chsys.c.obj + .PHONY : __/chibios/os/kernel/src/chsys.obj # target to build an object file @@ -1287,6 +1446,7 @@ __/chibios/os/kernel/src/chsys.c.obj: .PHONY : __/chibios/os/kernel/src/chsys.c.obj __/chibios/os/kernel/src/chsys.i: __/chibios/os/kernel/src/chsys.c.i + .PHONY : __/chibios/os/kernel/src/chsys.i # target to preprocess a source file @@ -1295,6 +1455,7 @@ __/chibios/os/kernel/src/chsys.c.i: .PHONY : __/chibios/os/kernel/src/chsys.c.i __/chibios/os/kernel/src/chsys.s: __/chibios/os/kernel/src/chsys.c.s + .PHONY : __/chibios/os/kernel/src/chsys.s # target to generate assembly for a file @@ -1303,6 +1464,7 @@ __/chibios/os/kernel/src/chsys.c.s: .PHONY : __/chibios/os/kernel/src/chsys.c.s __/chibios/os/kernel/src/chthreads.obj: __/chibios/os/kernel/src/chthreads.c.obj + .PHONY : __/chibios/os/kernel/src/chthreads.obj # target to build an object file @@ -1311,6 +1473,7 @@ __/chibios/os/kernel/src/chthreads.c.obj: .PHONY : __/chibios/os/kernel/src/chthreads.c.obj __/chibios/os/kernel/src/chthreads.i: __/chibios/os/kernel/src/chthreads.c.i + .PHONY : __/chibios/os/kernel/src/chthreads.i # target to preprocess a source file @@ -1319,6 +1482,7 @@ __/chibios/os/kernel/src/chthreads.c.i: .PHONY : __/chibios/os/kernel/src/chthreads.c.i __/chibios/os/kernel/src/chthreads.s: __/chibios/os/kernel/src/chthreads.c.s + .PHONY : __/chibios/os/kernel/src/chthreads.s # target to generate assembly for a file @@ -1327,6 +1491,7 @@ __/chibios/os/kernel/src/chthreads.c.s: .PHONY : __/chibios/os/kernel/src/chthreads.c.s __/chibios/os/kernel/src/chvt.obj: __/chibios/os/kernel/src/chvt.c.obj + .PHONY : __/chibios/os/kernel/src/chvt.obj # target to build an object file @@ -1335,6 +1500,7 @@ __/chibios/os/kernel/src/chvt.c.obj: .PHONY : __/chibios/os/kernel/src/chvt.c.obj __/chibios/os/kernel/src/chvt.i: __/chibios/os/kernel/src/chvt.c.i + .PHONY : __/chibios/os/kernel/src/chvt.i # target to preprocess a source file @@ -1343,6 +1509,7 @@ __/chibios/os/kernel/src/chvt.c.i: .PHONY : __/chibios/os/kernel/src/chvt.c.i __/chibios/os/kernel/src/chvt.s: __/chibios/os/kernel/src/chvt.c.s + .PHONY : __/chibios/os/kernel/src/chvt.s # target to generate assembly for a file @@ -1351,6 +1518,7 @@ __/chibios/os/kernel/src/chvt.c.s: .PHONY : __/chibios/os/kernel/src/chvt.c.s __/chibios/os/ports/GCC/ARMCMx/chcore.obj: __/chibios/os/ports/GCC/ARMCMx/chcore.c.obj + .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore.obj # target to build an object file @@ -1359,6 +1527,7 @@ __/chibios/os/ports/GCC/ARMCMx/chcore.c.obj: .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore.c.obj __/chibios/os/ports/GCC/ARMCMx/chcore.i: __/chibios/os/ports/GCC/ARMCMx/chcore.c.i + .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore.i # target to preprocess a source file @@ -1367,6 +1536,7 @@ __/chibios/os/ports/GCC/ARMCMx/chcore.c.i: .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore.c.i __/chibios/os/ports/GCC/ARMCMx/chcore.s: __/chibios/os/ports/GCC/ARMCMx/chcore.c.s + .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore.s # target to generate assembly for a file @@ -1375,6 +1545,7 @@ __/chibios/os/ports/GCC/ARMCMx/chcore.c.s: .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore.c.s __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.obj: __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.obj + .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.obj # target to build an object file @@ -1383,6 +1554,7 @@ __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.obj: .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.obj __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.i: __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.i + .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.i # target to preprocess a source file @@ -1391,6 +1563,7 @@ __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.i: .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.i __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.s: __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.s + .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.s # target to generate assembly for a file @@ -1399,6 +1572,7 @@ __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.s: .PHONY : __/chibios/os/ports/GCC/ARMCMx/chcore_v6m.c.s __/chibios/os/ports/GCC/ARMCMx/crt0.obj: __/chibios/os/ports/GCC/ARMCMx/crt0.c.obj + .PHONY : __/chibios/os/ports/GCC/ARMCMx/crt0.obj # target to build an object file @@ -1407,6 +1581,7 @@ __/chibios/os/ports/GCC/ARMCMx/crt0.c.obj: .PHONY : __/chibios/os/ports/GCC/ARMCMx/crt0.c.obj __/chibios/os/ports/GCC/ARMCMx/crt0.i: __/chibios/os/ports/GCC/ARMCMx/crt0.c.i + .PHONY : __/chibios/os/ports/GCC/ARMCMx/crt0.i # target to preprocess a source file @@ -1415,6 +1590,7 @@ __/chibios/os/ports/GCC/ARMCMx/crt0.c.i: .PHONY : __/chibios/os/ports/GCC/ARMCMx/crt0.c.i __/chibios/os/ports/GCC/ARMCMx/crt0.s: __/chibios/os/ports/GCC/ARMCMx/crt0.c.s + .PHONY : __/chibios/os/ports/GCC/ARMCMx/crt0.s # target to generate assembly for a file @@ -1423,6 +1599,7 @@ __/chibios/os/ports/GCC/ARMCMx/crt0.c.s: .PHONY : __/chibios/os/ports/GCC/ARMCMx/crt0.c.s __/chibios/os/ports/common/ARMCMx/nvic.obj: __/chibios/os/ports/common/ARMCMx/nvic.c.obj + .PHONY : __/chibios/os/ports/common/ARMCMx/nvic.obj # target to build an object file @@ -1431,6 +1608,7 @@ __/chibios/os/ports/common/ARMCMx/nvic.c.obj: .PHONY : __/chibios/os/ports/common/ARMCMx/nvic.c.obj __/chibios/os/ports/common/ARMCMx/nvic.i: __/chibios/os/ports/common/ARMCMx/nvic.c.i + .PHONY : __/chibios/os/ports/common/ARMCMx/nvic.i # target to preprocess a source file @@ -1439,6 +1617,7 @@ __/chibios/os/ports/common/ARMCMx/nvic.c.i: .PHONY : __/chibios/os/ports/common/ARMCMx/nvic.c.i __/chibios/os/ports/common/ARMCMx/nvic.s: __/chibios/os/ports/common/ARMCMx/nvic.c.s + .PHONY : __/chibios/os/ports/common/ARMCMx/nvic.s # target to generate assembly for a file @@ -1447,6 +1626,7 @@ __/chibios/os/ports/common/ARMCMx/nvic.c.s: .PHONY : __/chibios/os/ports/common/ARMCMx/nvic.c.s __/chibios/test/test.obj: __/chibios/test/test.c.obj + .PHONY : __/chibios/test/test.obj # target to build an object file @@ -1455,6 +1635,7 @@ __/chibios/test/test.c.obj: .PHONY : __/chibios/test/test.c.obj __/chibios/test/test.i: __/chibios/test/test.c.i + .PHONY : __/chibios/test/test.i # target to preprocess a source file @@ -1463,6 +1644,7 @@ __/chibios/test/test.c.i: .PHONY : __/chibios/test/test.c.i __/chibios/test/test.s: __/chibios/test/test.c.s + .PHONY : __/chibios/test/test.s # target to generate assembly for a file @@ -1471,6 +1653,7 @@ __/chibios/test/test.c.s: .PHONY : __/chibios/test/test.c.s __/chibios/test/testbmk.obj: __/chibios/test/testbmk.c.obj + .PHONY : __/chibios/test/testbmk.obj # target to build an object file @@ -1479,6 +1662,7 @@ __/chibios/test/testbmk.c.obj: .PHONY : __/chibios/test/testbmk.c.obj __/chibios/test/testbmk.i: __/chibios/test/testbmk.c.i + .PHONY : __/chibios/test/testbmk.i # target to preprocess a source file @@ -1487,6 +1671,7 @@ __/chibios/test/testbmk.c.i: .PHONY : __/chibios/test/testbmk.c.i __/chibios/test/testbmk.s: __/chibios/test/testbmk.c.s + .PHONY : __/chibios/test/testbmk.s # target to generate assembly for a file @@ -1495,6 +1680,7 @@ __/chibios/test/testbmk.c.s: .PHONY : __/chibios/test/testbmk.c.s __/chibios/test/testdyn.obj: __/chibios/test/testdyn.c.obj + .PHONY : __/chibios/test/testdyn.obj # target to build an object file @@ -1503,6 +1689,7 @@ __/chibios/test/testdyn.c.obj: .PHONY : __/chibios/test/testdyn.c.obj __/chibios/test/testdyn.i: __/chibios/test/testdyn.c.i + .PHONY : __/chibios/test/testdyn.i # target to preprocess a source file @@ -1511,6 +1698,7 @@ __/chibios/test/testdyn.c.i: .PHONY : __/chibios/test/testdyn.c.i __/chibios/test/testdyn.s: __/chibios/test/testdyn.c.s + .PHONY : __/chibios/test/testdyn.s # target to generate assembly for a file @@ -1519,6 +1707,7 @@ __/chibios/test/testdyn.c.s: .PHONY : __/chibios/test/testdyn.c.s __/chibios/test/testevt.obj: __/chibios/test/testevt.c.obj + .PHONY : __/chibios/test/testevt.obj # target to build an object file @@ -1527,6 +1716,7 @@ __/chibios/test/testevt.c.obj: .PHONY : __/chibios/test/testevt.c.obj __/chibios/test/testevt.i: __/chibios/test/testevt.c.i + .PHONY : __/chibios/test/testevt.i # target to preprocess a source file @@ -1535,6 +1725,7 @@ __/chibios/test/testevt.c.i: .PHONY : __/chibios/test/testevt.c.i __/chibios/test/testevt.s: __/chibios/test/testevt.c.s + .PHONY : __/chibios/test/testevt.s # target to generate assembly for a file @@ -1543,6 +1734,7 @@ __/chibios/test/testevt.c.s: .PHONY : __/chibios/test/testevt.c.s __/chibios/test/testheap.obj: __/chibios/test/testheap.c.obj + .PHONY : __/chibios/test/testheap.obj # target to build an object file @@ -1551,6 +1743,7 @@ __/chibios/test/testheap.c.obj: .PHONY : __/chibios/test/testheap.c.obj __/chibios/test/testheap.i: __/chibios/test/testheap.c.i + .PHONY : __/chibios/test/testheap.i # target to preprocess a source file @@ -1559,6 +1752,7 @@ __/chibios/test/testheap.c.i: .PHONY : __/chibios/test/testheap.c.i __/chibios/test/testheap.s: __/chibios/test/testheap.c.s + .PHONY : __/chibios/test/testheap.s # target to generate assembly for a file @@ -1567,6 +1761,7 @@ __/chibios/test/testheap.c.s: .PHONY : __/chibios/test/testheap.c.s __/chibios/test/testmbox.obj: __/chibios/test/testmbox.c.obj + .PHONY : __/chibios/test/testmbox.obj # target to build an object file @@ -1575,6 +1770,7 @@ __/chibios/test/testmbox.c.obj: .PHONY : __/chibios/test/testmbox.c.obj __/chibios/test/testmbox.i: __/chibios/test/testmbox.c.i + .PHONY : __/chibios/test/testmbox.i # target to preprocess a source file @@ -1583,6 +1779,7 @@ __/chibios/test/testmbox.c.i: .PHONY : __/chibios/test/testmbox.c.i __/chibios/test/testmbox.s: __/chibios/test/testmbox.c.s + .PHONY : __/chibios/test/testmbox.s # target to generate assembly for a file @@ -1591,6 +1788,7 @@ __/chibios/test/testmbox.c.s: .PHONY : __/chibios/test/testmbox.c.s __/chibios/test/testmsg.obj: __/chibios/test/testmsg.c.obj + .PHONY : __/chibios/test/testmsg.obj # target to build an object file @@ -1599,6 +1797,7 @@ __/chibios/test/testmsg.c.obj: .PHONY : __/chibios/test/testmsg.c.obj __/chibios/test/testmsg.i: __/chibios/test/testmsg.c.i + .PHONY : __/chibios/test/testmsg.i # target to preprocess a source file @@ -1607,6 +1806,7 @@ __/chibios/test/testmsg.c.i: .PHONY : __/chibios/test/testmsg.c.i __/chibios/test/testmsg.s: __/chibios/test/testmsg.c.s + .PHONY : __/chibios/test/testmsg.s # target to generate assembly for a file @@ -1615,6 +1815,7 @@ __/chibios/test/testmsg.c.s: .PHONY : __/chibios/test/testmsg.c.s __/chibios/test/testmtx.obj: __/chibios/test/testmtx.c.obj + .PHONY : __/chibios/test/testmtx.obj # target to build an object file @@ -1623,6 +1824,7 @@ __/chibios/test/testmtx.c.obj: .PHONY : __/chibios/test/testmtx.c.obj __/chibios/test/testmtx.i: __/chibios/test/testmtx.c.i + .PHONY : __/chibios/test/testmtx.i # target to preprocess a source file @@ -1631,6 +1833,7 @@ __/chibios/test/testmtx.c.i: .PHONY : __/chibios/test/testmtx.c.i __/chibios/test/testmtx.s: __/chibios/test/testmtx.c.s + .PHONY : __/chibios/test/testmtx.s # target to generate assembly for a file @@ -1639,6 +1842,7 @@ __/chibios/test/testmtx.c.s: .PHONY : __/chibios/test/testmtx.c.s __/chibios/test/testpools.obj: __/chibios/test/testpools.c.obj + .PHONY : __/chibios/test/testpools.obj # target to build an object file @@ -1647,6 +1851,7 @@ __/chibios/test/testpools.c.obj: .PHONY : __/chibios/test/testpools.c.obj __/chibios/test/testpools.i: __/chibios/test/testpools.c.i + .PHONY : __/chibios/test/testpools.i # target to preprocess a source file @@ -1655,6 +1860,7 @@ __/chibios/test/testpools.c.i: .PHONY : __/chibios/test/testpools.c.i __/chibios/test/testpools.s: __/chibios/test/testpools.c.s + .PHONY : __/chibios/test/testpools.s # target to generate assembly for a file @@ -1663,6 +1869,7 @@ __/chibios/test/testpools.c.s: .PHONY : __/chibios/test/testpools.c.s __/chibios/test/testqueues.obj: __/chibios/test/testqueues.c.obj + .PHONY : __/chibios/test/testqueues.obj # target to build an object file @@ -1671,6 +1878,7 @@ __/chibios/test/testqueues.c.obj: .PHONY : __/chibios/test/testqueues.c.obj __/chibios/test/testqueues.i: __/chibios/test/testqueues.c.i + .PHONY : __/chibios/test/testqueues.i # target to preprocess a source file @@ -1679,6 +1887,7 @@ __/chibios/test/testqueues.c.i: .PHONY : __/chibios/test/testqueues.c.i __/chibios/test/testqueues.s: __/chibios/test/testqueues.c.s + .PHONY : __/chibios/test/testqueues.s # target to generate assembly for a file @@ -1687,6 +1896,7 @@ __/chibios/test/testqueues.c.s: .PHONY : __/chibios/test/testqueues.c.s __/chibios/test/testsem.obj: __/chibios/test/testsem.c.obj + .PHONY : __/chibios/test/testsem.obj # target to build an object file @@ -1695,6 +1905,7 @@ __/chibios/test/testsem.c.obj: .PHONY : __/chibios/test/testsem.c.obj __/chibios/test/testsem.i: __/chibios/test/testsem.c.i + .PHONY : __/chibios/test/testsem.i # target to preprocess a source file @@ -1703,6 +1914,7 @@ __/chibios/test/testsem.c.i: .PHONY : __/chibios/test/testsem.c.i __/chibios/test/testsem.s: __/chibios/test/testsem.c.s + .PHONY : __/chibios/test/testsem.s # target to generate assembly for a file @@ -1711,6 +1923,7 @@ __/chibios/test/testsem.c.s: .PHONY : __/chibios/test/testsem.c.s __/chibios/test/testthd.obj: __/chibios/test/testthd.c.obj + .PHONY : __/chibios/test/testthd.obj # target to build an object file @@ -1719,6 +1932,7 @@ __/chibios/test/testthd.c.obj: .PHONY : __/chibios/test/testthd.c.obj __/chibios/test/testthd.i: __/chibios/test/testthd.c.i + .PHONY : __/chibios/test/testthd.i # target to preprocess a source file @@ -1727,6 +1941,7 @@ __/chibios/test/testthd.c.i: .PHONY : __/chibios/test/testthd.c.i __/chibios/test/testthd.s: __/chibios/test/testthd.c.s + .PHONY : __/chibios/test/testthd.s # target to generate assembly for a file @@ -1735,6 +1950,7 @@ __/chibios/test/testthd.c.s: .PHONY : __/chibios/test/testthd.c.s __/common/ais_baseband.obj: __/common/ais_baseband.cpp.obj + .PHONY : __/common/ais_baseband.obj # target to build an object file @@ -1743,6 +1959,7 @@ __/common/ais_baseband.cpp.obj: .PHONY : __/common/ais_baseband.cpp.obj __/common/ais_baseband.i: __/common/ais_baseband.cpp.i + .PHONY : __/common/ais_baseband.i # target to preprocess a source file @@ -1751,6 +1968,7 @@ __/common/ais_baseband.cpp.i: .PHONY : __/common/ais_baseband.cpp.i __/common/ais_baseband.s: __/common/ais_baseband.cpp.s + .PHONY : __/common/ais_baseband.s # target to generate assembly for a file @@ -1759,6 +1977,7 @@ __/common/ais_baseband.cpp.s: .PHONY : __/common/ais_baseband.cpp.s __/common/ais_packet.obj: __/common/ais_packet.cpp.obj + .PHONY : __/common/ais_packet.obj # target to build an object file @@ -1767,6 +1986,7 @@ __/common/ais_packet.cpp.obj: .PHONY : __/common/ais_packet.cpp.obj __/common/ais_packet.i: __/common/ais_packet.cpp.i + .PHONY : __/common/ais_packet.i # target to preprocess a source file @@ -1775,6 +1995,7 @@ __/common/ais_packet.cpp.i: .PHONY : __/common/ais_packet.cpp.i __/common/ais_packet.s: __/common/ais_packet.cpp.s + .PHONY : __/common/ais_packet.s # target to generate assembly for a file @@ -1783,6 +2004,7 @@ __/common/ais_packet.cpp.s: .PHONY : __/common/ais_packet.cpp.s __/common/chibios_cpp.obj: __/common/chibios_cpp.cpp.obj + .PHONY : __/common/chibios_cpp.obj # target to build an object file @@ -1791,6 +2013,7 @@ __/common/chibios_cpp.cpp.obj: .PHONY : __/common/chibios_cpp.cpp.obj __/common/chibios_cpp.i: __/common/chibios_cpp.cpp.i + .PHONY : __/common/chibios_cpp.i # target to preprocess a source file @@ -1799,6 +2022,7 @@ __/common/chibios_cpp.cpp.i: .PHONY : __/common/chibios_cpp.cpp.i __/common/chibios_cpp.s: __/common/chibios_cpp.cpp.s + .PHONY : __/common/chibios_cpp.s # target to generate assembly for a file @@ -1807,6 +2031,7 @@ __/common/chibios_cpp.cpp.s: .PHONY : __/common/chibios_cpp.cpp.s __/common/cpld_max5.obj: __/common/cpld_max5.cpp.obj + .PHONY : __/common/cpld_max5.obj # target to build an object file @@ -1815,6 +2040,7 @@ __/common/cpld_max5.cpp.obj: .PHONY : __/common/cpld_max5.cpp.obj __/common/cpld_max5.i: __/common/cpld_max5.cpp.i + .PHONY : __/common/cpld_max5.i # target to preprocess a source file @@ -1823,6 +2049,7 @@ __/common/cpld_max5.cpp.i: .PHONY : __/common/cpld_max5.cpp.i __/common/cpld_max5.s: __/common/cpld_max5.cpp.s + .PHONY : __/common/cpld_max5.s # target to generate assembly for a file @@ -1831,6 +2058,7 @@ __/common/cpld_max5.cpp.s: .PHONY : __/common/cpld_max5.cpp.s __/common/cpld_xilinx.obj: __/common/cpld_xilinx.cpp.obj + .PHONY : __/common/cpld_xilinx.obj # target to build an object file @@ -1839,6 +2067,7 @@ __/common/cpld_xilinx.cpp.obj: .PHONY : __/common/cpld_xilinx.cpp.obj __/common/cpld_xilinx.i: __/common/cpld_xilinx.cpp.i + .PHONY : __/common/cpld_xilinx.i # target to preprocess a source file @@ -1847,6 +2076,7 @@ __/common/cpld_xilinx.cpp.i: .PHONY : __/common/cpld_xilinx.cpp.i __/common/cpld_xilinx.s: __/common/cpld_xilinx.cpp.s + .PHONY : __/common/cpld_xilinx.s # target to generate assembly for a file @@ -1855,6 +2085,7 @@ __/common/cpld_xilinx.cpp.s: .PHONY : __/common/cpld_xilinx.cpp.s __/common/debug.obj: __/common/debug.cpp.obj + .PHONY : __/common/debug.obj # target to build an object file @@ -1863,6 +2094,7 @@ __/common/debug.cpp.obj: .PHONY : __/common/debug.cpp.obj __/common/debug.i: __/common/debug.cpp.i + .PHONY : __/common/debug.i # target to preprocess a source file @@ -1871,6 +2103,7 @@ __/common/debug.cpp.i: .PHONY : __/common/debug.cpp.i __/common/debug.s: __/common/debug.cpp.s + .PHONY : __/common/debug.s # target to generate assembly for a file @@ -1879,6 +2112,7 @@ __/common/debug.cpp.s: .PHONY : __/common/debug.cpp.s __/common/ert_packet.obj: __/common/ert_packet.cpp.obj + .PHONY : __/common/ert_packet.obj # target to build an object file @@ -1887,6 +2121,7 @@ __/common/ert_packet.cpp.obj: .PHONY : __/common/ert_packet.cpp.obj __/common/ert_packet.i: __/common/ert_packet.cpp.i + .PHONY : __/common/ert_packet.i # target to preprocess a source file @@ -1895,6 +2130,7 @@ __/common/ert_packet.cpp.i: .PHONY : __/common/ert_packet.cpp.i __/common/ert_packet.s: __/common/ert_packet.cpp.s + .PHONY : __/common/ert_packet.s # target to generate assembly for a file @@ -1903,6 +2139,7 @@ __/common/ert_packet.cpp.s: .PHONY : __/common/ert_packet.cpp.s __/common/event.obj: __/common/event.cpp.obj + .PHONY : __/common/event.obj # target to build an object file @@ -1911,6 +2148,7 @@ __/common/event.cpp.obj: .PHONY : __/common/event.cpp.obj __/common/event.i: __/common/event.cpp.i + .PHONY : __/common/event.i # target to preprocess a source file @@ -1919,6 +2157,7 @@ __/common/event.cpp.i: .PHONY : __/common/event.cpp.i __/common/event.s: __/common/event.cpp.s + .PHONY : __/common/event.s # target to generate assembly for a file @@ -1927,6 +2166,7 @@ __/common/event.cpp.s: .PHONY : __/common/event.cpp.s __/common/gcc.obj: __/common/gcc.cpp.obj + .PHONY : __/common/gcc.obj # target to build an object file @@ -1935,6 +2175,7 @@ __/common/gcc.cpp.obj: .PHONY : __/common/gcc.cpp.obj __/common/gcc.i: __/common/gcc.cpp.i + .PHONY : __/common/gcc.i # target to preprocess a source file @@ -1943,6 +2184,7 @@ __/common/gcc.cpp.i: .PHONY : __/common/gcc.cpp.i __/common/gcc.s: __/common/gcc.cpp.s + .PHONY : __/common/gcc.s # target to generate assembly for a file @@ -1951,6 +2193,7 @@ __/common/gcc.cpp.s: .PHONY : __/common/gcc.cpp.s __/common/hackrf_hal.obj: __/common/hackrf_hal.cpp.obj + .PHONY : __/common/hackrf_hal.obj # target to build an object file @@ -1959,6 +2202,7 @@ __/common/hackrf_hal.cpp.obj: .PHONY : __/common/hackrf_hal.cpp.obj __/common/hackrf_hal.i: __/common/hackrf_hal.cpp.i + .PHONY : __/common/hackrf_hal.i # target to preprocess a source file @@ -1967,6 +2211,7 @@ __/common/hackrf_hal.cpp.i: .PHONY : __/common/hackrf_hal.cpp.i __/common/hackrf_hal.s: __/common/hackrf_hal.cpp.s + .PHONY : __/common/hackrf_hal.s # target to generate assembly for a file @@ -1975,6 +2220,7 @@ __/common/hackrf_hal.cpp.s: .PHONY : __/common/hackrf_hal.cpp.s __/common/i2c_pp.obj: __/common/i2c_pp.cpp.obj + .PHONY : __/common/i2c_pp.obj # target to build an object file @@ -1983,6 +2229,7 @@ __/common/i2c_pp.cpp.obj: .PHONY : __/common/i2c_pp.cpp.obj __/common/i2c_pp.i: __/common/i2c_pp.cpp.i + .PHONY : __/common/i2c_pp.i # target to preprocess a source file @@ -1991,6 +2238,7 @@ __/common/i2c_pp.cpp.i: .PHONY : __/common/i2c_pp.cpp.i __/common/i2c_pp.s: __/common/i2c_pp.cpp.s + .PHONY : __/common/i2c_pp.s # target to generate assembly for a file @@ -1999,6 +2247,7 @@ __/common/i2c_pp.cpp.s: .PHONY : __/common/i2c_pp.cpp.s __/common/jtag.obj: __/common/jtag.cpp.obj + .PHONY : __/common/jtag.obj # target to build an object file @@ -2007,6 +2256,7 @@ __/common/jtag.cpp.obj: .PHONY : __/common/jtag.cpp.obj __/common/jtag.i: __/common/jtag.cpp.i + .PHONY : __/common/jtag.i # target to preprocess a source file @@ -2015,6 +2265,7 @@ __/common/jtag.cpp.i: .PHONY : __/common/jtag.cpp.i __/common/jtag.s: __/common/jtag.cpp.s + .PHONY : __/common/jtag.s # target to generate assembly for a file @@ -2023,6 +2274,7 @@ __/common/jtag.cpp.s: .PHONY : __/common/jtag.cpp.s __/common/jtag_tap.obj: __/common/jtag_tap.cpp.obj + .PHONY : __/common/jtag_tap.obj # target to build an object file @@ -2031,6 +2283,7 @@ __/common/jtag_tap.cpp.obj: .PHONY : __/common/jtag_tap.cpp.obj __/common/jtag_tap.i: __/common/jtag_tap.cpp.i + .PHONY : __/common/jtag_tap.i # target to preprocess a source file @@ -2039,6 +2292,7 @@ __/common/jtag_tap.cpp.i: .PHONY : __/common/jtag_tap.cpp.i __/common/jtag_tap.s: __/common/jtag_tap.cpp.s + .PHONY : __/common/jtag_tap.s # target to generate assembly for a file @@ -2047,6 +2301,7 @@ __/common/jtag_tap.cpp.s: .PHONY : __/common/jtag_tap.cpp.s __/common/lcd_ili9341.obj: __/common/lcd_ili9341.cpp.obj + .PHONY : __/common/lcd_ili9341.obj # target to build an object file @@ -2055,6 +2310,7 @@ __/common/lcd_ili9341.cpp.obj: .PHONY : __/common/lcd_ili9341.cpp.obj __/common/lcd_ili9341.i: __/common/lcd_ili9341.cpp.i + .PHONY : __/common/lcd_ili9341.i # target to preprocess a source file @@ -2063,6 +2319,7 @@ __/common/lcd_ili9341.cpp.i: .PHONY : __/common/lcd_ili9341.cpp.i __/common/lcd_ili9341.s: __/common/lcd_ili9341.cpp.s + .PHONY : __/common/lcd_ili9341.s # target to generate assembly for a file @@ -2071,6 +2328,7 @@ __/common/lcd_ili9341.cpp.s: .PHONY : __/common/lcd_ili9341.cpp.s __/common/lfsr_random.obj: __/common/lfsr_random.cpp.obj + .PHONY : __/common/lfsr_random.obj # target to build an object file @@ -2079,6 +2337,7 @@ __/common/lfsr_random.cpp.obj: .PHONY : __/common/lfsr_random.cpp.obj __/common/lfsr_random.i: __/common/lfsr_random.cpp.i + .PHONY : __/common/lfsr_random.i # target to preprocess a source file @@ -2087,6 +2346,7 @@ __/common/lfsr_random.cpp.i: .PHONY : __/common/lfsr_random.cpp.i __/common/lfsr_random.s: __/common/lfsr_random.cpp.s + .PHONY : __/common/lfsr_random.s # target to generate assembly for a file @@ -2095,6 +2355,7 @@ __/common/lfsr_random.cpp.s: .PHONY : __/common/lfsr_random.cpp.s __/common/manchester.obj: __/common/manchester.cpp.obj + .PHONY : __/common/manchester.obj # target to build an object file @@ -2103,6 +2364,7 @@ __/common/manchester.cpp.obj: .PHONY : __/common/manchester.cpp.obj __/common/manchester.i: __/common/manchester.cpp.i + .PHONY : __/common/manchester.i # target to preprocess a source file @@ -2111,6 +2373,7 @@ __/common/manchester.cpp.i: .PHONY : __/common/manchester.cpp.i __/common/manchester.s: __/common/manchester.cpp.s + .PHONY : __/common/manchester.s # target to generate assembly for a file @@ -2119,6 +2382,7 @@ __/common/manchester.cpp.s: .PHONY : __/common/manchester.cpp.s __/common/message_queue.obj: __/common/message_queue.cpp.obj + .PHONY : __/common/message_queue.obj # target to build an object file @@ -2127,6 +2391,7 @@ __/common/message_queue.cpp.obj: .PHONY : __/common/message_queue.cpp.obj __/common/message_queue.i: __/common/message_queue.cpp.i + .PHONY : __/common/message_queue.i # target to preprocess a source file @@ -2135,6 +2400,7 @@ __/common/message_queue.cpp.i: .PHONY : __/common/message_queue.cpp.i __/common/message_queue.s: __/common/message_queue.cpp.s + .PHONY : __/common/message_queue.s # target to generate assembly for a file @@ -2143,6 +2409,7 @@ __/common/message_queue.cpp.s: .PHONY : __/common/message_queue.cpp.s __/common/msgpack.obj: __/common/msgpack.cpp.obj + .PHONY : __/common/msgpack.obj # target to build an object file @@ -2151,6 +2418,7 @@ __/common/msgpack.cpp.obj: .PHONY : __/common/msgpack.cpp.obj __/common/msgpack.i: __/common/msgpack.cpp.i + .PHONY : __/common/msgpack.i # target to preprocess a source file @@ -2159,6 +2427,7 @@ __/common/msgpack.cpp.i: .PHONY : __/common/msgpack.cpp.i __/common/msgpack.s: __/common/msgpack.cpp.s + .PHONY : __/common/msgpack.s # target to generate assembly for a file @@ -2167,6 +2436,7 @@ __/common/msgpack.cpp.s: .PHONY : __/common/msgpack.cpp.s __/common/png_writer.obj: __/common/png_writer.cpp.obj + .PHONY : __/common/png_writer.obj # target to build an object file @@ -2175,6 +2445,7 @@ __/common/png_writer.cpp.obj: .PHONY : __/common/png_writer.cpp.obj __/common/png_writer.i: __/common/png_writer.cpp.i + .PHONY : __/common/png_writer.i # target to preprocess a source file @@ -2183,6 +2454,7 @@ __/common/png_writer.cpp.i: .PHONY : __/common/png_writer.cpp.i __/common/png_writer.s: __/common/png_writer.cpp.s + .PHONY : __/common/png_writer.s # target to generate assembly for a file @@ -2191,6 +2463,7 @@ __/common/png_writer.cpp.s: .PHONY : __/common/png_writer.cpp.s __/common/pocsag_packet.obj: __/common/pocsag_packet.cpp.obj + .PHONY : __/common/pocsag_packet.obj # target to build an object file @@ -2199,6 +2472,7 @@ __/common/pocsag_packet.cpp.obj: .PHONY : __/common/pocsag_packet.cpp.obj __/common/pocsag_packet.i: __/common/pocsag_packet.cpp.i + .PHONY : __/common/pocsag_packet.i # target to preprocess a source file @@ -2207,6 +2481,7 @@ __/common/pocsag_packet.cpp.i: .PHONY : __/common/pocsag_packet.cpp.i __/common/pocsag_packet.s: __/common/pocsag_packet.cpp.s + .PHONY : __/common/pocsag_packet.s # target to generate assembly for a file @@ -2215,6 +2490,7 @@ __/common/pocsag_packet.cpp.s: .PHONY : __/common/pocsag_packet.cpp.s __/common/portapack_io.obj: __/common/portapack_io.cpp.obj + .PHONY : __/common/portapack_io.obj # target to build an object file @@ -2223,6 +2499,7 @@ __/common/portapack_io.cpp.obj: .PHONY : __/common/portapack_io.cpp.obj __/common/portapack_io.i: __/common/portapack_io.cpp.i + .PHONY : __/common/portapack_io.i # target to preprocess a source file @@ -2231,6 +2508,7 @@ __/common/portapack_io.cpp.i: .PHONY : __/common/portapack_io.cpp.i __/common/portapack_io.s: __/common/portapack_io.cpp.s + .PHONY : __/common/portapack_io.s # target to generate assembly for a file @@ -2239,6 +2517,7 @@ __/common/portapack_io.cpp.s: .PHONY : __/common/portapack_io.cpp.s __/common/portapack_persistent_memory.obj: __/common/portapack_persistent_memory.cpp.obj + .PHONY : __/common/portapack_persistent_memory.obj # target to build an object file @@ -2247,6 +2526,7 @@ __/common/portapack_persistent_memory.cpp.obj: .PHONY : __/common/portapack_persistent_memory.cpp.obj __/common/portapack_persistent_memory.i: __/common/portapack_persistent_memory.cpp.i + .PHONY : __/common/portapack_persistent_memory.i # target to preprocess a source file @@ -2255,6 +2535,7 @@ __/common/portapack_persistent_memory.cpp.i: .PHONY : __/common/portapack_persistent_memory.cpp.i __/common/portapack_persistent_memory.s: __/common/portapack_persistent_memory.cpp.s + .PHONY : __/common/portapack_persistent_memory.s # target to generate assembly for a file @@ -2263,6 +2544,7 @@ __/common/portapack_persistent_memory.cpp.s: .PHONY : __/common/portapack_persistent_memory.cpp.s __/common/portapack_shared_memory.obj: __/common/portapack_shared_memory.cpp.obj + .PHONY : __/common/portapack_shared_memory.obj # target to build an object file @@ -2271,6 +2553,7 @@ __/common/portapack_shared_memory.cpp.obj: .PHONY : __/common/portapack_shared_memory.cpp.obj __/common/portapack_shared_memory.i: __/common/portapack_shared_memory.cpp.i + .PHONY : __/common/portapack_shared_memory.i # target to preprocess a source file @@ -2279,6 +2562,7 @@ __/common/portapack_shared_memory.cpp.i: .PHONY : __/common/portapack_shared_memory.cpp.i __/common/portapack_shared_memory.s: __/common/portapack_shared_memory.cpp.s + .PHONY : __/common/portapack_shared_memory.s # target to generate assembly for a file @@ -2287,6 +2571,7 @@ __/common/portapack_shared_memory.cpp.s: .PHONY : __/common/portapack_shared_memory.cpp.s __/common/tpms_packet.obj: __/common/tpms_packet.cpp.obj + .PHONY : __/common/tpms_packet.obj # target to build an object file @@ -2295,6 +2580,7 @@ __/common/tpms_packet.cpp.obj: .PHONY : __/common/tpms_packet.cpp.obj __/common/tpms_packet.i: __/common/tpms_packet.cpp.i + .PHONY : __/common/tpms_packet.i # target to preprocess a source file @@ -2303,6 +2589,7 @@ __/common/tpms_packet.cpp.i: .PHONY : __/common/tpms_packet.cpp.i __/common/tpms_packet.s: __/common/tpms_packet.cpp.s + .PHONY : __/common/tpms_packet.s # target to generate assembly for a file @@ -2311,6 +2598,7 @@ __/common/tpms_packet.cpp.s: .PHONY : __/common/tpms_packet.cpp.s __/common/ui.obj: __/common/ui.cpp.obj + .PHONY : __/common/ui.obj # target to build an object file @@ -2319,6 +2607,7 @@ __/common/ui.cpp.obj: .PHONY : __/common/ui.cpp.obj __/common/ui.i: __/common/ui.cpp.i + .PHONY : __/common/ui.i # target to preprocess a source file @@ -2327,6 +2616,7 @@ __/common/ui.cpp.i: .PHONY : __/common/ui.cpp.i __/common/ui.s: __/common/ui.cpp.s + .PHONY : __/common/ui.s # target to generate assembly for a file @@ -2335,6 +2625,7 @@ __/common/ui.cpp.s: .PHONY : __/common/ui.cpp.s __/common/ui_focus.obj: __/common/ui_focus.cpp.obj + .PHONY : __/common/ui_focus.obj # target to build an object file @@ -2343,6 +2634,7 @@ __/common/ui_focus.cpp.obj: .PHONY : __/common/ui_focus.cpp.obj __/common/ui_focus.i: __/common/ui_focus.cpp.i + .PHONY : __/common/ui_focus.i # target to preprocess a source file @@ -2351,6 +2643,7 @@ __/common/ui_focus.cpp.i: .PHONY : __/common/ui_focus.cpp.i __/common/ui_focus.s: __/common/ui_focus.cpp.s + .PHONY : __/common/ui_focus.s # target to generate assembly for a file @@ -2359,6 +2652,7 @@ __/common/ui_focus.cpp.s: .PHONY : __/common/ui_focus.cpp.s __/common/ui_painter.obj: __/common/ui_painter.cpp.obj + .PHONY : __/common/ui_painter.obj # target to build an object file @@ -2367,6 +2661,7 @@ __/common/ui_painter.cpp.obj: .PHONY : __/common/ui_painter.cpp.obj __/common/ui_painter.i: __/common/ui_painter.cpp.i + .PHONY : __/common/ui_painter.i # target to preprocess a source file @@ -2375,6 +2670,7 @@ __/common/ui_painter.cpp.i: .PHONY : __/common/ui_painter.cpp.i __/common/ui_painter.s: __/common/ui_painter.cpp.s + .PHONY : __/common/ui_painter.s # target to generate assembly for a file @@ -2383,6 +2679,7 @@ __/common/ui_painter.cpp.s: .PHONY : __/common/ui_painter.cpp.s __/common/ui_text.obj: __/common/ui_text.cpp.obj + .PHONY : __/common/ui_text.obj # target to build an object file @@ -2391,6 +2688,7 @@ __/common/ui_text.cpp.obj: .PHONY : __/common/ui_text.cpp.obj __/common/ui_text.i: __/common/ui_text.cpp.i + .PHONY : __/common/ui_text.i # target to preprocess a source file @@ -2399,6 +2697,7 @@ __/common/ui_text.cpp.i: .PHONY : __/common/ui_text.cpp.i __/common/ui_text.s: __/common/ui_text.cpp.s + .PHONY : __/common/ui_text.s # target to generate assembly for a file @@ -2407,6 +2706,7 @@ __/common/ui_text.cpp.s: .PHONY : __/common/ui_text.cpp.s __/common/ui_widget.obj: __/common/ui_widget.cpp.obj + .PHONY : __/common/ui_widget.obj # target to build an object file @@ -2415,6 +2715,7 @@ __/common/ui_widget.cpp.obj: .PHONY : __/common/ui_widget.cpp.obj __/common/ui_widget.i: __/common/ui_widget.cpp.i + .PHONY : __/common/ui_widget.i # target to preprocess a source file @@ -2423,6 +2724,7 @@ __/common/ui_widget.cpp.i: .PHONY : __/common/ui_widget.cpp.i __/common/ui_widget.s: __/common/ui_widget.cpp.s + .PHONY : __/common/ui_widget.s # target to generate assembly for a file @@ -2431,6 +2733,7 @@ __/common/ui_widget.cpp.s: .PHONY : __/common/ui_widget.cpp.s __/common/utility.obj: __/common/utility.cpp.obj + .PHONY : __/common/utility.obj # target to build an object file @@ -2439,6 +2742,7 @@ __/common/utility.cpp.obj: .PHONY : __/common/utility.cpp.obj __/common/utility.i: __/common/utility.cpp.i + .PHONY : __/common/utility.i # target to preprocess a source file @@ -2447,6 +2751,7 @@ __/common/utility.cpp.i: .PHONY : __/common/utility.cpp.i __/common/utility.s: __/common/utility.cpp.s + .PHONY : __/common/utility.s # target to generate assembly for a file @@ -2455,6 +2760,7 @@ __/common/utility.cpp.s: .PHONY : __/common/utility.cpp.s __/common/wm8731.obj: __/common/wm8731.cpp.obj + .PHONY : __/common/wm8731.obj # target to build an object file @@ -2463,6 +2769,7 @@ __/common/wm8731.cpp.obj: .PHONY : __/common/wm8731.cpp.obj __/common/wm8731.i: __/common/wm8731.cpp.i + .PHONY : __/common/wm8731.i # target to preprocess a source file @@ -2471,6 +2778,7 @@ __/common/wm8731.cpp.i: .PHONY : __/common/wm8731.cpp.i __/common/wm8731.s: __/common/wm8731.cpp.s + .PHONY : __/common/wm8731.s # target to generate assembly for a file @@ -2479,6 +2787,7 @@ __/common/wm8731.cpp.s: .PHONY : __/common/wm8731.cpp.s adsb.obj: adsb.cpp.obj + .PHONY : adsb.obj # target to build an object file @@ -2487,6 +2796,7 @@ adsb.cpp.obj: .PHONY : adsb.cpp.obj adsb.i: adsb.cpp.i + .PHONY : adsb.i # target to preprocess a source file @@ -2495,6 +2805,7 @@ adsb.cpp.i: .PHONY : adsb.cpp.i adsb.s: adsb.cpp.s + .PHONY : adsb.s # target to generate assembly for a file @@ -2503,6 +2814,7 @@ adsb.cpp.s: .PHONY : adsb.cpp.s afsk.obj: afsk.cpp.obj + .PHONY : afsk.obj # target to build an object file @@ -2511,6 +2823,7 @@ afsk.cpp.obj: .PHONY : afsk.cpp.obj afsk.i: afsk.cpp.i + .PHONY : afsk.i # target to preprocess a source file @@ -2519,6 +2832,7 @@ afsk.cpp.i: .PHONY : afsk.cpp.i afsk.s: afsk.cpp.s + .PHONY : afsk.s # target to generate assembly for a file @@ -2527,6 +2841,7 @@ afsk.cpp.s: .PHONY : afsk.cpp.s ais_app.obj: ais_app.cpp.obj + .PHONY : ais_app.obj # target to build an object file @@ -2535,6 +2850,7 @@ ais_app.cpp.obj: .PHONY : ais_app.cpp.obj ais_app.i: ais_app.cpp.i + .PHONY : ais_app.i # target to preprocess a source file @@ -2543,6 +2859,7 @@ ais_app.cpp.i: .PHONY : ais_app.cpp.i ais_app.s: ais_app.cpp.s + .PHONY : ais_app.s # target to generate assembly for a file @@ -2551,6 +2868,7 @@ ais_app.cpp.s: .PHONY : ais_app.cpp.s analog_audio_app.obj: analog_audio_app.cpp.obj + .PHONY : analog_audio_app.obj # target to build an object file @@ -2559,6 +2877,7 @@ analog_audio_app.cpp.obj: .PHONY : analog_audio_app.cpp.obj analog_audio_app.i: analog_audio_app.cpp.i + .PHONY : analog_audio_app.i # target to preprocess a source file @@ -2567,6 +2886,7 @@ analog_audio_app.cpp.i: .PHONY : analog_audio_app.cpp.i analog_audio_app.s: analog_audio_app.cpp.s + .PHONY : analog_audio_app.s # target to generate assembly for a file @@ -2575,6 +2895,7 @@ analog_audio_app.cpp.s: .PHONY : analog_audio_app.cpp.s audio.obj: audio.cpp.obj + .PHONY : audio.obj # target to build an object file @@ -2583,6 +2904,7 @@ audio.cpp.obj: .PHONY : audio.cpp.obj audio.i: audio.cpp.i + .PHONY : audio.i # target to preprocess a source file @@ -2591,6 +2913,7 @@ audio.cpp.i: .PHONY : audio.cpp.i audio.s: audio.cpp.s + .PHONY : audio.s # target to generate assembly for a file @@ -2599,6 +2922,7 @@ audio.cpp.s: .PHONY : audio.cpp.s baseband_api.obj: baseband_api.cpp.obj + .PHONY : baseband_api.obj # target to build an object file @@ -2607,6 +2931,7 @@ baseband_api.cpp.obj: .PHONY : baseband_api.cpp.obj baseband_api.i: baseband_api.cpp.i + .PHONY : baseband_api.i # target to preprocess a source file @@ -2615,6 +2940,7 @@ baseband_api.cpp.i: .PHONY : baseband_api.cpp.i baseband_api.s: baseband_api.cpp.s + .PHONY : baseband_api.s # target to generate assembly for a file @@ -2623,6 +2949,7 @@ baseband_api.cpp.s: .PHONY : baseband_api.cpp.s baseband_cpld.obj: baseband_cpld.cpp.obj + .PHONY : baseband_cpld.obj # target to build an object file @@ -2631,6 +2958,7 @@ baseband_cpld.cpp.obj: .PHONY : baseband_cpld.cpp.obj baseband_cpld.i: baseband_cpld.cpp.i + .PHONY : baseband_cpld.i # target to preprocess a source file @@ -2639,6 +2967,7 @@ baseband_cpld.cpp.i: .PHONY : baseband_cpld.cpp.i baseband_cpld.s: baseband_cpld.cpp.s + .PHONY : baseband_cpld.s # target to generate assembly for a file @@ -2647,6 +2976,7 @@ baseband_cpld.cpp.s: .PHONY : baseband_cpld.cpp.s capture_app.obj: capture_app.cpp.obj + .PHONY : capture_app.obj # target to build an object file @@ -2655,6 +2985,7 @@ capture_app.cpp.obj: .PHONY : capture_app.cpp.obj capture_app.i: capture_app.cpp.i + .PHONY : capture_app.i # target to preprocess a source file @@ -2663,6 +2994,7 @@ capture_app.cpp.i: .PHONY : capture_app.cpp.i capture_app.s: capture_app.cpp.s + .PHONY : capture_app.s # target to generate assembly for a file @@ -2671,6 +3003,7 @@ capture_app.cpp.s: .PHONY : capture_app.cpp.s capture_thread.obj: capture_thread.cpp.obj + .PHONY : capture_thread.obj # target to build an object file @@ -2679,6 +3012,7 @@ capture_thread.cpp.obj: .PHONY : capture_thread.cpp.obj capture_thread.i: capture_thread.cpp.i + .PHONY : capture_thread.i # target to preprocess a source file @@ -2687,6 +3021,7 @@ capture_thread.cpp.i: .PHONY : capture_thread.cpp.i capture_thread.s: capture_thread.cpp.s + .PHONY : capture_thread.s # target to generate assembly for a file @@ -2695,6 +3030,7 @@ capture_thread.cpp.s: .PHONY : capture_thread.cpp.s clock_manager.obj: clock_manager.cpp.obj + .PHONY : clock_manager.obj # target to build an object file @@ -2703,6 +3039,7 @@ clock_manager.cpp.obj: .PHONY : clock_manager.cpp.obj clock_manager.i: clock_manager.cpp.i + .PHONY : clock_manager.i # target to preprocess a source file @@ -2711,6 +3048,7 @@ clock_manager.cpp.i: .PHONY : clock_manager.cpp.i clock_manager.s: clock_manager.cpp.s + .PHONY : clock_manager.s # target to generate assembly for a file @@ -2719,6 +3057,7 @@ clock_manager.cpp.s: .PHONY : clock_manager.cpp.s core_control.obj: core_control.cpp.obj + .PHONY : core_control.obj # target to build an object file @@ -2727,6 +3066,7 @@ core_control.cpp.obj: .PHONY : core_control.cpp.obj core_control.i: core_control.cpp.i + .PHONY : core_control.i # target to preprocess a source file @@ -2735,6 +3075,7 @@ core_control.cpp.i: .PHONY : core_control.cpp.i core_control.s: core_control.cpp.s + .PHONY : core_control.s # target to generate assembly for a file @@ -2743,6 +3084,7 @@ core_control.cpp.s: .PHONY : core_control.cpp.s cpld_update.obj: cpld_update.cpp.obj + .PHONY : cpld_update.obj # target to build an object file @@ -2751,6 +3093,7 @@ cpld_update.cpp.obj: .PHONY : cpld_update.cpp.obj cpld_update.i: cpld_update.cpp.i + .PHONY : cpld_update.i # target to preprocess a source file @@ -2759,6 +3102,7 @@ cpld_update.cpp.i: .PHONY : cpld_update.cpp.i cpld_update.s: cpld_update.cpp.s + .PHONY : cpld_update.s # target to generate assembly for a file @@ -2767,6 +3111,7 @@ cpld_update.cpp.s: .PHONY : cpld_update.cpp.s ctcss.obj: ctcss.cpp.obj + .PHONY : ctcss.obj # target to build an object file @@ -2775,6 +3120,7 @@ ctcss.cpp.obj: .PHONY : ctcss.cpp.obj ctcss.i: ctcss.cpp.i + .PHONY : ctcss.i # target to preprocess a source file @@ -2783,6 +3129,7 @@ ctcss.cpp.i: .PHONY : ctcss.cpp.i ctcss.s: ctcss.cpp.s + .PHONY : ctcss.s # target to generate assembly for a file @@ -2791,6 +3138,7 @@ ctcss.cpp.s: .PHONY : ctcss.cpp.s debounce.obj: debounce.cpp.obj + .PHONY : debounce.obj # target to build an object file @@ -2799,6 +3147,7 @@ debounce.cpp.obj: .PHONY : debounce.cpp.obj debounce.i: debounce.cpp.i + .PHONY : debounce.i # target to preprocess a source file @@ -2807,6 +3156,7 @@ debounce.cpp.i: .PHONY : debounce.cpp.i debounce.s: debounce.cpp.s + .PHONY : debounce.s # target to generate assembly for a file @@ -2815,6 +3165,7 @@ debounce.cpp.s: .PHONY : debounce.cpp.s encoder.obj: encoder.cpp.obj + .PHONY : encoder.obj # target to build an object file @@ -2823,6 +3174,7 @@ encoder.cpp.obj: .PHONY : encoder.cpp.obj encoder.i: encoder.cpp.i + .PHONY : encoder.i # target to preprocess a source file @@ -2831,6 +3183,7 @@ encoder.cpp.i: .PHONY : encoder.cpp.i encoder.s: encoder.cpp.s + .PHONY : encoder.s # target to generate assembly for a file @@ -2839,6 +3192,7 @@ encoder.cpp.s: .PHONY : encoder.cpp.s ert_app.obj: ert_app.cpp.obj + .PHONY : ert_app.obj # target to build an object file @@ -2847,6 +3201,7 @@ ert_app.cpp.obj: .PHONY : ert_app.cpp.obj ert_app.i: ert_app.cpp.i + .PHONY : ert_app.i # target to preprocess a source file @@ -2855,6 +3210,7 @@ ert_app.cpp.i: .PHONY : ert_app.cpp.i ert_app.s: ert_app.cpp.s + .PHONY : ert_app.s # target to generate assembly for a file @@ -2863,6 +3219,7 @@ ert_app.cpp.s: .PHONY : ert_app.cpp.s event_m0.obj: event_m0.cpp.obj + .PHONY : event_m0.obj # target to build an object file @@ -2871,6 +3228,7 @@ event_m0.cpp.obj: .PHONY : event_m0.cpp.obj event_m0.i: event_m0.cpp.i + .PHONY : event_m0.i # target to preprocess a source file @@ -2879,6 +3237,7 @@ event_m0.cpp.i: .PHONY : event_m0.cpp.i event_m0.s: event_m0.cpp.s + .PHONY : event_m0.s # target to generate assembly for a file @@ -2887,6 +3246,7 @@ event_m0.cpp.s: .PHONY : event_m0.cpp.s file.obj: file.cpp.obj + .PHONY : file.obj # target to build an object file @@ -2895,6 +3255,7 @@ file.cpp.obj: .PHONY : file.cpp.obj file.i: file.cpp.i + .PHONY : file.i # target to preprocess a source file @@ -2903,6 +3264,7 @@ file.cpp.i: .PHONY : file.cpp.i file.s: file.cpp.s + .PHONY : file.s # target to generate assembly for a file @@ -2911,6 +3273,7 @@ file.cpp.s: .PHONY : file.cpp.s filewriter.obj: filewriter.cpp.obj + .PHONY : filewriter.obj # target to build an object file @@ -2919,6 +3282,7 @@ filewriter.cpp.obj: .PHONY : filewriter.cpp.obj filewriter.i: filewriter.cpp.i + .PHONY : filewriter.i # target to preprocess a source file @@ -2927,6 +3291,7 @@ filewriter.cpp.i: .PHONY : filewriter.cpp.i filewriter.s: filewriter.cpp.s + .PHONY : filewriter.s # target to generate assembly for a file @@ -2935,6 +3300,7 @@ filewriter.cpp.s: .PHONY : filewriter.cpp.s hackrf_cpld_data.obj: hackrf_cpld_data.cpp.obj + .PHONY : hackrf_cpld_data.obj # target to build an object file @@ -2943,6 +3309,7 @@ hackrf_cpld_data.cpp.obj: .PHONY : hackrf_cpld_data.cpp.obj hackrf_cpld_data.i: hackrf_cpld_data.cpp.i + .PHONY : hackrf_cpld_data.i # target to preprocess a source file @@ -2951,6 +3318,7 @@ hackrf_cpld_data.cpp.i: .PHONY : hackrf_cpld_data.cpp.i hackrf_cpld_data.s: hackrf_cpld_data.cpp.s + .PHONY : hackrf_cpld_data.s # target to generate assembly for a file @@ -2959,6 +3327,7 @@ hackrf_cpld_data.cpp.s: .PHONY : hackrf_cpld_data.cpp.s irq_controls.obj: irq_controls.cpp.obj + .PHONY : irq_controls.obj # target to build an object file @@ -2967,6 +3336,7 @@ irq_controls.cpp.obj: .PHONY : irq_controls.cpp.obj irq_controls.i: irq_controls.cpp.i + .PHONY : irq_controls.i # target to preprocess a source file @@ -2975,6 +3345,7 @@ irq_controls.cpp.i: .PHONY : irq_controls.cpp.i irq_controls.s: irq_controls.cpp.s + .PHONY : irq_controls.s # target to generate assembly for a file @@ -2983,6 +3354,7 @@ irq_controls.cpp.s: .PHONY : irq_controls.cpp.s irq_lcd_frame.obj: irq_lcd_frame.cpp.obj + .PHONY : irq_lcd_frame.obj # target to build an object file @@ -2991,6 +3363,7 @@ irq_lcd_frame.cpp.obj: .PHONY : irq_lcd_frame.cpp.obj irq_lcd_frame.i: irq_lcd_frame.cpp.i + .PHONY : irq_lcd_frame.i # target to preprocess a source file @@ -2999,6 +3372,7 @@ irq_lcd_frame.cpp.i: .PHONY : irq_lcd_frame.cpp.i irq_lcd_frame.s: irq_lcd_frame.cpp.s + .PHONY : irq_lcd_frame.s # target to generate assembly for a file @@ -3007,6 +3381,7 @@ irq_lcd_frame.cpp.s: .PHONY : irq_lcd_frame.cpp.s irq_rtc.obj: irq_rtc.cpp.obj + .PHONY : irq_rtc.obj # target to build an object file @@ -3015,6 +3390,7 @@ irq_rtc.cpp.obj: .PHONY : irq_rtc.cpp.obj irq_rtc.i: irq_rtc.cpp.i + .PHONY : irq_rtc.i # target to preprocess a source file @@ -3023,6 +3399,7 @@ irq_rtc.cpp.i: .PHONY : irq_rtc.cpp.i irq_rtc.s: irq_rtc.cpp.s + .PHONY : irq_rtc.s # target to generate assembly for a file @@ -3031,6 +3408,7 @@ irq_rtc.cpp.s: .PHONY : irq_rtc.cpp.s log_file.obj: log_file.cpp.obj + .PHONY : log_file.obj # target to build an object file @@ -3039,6 +3417,7 @@ log_file.cpp.obj: .PHONY : log_file.cpp.obj log_file.i: log_file.cpp.i + .PHONY : log_file.i # target to preprocess a source file @@ -3047,6 +3426,7 @@ log_file.cpp.i: .PHONY : log_file.cpp.i log_file.s: log_file.cpp.s + .PHONY : log_file.s # target to generate assembly for a file @@ -3055,6 +3435,7 @@ log_file.cpp.s: .PHONY : log_file.cpp.s main.obj: main.cpp.obj + .PHONY : main.obj # target to build an object file @@ -3063,6 +3444,7 @@ main.cpp.obj: .PHONY : main.cpp.obj main.i: main.cpp.i + .PHONY : main.i # target to preprocess a source file @@ -3071,6 +3453,7 @@ main.cpp.i: .PHONY : main.cpp.i main.s: main.cpp.s + .PHONY : main.s # target to generate assembly for a file @@ -3079,6 +3462,7 @@ main.cpp.s: .PHONY : main.cpp.s max2837.obj: max2837.cpp.obj + .PHONY : max2837.obj # target to build an object file @@ -3087,6 +3471,7 @@ max2837.cpp.obj: .PHONY : max2837.cpp.obj max2837.i: max2837.cpp.i + .PHONY : max2837.i # target to preprocess a source file @@ -3095,6 +3480,7 @@ max2837.cpp.i: .PHONY : max2837.cpp.i max2837.s: max2837.cpp.s + .PHONY : max2837.s # target to generate assembly for a file @@ -3103,6 +3489,7 @@ max2837.cpp.s: .PHONY : max2837.cpp.s max5864.obj: max5864.cpp.obj + .PHONY : max5864.obj # target to build an object file @@ -3111,6 +3498,7 @@ max5864.cpp.obj: .PHONY : max5864.cpp.obj max5864.i: max5864.cpp.i + .PHONY : max5864.i # target to preprocess a source file @@ -3119,6 +3507,7 @@ max5864.cpp.i: .PHONY : max5864.cpp.i max5864.s: max5864.cpp.s + .PHONY : max5864.s # target to generate assembly for a file @@ -3127,6 +3516,7 @@ max5864.cpp.s: .PHONY : max5864.cpp.s pocsag_app.obj: pocsag_app.cpp.obj + .PHONY : pocsag_app.obj # target to build an object file @@ -3135,6 +3525,7 @@ pocsag_app.cpp.obj: .PHONY : pocsag_app.cpp.obj pocsag_app.i: pocsag_app.cpp.i + .PHONY : pocsag_app.i # target to preprocess a source file @@ -3143,6 +3534,7 @@ pocsag_app.cpp.i: .PHONY : pocsag_app.cpp.i pocsag_app.s: pocsag_app.cpp.s + .PHONY : pocsag_app.s # target to generate assembly for a file @@ -3151,6 +3543,7 @@ pocsag_app.cpp.s: .PHONY : pocsag_app.cpp.s portapack.obj: portapack.cpp.obj + .PHONY : portapack.obj # target to build an object file @@ -3159,6 +3552,7 @@ portapack.cpp.obj: .PHONY : portapack.cpp.obj portapack.i: portapack.cpp.i + .PHONY : portapack.i # target to preprocess a source file @@ -3167,6 +3561,7 @@ portapack.cpp.i: .PHONY : portapack.cpp.i portapack.s: portapack.cpp.s + .PHONY : portapack.s # target to generate assembly for a file @@ -3175,6 +3570,7 @@ portapack.cpp.s: .PHONY : portapack.cpp.s portapack_cpld_data.obj: portapack_cpld_data.cpp.obj + .PHONY : portapack_cpld_data.obj # target to build an object file @@ -3183,6 +3579,7 @@ portapack_cpld_data.cpp.obj: .PHONY : portapack_cpld_data.cpp.obj portapack_cpld_data.i: portapack_cpld_data.cpp.i + .PHONY : portapack_cpld_data.i # target to preprocess a source file @@ -3191,6 +3588,7 @@ portapack_cpld_data.cpp.i: .PHONY : portapack_cpld_data.cpp.i portapack_cpld_data.s: portapack_cpld_data.cpp.s + .PHONY : portapack_cpld_data.s # target to generate assembly for a file @@ -3199,6 +3597,7 @@ portapack_cpld_data.cpp.s: .PHONY : portapack_cpld_data.cpp.s radio.obj: radio.cpp.obj + .PHONY : radio.obj # target to build an object file @@ -3207,6 +3606,7 @@ radio.cpp.obj: .PHONY : radio.cpp.obj radio.i: radio.cpp.i + .PHONY : radio.i # target to preprocess a source file @@ -3215,6 +3615,7 @@ radio.cpp.i: .PHONY : radio.cpp.i radio.s: radio.cpp.s + .PHONY : radio.s # target to generate assembly for a file @@ -3223,6 +3624,7 @@ radio.cpp.s: .PHONY : radio.cpp.s rds.obj: rds.cpp.obj + .PHONY : rds.obj # target to build an object file @@ -3231,6 +3633,7 @@ rds.cpp.obj: .PHONY : rds.cpp.obj rds.i: rds.cpp.i + .PHONY : rds.i # target to preprocess a source file @@ -3239,6 +3642,7 @@ rds.cpp.i: .PHONY : rds.cpp.i rds.s: rds.cpp.s + .PHONY : rds.s # target to generate assembly for a file @@ -3247,6 +3651,7 @@ rds.cpp.s: .PHONY : rds.cpp.s receiver_model.obj: receiver_model.cpp.obj + .PHONY : receiver_model.obj # target to build an object file @@ -3255,6 +3660,7 @@ receiver_model.cpp.obj: .PHONY : receiver_model.cpp.obj receiver_model.i: receiver_model.cpp.i + .PHONY : receiver_model.i # target to preprocess a source file @@ -3263,6 +3669,7 @@ receiver_model.cpp.i: .PHONY : receiver_model.cpp.i receiver_model.s: receiver_model.cpp.s + .PHONY : receiver_model.s # target to generate assembly for a file @@ -3271,6 +3678,7 @@ receiver_model.cpp.s: .PHONY : receiver_model.cpp.s recent_entries.obj: recent_entries.cpp.obj + .PHONY : recent_entries.obj # target to build an object file @@ -3279,6 +3687,7 @@ recent_entries.cpp.obj: .PHONY : recent_entries.cpp.obj recent_entries.i: recent_entries.cpp.i + .PHONY : recent_entries.i # target to preprocess a source file @@ -3287,6 +3696,7 @@ recent_entries.cpp.i: .PHONY : recent_entries.cpp.i recent_entries.s: recent_entries.cpp.s + .PHONY : recent_entries.s # target to generate assembly for a file @@ -3295,6 +3705,7 @@ recent_entries.cpp.s: .PHONY : recent_entries.cpp.s rf_path.obj: rf_path.cpp.obj + .PHONY : rf_path.obj # target to build an object file @@ -3303,6 +3714,7 @@ rf_path.cpp.obj: .PHONY : rf_path.cpp.obj rf_path.i: rf_path.cpp.i + .PHONY : rf_path.i # target to preprocess a source file @@ -3311,6 +3723,7 @@ rf_path.cpp.i: .PHONY : rf_path.cpp.i rf_path.s: rf_path.cpp.s + .PHONY : rf_path.s # target to generate assembly for a file @@ -3319,6 +3732,7 @@ rf_path.cpp.s: .PHONY : rf_path.cpp.s rffc507x.obj: rffc507x.cpp.obj + .PHONY : rffc507x.obj # target to build an object file @@ -3327,6 +3741,7 @@ rffc507x.cpp.obj: .PHONY : rffc507x.cpp.obj rffc507x.i: rffc507x.cpp.i + .PHONY : rffc507x.i # target to preprocess a source file @@ -3335,6 +3750,7 @@ rffc507x.cpp.i: .PHONY : rffc507x.cpp.i rffc507x.s: rffc507x.cpp.s + .PHONY : rffc507x.s # target to generate assembly for a file @@ -3343,6 +3759,7 @@ rffc507x.cpp.s: .PHONY : rffc507x.cpp.s rffc507x_spi.obj: rffc507x_spi.cpp.obj + .PHONY : rffc507x_spi.obj # target to build an object file @@ -3351,6 +3768,7 @@ rffc507x_spi.cpp.obj: .PHONY : rffc507x_spi.cpp.obj rffc507x_spi.i: rffc507x_spi.cpp.i + .PHONY : rffc507x_spi.i # target to preprocess a source file @@ -3359,6 +3777,7 @@ rffc507x_spi.cpp.i: .PHONY : rffc507x_spi.cpp.i rffc507x_spi.s: rffc507x_spi.cpp.s + .PHONY : rffc507x_spi.s # target to generate assembly for a file @@ -3367,6 +3786,7 @@ rffc507x_spi.cpp.s: .PHONY : rffc507x_spi.cpp.s sd_card.obj: sd_card.cpp.obj + .PHONY : sd_card.obj # target to build an object file @@ -3375,6 +3795,7 @@ sd_card.cpp.obj: .PHONY : sd_card.cpp.obj sd_card.i: sd_card.cpp.i + .PHONY : sd_card.i # target to preprocess a source file @@ -3383,6 +3804,7 @@ sd_card.cpp.i: .PHONY : sd_card.cpp.i sd_card.s: sd_card.cpp.s + .PHONY : sd_card.s # target to generate assembly for a file @@ -3391,6 +3813,7 @@ sd_card.cpp.s: .PHONY : sd_card.cpp.s si5351.obj: si5351.cpp.obj + .PHONY : si5351.obj # target to build an object file @@ -3399,6 +3822,7 @@ si5351.cpp.obj: .PHONY : si5351.cpp.obj si5351.i: si5351.cpp.i + .PHONY : si5351.i # target to preprocess a source file @@ -3407,6 +3831,7 @@ si5351.cpp.i: .PHONY : si5351.cpp.i si5351.s: si5351.cpp.s + .PHONY : si5351.s # target to generate assembly for a file @@ -3415,6 +3840,7 @@ si5351.cpp.s: .PHONY : si5351.cpp.s spectrum_color_lut.obj: spectrum_color_lut.cpp.obj + .PHONY : spectrum_color_lut.obj # target to build an object file @@ -3423,6 +3849,7 @@ spectrum_color_lut.cpp.obj: .PHONY : spectrum_color_lut.cpp.obj spectrum_color_lut.i: spectrum_color_lut.cpp.i + .PHONY : spectrum_color_lut.i # target to preprocess a source file @@ -3431,6 +3858,7 @@ spectrum_color_lut.cpp.i: .PHONY : spectrum_color_lut.cpp.i spectrum_color_lut.s: spectrum_color_lut.cpp.s + .PHONY : spectrum_color_lut.s # target to generate assembly for a file @@ -3439,6 +3867,7 @@ spectrum_color_lut.cpp.s: .PHONY : spectrum_color_lut.cpp.s spi_pp.obj: spi_pp.cpp.obj + .PHONY : spi_pp.obj # target to build an object file @@ -3447,6 +3876,7 @@ spi_pp.cpp.obj: .PHONY : spi_pp.cpp.obj spi_pp.i: spi_pp.cpp.i + .PHONY : spi_pp.i # target to preprocess a source file @@ -3455,6 +3885,7 @@ spi_pp.cpp.i: .PHONY : spi_pp.cpp.i spi_pp.s: spi_pp.cpp.s + .PHONY : spi_pp.s # target to generate assembly for a file @@ -3463,6 +3894,7 @@ spi_pp.cpp.s: .PHONY : spi_pp.cpp.s string_format.obj: string_format.cpp.obj + .PHONY : string_format.obj # target to build an object file @@ -3471,6 +3903,7 @@ string_format.cpp.obj: .PHONY : string_format.cpp.obj string_format.i: string_format.cpp.i + .PHONY : string_format.i # target to preprocess a source file @@ -3479,6 +3912,7 @@ string_format.cpp.i: .PHONY : string_format.cpp.i string_format.s: string_format.cpp.s + .PHONY : string_format.s # target to generate assembly for a file @@ -3487,6 +3921,7 @@ string_format.cpp.s: .PHONY : string_format.cpp.s temperature_logger.obj: temperature_logger.cpp.obj + .PHONY : temperature_logger.obj # target to build an object file @@ -3495,6 +3930,7 @@ temperature_logger.cpp.obj: .PHONY : temperature_logger.cpp.obj temperature_logger.i: temperature_logger.cpp.i + .PHONY : temperature_logger.i # target to preprocess a source file @@ -3503,6 +3939,7 @@ temperature_logger.cpp.i: .PHONY : temperature_logger.cpp.i temperature_logger.s: temperature_logger.cpp.s + .PHONY : temperature_logger.s # target to generate assembly for a file @@ -3511,6 +3948,7 @@ temperature_logger.cpp.s: .PHONY : temperature_logger.cpp.s time.obj: time.cpp.obj + .PHONY : time.obj # target to build an object file @@ -3519,6 +3957,7 @@ time.cpp.obj: .PHONY : time.cpp.obj time.i: time.cpp.i + .PHONY : time.i # target to preprocess a source file @@ -3527,6 +3966,7 @@ time.cpp.i: .PHONY : time.cpp.i time.s: time.cpp.s + .PHONY : time.s # target to generate assembly for a file @@ -3535,6 +3975,7 @@ time.cpp.s: .PHONY : time.cpp.s touch.obj: touch.cpp.obj + .PHONY : touch.obj # target to build an object file @@ -3543,6 +3984,7 @@ touch.cpp.obj: .PHONY : touch.cpp.obj touch.i: touch.cpp.i + .PHONY : touch.i # target to preprocess a source file @@ -3551,6 +3993,7 @@ touch.cpp.i: .PHONY : touch.cpp.i touch.s: touch.cpp.s + .PHONY : touch.s # target to generate assembly for a file @@ -3559,6 +4002,7 @@ touch.cpp.s: .PHONY : touch.cpp.s touch_adc.obj: touch_adc.cpp.obj + .PHONY : touch_adc.obj # target to build an object file @@ -3567,6 +4011,7 @@ touch_adc.cpp.obj: .PHONY : touch_adc.cpp.obj touch_adc.i: touch_adc.cpp.i + .PHONY : touch_adc.i # target to preprocess a source file @@ -3575,6 +4020,7 @@ touch_adc.cpp.i: .PHONY : touch_adc.cpp.i touch_adc.s: touch_adc.cpp.s + .PHONY : touch_adc.s # target to generate assembly for a file @@ -3583,6 +4029,7 @@ touch_adc.cpp.s: .PHONY : touch_adc.cpp.s tpms_app.obj: tpms_app.cpp.obj + .PHONY : tpms_app.obj # target to build an object file @@ -3591,6 +4038,7 @@ tpms_app.cpp.obj: .PHONY : tpms_app.cpp.obj tpms_app.i: tpms_app.cpp.i + .PHONY : tpms_app.i # target to preprocess a source file @@ -3599,6 +4047,7 @@ tpms_app.cpp.i: .PHONY : tpms_app.cpp.i tpms_app.s: tpms_app.cpp.s + .PHONY : tpms_app.s # target to generate assembly for a file @@ -3607,6 +4056,7 @@ tpms_app.cpp.s: .PHONY : tpms_app.cpp.s transmitter_model.obj: transmitter_model.cpp.obj + .PHONY : transmitter_model.obj # target to build an object file @@ -3615,6 +4065,7 @@ transmitter_model.cpp.obj: .PHONY : transmitter_model.cpp.obj transmitter_model.i: transmitter_model.cpp.i + .PHONY : transmitter_model.i # target to preprocess a source file @@ -3623,6 +4074,7 @@ transmitter_model.cpp.i: .PHONY : transmitter_model.cpp.i transmitter_model.s: transmitter_model.cpp.s + .PHONY : transmitter_model.s # target to generate assembly for a file @@ -3631,6 +4083,7 @@ transmitter_model.cpp.s: .PHONY : transmitter_model.cpp.s tuning.obj: tuning.cpp.obj + .PHONY : tuning.obj # target to build an object file @@ -3639,6 +4092,7 @@ tuning.cpp.obj: .PHONY : tuning.cpp.obj tuning.i: tuning.cpp.i + .PHONY : tuning.i # target to preprocess a source file @@ -3647,6 +4101,7 @@ tuning.cpp.i: .PHONY : tuning.cpp.i tuning.s: tuning.cpp.s + .PHONY : tuning.s # target to generate assembly for a file @@ -3655,6 +4110,7 @@ tuning.cpp.s: .PHONY : tuning.cpp.s ui_about.obj: ui_about.cpp.obj + .PHONY : ui_about.obj # target to build an object file @@ -3663,6 +4119,7 @@ ui_about.cpp.obj: .PHONY : ui_about.cpp.obj ui_about.i: ui_about.cpp.i + .PHONY : ui_about.i # target to preprocess a source file @@ -3671,6 +4128,7 @@ ui_about.cpp.i: .PHONY : ui_about.cpp.i ui_about.s: ui_about.cpp.s + .PHONY : ui_about.s # target to generate assembly for a file @@ -3679,6 +4137,7 @@ ui_about.cpp.s: .PHONY : ui_about.cpp.s ui_adsbtx.obj: ui_adsbtx.cpp.obj + .PHONY : ui_adsbtx.obj # target to build an object file @@ -3687,6 +4146,7 @@ ui_adsbtx.cpp.obj: .PHONY : ui_adsbtx.cpp.obj ui_adsbtx.i: ui_adsbtx.cpp.i + .PHONY : ui_adsbtx.i # target to preprocess a source file @@ -3695,6 +4155,7 @@ ui_adsbtx.cpp.i: .PHONY : ui_adsbtx.cpp.i ui_adsbtx.s: ui_adsbtx.cpp.s + .PHONY : ui_adsbtx.s # target to generate assembly for a file @@ -3703,6 +4164,7 @@ ui_adsbtx.cpp.s: .PHONY : ui_adsbtx.cpp.s ui_afsksetup.obj: ui_afsksetup.cpp.obj + .PHONY : ui_afsksetup.obj # target to build an object file @@ -3711,6 +4173,7 @@ ui_afsksetup.cpp.obj: .PHONY : ui_afsksetup.cpp.obj ui_afsksetup.i: ui_afsksetup.cpp.i + .PHONY : ui_afsksetup.i # target to preprocess a source file @@ -3719,6 +4182,7 @@ ui_afsksetup.cpp.i: .PHONY : ui_afsksetup.cpp.i ui_afsksetup.s: ui_afsksetup.cpp.s + .PHONY : ui_afsksetup.s # target to generate assembly for a file @@ -3727,6 +4191,7 @@ ui_afsksetup.cpp.s: .PHONY : ui_afsksetup.cpp.s ui_alphanum.obj: ui_alphanum.cpp.obj + .PHONY : ui_alphanum.obj # target to build an object file @@ -3735,6 +4200,7 @@ ui_alphanum.cpp.obj: .PHONY : ui_alphanum.cpp.obj ui_alphanum.i: ui_alphanum.cpp.i + .PHONY : ui_alphanum.i # target to preprocess a source file @@ -3743,6 +4209,7 @@ ui_alphanum.cpp.i: .PHONY : ui_alphanum.cpp.i ui_alphanum.s: ui_alphanum.cpp.s + .PHONY : ui_alphanum.s # target to generate assembly for a file @@ -3751,6 +4218,7 @@ ui_alphanum.cpp.s: .PHONY : ui_alphanum.cpp.s ui_audio.obj: ui_audio.cpp.obj + .PHONY : ui_audio.obj # target to build an object file @@ -3759,6 +4227,7 @@ ui_audio.cpp.obj: .PHONY : ui_audio.cpp.obj ui_audio.i: ui_audio.cpp.i + .PHONY : ui_audio.i # target to preprocess a source file @@ -3767,6 +4236,7 @@ ui_audio.cpp.i: .PHONY : ui_audio.cpp.i ui_audio.s: ui_audio.cpp.s + .PHONY : ui_audio.s # target to generate assembly for a file @@ -3775,6 +4245,7 @@ ui_audio.cpp.s: .PHONY : ui_audio.cpp.s ui_baseband_stats_view.obj: ui_baseband_stats_view.cpp.obj + .PHONY : ui_baseband_stats_view.obj # target to build an object file @@ -3783,6 +4254,7 @@ ui_baseband_stats_view.cpp.obj: .PHONY : ui_baseband_stats_view.cpp.obj ui_baseband_stats_view.i: ui_baseband_stats_view.cpp.i + .PHONY : ui_baseband_stats_view.i # target to preprocess a source file @@ -3791,6 +4263,7 @@ ui_baseband_stats_view.cpp.i: .PHONY : ui_baseband_stats_view.cpp.i ui_baseband_stats_view.s: ui_baseband_stats_view.cpp.s + .PHONY : ui_baseband_stats_view.s # target to generate assembly for a file @@ -3798,7 +4271,35 @@ ui_baseband_stats_view.cpp.s: cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_baseband_stats_view.cpp.s .PHONY : ui_baseband_stats_view.cpp.s +ui_bht_tx.obj: ui_bht_tx.cpp.obj + +.PHONY : ui_bht_tx.obj + +# target to build an object file +ui_bht_tx.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_bht_tx.cpp.obj +.PHONY : ui_bht_tx.cpp.obj + +ui_bht_tx.i: ui_bht_tx.cpp.i + +.PHONY : ui_bht_tx.i + +# target to preprocess a source file +ui_bht_tx.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_bht_tx.cpp.i +.PHONY : ui_bht_tx.cpp.i + +ui_bht_tx.s: ui_bht_tx.cpp.s + +.PHONY : ui_bht_tx.s + +# target to generate assembly for a file +ui_bht_tx.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_bht_tx.cpp.s +.PHONY : ui_bht_tx.cpp.s + ui_channel.obj: ui_channel.cpp.obj + .PHONY : ui_channel.obj # target to build an object file @@ -3807,6 +4308,7 @@ ui_channel.cpp.obj: .PHONY : ui_channel.cpp.obj ui_channel.i: ui_channel.cpp.i + .PHONY : ui_channel.i # target to preprocess a source file @@ -3815,6 +4317,7 @@ ui_channel.cpp.i: .PHONY : ui_channel.cpp.i ui_channel.s: ui_channel.cpp.s + .PHONY : ui_channel.s # target to generate assembly for a file @@ -3823,6 +4326,7 @@ ui_channel.cpp.s: .PHONY : ui_channel.cpp.s ui_closecall.obj: ui_closecall.cpp.obj + .PHONY : ui_closecall.obj # target to build an object file @@ -3831,6 +4335,7 @@ ui_closecall.cpp.obj: .PHONY : ui_closecall.cpp.obj ui_closecall.i: ui_closecall.cpp.i + .PHONY : ui_closecall.i # target to preprocess a source file @@ -3839,6 +4344,7 @@ ui_closecall.cpp.i: .PHONY : ui_closecall.cpp.i ui_closecall.s: ui_closecall.cpp.s + .PHONY : ui_closecall.s # target to generate assembly for a file @@ -3847,6 +4353,7 @@ ui_closecall.cpp.s: .PHONY : ui_closecall.cpp.s ui_debug.obj: ui_debug.cpp.obj + .PHONY : ui_debug.obj # target to build an object file @@ -3855,6 +4362,7 @@ ui_debug.cpp.obj: .PHONY : ui_debug.cpp.obj ui_debug.i: ui_debug.cpp.i + .PHONY : ui_debug.i # target to preprocess a source file @@ -3863,6 +4371,7 @@ ui_debug.cpp.i: .PHONY : ui_debug.cpp.i ui_debug.s: ui_debug.cpp.s + .PHONY : ui_debug.s # target to generate assembly for a file @@ -3871,6 +4380,7 @@ ui_debug.cpp.s: .PHONY : ui_debug.cpp.s ui_encoders.obj: ui_encoders.cpp.obj + .PHONY : ui_encoders.obj # target to build an object file @@ -3879,6 +4389,7 @@ ui_encoders.cpp.obj: .PHONY : ui_encoders.cpp.obj ui_encoders.i: ui_encoders.cpp.i + .PHONY : ui_encoders.i # target to preprocess a source file @@ -3887,6 +4398,7 @@ ui_encoders.cpp.i: .PHONY : ui_encoders.cpp.i ui_encoders.s: ui_encoders.cpp.s + .PHONY : ui_encoders.s # target to generate assembly for a file @@ -3895,6 +4407,7 @@ ui_encoders.cpp.s: .PHONY : ui_encoders.cpp.s ui_font_fixed_8x16.obj: ui_font_fixed_8x16.cpp.obj + .PHONY : ui_font_fixed_8x16.obj # target to build an object file @@ -3903,6 +4416,7 @@ ui_font_fixed_8x16.cpp.obj: .PHONY : ui_font_fixed_8x16.cpp.obj ui_font_fixed_8x16.i: ui_font_fixed_8x16.cpp.i + .PHONY : ui_font_fixed_8x16.i # target to preprocess a source file @@ -3911,6 +4425,7 @@ ui_font_fixed_8x16.cpp.i: .PHONY : ui_font_fixed_8x16.cpp.i ui_font_fixed_8x16.s: ui_font_fixed_8x16.cpp.s + .PHONY : ui_font_fixed_8x16.s # target to generate assembly for a file @@ -3919,6 +4434,7 @@ ui_font_fixed_8x16.cpp.s: .PHONY : ui_font_fixed_8x16.cpp.s ui_freqman.obj: ui_freqman.cpp.obj + .PHONY : ui_freqman.obj # target to build an object file @@ -3927,6 +4443,7 @@ ui_freqman.cpp.obj: .PHONY : ui_freqman.cpp.obj ui_freqman.i: ui_freqman.cpp.i + .PHONY : ui_freqman.i # target to preprocess a source file @@ -3935,6 +4452,7 @@ ui_freqman.cpp.i: .PHONY : ui_freqman.cpp.i ui_freqman.s: ui_freqman.cpp.s + .PHONY : ui_freqman.s # target to generate assembly for a file @@ -3943,6 +4461,7 @@ ui_freqman.cpp.s: .PHONY : ui_freqman.cpp.s ui_handwrite.obj: ui_handwrite.cpp.obj + .PHONY : ui_handwrite.obj # target to build an object file @@ -3951,6 +4470,7 @@ ui_handwrite.cpp.obj: .PHONY : ui_handwrite.cpp.obj ui_handwrite.i: ui_handwrite.cpp.i + .PHONY : ui_handwrite.i # target to preprocess a source file @@ -3959,6 +4479,7 @@ ui_handwrite.cpp.i: .PHONY : ui_handwrite.cpp.i ui_handwrite.s: ui_handwrite.cpp.s + .PHONY : ui_handwrite.s # target to generate assembly for a file @@ -3967,6 +4488,7 @@ ui_handwrite.cpp.s: .PHONY : ui_handwrite.cpp.s ui_jammer.obj: ui_jammer.cpp.obj + .PHONY : ui_jammer.obj # target to build an object file @@ -3975,6 +4497,7 @@ ui_jammer.cpp.obj: .PHONY : ui_jammer.cpp.obj ui_jammer.i: ui_jammer.cpp.i + .PHONY : ui_jammer.i # target to preprocess a source file @@ -3983,6 +4506,7 @@ ui_jammer.cpp.i: .PHONY : ui_jammer.cpp.i ui_jammer.s: ui_jammer.cpp.s + .PHONY : ui_jammer.s # target to generate assembly for a file @@ -3991,6 +4515,7 @@ ui_jammer.cpp.s: .PHONY : ui_jammer.cpp.s ui_lcr.obj: ui_lcr.cpp.obj + .PHONY : ui_lcr.obj # target to build an object file @@ -3999,6 +4524,7 @@ ui_lcr.cpp.obj: .PHONY : ui_lcr.cpp.obj ui_lcr.i: ui_lcr.cpp.i + .PHONY : ui_lcr.i # target to preprocess a source file @@ -4007,6 +4533,7 @@ ui_lcr.cpp.i: .PHONY : ui_lcr.cpp.i ui_lcr.s: ui_lcr.cpp.s + .PHONY : ui_lcr.s # target to generate assembly for a file @@ -4015,6 +4542,7 @@ ui_lcr.cpp.s: .PHONY : ui_lcr.cpp.s ui_menu.obj: ui_menu.cpp.obj + .PHONY : ui_menu.obj # target to build an object file @@ -4023,6 +4551,7 @@ ui_menu.cpp.obj: .PHONY : ui_menu.cpp.obj ui_menu.i: ui_menu.cpp.i + .PHONY : ui_menu.i # target to preprocess a source file @@ -4031,6 +4560,7 @@ ui_menu.cpp.i: .PHONY : ui_menu.cpp.i ui_menu.s: ui_menu.cpp.s + .PHONY : ui_menu.s # target to generate assembly for a file @@ -4038,7 +4568,35 @@ ui_menu.cpp.s: cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_menu.cpp.s .PHONY : ui_menu.cpp.s +ui_morse.obj: ui_morse.cpp.obj + +.PHONY : ui_morse.obj + +# target to build an object file +ui_morse.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_morse.cpp.obj +.PHONY : ui_morse.cpp.obj + +ui_morse.i: ui_morse.cpp.i + +.PHONY : ui_morse.i + +# target to preprocess a source file +ui_morse.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_morse.cpp.i +.PHONY : ui_morse.cpp.i + +ui_morse.s: ui_morse.cpp.s + +.PHONY : ui_morse.s + +# target to generate assembly for a file +ui_morse.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_morse.cpp.s +.PHONY : ui_morse.cpp.s + ui_navigation.obj: ui_navigation.cpp.obj + .PHONY : ui_navigation.obj # target to build an object file @@ -4047,6 +4605,7 @@ ui_navigation.cpp.obj: .PHONY : ui_navigation.cpp.obj ui_navigation.i: ui_navigation.cpp.i + .PHONY : ui_navigation.i # target to preprocess a source file @@ -4055,6 +4614,7 @@ ui_navigation.cpp.i: .PHONY : ui_navigation.cpp.i ui_navigation.s: ui_navigation.cpp.s + .PHONY : ui_navigation.s # target to generate assembly for a file @@ -4063,6 +4623,7 @@ ui_navigation.cpp.s: .PHONY : ui_navigation.cpp.s ui_numbers.obj: ui_numbers.cpp.obj + .PHONY : ui_numbers.obj # target to build an object file @@ -4071,6 +4632,7 @@ ui_numbers.cpp.obj: .PHONY : ui_numbers.cpp.obj ui_numbers.i: ui_numbers.cpp.i + .PHONY : ui_numbers.i # target to preprocess a source file @@ -4079,6 +4641,7 @@ ui_numbers.cpp.i: .PHONY : ui_numbers.cpp.i ui_numbers.s: ui_numbers.cpp.s + .PHONY : ui_numbers.s # target to generate assembly for a file @@ -4087,6 +4650,7 @@ ui_numbers.cpp.s: .PHONY : ui_numbers.cpp.s ui_nuoptix.obj: ui_nuoptix.cpp.obj + .PHONY : ui_nuoptix.obj # target to build an object file @@ -4095,6 +4659,7 @@ ui_nuoptix.cpp.obj: .PHONY : ui_nuoptix.cpp.obj ui_nuoptix.i: ui_nuoptix.cpp.i + .PHONY : ui_nuoptix.i # target to preprocess a source file @@ -4103,6 +4668,7 @@ ui_nuoptix.cpp.i: .PHONY : ui_nuoptix.cpp.i ui_nuoptix.s: ui_nuoptix.cpp.s + .PHONY : ui_nuoptix.s # target to generate assembly for a file @@ -4111,6 +4677,7 @@ ui_nuoptix.cpp.s: .PHONY : ui_nuoptix.cpp.s ui_rds.obj: ui_rds.cpp.obj + .PHONY : ui_rds.obj # target to build an object file @@ -4119,6 +4686,7 @@ ui_rds.cpp.obj: .PHONY : ui_rds.cpp.obj ui_rds.i: ui_rds.cpp.i + .PHONY : ui_rds.i # target to preprocess a source file @@ -4127,6 +4695,7 @@ ui_rds.cpp.i: .PHONY : ui_rds.cpp.i ui_rds.s: ui_rds.cpp.s + .PHONY : ui_rds.s # target to generate assembly for a file @@ -4135,6 +4704,7 @@ ui_rds.cpp.s: .PHONY : ui_rds.cpp.s ui_receiver.obj: ui_receiver.cpp.obj + .PHONY : ui_receiver.obj # target to build an object file @@ -4143,6 +4713,7 @@ ui_receiver.cpp.obj: .PHONY : ui_receiver.cpp.obj ui_receiver.i: ui_receiver.cpp.i + .PHONY : ui_receiver.i # target to preprocess a source file @@ -4151,6 +4722,7 @@ ui_receiver.cpp.i: .PHONY : ui_receiver.cpp.i ui_receiver.s: ui_receiver.cpp.s + .PHONY : ui_receiver.s # target to generate assembly for a file @@ -4159,6 +4731,7 @@ ui_receiver.cpp.s: .PHONY : ui_receiver.cpp.s ui_record_view.obj: ui_record_view.cpp.obj + .PHONY : ui_record_view.obj # target to build an object file @@ -4167,6 +4740,7 @@ ui_record_view.cpp.obj: .PHONY : ui_record_view.cpp.obj ui_record_view.i: ui_record_view.cpp.i + .PHONY : ui_record_view.i # target to preprocess a source file @@ -4175,6 +4749,7 @@ ui_record_view.cpp.i: .PHONY : ui_record_view.cpp.i ui_record_view.s: ui_record_view.cpp.s + .PHONY : ui_record_view.s # target to generate assembly for a file @@ -4183,6 +4758,7 @@ ui_record_view.cpp.s: .PHONY : ui_record_view.cpp.s ui_rssi.obj: ui_rssi.cpp.obj + .PHONY : ui_rssi.obj # target to build an object file @@ -4191,6 +4767,7 @@ ui_rssi.cpp.obj: .PHONY : ui_rssi.cpp.obj ui_rssi.i: ui_rssi.cpp.i + .PHONY : ui_rssi.i # target to preprocess a source file @@ -4199,6 +4776,7 @@ ui_rssi.cpp.i: .PHONY : ui_rssi.cpp.i ui_rssi.s: ui_rssi.cpp.s + .PHONY : ui_rssi.s # target to generate assembly for a file @@ -4207,6 +4785,7 @@ ui_rssi.cpp.s: .PHONY : ui_rssi.cpp.s ui_sd_card_debug.obj: ui_sd_card_debug.cpp.obj + .PHONY : ui_sd_card_debug.obj # target to build an object file @@ -4215,6 +4794,7 @@ ui_sd_card_debug.cpp.obj: .PHONY : ui_sd_card_debug.cpp.obj ui_sd_card_debug.i: ui_sd_card_debug.cpp.i + .PHONY : ui_sd_card_debug.i # target to preprocess a source file @@ -4223,6 +4803,7 @@ ui_sd_card_debug.cpp.i: .PHONY : ui_sd_card_debug.cpp.i ui_sd_card_debug.s: ui_sd_card_debug.cpp.s + .PHONY : ui_sd_card_debug.s # target to generate assembly for a file @@ -4231,6 +4812,7 @@ ui_sd_card_debug.cpp.s: .PHONY : ui_sd_card_debug.cpp.s ui_sd_card_status_view.obj: ui_sd_card_status_view.cpp.obj + .PHONY : ui_sd_card_status_view.obj # target to build an object file @@ -4239,6 +4821,7 @@ ui_sd_card_status_view.cpp.obj: .PHONY : ui_sd_card_status_view.cpp.obj ui_sd_card_status_view.i: ui_sd_card_status_view.cpp.i + .PHONY : ui_sd_card_status_view.i # target to preprocess a source file @@ -4247,6 +4830,7 @@ ui_sd_card_status_view.cpp.i: .PHONY : ui_sd_card_status_view.cpp.i ui_sd_card_status_view.s: ui_sd_card_status_view.cpp.s + .PHONY : ui_sd_card_status_view.s # target to generate assembly for a file @@ -4255,6 +4839,7 @@ ui_sd_card_status_view.cpp.s: .PHONY : ui_sd_card_status_view.cpp.s ui_setup.obj: ui_setup.cpp.obj + .PHONY : ui_setup.obj # target to build an object file @@ -4263,6 +4848,7 @@ ui_setup.cpp.obj: .PHONY : ui_setup.cpp.obj ui_setup.i: ui_setup.cpp.i + .PHONY : ui_setup.i # target to preprocess a source file @@ -4271,6 +4857,7 @@ ui_setup.cpp.i: .PHONY : ui_setup.cpp.i ui_setup.s: ui_setup.cpp.s + .PHONY : ui_setup.s # target to generate assembly for a file @@ -4279,6 +4866,7 @@ ui_setup.cpp.s: .PHONY : ui_setup.cpp.s ui_soundboard.obj: ui_soundboard.cpp.obj + .PHONY : ui_soundboard.obj # target to build an object file @@ -4287,6 +4875,7 @@ ui_soundboard.cpp.obj: .PHONY : ui_soundboard.cpp.obj ui_soundboard.i: ui_soundboard.cpp.i + .PHONY : ui_soundboard.i # target to preprocess a source file @@ -4295,6 +4884,7 @@ ui_soundboard.cpp.i: .PHONY : ui_soundboard.cpp.i ui_soundboard.s: ui_soundboard.cpp.s + .PHONY : ui_soundboard.s # target to generate assembly for a file @@ -4303,6 +4893,7 @@ ui_soundboard.cpp.s: .PHONY : ui_soundboard.cpp.s ui_spectrum.obj: ui_spectrum.cpp.obj + .PHONY : ui_spectrum.obj # target to build an object file @@ -4311,6 +4902,7 @@ ui_spectrum.cpp.obj: .PHONY : ui_spectrum.cpp.obj ui_spectrum.i: ui_spectrum.cpp.i + .PHONY : ui_spectrum.i # target to preprocess a source file @@ -4319,6 +4911,7 @@ ui_spectrum.cpp.i: .PHONY : ui_spectrum.cpp.i ui_spectrum.s: ui_spectrum.cpp.s + .PHONY : ui_spectrum.s # target to generate assembly for a file @@ -4327,6 +4920,7 @@ ui_spectrum.cpp.s: .PHONY : ui_spectrum.cpp.s ui_textentry.obj: ui_textentry.cpp.obj + .PHONY : ui_textentry.obj # target to build an object file @@ -4335,6 +4929,7 @@ ui_textentry.cpp.obj: .PHONY : ui_textentry.cpp.obj ui_textentry.i: ui_textentry.cpp.i + .PHONY : ui_textentry.i # target to preprocess a source file @@ -4343,6 +4938,7 @@ ui_textentry.cpp.i: .PHONY : ui_textentry.cpp.i ui_textentry.s: ui_textentry.cpp.s + .PHONY : ui_textentry.s # target to generate assembly for a file @@ -4351,6 +4947,7 @@ ui_textentry.cpp.s: .PHONY : ui_textentry.cpp.s ui_touch_calibration.obj: ui_touch_calibration.cpp.obj + .PHONY : ui_touch_calibration.obj # target to build an object file @@ -4359,6 +4956,7 @@ ui_touch_calibration.cpp.obj: .PHONY : ui_touch_calibration.cpp.obj ui_touch_calibration.i: ui_touch_calibration.cpp.i + .PHONY : ui_touch_calibration.i # target to preprocess a source file @@ -4367,6 +4965,7 @@ ui_touch_calibration.cpp.i: .PHONY : ui_touch_calibration.cpp.i ui_touch_calibration.s: ui_touch_calibration.cpp.s + .PHONY : ui_touch_calibration.s # target to generate assembly for a file @@ -4375,6 +4974,7 @@ ui_touch_calibration.cpp.s: .PHONY : ui_touch_calibration.cpp.s ui_whipcalc.obj: ui_whipcalc.cpp.obj + .PHONY : ui_whipcalc.obj # target to build an object file @@ -4383,6 +4983,7 @@ ui_whipcalc.cpp.obj: .PHONY : ui_whipcalc.cpp.obj ui_whipcalc.i: ui_whipcalc.cpp.i + .PHONY : ui_whipcalc.i # target to preprocess a source file @@ -4391,6 +4992,7 @@ ui_whipcalc.cpp.i: .PHONY : ui_whipcalc.cpp.i ui_whipcalc.s: ui_whipcalc.cpp.s + .PHONY : ui_whipcalc.s # target to generate assembly for a file @@ -4398,31 +5000,35 @@ ui_whipcalc.cpp.s: cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_whipcalc.cpp.s .PHONY : ui_whipcalc.cpp.s -ui_xylos.obj: ui_xylos.cpp.obj -.PHONY : ui_xylos.obj +ui_whistle.obj: ui_whistle.cpp.obj + +.PHONY : ui_whistle.obj # target to build an object file -ui_xylos.cpp.obj: - cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_xylos.cpp.obj -.PHONY : ui_xylos.cpp.obj +ui_whistle.cpp.obj: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_whistle.cpp.obj +.PHONY : ui_whistle.cpp.obj -ui_xylos.i: ui_xylos.cpp.i -.PHONY : ui_xylos.i +ui_whistle.i: ui_whistle.cpp.i + +.PHONY : ui_whistle.i # target to preprocess a source file -ui_xylos.cpp.i: - cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_xylos.cpp.i -.PHONY : ui_xylos.cpp.i +ui_whistle.cpp.i: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_whistle.cpp.i +.PHONY : ui_whistle.cpp.i -ui_xylos.s: ui_xylos.cpp.s -.PHONY : ui_xylos.s +ui_whistle.s: ui_whistle.cpp.s + +.PHONY : ui_whistle.s # target to generate assembly for a file -ui_xylos.cpp.s: - cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_xylos.cpp.s -.PHONY : ui_xylos.cpp.s +ui_whistle.cpp.s: + cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_whistle.cpp.s +.PHONY : ui_whistle.cpp.s wavfile.obj: wavfile.cpp.obj + .PHONY : wavfile.obj # target to build an object file @@ -4431,6 +5037,7 @@ wavfile.cpp.obj: .PHONY : wavfile.cpp.obj wavfile.i: wavfile.cpp.i + .PHONY : wavfile.i # target to preprocess a source file @@ -4439,6 +5046,7 @@ wavfile.cpp.i: .PHONY : wavfile.cpp.i wavfile.s: wavfile.cpp.s + .PHONY : wavfile.s # target to generate assembly for a file @@ -4452,10 +5060,10 @@ help: @echo "... all (the default if no target is provided)" @echo "... clean" @echo "... depend" - @echo "... application" - @echo "... application.elf" @echo "... edit_cache" @echo "... rebuild_cache" + @echo "... application" + @echo "... application.elf" @echo "... __/chibios-portapack/boards/GSG_HACKRF_ONE/board.obj" @echo "... __/chibios-portapack/boards/GSG_HACKRF_ONE/board.i" @echo "... __/chibios-portapack/boards/GSG_HACKRF_ONE/board.s" @@ -4915,6 +5523,9 @@ help: @echo "... ui_baseband_stats_view.obj" @echo "... ui_baseband_stats_view.i" @echo "... ui_baseband_stats_view.s" + @echo "... ui_bht_tx.obj" + @echo "... ui_bht_tx.i" + @echo "... ui_bht_tx.s" @echo "... ui_channel.obj" @echo "... ui_channel.i" @echo "... ui_channel.s" @@ -4945,6 +5556,9 @@ help: @echo "... ui_menu.obj" @echo "... ui_menu.i" @echo "... ui_menu.s" + @echo "... ui_morse.obj" + @echo "... ui_morse.i" + @echo "... ui_morse.s" @echo "... ui_navigation.obj" @echo "... ui_navigation.i" @echo "... ui_navigation.s" @@ -4990,9 +5604,9 @@ help: @echo "... ui_whipcalc.obj" @echo "... ui_whipcalc.i" @echo "... ui_whipcalc.s" - @echo "... ui_xylos.obj" - @echo "... ui_xylos.i" - @echo "... ui_xylos.s" + @echo "... ui_whistle.obj" + @echo "... ui_whistle.i" + @echo "... ui_whistle.s" @echo "... wavfile.obj" @echo "... wavfile.i" @echo "... wavfile.s" diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 04131f28e..18a833583 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -79,10 +79,14 @@ void WFMConfig::apply() const { audio::set_rate(audio::Rate::Hz_48000); } -void set_ccir_data( const uint32_t samples_per_tone, const uint16_t tone_count) { - const CCIRConfigureMessage message { - samples_per_tone, - tone_count +void set_tones_data(const uint64_t bw, const uint32_t pre_silence, const uint16_t tone_count, + const bool dual_tone, const bool audio_out) { + const TonesConfigureMessage message { + (uint32_t)(262144 * bw) / 1536000, + pre_silence, + tone_count, + dual_tone, + audio_out }; send_message(&message); } @@ -158,14 +162,14 @@ void set_rds_data(const uint16_t message_length) { send_message(&message); } -void set_dtmf_data(const uint32_t bw, const uint32_t tone_length, const uint32_t pause_length) { +/*void set_dtmf_data(const uint32_t bw, const uint32_t tone_length, const uint32_t pause_length) { const DTMFTXConfigMessage message { bw, tone_length, pause_length }; send_message(&message); -} +}*/ static bool baseband_image_running = false; diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 6b329f4c4..b2816d07a 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -53,7 +53,8 @@ struct WFMConfig { void apply() const; }; -void set_ccir_data( const uint32_t samples_per_tone, const uint16_t tone_count); +void set_tones_data(const uint64_t bw, const uint32_t pre_silence, const uint16_t tone_count, + const bool dual_tone, const bool audio_out); void set_audiotx_data(const uint32_t divider, const uint32_t bw, const bool ctcss_enabled, const uint32_t ctcss_phase_inc); void set_fifo_data(const int8_t * data); void set_pwmrssi(int32_t avg, bool enabled); @@ -64,7 +65,7 @@ void set_ook_data(const uint32_t stream_length, const uint32_t samples_per_bit, void set_pocsag(); void set_adsb(); void set_rds_data(const uint16_t message_length); -void set_dtmf_data(const uint32_t bw, const uint32_t tone_length, const uint32_t pause_length); +//void set_dtmf_data(const uint32_t bw, const uint32_t tone_length, const uint32_t pause_length); void run_image(const portapack::spi_flash::image_tag_t image_tag); void shutdown(); diff --git a/firmware/application/bitmap.hpp b/firmware/application/bitmap.hpp index 6842fb925..153b80c5e 100644 --- a/firmware/application/bitmap.hpp +++ b/firmware/application/bitmap.hpp @@ -27,6 +27,52 @@ namespace ui { +static constexpr uint8_t bitmap_stealth_data[] = { + 0x00, 0x00, + 0x00, 0x00, + 0xE0, 0x07, + 0xF8, 0x1F, + 0xFC, 0x3F, + 0xFC, 0x3F, + 0xE4, 0x27, + 0xC4, 0x23, + 0xEC, 0x37, + 0x7C, 0x3E, + 0x7C, 0x1E, + 0x2C, 0x0C, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x00, 0x00 +}; + +static constexpr Bitmap bitmap_stealth { + { 16, 16 }, bitmap_stealth_data +}; + +static constexpr uint8_t bitmap_speaker_data[] = { + 0x00, 0x00, + 0x00, 0x20, + 0x00, 0x30, + 0x00, 0x38, + 0x00, 0x3C, + 0xDC, 0x3E, + 0xDC, 0x3F, + 0xDC, 0x3F, + 0xDC, 0x3F, + 0xDC, 0x3F, + 0xDC, 0x3E, + 0x00, 0x3C, + 0x00, 0x38, + 0x00, 0x30, + 0x00, 0x20, + 0x00, 0x00 +}; + +static constexpr Bitmap bitmap_speaker { + { 16, 16 }, bitmap_speaker_data +}; + static constexpr uint8_t bitmap_more_data[] = { 0x00, 0x00, 0xC0, 0x03, @@ -78,15 +124,15 @@ static constexpr uint8_t bitmap_keyboard_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF8, 0x0F, - 0x88, 0x08, - 0x88, 0x08, - 0x88, 0x08, - 0xFE, 0x3F, - 0x22, 0x22, - 0x22, 0x22, - 0x22, 0x22, - 0xFE, 0x3F, + 0xF0, 0x1F, + 0x10, 0x11, + 0x10, 0x11, + 0x10, 0x11, + 0xFC, 0x7F, + 0x44, 0x44, + 0x44, 0x44, + 0x44, 0x44, + 0xFC, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/firmware/application/demofont.hpp b/firmware/application/demofont.hpp index 6e1ec5c4f..26807d5e7 100644 --- a/firmware/application/demofont.hpp +++ b/firmware/application/demofont.hpp @@ -1,4 +1,4 @@ -unsigned char demofont_bin[] = { +const uint8_t demofont_bin[] = { 0xff, 0xff, 0xff, 0xff, 0xc7, 0xe4, 0xeb, 0xa3, 0xc0, 0xef, 0x82, 0x65, 0xcc, 0x6a, 0x50, 0xc8, 0x8c, 0x99, 0xa6, 0x78, 0x76, 0x8d, 0x57, 0x66, 0xa5, 0x3f, 0x52, 0x7d, 0x2d, 0x66, 0x91, 0x19, 0x46, 0x72, 0x00, 0x5e, diff --git a/firmware/application/encoders.hpp b/firmware/application/encoders.hpp new file mode 100644 index 000000000..e89ca20ba --- /dev/null +++ b/firmware/application/encoders.hpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#ifndef __ENCODERS_H__ +#define __ENCODERS_H__ + +namespace encoders { + + #define ENC_TYPES_COUNT 14 + + struct encoder_def_t { + std::string name; // Encoder chip ref/name + std::string address_symbols; // "01", "01F"... + std::string data_symbols; // Same + uint16_t clk_per_symbol; // Oscillator periods per symbol + uint16_t clk_per_fragment; // Oscillator periods per symbol fragment (state) + std::vector bit_format; // List of fragments for each symbol in previous *_symbols list order + uint8_t word_length; // Total # of symbols (not counting sync) + std::string word_format; // A for Address, D for Data, S for sync + std::string sync; // Like bit_format + uint32_t default_speed; // Default encoder clk frequency (often set by shitty resistor) + uint8_t repeat_min; // Minimum repeat count + uint16_t pause_symbols; // Length of pause between repeats in symbols + }; + + // Warning ! If this is changed, make sure that the UM3750 index is still good in ui_bht_tx.cpp ! + const encoder_def_t encoder_defs[ENC_TYPES_COUNT] = { + // PT2260-R2 + { + "2260-R2", + "01F", "01", + 1024, 128, + { "10001000", "11101110", "10001110" }, + 12, "AAAAAAAAAADDS", + "10000000000000000000000000000000", + 150000, 2, + 0 + }, + + // PT2260-R4 + { + "2260-R4", + "01F", "01", + 1024, 128, + { "10001000", "11101110", "10001110" }, + 12, "AAAAAAAADDDDS", + "10000000000000000000000000000000", + 150000, 2, + 0 + }, + + // PT2262 + { + "2262 ", + "01F", "01F", + 32, 4, + { "10001000", "11101110", "10001110" }, + 12, "AAAAAAAAAAAAS", + "10000000000000000000000000000000", + 20000, 4, + 0 + }, + + // 16-bit ? + { + "16-bit ", + "01", "01", + 32, 8, + { "1110", "1000" }, // Opposite ? + 16, "AAAAAAAAAAAAAAAAS", + "100000000000000000000", + 25000, 50, + 0 // ? + }, + + // RT1527 + { + "1527 ", + "01", "01", + 128, 32, + { "1000", "1110" }, + 24, "SAAAAAAAAAAAAAAAAAAAADDDD", + "10000000000000000000000000000000", + 100000, 4, + 10 // ? + }, + + // HK526E + { + "526 ", + "01", "01", + 24, 8, + { "110", "100" }, + 12, "AAAAAAAAAAAA", + "", + 20000, 4, + 10 // ? + }, + + // HT12E + { + "12E ", + "01", "01", + 3, 1, + { "011", "001" }, + 12, "SAAAAAAAADDDD", + "0000000000000000000000000000000000001", + 3000, 4, + 10 // ? + }, + + // VD5026 13 bits ? + { + "5026 ", + "0123", "0123", + 128, 8, + { "1000000010000000", "1111111011111110", "1111111010000000", "1000000011111110" }, + 12, "SAAAAAAAAAAAA", + "000000000000000000000000000000000000000000000001", // ? + 100000, 4, + 10 // ? + }, + + // UM3750 + { + "UM3750 ", + "01", "01", + 96, 32, + { "011", "001" }, + 12, "SAAAAAAAAAAAA", + "1", + 100000, 4, + 0 // ? + }, + + // UM3758 + { + "UM3758 ", + "01F", "01", + 96, 16, + { "011011", "001001", "011001" }, + 18, "SAAAAAAAAAADDDDDDDD", + "1", + 160000, 4, + 10 // ? + }, + + // BA5104 + { + "BA5104 ", + "01", "01", + 3072, 768, + { "1000", "1110" }, + 9, "SDDAAAAAAA", + "", + 455000, 4, + 10 // ? + }, + + // MC145026 + { + "145026 ", + "01F", "01", + 16, 1, + { "0111111101111111", "0100000001000000", "0111111101000000" }, + 9, "SAAAAADDDD", + "000000000000000000", + 455000, 2, + 2 + }, + + // HT6*** TODO: Add individual variations + { + "HT6*** ", + "01F", "01", + 198, 33, + { "011011", "001001", "001011" }, + 18, "SAAAAAAAAAAAADDDDDD", + "0000000000000000000000000000000000001011001011001", + 80000, 3, + 10 // ? + }, + + // TC9148 + { + "TC9148 ", + "01", "01", + 48, 12, + { "1000", "1110", }, + 12, "AAAAAAAAAAAA", + "", + 455000, 3, + 10 // ? + } + }; + +} /* namespace encoders */ + +#endif/*__ENCODERS_H__*/ diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index a55410b0f..64e92b8b8 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -92,6 +92,7 @@ private: static MessageHandlerMap message_map; Thread* EventDispatcher::thread_event_loop = nullptr; bool EventDispatcher::is_running = false; +bool EventDispatcher::display_sleep = false; EventDispatcher::EventDispatcher( ui::Widget* const top_widget, @@ -130,7 +131,7 @@ void EventDispatcher::set_display_sleep(const bool sleep) { portapack::display.wake(); portapack::io.lcd_backlight(true); } - display_sleep = sleep; + EventDispatcher::display_sleep = sleep; }; eventmask_t EventDispatcher::wait() { @@ -187,8 +188,12 @@ void EventDispatcher::dispatch(const eventmask_t events) { if( events & EVT_MASK_SWITCHES ) { handle_switches(); } + + /*if( events & EVT_MASK_LCD_FRAME_SYNC ) { + blink_timer(); + }*/ - if( !display_sleep ) { + if( !EventDispatcher::display_sleep ) { if( events & EVT_MASK_LCD_FRAME_SYNC ) { handle_lcd_frame_sync(); } @@ -286,7 +291,7 @@ void EventDispatcher::handle_switches() { portapack::bl_tick_counter = 0; - if( display_sleep ) { + if( EventDispatcher::display_sleep ) { // Swallow event, wake up display. if( switches_state.any() ) { set_display_sleep(false); @@ -308,7 +313,7 @@ void EventDispatcher::handle_switches() { void EventDispatcher::handle_encoder() { portapack::bl_tick_counter = 0; - if( display_sleep ) { + if( EventDispatcher::display_sleep ) { // Swallow event, wake up display. set_display_sleep(false); return; diff --git a/firmware/application/event_m0.hpp b/firmware/application/event_m0.hpp index f89f0b756..3cda1c83b 100644 --- a/firmware/application/event_m0.hpp +++ b/firmware/application/event_m0.hpp @@ -52,7 +52,7 @@ public: void run(); static void request_stop(); - void set_display_sleep(const bool sleep); + static void set_display_sleep(const bool sleep); static inline void check_fifo_isr() { if( !shared_memory.application_queue.is_empty() ) { @@ -101,7 +101,7 @@ private: uint32_t encoder_last = 0; static bool is_running; bool sd_card_present = false; - bool display_sleep = false; + static bool display_sleep; bool halt = false; eventmask_t wait(); @@ -117,6 +117,7 @@ private: void on_touch_event(ui::TouchEvent event); + //void blink_timer(); void handle_lcd_frame_sync(); void handle_switches(); void handle_encoder(); diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 4951518ea..3496717eb 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -23,38 +23,47 @@ // Bitmaps generated with: // Gimp image > indexed colors (16), then "xxd -i *.bmp" -//TEST: RDS //TEST: Imperial in whipcalc //TEST: Numbers //TEST: Jammer -//TODO: Morse coder/beacon +//BUG: Xylos doesn't play last tone ? //BUG (fixed ?): Soundboard crashes on exit if no wav files on sd card -//BUG (fixed ?): No audio in about when shown second time -//BUG: Unistroke text entry screen doesn't care about string max length parameter +//BUG (fixed ?): Unistroke text entry screen doesn't care about string max length parameter //BUG: POCSAG RX sometimes misses the first codeword after SYNC +//BUG: Check AFSK transmit end, skips last bits ? +//BUG: RDS doesn't stop baseband when stopping tx ? -//TODO: Use ModalMessageView with yes/no for TX +//TODO: Mousejack ? +//TODO: Waveform widget ? +//TODO: Frequency manager save/load (ui_freqman) +//TODO: Move frequencykeypad from ui_receiver to ui_widget (used everywhere) +//TODO: ADS-B draw trajectory + GPS coordinates + scale, and playback +//TODO: Finish EPAR tx +//TODO: Wav visualizer +//TODO: Analog TV tx with camcorder font character generator +//TODO: Test dual tone in proc_tones and remove proc_dtmf_tx +//TODO: Morse coder for foxhunts +//TODO: Make Morse coder and Whistle use proc_tones +//TODO: RDS multiple groups (sequence) +//TODO: Frequency manager +//TODO: IQ replay +//TODO: Use ModalMessageView confirmation for TX ? //TODO: Show address/data bit fields in OOK TX //TODO: Scan for OOK TX //TODO: Check more OOK encoders //TODO: POCSAG 512 and 2400 (all 3 at the same time, or parameter ?) -//TODO: Check AFSK transmit end, skips last bits ? //TODO: Use msgpack for settings, lists... on sd card -//TODO: Frequency manager -//TODO: Replay //Multimon-style stuff: //TODO: AFSK receiver //TODO: CTCSS detector //TODO: DMR detector -//TODO: Closecall wide range fix //TODO: SD card wiper //TODO: GSM channel detector //TODO: SIGFOX RX/TX //TODO: Bodet :) -//TODO: Whistler //TODO: LCR full message former (see norm) //TODO: AFSK NRZI @@ -62,16 +71,15 @@ //TODO: Playdead amnesia and login //TODO: Setup: Play dead by default ? Enable/disable ? -//TODO: Hide statusview when playing dead -//TODO: Persistent playdead ! -//In case of disaster: +//BUG (fixed ?): No audio in about when shown second time + //TODO: Show MD5 mismatches for modules not found, etc... //TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule //BUG: Description doesn't show up first time going to system>module info (UI drawn on top) - //TODO: Draw on touchscreen and transmit as spectrum paint //TODO: Two players tic-tac-toe +//TODO: Analog TV pong game #include "ch.h" diff --git a/firmware/application/rds.cpp b/firmware/application/rds.cpp index e63893680..743926bdb 100644 --- a/firmware/application/rds.cpp +++ b/firmware/application/rds.cpp @@ -82,9 +82,17 @@ void make_4A_group(uint32_t blocks[], const uint16_t PI_code, const bool TP, con uint32_t L = 0; uint32_t day_code; +<<<<<<< HEAD + // 57723 + + if ((month == 1) || (month == 2)) L = 1; + + day_code = 14956 + day + (uint32_t)((float)(year - 1900 - L) * 365.25) + uint16_t((float)((month + 1) + L * 12) * 30.6001); +======= if ((month == 1) || (month == 2)) L = 1; day_code = 14956 + day + (uint32_t)((float)(year - L) * 365.25) + uint16_t(((month + 1) * L * 12) * 30.6001); +>>>>>>> d402a87... RDS radiotext and time group generators blocks[0] = PI_code; blocks[1] = (0x4 << 12) | (0 << 11) | (b2b(TP) << 10) | ((PTY & 0x1F) << 5) | ((day_code & 0x18000) >> 15); @@ -98,7 +106,11 @@ uint16_t gen_PSN(const char * psname, const RDS_flags * rds_flags) { // 4 groups with 2 PSN characters in each for (c = 0; c < 4; c++) +<<<<<<< HEAD make_0B_group(&group[c][0], rds_flags->PI_code, rds_flags->TP, rds_flags->PTY, rds_flags->TA, rds_flags->MS, rds_flags->DI, c, &psname[c * 2]); +======= + make_0B_group(&group[c][0], rds_flags->PI_code, rds_flags->TP, rds_flags->PTY, rds_flags->TA, rds_flags->MS, rds_flags->DI, c, &psname[c * 2]); +>>>>>>> d402a87... RDS radiotext and time group generators // Generate checkbits for each block of each group for (c = 0; c < 4; c++) { @@ -108,7 +120,7 @@ uint16_t gen_PSN(const char * psname, const RDS_flags * rds_flags) { group[c][3] = makeblock(group[c][3], RDS_OFFSET_D); } - uint32_t * tx_data_u32 = (uint32_t*)shared_memory.tx_data; + uint32_t * tx_data_u32 = (uint32_t*)shared_memory.bb_data.data; // Copy to tx_data for baseband for (c = 0; c < 4 * 4; c++) @@ -150,7 +162,7 @@ uint16_t gen_RadioText(const char * text, const bool AB, const RDS_flags * rds_ group[i + 3] = makeblock(group[i + 3], RDS_OFFSET_D); } - uint32_t * tx_data_u32 = (uint32_t*)shared_memory.tx_data; + uint32_t * tx_data_u32 = (uint32_t*)shared_memory.bb_data.data; // Copy to tx_data for baseband for (c = 0; c < (groups * 4); c++) @@ -175,7 +187,11 @@ uint16_t gen_ClockTime(const RDS_flags * rds_flags, group[2] = makeblock(group[2], RDS_OFFSET_C); group[3] = makeblock(group[3], RDS_OFFSET_D); +<<<<<<< HEAD + uint32_t * tx_data_u32 = (uint32_t*)shared_memory.bb_data.data; +======= uint32_t * tx_data_u32 = (uint32_t*)shared_memory.tx_data; +>>>>>>> d402a87... RDS radiotext and time group generators // Copy to tx_data for baseband for (c = 0; c < 4; c++) diff --git a/firmware/application/rds.hpp b/firmware/application/rds.hpp index 35b891e50..071ca9525 100644 --- a/firmware/application/rds.hpp +++ b/firmware/application/rds.hpp @@ -37,11 +37,19 @@ namespace rds { struct RDS_flags { uint16_t PI_code; +<<<<<<< HEAD + uint8_t PTY; + uint8_t DI; + bool TP; + bool TA; + bool MS; +======= bool TP; uint8_t PTY; bool TA; bool MS; bool DI; +>>>>>>> d402a87... RDS radiotext and time group generators }; uint32_t makeblock(uint32_t blockdata, uint16_t offset); diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 35059f5c7..c5d95125b 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -24,6 +24,8 @@ #include "baseband_api.hpp" #include "portapack_persistent_memory.hpp" +#include "hackrf_gpio.hpp" +using namespace hackrf::one; using namespace portapack; #include "radio.hpp" @@ -159,6 +161,7 @@ void ReceiverModel::enable() { update_sampling_rate(); update_modulation(); update_headphone_volume(); + led_rx.on(); } void ReceiverModel::disable() { @@ -168,6 +171,7 @@ void ReceiverModel::disable() { // TODO: Responsibility for enabling/disabling the radio is muddy. // Some happens in ReceiverModel, some inside radio namespace. radio::disable(); + led_rx.off(); } int32_t ReceiverModel::tuning_offset() { diff --git a/firmware/application/transmitter_model.cpp b/firmware/application/transmitter_model.cpp index 6ded622ba..f32cbff8e 100644 --- a/firmware/application/transmitter_model.cpp +++ b/firmware/application/transmitter_model.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -24,8 +25,12 @@ #include "baseband_api.hpp" #include "portapack_persistent_memory.hpp" +#include "hackrf_gpio.hpp" +using namespace hackrf::one; using namespace portapack; +#include "time.hpp" +#include "event_m0.hpp" #include "radio.hpp" #include "audio.hpp" @@ -83,6 +88,11 @@ uint32_t TransmitterModel::baseband_oversampling() const { return baseband_configuration.decimation_factor; } +void TransmitterModel::on_tick_second() { + if (portapack::persistent_memory::stealth_mode()) + led_tx.toggle(); +} + void TransmitterModel::enable() { enabled_ = true; radio::set_direction(rf::Direction::Transmit); @@ -92,6 +102,13 @@ void TransmitterModel::enable() { update_vga(); update_baseband_bandwidth(); update_baseband_configuration(); + + led_tx.on(); + signal_token_tick_second = time::signal_tick_second += [this]() { + this->on_tick_second(); + }; + if (portapack::persistent_memory::stealth_mode()) + EventDispatcher::set_display_sleep(true); } void TransmitterModel::disable() { @@ -100,6 +117,9 @@ void TransmitterModel::disable() { // TODO: Responsibility for enabling/disabling the radio is muddy. // Some happens in ReceiverModel, some inside radio namespace. radio::disable(); + + time::signal_tick_second -= signal_token_tick_second; + led_tx.off(); } void TransmitterModel::update_tuning_frequency() { diff --git a/firmware/application/transmitter_model.hpp b/firmware/application/transmitter_model.hpp index 8fc8c9c36..622077a14 100644 --- a/firmware/application/transmitter_model.hpp +++ b/firmware/application/transmitter_model.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -30,6 +31,7 @@ #include "rf_path.hpp" #include "max2837.hpp" #include "volume.hpp" +#include "signal.hpp" class TransmitterModel { public: @@ -70,6 +72,7 @@ private: .sampling_rate = 3072000, .decimation_factor = 1, }; + SignalToken signal_token_tick_second; void update_tuning_frequency(); void update_rf_amp(); @@ -78,6 +81,7 @@ private: void update_vga(); void update_modulation(); void update_baseband_configuration(); + void on_tick_second(); }; #endif/*__TRANSMITTER_MODEL_H__*/ diff --git a/firmware/application/ui_about.cpp b/firmware/application/ui_about.cpp index fe16df3f7..1229606f5 100644 --- a/firmware/application/ui_about.cpp +++ b/firmware/application/ui_about.cpp @@ -20,19 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#include - -#include "demofont.hpp" -#include "ymdata.hpp" - #include "cpld_update.hpp" #include "portapack.hpp" -#include "audio.hpp" #include "event_m0.hpp" #include "ui_about.hpp" -#include "touch.hpp" -#include "sine_table.hpp" #include "portapack_shared_memory.hpp" #include "portapack_persistent_memory.hpp" @@ -45,371 +37,130 @@ using namespace lpc43xx; using namespace portapack; namespace ui { - -void AboutView::on_show() { - transmitter_model.set_tuning_frequency(1337000000); // TODO: Change - transmitter_model.set_baseband_configuration({ - .mode = 0, - .sampling_rate = 1536000, - .decimation_factor = 1, - }); - transmitter_model.set_rf_amp(true); - transmitter_model.set_lna(40); - transmitter_model.set_vga(40); - transmitter_model.set_baseband_bandwidth(1750000); - transmitter_model.enable(); - - baseband::set_audiotx_data(32, 50, false, 0); - - //audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max); -} - -void AboutView::render_video() { - uint8_t p, r, luma, chroma, cy; - ui::Color cc; - char ch; - float s; - - // Send framebuffer to LCD. Gotta go fast ! - display.render_box({30, 112}, {180, 72}, framebuffer); - - // Clear framebuffer to black - memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color)); - - // Drum hit palette animation - if (drum > 1) drum--; - - // Render copper bars from Y buffer - for (p = 0; p < 72; p++) { - luma = copperbuffer[p] & 0x0F; // 0 is transparent - if (luma) { - chroma = copperbuffer[p]>>4; - cc = ui::Color(std::min((coppercolor[chroma][0]/luma)*drum,255), std::min((coppercolor[chroma][1]/luma)*drum,255), std::min((coppercolor[chroma][2]/luma)*drum,255)); - for (r = 0; r < 180; r++) - framebuffer[(p*180)+r] = cc; - } - } - - // Scroll in/out state machine - if (anim_state == 0) { - // Scroll in - if (ofy < 8) { - ofy++; - anim_state = 0; - } else { - anim_state = 1; - } - if (ofx < (int16_t)(180 - (strlen(credits[credits_index].name) * 16) - 8)) { - ofx += 8; - anim_state = 0; - } - } else if (anim_state == 1) { - // Just wait - if (credits_timer == (30*3)) { - credits_timer = 0; - anim_state = 2; - } else { - credits_timer++; - } - } else { - // Scroll out - if (credits[credits_index].change == true) { - if (ofy > -24) { - ofy--; - anim_state = 2; - } else { - anim_state = 0; - } - } else { - anim_state = 0; - } - if (ofx < 180) { - ofx += 8; - anim_state = 2; - } - - // Switch to next text - if (anim_state == 0) { - if (credits_index == 9) - credits_index = 0; - else - credits_index++; - ofx = -(strlen(credits[credits_index].name) * 16) - 16; - } - } - - // Sine text ("role") - p = 0; - while ((ch = credits[credits_index].role[p])) { - draw_demoglyph({(ui::Coord)(8+(p*16)), (ui::Coord)(ofy+(sine_table_f32[((p*16)+(phase>>5))&0xFF] * 8))}, ch, paletteA); - p++; - } - - // Scroll text (name) - p = 0; - while ((ch = credits[credits_index].name[p])) { - draw_demoglyph({(ui::Coord)(ofx+(p*16)), 56}, ch, paletteB); - p++; - } - - // Clear bars Y buffer - memset(copperbuffer, 0, 72); - - // Render bars to Y buffer - for (p = 0; p < 5; p++) { - cy = copperbars[p]; - for (r = 0; r < 16; r++) - copperbuffer[cy+r] = copperluma[r] + (p<<4); - } - - // Animate bars positions - for (p = 0; p < 5; p++) { - s = sine_table_f32[((p*32)+(phase/24))&0xFF]; - s += sine_table_f32[((p*16)+(phase/35))&0xFF]; - copperbars[p] = 28+(uint8_t)(s * 14); - } - - phase += 128; -} - -void AboutView::draw_demoglyph(ui::Point p, char ch, ui::Color * pal) { - uint8_t x, y, c, cl, cr; - uint16_t che; - int16_t lbx, il; - - // Map ASCII to font bitmap - if ((ch >= 32) || (ch < 96)) - che = char_map[ch-32]; - else - che = 0xFF; - - if (che < 0xFF) { - che = (che * 128) + 48; // Start in bitmap - - il = (180 * p.y) + p.x; // Start il framebuffer - - for (y = 0; y < 16; y++) { - if (p.y + y >= 72) break; // Over bottom of framebuffer, abort - if (p.y + y >= 0) { - for (x = 0; x < 8; x++) { - c = demofont_bin[x+(y*8)+che]; // Split byte in 2 4BPP pixels - cl = c >> 4; - cr = c & 0x0F; - lbx = p.x + (x*2); - if (cl && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cl]; - lbx++; - il++; - if (cr && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cr]; - il++; - } - il += 180-16; - } else { - il += 180; - } - } - } -} - -void AboutView::render_audio() { - uint8_t i, ymdata; - uint16_t ym_render_cnt; - - // This is heavily inspired by MAME's ay8910.cpp and the YM2149's datasheet - - // Render 1024 music samples - for (ym_render_cnt = 0; ym_render_cnt < 1024; ym_render_cnt++) { - - // Update registers at 48000/960 = 50Hz - if (ym_sample_cnt == 0) { - // "Decompress" on the fly and update YM registers - for (i = 0; i < 14; i++) { - if (!ym_regs[i].cnt) { - // New run - ymdata = ymdata_bin[ym_regs[i].ptr++]; - ym_regs[i].cnt = ymdata & 0x7F; - if (ymdata & 0x80) { - ym_regs[i].same = true; - ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++]; - } else { - ym_regs[i].same = false; - } - // Detect drum on channel B - if (i == 3) - if (ym_regs[3].value > 2) drum = 4; - } - if (ym_regs[i].same == false) { - ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++]; - if (i == 13) { - // Update envelope attributes - ym_env_att = (ym_regs[13].value & 4) ? 0x1F : 0x00; - if (!(ym_regs[13].value & 8)) { - ym_env_hold = 1; - ym_env_alt = ym_env_att; - } else { - ym_env_hold = ym_regs[13].value & 1; - ym_env_alt = ym_regs[13].value & 2; - } - // Reset envelope counter - ym_env_step = 0x1F; - ym_env_holding = 0; - ym_env_vol = (ym_env_step ^ ym_env_att); - } - } - ym_regs[i].cnt--; - } - ym_frame++; - } - - // Square wave oscillators - // 2457600/16/48000 = 3.2, but 4 sounds better than 3... - for (i = 0; i < 3; i++) { - ym_osc_cnt[i] += 4; - if (ym_osc_cnt[i] >= (ym_regs[i*2].value | ((ym_regs[(i*2)+1].value & 0x0f) << 8))) { - ym_osc_cnt[i] = 0; - ym_osc_out[i] ^= 1; - } - } - - // Noise generator - ym_noise_cnt += 4; - if (ym_noise_cnt >= ((ym_regs[6].value & 0x1F) * 2)) { - ym_noise_cnt = 0; - ym_rng ^= (((ym_rng & 1) ^ ((ym_rng >> 3) & 1)) << 17); - ym_rng >>= 1; - } - - // Mix tones and noise - for (i = 0; i < 3; i++) - ym_ch[i] = (ym_osc_out[i] | ((ym_regs[7].value >> i) & 1)) & ((ym_rng & 1) | ((ym_regs[7].value >> (i + 3)) & 1)); - - // Envelope generator - if (!ym_env_holding) { - ym_env_cnt += 8; - if (ym_env_cnt >= (ym_regs[11].value | (ym_regs[12].value<<8))) { - ym_env_cnt = 0; - ym_env_step--; - if (ym_env_step < 0) { - if (ym_env_hold) { - if (ym_env_alt) - ym_env_att ^= 0x1F; - ym_env_holding = 1; - ym_env_step = 0; - } else { - if (ym_env_alt && (ym_env_step & 0x20)) - ym_env_att ^= 0x1F; - ym_env_step &= 0x1F; - } - } - } - } - ym_env_vol = (ym_env_step ^ ym_env_att); - - ym_out = 0; - for (i = 0; i < 3; i++) { - if (ym_regs[i + 8].value & 0x10) { - // Envelope mode - ym_out += (ym_ch[i] ? ym_env_vol : 0); - } else { - // Fixed mode - ym_out += (ym_ch[i] ? (ym_regs[i + 8].value & 0x0F) : 0); - } - } - - ym_buffer[ym_render_cnt] = (ym_out * 2) - 45; - - if (ym_sample_cnt < 960) { - ym_sample_cnt++; - } else { - ym_sample_cnt = 0; - } - - // Loop - if (ym_frame == ym_frames) ym_init(); - } -} void AboutView::update() { - if (framebuffer) { - // Update 1 out of 2 frames, 60Hz is very laggy - if (refresh_cnt & 1) render_video(); - refresh_cnt++; - } + size_t c; + int32_t n; + std::string text; + Coord y_val, x_pos = 0; + uint32_t flag; - // Slowly increase volume to avoid jumpscare - if (headphone_vol < (70 << 2)) { - audio::headphone::set_volume(volume_t::decibel((headphone_vol/4) - 99) + audio::headphone::volume_range().max); - headphone_vol++; - } -} + if (scroll & 1) { + if (!((scroll >> 1) & 15)) { + if (line_feed) { + line_feed = false; + } else { + // Find a free text widget + for (c = 0; c < 10; c++) + if (text_line[c].screen_pos().y >= 200) break; + + if (c < 10) { + flag = credits[credits_index].flag & 0x3F; + line_feed = (credits[credits_index].flag & 0x40) ? true : false; + + if (flag == SECTION) { + if (!second) { + text = credits[credits_index].role; + if (credits[credits_index].name != "") + second = true; + else { + credits_index++; + line_feed = true; + } + } else { + text = credits[credits_index].name; + second = false; + line_feed = true; + credits_index++; + } + x_pos = (240 - (text.size() * 8)) / 2; + } else if (flag == TITLE) { + text = credits[credits_index].role; + x_pos = 120 - (text.size() * 8); + if (credits[credits_index].name != "") + text += " " + credits[credits_index].name; + credits_index++; + } else if (flag == MEMBER) { + if (!second) { + text = credits[credits_index].role; + if (credits[credits_index].name != "") + second = true; + else + credits_index++; + } else { + text = credits[credits_index].name; + second = false; + credits_index++; + } + x_pos = 136; + } + + if (!(flag & 0x80)) { + text_line[c].set_parent_rect({{ x_pos, 200 - 16 }, { (Dim)text.size() * 8, 17 }}); + text_line[c].set(text); + text_line[c].hidden(false); + } + } + } + } -void AboutView::ym_init() { - uint8_t reg; - - for (reg = 0; reg < 14; reg++) { - ym_regs[reg].cnt = 0; - // Pick up start pointers for each YM registers RLE blocks - ym_regs[reg].ptr = ((uint16_t)(ymdata_bin[(reg*2)+3])<<8) + ymdata_bin[(reg*2)+2]; - ym_regs[reg].same = false; // Useless ? - ym_regs[reg].value = 0; // Useless ? + // Scroll text lines + for (c = 0; c < 10; c++) { + y_val = text_line[c].screen_pos().y - 16; + if (y_val < 32) { + text_line[c].set_parent_rect({{ text_line[c].screen_pos().x, 200 }, { text_line[c].size() }}); + text_line[c].hidden(true); + } else { + if (y_val < 200) { + text_line[c].set_parent_rect({{ text_line[c].screen_pos().x, y_val - 1 }, { text_line[c].size() }}); + n = (y_val - 32) >> 2; + if (n > 19) + n = (38 - n); + else + n -= 3; + if (n > 3) n = 3; + if (n < 0) n = 0; + text_line[c].set_style(&styles[n]); + } + } + } } - - ym_frame = 0; + scroll++; } AboutView::AboutView( NavigationView& nav ) { - uint8_t p, c; - - baseband::run_image(portapack::spi_flash::image_tag_audio_tx); + //uint8_t p, c; add_children({ { - &text_title, - &text_firmware, &text_cpld_hackrf, &text_cpld_hackrf_status, &button_ok, } }); + for (auto& text : text_line) { + text.set(""); + text.set_parent_rect({ + static_cast(0), + static_cast(200), + 0, 0 + }); + add_child(&text); + } + if( cpld_hackrf_verify_eeprom() ) { text_cpld_hackrf_status.set(" OK"); } else { text_cpld_hackrf_status.set("BAD"); } - - // Politely ask for about 26kB - framebuffer = (ui::Color *)chHeapAlloc(0x0, 180 * 72 * sizeof(ui::Color)); - - if (framebuffer) { - memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color)); - - // Copy original font palette - c = 0; - for (p = 0; p < 48; p+=3) - paletteA[c++] = ui::Color(demofont_bin[p], demofont_bin[p+1], demofont_bin[p+2]); - - // Increase red in another one - c = 0; - for (p = 0; p < 48; p+=3) - paletteB[c++] = ui::Color(std::min(demofont_bin[p]+64, 255), demofont_bin[p+1], demofont_bin[p+2]); - } - - // Init YM synth - ym_frames = ((uint16_t)(ymdata_bin[1])<<8) + ymdata_bin[0]; - ym_init(); button_ok.on_select = [this,&nav](Button&){ - if (framebuffer) chHeapFree(framebuffer); // Do NOT forget this nav.pop(); }; } -AboutView::~AboutView() { - transmitter_model.disable(); - baseband::shutdown(); -} - void AboutView::focus() { button_ok.focus(); } diff --git a/firmware/application/ui_about.hpp b/firmware/application/ui_about.hpp index 91158275a..15031bcaa 100644 --- a/firmware/application/ui_about.hpp +++ b/firmware/application/ui_about.hpp @@ -26,8 +26,7 @@ #include "ui_widget.hpp" #include "ui_menu.hpp" #include "ui_navigation.hpp" -#include "transmitter_model.hpp" -#include "baseband_api.hpp" +#include "ui_font_fixed_8x16.hpp" #include @@ -36,103 +35,73 @@ namespace ui { class AboutView : public View { public: AboutView(NavigationView& nav); - ~AboutView(); - void on_show() override; void focus() override; + + std::string title() const override { return "About"; }; private: - void ym_init(); void update(); - void render_video(); - void render_audio(); - void draw_demoglyph(ui::Point p, char ch, ui::Color * pal); - uint16_t debug_cnt = 0; - - typedef struct ymreg_t { - uint8_t value; - uint8_t cnt; - uint16_t ptr; - bool same; - } ymreg_t; - - uint16_t headphone_vol = 5 << 2; - - ymreg_t ym_regs[14]; - uint16_t ym_frames; - uint16_t ym_frame; - uint8_t drum = 0; - uint16_t ym_osc_cnt[3]; - uint32_t ym_rng = 1; - uint16_t ym_noise_cnt; - uint8_t ym_env_att, ym_env_hold, ym_env_alt, ym_env_holding, ym_env_vol; - int8_t ym_env_step; - uint16_t ym_env_cnt; - uint8_t ym_osc_out[3]; - uint8_t ym_ch[3]; - uint8_t ym_out; - uint16_t ym_sample_cnt = 0; - - int8_t ym_buffer[1024]; - uint8_t refresh_cnt; - ui::Color paletteA[16]; - ui::Color paletteB[16]; - ui::Color * framebuffer; - uint32_t phase = 0; - uint8_t copperbars[5] = { 0 }; - uint8_t copperbuffer[72] = { 0 }; - - uint8_t anim_state = 0; uint8_t credits_index = 0; - uint16_t credits_timer = 0; + uint32_t scroll = 0; + bool second = false; + bool line_feed = false; - int16_t ofx = -180, ofy = -24; - - const uint8_t char_map[64] = { 0xFF, 27, 46, 0xFF, 0xFF, 0xFF, 28, 45, - 58, 59, 0xFF, 43, 40, 57, 26, 42, - 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 41, 0xFF, 0xFF, 0xFF, 0xFF, 44, - 0xFF, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - - const uint8_t copperluma[16] = { 8,7,6,5,4,3,2,1,1,2,3,4,5,6,7,8 }; - const uint8_t coppercolor[5][3] = { { 255,0,0 }, - { 0,255,0 }, - { 0,0,255 }, - { 255,0,255 }, - { 255,255,0 } }; + Style styles[4] = { style_black, style_dark_grey, style_light_grey, style_white }; + static constexpr Style style_white { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color(255, 255, 255) + }; + static constexpr Style style_light_grey { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color(170, 170, 170) + }; + static constexpr Style style_dark_grey { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color(85, 85, 85) + }; + static constexpr Style style_black { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color(0, 0, 0) + }; + + enum flags { + SECTION = 0, + MEMBER = 1, + MEMBER_LF = 0x41, + TITLE = 2, + TITLE_LF = 0x42, + END = 0x80 + }; + typedef struct credits_t { - char role[12]; - char name[12]; - bool change; + std::string role; + std::string name; + flags flag; } credits_t; - // 0123456789A 0123456789A - const credits_t credits[10] = { {"GURUS", "J. BOONE", false}, - {"GURUS", "M. OSSMANN", true}, - {"BUGS", "FURRTEK", true}, - {"RDS WAVE", "C. JACQUET", true}, - {"POCSAG RX", "T. SAILER", false}, - {"POCSAG RX", "E. OENAL", true}, - {"XYLOS DATA", "CLX", true}, - {"GREETS TO", "SIGMOUNTE", false}, - {"GREETS TO", "WINDYOONA", true}, - {"THIS MUSIC", "BIG ALEC", true} + const credits_t credits[13] = { {"Portapack|HAVOC", "Git hash " GIT_REVISION, SECTION}, + {"Gurus", "J. Boone", TITLE}, + {"M. Ossmann", "", MEMBER_LF}, + {"Immaturity", "Furrtek", TITLE_LF}, + {"POCSAG rx", "T. Sailer", TITLE}, + {"E. Oenal", "", MEMBER_LF}, + {"RDS waveform", "C. Jacquet", TITLE_LF}, + {"Xy. infos", "cLx", TITLE_LF}, + {"Thanks", "", SECTION}, + {"Rainer Matla", "Keld Norman", TITLE}, + {"Sigmounte", "Waax", TITLE}, + {"Windyoona", "Channels", TITLE_LF}, + {"", "MMXVI", END} }; - Text text_title { - { 100, 32, 40, 16 }, - "About", - }; - - Text text_firmware { - { 0, 236, 240, 16 }, - "Git Commit Hash " GIT_REVISION, - }; + std::array text_line; Text text_cpld_hackrf { { 0, 252, 11*8, 16 }, @@ -156,17 +125,6 @@ private: } }; - MessageHandlerRegistration message_handler_fifo_signal { - Message::ID::FIFOSignal, - [this](const Message* const p) { - const auto message = static_cast(p); - if (message->signaltype == 1) { - this->render_audio(); - baseband::set_fifo_data(ym_buffer); - } - } - }; - }; } /* namespace ui */ diff --git a/firmware/application/ui_about_demo.cpp b/firmware/application/ui_about_demo.cpp new file mode 100644 index 000000000..d66929bd2 --- /dev/null +++ b/firmware/application/ui_about_demo.cpp @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include "demofont.hpp" +#include "ymdata.hpp" + +#include "cpld_update.hpp" +#include "portapack.hpp" +#include "audio.hpp" +#include "event_m0.hpp" + +#include "ui_about.hpp" +#include "touch.hpp" +#include "sine_table.hpp" + +#include "portapack_shared_memory.hpp" +#include "portapack_persistent_memory.hpp" +#include "lpc43xx_cpp.hpp" + +#include +#include + +using namespace lpc43xx; +using namespace portapack; + +namespace ui { + +void AboutView::on_show() { + transmitter_model.set_tuning_frequency(1337000000); // TODO: Change + transmitter_model.set_baseband_configuration({ + .mode = 0, + .sampling_rate = 1536000, + .decimation_factor = 1, + }); + transmitter_model.set_rf_amp(true); + transmitter_model.set_lna(40); + transmitter_model.set_vga(40); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + baseband::set_audiotx_data(32, 50, false, 0); + + //audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max); +} + +void AboutView::render_video() { + uint8_t p, r, luma, chroma, cy; + ui::Color cc; + char ch; + float s; + + // Send framebuffer to LCD. Gotta go fast ! + display.render_box({30, 112}, {180, 72}, framebuffer); + + // Clear framebuffer to black + memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color)); + + // Drum hit palette animation + if (drum > 1) drum--; + + // Render copper bars from Y buffer + for (p = 0; p < 72; p++) { + luma = copperbuffer[p] & 0x0F; // 0 is transparent + if (luma) { + chroma = copperbuffer[p]>>4; + cc = ui::Color(std::min((coppercolor[chroma][0]/luma)*drum,255), std::min((coppercolor[chroma][1]/luma)*drum,255), std::min((coppercolor[chroma][2]/luma)*drum,255)); + for (r = 0; r < 180; r++) + framebuffer[(p*180)+r] = cc; + } + } + + // Scroll in/out state machine + if (anim_state == 0) { + // Scroll in + if (ofy < 8) { + ofy++; + anim_state = 0; + } else { + anim_state = 1; + } + if (ofx < (int16_t)(180 - (strlen(credits[credits_index].name) * 16) - 8)) { + ofx += 8; + anim_state = 0; + } + } else if (anim_state == 1) { + // Just wait + if (credits_timer == (30*3)) { + credits_timer = 0; + anim_state = 2; + } else { + credits_timer++; + } + } else { + // Scroll out + if (credits[credits_index].change == true) { + if (ofy > -24) { + ofy--; + anim_state = 2; + } else { + anim_state = 0; + } + } else { + anim_state = 0; + } + if (ofx < 180) { + ofx += 8; + anim_state = 2; + } + + // Switch to next text + if (anim_state == 0) { + if (credits_index == 9) + credits_index = 0; + else + credits_index++; + ofx = -(strlen(credits[credits_index].name) * 16) - 16; + } + } + + // Sine text ("role") + p = 0; + while ((ch = credits[credits_index].role[p])) { + draw_demoglyph({(ui::Coord)(8+(p*16)), (ui::Coord)(ofy+(sine_table_f32[((p*16)+(phase>>5))&0xFF] * 8))}, ch, paletteA); + p++; + } + + // Scroll text (name) + p = 0; + while ((ch = credits[credits_index].name[p])) { + draw_demoglyph({(ui::Coord)(ofx+(p*16)), 56}, ch, paletteB); + p++; + } + + // Clear bars Y buffer + memset(copperbuffer, 0, 72); + + // Render bars to Y buffer + for (p = 0; p < 5; p++) { + cy = copperbars[p]; + for (r = 0; r < 16; r++) + copperbuffer[cy+r] = copperluma[r] + (p<<4); + } + + // Animate bars positions + for (p = 0; p < 5; p++) { + s = sine_table_f32[((p*32)+(phase/24))&0xFF]; + s += sine_table_f32[((p*16)+(phase/35))&0xFF]; + copperbars[p] = 28+(uint8_t)(s * 14); + } + + phase += 128; +} + +void AboutView::draw_demoglyph(ui::Point p, char ch, ui::Color * pal) { + uint8_t x, y, c, cl, cr; + uint16_t che; + int16_t lbx, il; + + // Map ASCII to font bitmap + if ((ch >= 32) || (ch < 96)) + che = char_map[ch-32]; + else + che = 0xFF; + + if (che < 0xFF) { + che = (che * 128) + 48; // Start in bitmap + + il = (180 * p.y) + p.x; // Start il framebuffer + + for (y = 0; y < 16; y++) { + if (p.y + y >= 72) break; // Over bottom of framebuffer, abort + if (p.y + y >= 0) { + for (x = 0; x < 8; x++) { + c = demofont_bin[x+(y*8)+che]; // Split byte in 2 4BPP pixels + cl = c >> 4; + cr = c & 0x0F; + lbx = p.x + (x*2); + if (cl && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cl]; + lbx++; + il++; + if (cr && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cr]; + il++; + } + il += 180-16; + } else { + il += 180; + } + } + } +} + +void AboutView::render_audio() { + uint8_t i, ymdata; + uint16_t ym_render_cnt; + + // This is heavily inspired by MAME's ay8910.cpp and the YM2149's datasheet + + // Render 1024 music samples + for (ym_render_cnt = 0; ym_render_cnt < 1024; ym_render_cnt++) { + + // Update registers at 48000/960 = 50Hz + if (ym_sample_cnt == 0) { + // "Decompress" on the fly and update YM registers + for (i = 0; i < 14; i++) { + if (!ym_regs[i].cnt) { + // New run + ymdata = ymdata_bin[ym_regs[i].ptr++]; + ym_regs[i].cnt = ymdata & 0x7F; + if (ymdata & 0x80) { + ym_regs[i].same = true; + ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++]; + } else { + ym_regs[i].same = false; + } + // Detect drum on channel B + if (i == 3) + if (ym_regs[3].value > 2) drum = 4; + } + if (ym_regs[i].same == false) { + ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++]; + if (i == 13) { + // Update envelope attributes + ym_env_att = (ym_regs[13].value & 4) ? 0x1F : 0x00; + if (!(ym_regs[13].value & 8)) { + ym_env_hold = 1; + ym_env_alt = ym_env_att; + } else { + ym_env_hold = ym_regs[13].value & 1; + ym_env_alt = ym_regs[13].value & 2; + } + // Reset envelope counter + ym_env_step = 0x1F; + ym_env_holding = 0; + ym_env_vol = (ym_env_step ^ ym_env_att); + } + } + ym_regs[i].cnt--; + } + ym_frame++; + } + + // Square wave oscillators + // 2457600/16/48000 = 3.2, but 4 sounds better than 3... + for (i = 0; i < 3; i++) { + ym_osc_cnt[i] += 4; + if (ym_osc_cnt[i] >= (ym_regs[i*2].value | ((ym_regs[(i*2)+1].value & 0x0f) << 8))) { + ym_osc_cnt[i] = 0; + ym_osc_out[i] ^= 1; + } + } + + // Noise generator + ym_noise_cnt += 4; + if (ym_noise_cnt >= ((ym_regs[6].value & 0x1F) * 2)) { + ym_noise_cnt = 0; + ym_rng ^= (((ym_rng & 1) ^ ((ym_rng >> 3) & 1)) << 17); + ym_rng >>= 1; + } + + // Mix tones and noise + for (i = 0; i < 3; i++) + ym_ch[i] = (ym_osc_out[i] | ((ym_regs[7].value >> i) & 1)) & ((ym_rng & 1) | ((ym_regs[7].value >> (i + 3)) & 1)); + + // Envelope generator + if (!ym_env_holding) { + ym_env_cnt += 8; + if (ym_env_cnt >= (ym_regs[11].value | (ym_regs[12].value<<8))) { + ym_env_cnt = 0; + ym_env_step--; + if (ym_env_step < 0) { + if (ym_env_hold) { + if (ym_env_alt) + ym_env_att ^= 0x1F; + ym_env_holding = 1; + ym_env_step = 0; + } else { + if (ym_env_alt && (ym_env_step & 0x20)) + ym_env_att ^= 0x1F; + ym_env_step &= 0x1F; + } + } + } + } + ym_env_vol = (ym_env_step ^ ym_env_att); + + ym_out = 0; + for (i = 0; i < 3; i++) { + if (ym_regs[i + 8].value & 0x10) { + // Envelope mode + ym_out += (ym_ch[i] ? ym_env_vol : 0); + } else { + // Fixed mode + ym_out += (ym_ch[i] ? (ym_regs[i + 8].value & 0x0F) : 0); + } + } + + ym_buffer[ym_render_cnt] = (ym_out * 2) - 45; + + if (ym_sample_cnt < 960) { + ym_sample_cnt++; + } else { + ym_sample_cnt = 0; + } + + // Loop + if (ym_frame == ym_frames) ym_init(); + } +} + +void AboutView::update() { + if (framebuffer) { + // Update 1 out of 2 frames, 60Hz is very laggy + if (refresh_cnt & 1) render_video(); + refresh_cnt++; + } + + // Slowly increase volume to avoid jumpscare + if (headphone_vol < (70 << 2)) { + audio::headphone::set_volume(volume_t::decibel((headphone_vol/4) - 99) + audio::headphone::volume_range().max); + headphone_vol++; + } +} + +void AboutView::ym_init() { + uint8_t reg; + + for (reg = 0; reg < 14; reg++) { + ym_regs[reg].cnt = 0; + // Pick up start pointers for each YM registers RLE blocks + ym_regs[reg].ptr = ((uint16_t)(ymdata_bin[(reg*2)+3])<<8) + ymdata_bin[(reg*2)+2]; + ym_regs[reg].same = false; // Useless ? + ym_regs[reg].value = 0; // Useless ? + } + + ym_frame = 0; +} + +AboutView::AboutView( + NavigationView& nav +) +{ + uint8_t p, c; + + baseband::run_image(portapack::spi_flash::image_tag_audio_tx); + + add_children({ { + &text_title, + &text_firmware, + &text_cpld_hackrf, + &text_cpld_hackrf_status, + &button_ok, + } }); + + if( cpld_hackrf_verify_eeprom() ) { + text_cpld_hackrf_status.set(" OK"); + } else { + text_cpld_hackrf_status.set("BAD"); + } + + // Politely ask for about 26kB + framebuffer = (ui::Color *)chHeapAlloc(0x0, 180 * 72 * sizeof(ui::Color)); + + if (framebuffer) { + memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color)); + + // Copy original font palette + c = 0; + for (p = 0; p < 48; p+=3) + paletteA[c++] = ui::Color(demofont_bin[p], demofont_bin[p+1], demofont_bin[p+2]); + + // Increase red in another one + c = 0; + for (p = 0; p < 48; p+=3) + paletteB[c++] = ui::Color(std::min(demofont_bin[p]+64, 255), demofont_bin[p+1], demofont_bin[p+2]); + } + + // Init YM synth + ym_frames = ((uint16_t)(ymdata_bin[1])<<8) + ymdata_bin[0]; + ym_init(); + + + button_ok.on_select = [this,&nav](Button&){ + if (framebuffer) chHeapFree(framebuffer); // Do NOT forget this + nav.pop(); + }; +} + +AboutView::~AboutView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +void AboutView::focus() { + button_ok.focus(); +} + +} /* namespace ui */ diff --git a/firmware/application/ui_about_demo.hpp b/firmware/application/ui_about_demo.hpp new file mode 100644 index 000000000..080c61959 --- /dev/null +++ b/firmware/application/ui_about_demo.hpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UI_ABOUT_H__ +#define __UI_ABOUT_H__ + +#include "ui_widget.hpp" +#include "ui_menu.hpp" +#include "ui_navigation.hpp" +#include "transmitter_model.hpp" +#include "baseband_api.hpp" + +#include + +namespace ui { + +class AboutView : public View { +public: + AboutView(NavigationView& nav); + ~AboutView(); + + void on_show() override; + void focus() override; + +private: + void ym_init(); + void update(); + void render_video(); + void render_audio(); + void draw_demoglyph(ui::Point p, char ch, ui::Color * pal); + uint16_t debug_cnt = 0; + + typedef struct ymreg_t { + uint8_t value; + uint8_t cnt; + uint16_t ptr; + bool same; + } ymreg_t; + + uint16_t headphone_vol = 5 << 2; + + ymreg_t ym_regs[14]; + uint16_t ym_frames; + uint16_t ym_frame; + uint8_t drum = 0; + uint16_t ym_osc_cnt[3]; + uint32_t ym_rng = 1; + uint16_t ym_noise_cnt; + uint8_t ym_env_att, ym_env_hold, ym_env_alt, ym_env_holding, ym_env_vol; + int8_t ym_env_step; + uint16_t ym_env_cnt; + uint8_t ym_osc_out[3]; + uint8_t ym_ch[3]; + uint8_t ym_out; + uint16_t ym_sample_cnt = 0; + + int8_t ym_buffer[1024]; + + uint8_t refresh_cnt; + ui::Color paletteA[16]; + ui::Color paletteB[16]; + ui::Color * framebuffer; + uint32_t phase = 0; + uint8_t copperbars[5] = { 0 }; + uint8_t copperbuffer[72] = { 0 }; + + uint8_t anim_state = 0; + uint8_t credits_index = 0; + uint16_t credits_timer = 0; + + int16_t ofx = -180, ofy = -24; + + const uint8_t char_map[64] = { 0xFF, 27, 46, 0xFF, 0xFF, 0xFF, 28, 45, + 58, 59, 0xFF, 43, 40, 57, 26, 42, + 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 41, 0xFF, 0xFF, 0xFF, 0xFF, 44, + 0xFF, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + const uint8_t copperluma[16] = { 8,7,6,5,4,3,2,1,1,2,3,4,5,6,7,8 }; + const uint8_t coppercolor[5][3] = { { 255,0,0 }, + { 0,255,0 }, + { 0,0,255 }, + { 255,0,255 }, + { 255,255,0 } }; + + typedef struct credits_t { + char role[12]; + char name[12]; + bool change; + } credits_t; + + // 0123456789A 0123456789A + const credits_t credits[10] = { {"GURUS", "J. BOONE", false}, + {"GURUS", "M. OSSMANN", true}, + {"BUGS", "FURRTEK", true}, + {"RDS WAVE", "C. JACQUET", true}, + {"POCSAG RX", "T. SAILER", false}, + {"POCSAG RX", "E. OENAL", true}, + {"XYLOS DATA", "CLX", true}, + {"GREETS TO", "SIGMOUNTE", false}, + {"GREETS TO", "WINDYOONA", true}, + {"THIS MUSIC", "BIG ALEC", true} + }; + + Text text_title { + { 100, 32, 40, 16 }, + "About", + }; + + Text text_firmware { + { 0, 236, 240, 16 }, + "Git Commit Hash " GIT_REVISION, + }; + + Text text_cpld_hackrf { + { 0, 252, 11*8, 16 }, + "HackRF CPLD", + }; + + Text text_cpld_hackrf_status { + { 240 - 3*8, 252, 3*8, 16 }, + "???" + }; + + Button button_ok { + { 72, 272, 96, 24 }, + "OK" + }; + + MessageHandlerRegistration message_handler_update { + Message::ID::DisplayFrameSync, + [this](const Message* const) { + this->update(); + } + }; + + MessageHandlerRegistration message_handler_fifo_signal { + Message::ID::FIFOSignal, + [this](const Message* const p) { + const auto message = static_cast(p); + if (message->signaltype == 1) { + this->render_audio(); + baseband::set_fifo_data(ym_buffer); + } + } + }; + +}; + +} /* namespace ui */ + +#endif/*__UI_ABOUT_H__*/ diff --git a/firmware/application/ui_adsbtx.cpp b/firmware/application/ui_adsbtx.cpp index e94e1114e..adcae300e 100644 --- a/firmware/application/ui_adsbtx.cpp +++ b/firmware/application/ui_adsbtx.cpp @@ -95,7 +95,7 @@ void ADSBTxView::start_tx() { transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); - memcpy(shared_memory.tx_data, adsb_bin, 112); + memcpy(shared_memory.bb_data.data, adsb_bin, 112); baseband::set_adsb(); } diff --git a/firmware/application/ui_adsbtx.hpp b/firmware/application/ui_adsbtx.hpp index 43763c7d3..996c54d6c 100644 --- a/firmware/application/ui_adsbtx.hpp +++ b/firmware/application/ui_adsbtx.hpp @@ -163,7 +163,7 @@ private: Message::ID::TXDone, [this](const Message* const p) { const auto message = *reinterpret_cast(p); - this->on_txdone(message.n); + this->on_txdone(message.progress); } }; }; diff --git a/firmware/application/ui_alphanum.cpp b/firmware/application/ui_alphanum.cpp index 339792414..5e710045b 100644 --- a/firmware/application/ui_alphanum.cpp +++ b/firmware/application/ui_alphanum.cpp @@ -22,12 +22,7 @@ #include "ui_alphanum.hpp" -#include "ch.h" - -#include "ff.h" #include "portapack.hpp" -#include "radio.hpp" - #include "hackrf_hal.hpp" #include "portapack_shared_memory.hpp" @@ -45,9 +40,9 @@ void AlphanumView::paint(Painter& painter) { AlphanumView::AlphanumView( NavigationView& nav, char txt[], - uint8_t max_len -) { - _max_len = max_len; + size_t max_length +) : _max_length(max_length) +{ _lowercase = false; size_t n; @@ -64,14 +59,19 @@ AlphanumView::AlphanumView( }; txtidx = strlen(txt); - memcpy(txtinput, txt, max_len + 1); + memcpy(txtinput, txt, _max_length + 1); n = txtidx; while (n && (txtinput[n - 1] == ' ')) { txtinput[--n] = 0; txtidx--; } - add_child(&text_input); + add_children({ { + &text_input, + &button_lowercase, + &raw_char, + &button_ok + } }); const auto button_fn = [this](Button& button) { this->on_button(button); @@ -81,9 +81,9 @@ AlphanumView::AlphanumView( for (auto& button : buttons) { button.on_select = button_fn; button.set_parent_rect({ - static_cast((n % 5) * button_w), - static_cast((n / 5) * button_h + 24), - button_w, button_h + static_cast((n % 5) * (240 / 5)), + static_cast((n / 5) * 28 + 24), + 240 / 5, 28 }); if ((n < 10) || (n == 39)) button.set_style(&style_num); @@ -92,31 +92,28 @@ AlphanumView::AlphanumView( add_child(&button); n++; } - set_uppercase(); + set_keys(keys_upper); - add_child(&button_lowercase); - button_lowercase.on_select = [this, &nav, max_len](Button&) { + button_lowercase.on_select = [this, &nav](Button&) { if (_lowercase == true) { _lowercase = false; button_lowercase.set_text("UC"); - set_uppercase(); + set_keys(keys_upper); } else { _lowercase = true; button_lowercase.set_text("LC"); - set_lowercase(); + set_keys(keys_lower); } }; - add_child(&raw_char); - raw_char.set_value(0x30); - raw_char.on_select = [this, &nav, txt, max_len](NumberField&) { + raw_char.set_value('0'); + raw_char.on_select = [this, &nav](NumberField&) { char_add(raw_char.value()); update_text(); }; - add_child(&button_done); - button_done.on_select = [this, &nav, txt, max_len](Button&) { - memcpy(txt, txtinput, max_len + 1); + button_ok.on_select = [this, &nav, txt, max_length](Button&) { + memcpy(txt, txtinput, max_length + 1); if (on_changed) on_changed(this->value()); nav.pop(); }; @@ -140,29 +137,12 @@ void AlphanumView::move_cursor() { ); } -void AlphanumView::set_uppercase() { - const char* const key_caps = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. !<"; - +void AlphanumView::set_keys(const char * const key_list) { size_t n = 0; - for(auto& button : buttons) { - //add_child(&button); + + for (auto& button : buttons) { const std::string label { - key_caps[n] - }; - button.set_text(label); - n++; - } -} - - -void AlphanumView::set_lowercase() { - const char* const key_caps = "0123456789abcdefghijklmnopqrstuvwxyz:=?<"; - - size_t n = 0; - for(auto& button : buttons) { - //add_child(&button); - const std::string label { - key_caps[n] + key_list[n] }; button.set_text(label); n++; @@ -170,7 +150,7 @@ void AlphanumView::set_lowercase() { } void AlphanumView::focus() { - button_done.focus(); + button_ok.focus(); } char * AlphanumView::value() { @@ -180,30 +160,31 @@ char * AlphanumView::value() { void AlphanumView::on_button(Button& button) { const auto s = button.text(); - if( s == "<" ) { + + if (s == "<") char_delete(); - } else { + else char_add(s[0]); - } + update_text(); } void AlphanumView::char_add(const char c) { - if (txtidx < _max_len) { - txtinput[txtidx] = c; - txtidx++; - } + if (txtidx >= _max_length) return; + + txtinput[txtidx] = c; + txtidx++; } void AlphanumView::char_delete() { - if (txtidx) { - txtidx--; - txtinput[txtidx] = 0; - } + if (!txtidx) return; + + txtidx--; + txtinput[txtidx] = 0; } void AlphanumView::update_text() { - text_input.set(std::string(txtinput) + std::string(_max_len - strlen(txtinput), ' ')); + text_input.set(std::string(txtinput) + std::string(_max_length - strlen(txtinput), ' ')); move_cursor(); } diff --git a/firmware/application/ui_alphanum.hpp b/firmware/application/ui_alphanum.hpp index f3fee6391..0e1208895 100644 --- a/firmware/application/ui_alphanum.hpp +++ b/firmware/application/ui_alphanum.hpp @@ -29,12 +29,6 @@ #include "ui_menu.hpp" #include "ui_navigation.hpp" #include "ui_font_fixed_8x16.hpp" -#include "clock_manager.hpp" -#include "message.hpp" -#include "rf_path.hpp" -#include "max2837.hpp" -#include "volume.hpp" -#include "transmitter_model.hpp" namespace ui { @@ -42,26 +36,30 @@ class AlphanumView : public View { public: std::function on_changed; - AlphanumView(NavigationView& nav, char txt[], uint8_t max_len); + AlphanumView(NavigationView& nav, char txt[], size_t max_length); void paint(Painter& painter) override; void focus() override; char * value(); + + std::string title() const override { return "Text entry"; }; private: - uint8_t _max_len; + const char * const keys_upper = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. !<"; + const char * const keys_lower = "0123456789abcdefghijklmnopqrstuvwxyz:=?<"; + + size_t _max_length; uint8_t txtidx; bool _lowercase = false; - static constexpr size_t button_w = 240 / 5; - static constexpr size_t button_h = 28; char txtinput[29] = { 0 }; // 28 chars max void char_add(const char c); void char_delete(); - void set_lowercase(); - void set_uppercase(); + void set_keys(const char * const key_list); void move_cursor(); + void on_button(Button& button); + void update_text(); Text text_input { { 8, 0, 224, 16 } @@ -70,7 +68,7 @@ private: std::array buttons; Button button_lowercase { - { 88+64+16, 270, 32, 24 }, + { 21 * 8, 270, 32, 24 }, "UC" }; @@ -82,14 +80,10 @@ private: '0' }; - Button button_done { + Button button_ok { { 88, 270, 64, 24 }, - "Done" + "OK" }; - - void on_button(Button& button); - - void update_text(); }; } /* namespace ui */ diff --git a/firmware/application/ui_audio.hpp b/firmware/application/ui_audio.hpp index e1ae5ad70..23bc3cc98 100644 --- a/firmware/application/ui_audio.hpp +++ b/firmware/application/ui_audio.hpp @@ -28,8 +28,6 @@ #include "event_m0.hpp" -#include "message.hpp" - #include namespace ui { diff --git a/firmware/application/ui_bht_tx.cpp b/firmware/application/ui_bht_tx.cpp new file mode 100644 index 000000000..b0986b4da --- /dev/null +++ b/firmware/application/ui_bht_tx.cpp @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui_bht_tx.hpp" + +#include "portapack.hpp" +#include "baseband_api.hpp" +#include "portapack_persistent_memory.hpp" + +#include +#include + +using namespace portapack; + +namespace ui { + +void BHTView::focus() { + relay_states[0].focus(); +} + +BHTView::~BHTView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +void BHTView::generate_message() { + size_t c; + const encoder_def_t * um3750_def; + uint8_t bit[12]; + uint8_t city_code; + std::string ep_symbols; + char ook_bitstream[256]; + char ep_message[13] = { 0 }; + + if (!_mode) { + // Xy CCIR frame + + // Header + ccir_message[0] = (header_code_a.value() / 10) + '0'; + ccir_message[1] = (header_code_a.value() % 10) + '0'; + ccir_message[2] = (header_code_b.value() / 10) + '0'; + ccir_message[3] = (header_code_b.value() % 10) + '0'; + + // Addresses + ccir_message[4] = (city_code_xy.value() / 10) + '0'; + ccir_message[5] = (city_code_xy.value() % 10) + '0'; + ccir_message[6] = family_code_xy.value() + '0'; + + if (!checkbox_wcsubfamily.value()) + ccir_message[7] = subfamily_code.value() + '0'; + else + ccir_message[7] = 'A'; // Wildcard + + if (!checkbox_wcid.value()) { + ccir_message[8] = (receiver_code.value() / 10) + '0'; + ccir_message[9] = (receiver_code.value() % 10) + '0'; + } else { + ccir_message[8] = 'A'; // Wildcard + ccir_message[9] = 'A'; // Wildcard + } + + ccir_message[10] = 'B'; + + // Relay states + for (c = 0; c < 4; c++) + ccir_message[c + 11] = relay_states[c].selected_index() + '0'; + + ccir_message[15] = 'B'; + + // End + for (c = 16; c < 20; c++) + ccir_message[c] = '0'; + + ccir_message[20] = 0; + + // Replace repeats with E code + for (c = 1; c < 20; c++) + if (ccir_message[c] == ccir_message[c - 1]) ccir_message[c] = 'E'; + + // Display as text + text_message.set(ccir_message); + + ascii_to_ccir(ccir_message); + } else { + // EP frame + // Repeated 2x 26 times + // Whole frame + space = 128ms, data only = 64ms + + um3750_def = &encoder_defs[8]; + + city_code = city_code_ep.value(); + + for (c = 0; c < 8; c++) + bit[c] = (city_code >> c) & 1; + + bit[8] = family_code_ep.selected_index_value() >> 1; + bit[9] = family_code_ep.selected_index_value() & 1; + bit[10] = 0; // R1 first + if (relay_states[0].selected_index()) + bit[11] = relay_states[0].selected_index() - 1; + else + bit[11] = 0; + + for (c = 0; c < 12; c++) + ep_message[c] = bit[c] + '0'; + + text_message.set(ep_message); + + c = 0; + for (auto ch : um3750_def->word_format) { + if (ch == 'S') + ep_symbols += um3750_def->sync; + else + ep_symbols += um3750_def->bit_format[bit[c++]]; + } + + c = 0; + for (auto ch : ep_symbols) { + if (ch != '0') + ook_bitstream[c >> 3] |= (1 << (7 - (c & 7))); + c++; + } + } +} + +void BHTView::start_tx() { + + if (speaker_enabled && !_mode) + audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); + + transmitter_model.set_tuning_frequency(bht_freqs[options_freq.selected_index()]); + transmitter_model.set_baseband_configuration({ + .mode = 0, + .sampling_rate = 1536000U, + .decimation_factor = 1, + }); + transmitter_model.set_rf_amp(true); + transmitter_model.set_lna(40); + transmitter_model.set_vga(40); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + memcpy(shared_memory.bb_data.tones_data.message, ccir_message, 20); + + for (uint8_t c = 0; c < 16; c++) { + shared_memory.bb_data.tones_data.tone_defs[c].delta = ccir_deltas[c]; + shared_memory.bb_data.tones_data.tone_defs[c].duration = CCIR_TONE_LENGTH; + } + + audio::set_rate(audio::Rate::Hz_24000); + baseband::set_tones_data(10000, CCIR_SILENCE, 20, false, checkbox_speaker.value()); +} + +// ASCII to frequency LUT index +void BHTView::ascii_to_ccir(char * ascii) { + for (size_t c = 0; c < 20; c++) { + if (ascii[c] > '9') + ascii[c] -= 0x37; + else + ascii[c] -= '0'; + } +} + +void BHTView::on_tx_progress(const int progress, const bool done) { + size_t c; + uint8_t sr; + + if (tx_mode == SINGLE) { + if (done) { + audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max); + + transmitter_model.disable(); + progressbar.set_value(0); + + if (!checkbox_cligno.value()) { + tx_mode = IDLE; + button_transmit.set_style(&style_val); + button_transmit.set_text("START"); + } else { + chThdSleepMilliseconds(tempo_cligno.value() * 1000); // Dirty :( + + // Invert all relay states + for (c = 0; c < 4; c++) { + sr = relay_states[c].selected_index(); + if (sr > 0) relay_states[c].set_selected_index(sr ^ 3); + } + + generate_message(); + start_tx(); + } + } else { + progressbar.set_value(progress); + } + } +} + +BHTView::BHTView(NavigationView& nav) { + (void)nav; + size_t n; + + baseband::run_image(portapack::spi_flash::image_tag_tones); + //baseband::run_image(portapack::spi_flash::image_tag_encoders); + + add_children({ { + &options_mode, + &text_header, + &header_code_a, + &header_code_b, + &checkbox_speaker, + &bmp_speaker, + &text_city, + &city_code_xy, + &text_family, + &family_code_xy, + &text_subfamily, + &subfamily_code, + &checkbox_wcsubfamily, + &text_receiver, + &receiver_code, + &checkbox_wcid, + &text_freq, + &options_freq, + &text_relais, + &progressbar, + &text_message, + &button_transmit, + &checkbox_cligno, + &tempo_cligno, + &text_cligno + } }); + + options_mode.set_selected_index(0); // Xy + header_code_a.set_value(0); + header_code_b.set_value(0); + city_code_xy.set_value(18); + family_code_xy.set_value(1); + subfamily_code.set_value(1); + receiver_code.set_value(1); + options_freq.set_selected_index(0); + tempo_cligno.set_value(1); + progressbar.set_max(20); + relay_states[0].set_selected_index(1); // R1 OFF + + options_mode.on_change = [this](size_t mode, OptionsField::value_t) { + _mode = mode; + + if (_mode) { + // EP layout + remove_children({ { + &text_header, + &header_code_a, + &header_code_b, + &checkbox_speaker, + &bmp_speaker, + &city_code_xs, + &family_code_xy, + &text_subfamily, + &subfamily_code, + &checkbox_wcsubfamily, + &text_receiver, + &receiver_code, + &checkbox_wcid, + &relay_states[2], + &relay_states[3] + } }); + add_children({ { + &city_code_ep, + &family_code_ep + } }); + set_dirty(); + } else { + // Xy layout + remove_children({ { + &city_code_ep, + &family_code_ep + } }); + add_children({ { + &text_header, + &header_code_a, + &header_code_b, + &checkbox_speaker, + &bmp_speaker, + &city_code_xy, + &family_code_xy, + &text_subfamily, + &subfamily_code, + &checkbox_wcsubfamily, + &text_receiver, + &receiver_code, + &checkbox_wcid, + &relay_states[2], + &relay_states[3] + } }); + set_dirty(); + }; + generate_message(); + }; + + checkbox_speaker.on_select = [this](Checkbox&) { + speaker_enabled = checkbox_speaker.value(); + }; + + header_code_a.on_change = [this](int32_t) { + generate_message(); + }; + header_code_b.on_change = [this](int32_t) { + generate_message(); + }; + city_code_xy.on_change = [this](int32_t) { + generate_message(); + }; + family_code_xy.on_change = [this](int32_t) { + generate_message(); + }; + subfamily_code.on_change = [this](int32_t) { + generate_message(); + }; + receiver_code.on_change = [this](int32_t) { + generate_message(); + }; + + checkbox_wcsubfamily.on_select = [this](Checkbox&) { + if (checkbox_wcsubfamily.value()) { + subfamily_code.set_focusable(false); + subfamily_code.set_style(&style_grey); + text_subfamily.set_style(&style_grey); + } else { + subfamily_code.set_focusable(true); + subfamily_code.set_style(&style()); + text_subfamily.set_style(&style()); + } + generate_message(); + }; + + checkbox_wcid.on_select = [this](Checkbox&) { + if (checkbox_wcid.value()) { + receiver_code.set_focusable(false); + receiver_code.set_style(&style_grey); + text_receiver.set_style(&style_grey); + } else { + receiver_code.set_focusable(true); + receiver_code.set_style(&style()); + text_receiver.set_style(&style()); + } + generate_message(); + }; + + checkbox_wcsubfamily.set_value(true); + checkbox_wcid.set_value(true); + + const auto relay_state_fn = [this](size_t, OptionsField::value_t) { + this->generate_message(); + }; + + n = 0; + for (auto& relay_state : relay_states) { + relay_state.on_change = relay_state_fn; + relay_state.set_parent_rect({ + static_cast(26 + (n * 53)), + 174, + 24, 24 + }); + relay_state.set_options(relay_options); + add_child(&relay_state); + n++; + } + + button_transmit.set_style(&style_val); + + generate_message(); + + button_transmit.on_select = [this, &nav](Button&) { + if (tx_mode == IDLE) { + //auto modal_view = nav.push("TX", "TX ?", true); + //modal_view->on_choice = [this](bool choice) { + // if (choice) { + if (speaker_enabled && _mode) + audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); + tx_mode = SINGLE; + button_transmit.set_style(&style_cancel); + button_transmit.set_text("Wait"); + generate_message(); + start_tx(); + // } + //}; + } + }; +} + +} /* namespace ui */ diff --git a/firmware/application/ui_bht_tx.hpp b/firmware/application/ui_bht_tx.hpp new file mode 100644 index 000000000..226a94bf7 --- /dev/null +++ b/firmware/application/ui_bht_tx.hpp @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui.hpp" +#include "ui_widget.hpp" +#include "ui_navigation.hpp" +#include "ui_font_fixed_8x16.hpp" + +#include "bmp_bulb_on.hpp" +#include "bmp_bulb_off.hpp" +#include "bmp_bulb_ignore.hpp" + +#include "message.hpp" +#include "volume.hpp" +#include "audio.hpp" +#include "transmitter_model.hpp" +#include "encoders.hpp" +//#include "receiver_model.hpp" +#include "portapack.hpp" + +using namespace encoders; + +#define CCIR_TONE_LENGTH (153600-1) // 1536000*0.1 +#define CCIR_DELTA_COEF (43.691) // (65536*1024)/1536000 +#define CCIR_SILENCE (614400-1) // 400ms + +namespace ui { + +class BHTView : public View { +public: + BHTView(NavigationView& nav); + ~BHTView(); + + void focus() override; + + std::string title() const override { return "BHT transmit"; }; + +private: + const uint32_t ccir_deltas[16] = { + (uint32_t)(1981 * CCIR_DELTA_COEF), + (uint32_t)(1124 * CCIR_DELTA_COEF), + (uint32_t)(1197 * CCIR_DELTA_COEF), + (uint32_t)(1275 * CCIR_DELTA_COEF), + (uint32_t)(1358 * CCIR_DELTA_COEF), + (uint32_t)(1446 * CCIR_DELTA_COEF), + (uint32_t)(1540 * CCIR_DELTA_COEF), + (uint32_t)(1640 * CCIR_DELTA_COEF), + (uint32_t)(1747 * CCIR_DELTA_COEF), + (uint32_t)(1860 * CCIR_DELTA_COEF), + (uint32_t)(2400 * CCIR_DELTA_COEF), + (uint32_t)(930 * CCIR_DELTA_COEF), + (uint32_t)(2247 * CCIR_DELTA_COEF), + (uint32_t)(991 * CCIR_DELTA_COEF), + (uint32_t)(2110 * CCIR_DELTA_COEF), + (uint32_t)(1055 * CCIR_DELTA_COEF) + }; + + enum tx_modes { + IDLE = 0, + SINGLE, + SEQUENCE + }; + + tx_modes tx_mode = IDLE; + + struct bht_city { + std::string name; + uint8_t freq_index; + bool recent; + }; + + const bht_city bht_cities[122] = { + { "Aizenay", 0, false }, + { "Albertville", 3, false }, + { "Ales", 3, false }, + { "Artannes/Indre", 5, false }, + { "Avignon", 3, true }, + { "Azay-le-Rideau", 5, false }, + { "Baux Ste. Croix", 0, false }, + { "Beaugency", 4, false }, + { "Beaune", 4, false }, + { "Betton", 2, false }, + { "Bihorel", 0, true }, + { "Blanquefort", 4, true }, + { "Bobigny", 5, false }, + { "Bouffere", 4, true }, + { "Boulogne/Mer", 0, true }, + { "Bourg-en-Bresse", 3, false }, + { "Bourges", 0, false }, + { "Bouscat", 0, false }, + { "Carquefou", 5, false }, + { "St. Cast", 0, false }, + { "Caudebec/Caux", 3, true }, + { "Cercy-la-Tour", 5, false }, + { "Chamalieres", 5, false }, + { "St. Chamond", 5, false }, + { "Chapelle/Fgrtz", 2, false }, + { "Charite/Loire", 3, false }, + { "Charleville-Mzr", 1, false }, + { "Chilly Mazarin", 5, false }, + { "Clermont Frrd.", 5, false }, + { "Cluses", 2, false }, + { "Compiegne", 4, false }, + { "Coulanges/Nevers", 5, false }, + { "Cour Cheverny", 5, false }, + { "Cournon Auvergne", 5, false }, + { "Crolles", 5, true }, + { "Cublize", 4, true }, + { "Donges", 5, false }, + { "Emalleville", 0, false }, + { "Etrepagny", 0, false }, + { "Fecamp", 0, false }, + { "Ferriere", 0, false }, + { "Ferte Imbault", 5, false }, + { "Fontaine", 5, true }, + { "Forbach", 3, false }, + { "Fourchambault", 5, false }, + { "Fresnay/Sarthe", 3, false }, + { "St Fulgent", 5, true }, + { "Gaillac", 3, true }, + { "St. Georges/Grs", 0, false }, + { "St. Gervais/Frt", 5, false }, + { "Givors", 5, false }, + { "Guichen", 2, false }, + { "Guildo", 0, false }, + { "Guipry", 2, false }, + { "St Hilaire/Riez", 0, false }, + { "Hossegor/Capbrtn", 0, true }, + { "Houlbec-Cocherel", 0, false }, + { "Huisseau/Cosson", 5, false }, + { "Huningue", 5, false }, + { "Iffendic", 2, false }, + { "La Croix St. Ouen", 4, false }, + { "Langrune/Mer", 0, false }, + { "Le Neubourg", 2, true }, + { "St Leger/Vignes", 5, false }, + { "Levallois-Perret", 5, false }, + { "Lille", 5, true }, + { "Limoges", 5, false }, + { "Longueil-Anel", 4, false }, + { "Lormont", 5, true }, + { "Mantes-la-Jolie", 5, false }, + { "Martigues", 0, true }, + { "Marzy", 5, false }, + { "Ste. Memmie", 3, false }, + { "Menton", 0, true }, + { "Metz", 3, false }, + { "Mezidon Canon", 1, false }, + { "Millau", 5, false }, + { "Miniac-Morvan", 2, false }, + { "Mt. Pres Chambord", 5, false }, + { "Montesson", 5, false }, + { "Monts", 5, false }, + { "Noisy-le-Grand", 4, true }, + { "St Ouen", 5, false }, + { "Ozoir/Ferriere", 5, false }, + { "Pace", 2, false }, + { "Pelussin", 5, false }, + { "Petite Foret", 1, false }, + { "Plestin/Greves", 0, false }, + { "Pleumeur Bodou", 5, true }, + { "Pont Audemer", 0, false }, + { "Pontcharra", 5, true }, + { "Pontchateau", 5, false }, + { "Pressagny L'Org.", 0, false }, + { "Remiremont", 4, true }, + { "Ribeauville", 5, false }, + { "La Roche sur Yon", 0, false }, + { "Romorantin-Lant.", 5, false }, + { "Rueil Malmaison", 5, false }, + { "Sault-les-Rethel", 3, false }, + { "Selles-St-Denis", 5, false }, + { "Selles/Cher", 5, false }, + { "Sens", 4, false }, + { "Sezanne", 3, false }, + { "Sommesous", 3, false }, + { "Ste. Suzanne", 2, true }, + { "Talence", 3, true }, + { "Thionville", 3, false }, + { "Thonon-les-Bains", 2, false }, + { "Tours en Sologne", 5, true }, + { "Trelaze", 5, true }, + { "Trouville/Mer", 0, false }, + { "Tulle", 2, false }, + { "Ussel", 2, false }, + { "Valberg", 5, true }, + { "Valence", 5, false }, + { "Velizy", 5, false }, + { "Vesoul", 5, false }, + { "Ville S. la Ferte", 0, false }, + { "Villefrance/Saone", 5, false }, + { "Villers Cotterets", 3, false }, + { "Vitre", 2, false }, + { "Vitry-le-Francois", 4, true } + }; + + const rf::Frequency bht_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; + + char ccir_message[21]; + bool speaker_enabled = false; + size_t _mode = 0; + + void ascii_to_ccir(char * ascii); + void start_tx(); + void generate_message(); + void on_tx_progress(const int progress, const bool done); + + const Style style_val { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color::green(), + }; + const Style style_cancel { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color::red(), + }; + const Style style_grey { + .font = font::fixed_8x16, + .background = Color::black(), + .foreground = Color::grey(), + }; + + + OptionsField options_mode { + { 10 * 8, 4 }, + 10, + { + { "Mode Xy.", 0 }, + { "Mode EP.", 1 } + } + }; + + Checkbox checkbox_speaker { + { 22 * 8, 4 }, + 0, + "" + }; + Image bmp_speaker { + { 204, 8, 16, 16 }, + &bitmap_speaker, + ui::Color::white(), + ui::Color::black() + }; + + Text text_header { + { 8 * 8, 3 * 8, 7 * 8, 16 }, + "Header:" + }; + NumberField header_code_a { + { 16 * 8, 3 * 8 }, + 2, + { 0, 99 }, + 1, + '0' + }; + NumberField header_code_b { + { 18 * 8, 3 * 8 }, + 2, + { 0, 99 }, + 1, + '0' + }; + + Text text_city { + { 4 * 8, 5 * 8, 11 * 8, 16 }, + "Code ville:" + }; + NumberField city_code_xy { + { 16 * 8, 5 * 8 }, + 2, + { 0, 99 }, + 1, + ' ' + }; + NumberField city_code_ep { + { 16 * 8, 5 * 8 }, + 3, + { 0, 255 }, + 1, + ' ' + }; + + Text text_family { + { 7 * 8, 7 * 8, 8 * 8, 16 }, + "Famille:" + }; + NumberField family_code_xy { + { 16 * 8, 7 * 8 }, + 1, + { 0, 9 }, + 1, + ' ' + }; + OptionsField family_code_ep { + { 16 * 8, 7 * 8 }, + 2, + { + { "A ", 2 }, // See receiver PCB + { "B ", 1 }, + { "C ", 0 }, + { "TP", 3 } + } + }; + + Text text_subfamily { + { 2 * 8, 9 * 8 + 2, 13 * 8, 16 }, + "Sous-famille:" + }; + NumberField subfamily_code { + { 16 * 8, 9 * 8 + 2 }, + 1, + { 0, 9 }, + 1, + ' ' + }; + Checkbox checkbox_wcsubfamily { + { 20 * 8, 8 * 8 + 6 }, + 6, + "Toutes" + }; + + Text text_receiver { + { 2 * 8, 13 * 8, 13 * 8, 16 }, + "ID recepteur:" + }; + NumberField receiver_code { + { 16 * 8, 13 * 8 }, + 2, + { 0, 99 }, + 1, + '0' + }; + Checkbox checkbox_wcid { + { 20 * 8, 12 * 8 + 4 }, + 4, + "Tous" + }; + + Text text_freq { + { 6 * 8, 8 * 16, 10 * 8, 16 }, + "Frequence:" + }; + OptionsField options_freq { + { 17 * 8, 8 * 16}, + 7, + { + { "31.3250", 0 }, + { "31.3875", 1 }, + { "31.4375", 2 }, + { "31.4750", 3 }, + { "31.6875", 4 }, + { "31.9750", 5 }, + { "TEST 88", 6 } + } + }; + + Text text_relais { + { 8, 19 * 8, 13 * 8, 16 }, + "Etats relais:" + }; + + std::array relay_states; + + ImageOptionsField::options_t relay_options = { + { &bulb_ignore_bmp[0], 0 }, + { &bulb_off_bmp[0], 1 }, + { &bulb_on_bmp[0], 2 } + }; + + ProgressBar progressbar { + { 5 * 8, 27 * 8, 20 * 8, 16 }, + }; + Text text_message { + { 5 * 8, 29 * 8, 20 * 8, 16 }, + "" + }; + + Button button_transmit { + { 2 * 8, 16 * 16, 12 * 8, 32 }, + "START" + }; + + Checkbox checkbox_cligno { + { 16 * 8, 16 * 16 + 4}, + 3, + "J/N" + }; + NumberField tempo_cligno { + { 24 * 8, 16 * 16 + 8}, + 2, + { 1, 99 }, + 1, + ' ' + }; + Text text_cligno { + { 26 * 8, 16 * 16 + 8, 2 * 8, 16 }, + "s." + }; + + MessageHandlerRegistration message_handler_tx_done { + Message::ID::TXDone, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + this->on_tx_progress(message.progress, message.done); + } + }; +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_closecall.cpp b/firmware/application/ui_closecall.cpp index 44fab6869..6137571b7 100644 --- a/firmware/application/ui_closecall.cpp +++ b/firmware/application/ui_closecall.cpp @@ -23,13 +23,9 @@ #include "ui_closecall.hpp" #include "msgpack.hpp" -#include "ch.h" #include "time.hpp" - #include "event_m0.hpp" -#include "hackrf_gpio.hpp" #include "portapack.hpp" -#include "radio.hpp" #include "baseband_api.hpp" #include "string_format.hpp" diff --git a/firmware/application/ui_closecall.hpp b/firmware/application/ui_closecall.hpp index 61fa71dbc..304e737a8 100644 --- a/firmware/application/ui_closecall.hpp +++ b/firmware/application/ui_closecall.hpp @@ -25,8 +25,6 @@ #include "spectrum_color_lut.hpp" #include "ui_receiver.hpp" -#include "ui_spectrum.hpp" -#include "ui_record_view.hpp" #include "ui_font_fixed_8x16.hpp" namespace ui { diff --git a/firmware/application/ui_debug.hpp b/firmware/application/ui_debug.hpp index e3914cfd6..035091fe4 100644 --- a/firmware/application/ui_debug.hpp +++ b/firmware/application/ui_debug.hpp @@ -208,36 +208,6 @@ 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" - }; - - Text text_modules { - { 8, 32, 28 * 8, 16 }, - "TESTTESTTESTTESTTESTTESTTEST" - }; - - Button button_makefile { - { 72, 192, 96, 24 }, - "Play file" - }; - - Button button_done { - { 72, 240, 96, 24 }, - "Done" - }; -}; - class DebugLCRView : public View { public: DebugLCRView(NavigationView& nav, std::string lcrstring, uint8_t checksum); diff --git a/firmware/application/ui_encoders.cpp b/firmware/application/ui_encoders.cpp index 7e5024fc2..65bc837be 100644 --- a/firmware/application/ui_encoders.cpp +++ b/firmware/application/ui_encoders.cpp @@ -210,7 +210,7 @@ void EncodersView::start_tx(const bool scan) { transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); - memcpy(shared_memory.tx_data, ook_bitstream, 256); + memcpy(shared_memory.bb_data.data, ook_bitstream, 256); baseband::set_ook_data( ook_bitstream_length, @@ -233,7 +233,7 @@ void EncodersView::on_type_change(size_t index) { encoder_def = &encoder_defs[enc_type]; - numberfield_clk.set_value(encoder_def->default_frequency / 1000); + numberfield_clk.set_value(encoder_def->default_speed / 1000); // SymField setup word_length = encoder_def->word_length; diff --git a/firmware/application/ui_encoders.hpp b/firmware/application/ui_encoders.hpp index 35d8d575f..65871c473 100644 --- a/firmware/application/ui_encoders.hpp +++ b/firmware/application/ui_encoders.hpp @@ -24,12 +24,13 @@ #include "ui_widget.hpp" #include "ui_navigation.hpp" #include "ui_font_fixed_8x16.hpp" +#include "encoders.hpp" #include "message.hpp" #include "transmitter_model.hpp" -namespace ui { +using namespace encoders; -#define ENC_TYPES_COUNT 14 +namespace ui { class EncodersView : public View { public: @@ -43,191 +44,6 @@ public: std::string title() const override { return "Encoders TX"; }; private: - struct encoder_def_t { - std::string name; // Encoder chip ref/name - std::string address_symbols; // "01", "01F"... - std::string data_symbols; // Same - uint16_t clk_per_symbol; // Oscillator periods per symbol - uint16_t clk_per_fragment; // Oscillator periods per symbol fragment (state) - std::vector bit_format; // List of fragments for each symbol in previous *_symbols list order - uint8_t word_length; // Total # of symbols (not counting sync) - std::string word_format; // A for Address, D for Data, S for sync - std::string sync; // Like bit_format - uint32_t default_frequency; // Default encoder clk frequency (often set by shitty resistor) - uint8_t repeat_min; // Minimum repeat count - uint16_t pause_symbols; // Length of pause between repeats in symbols - }; - - const encoder_def_t encoder_defs[ENC_TYPES_COUNT] = { - // PT2260-R2 - { - "2260-R2", - "01F", "01", - 1024, 128, - { "10001000", "11101110", "10001110" }, - 12, "AAAAAAAAAADDS", - "10000000000000000000000000000000", - 150000, 2, - 0 - }, - - // PT2260-R4 - { - "2260-R4", - "01F", "01", - 1024, 128, - { "10001000", "11101110", "10001110" }, - 12, "AAAAAAAADDDDS", - "10000000000000000000000000000000", - 150000, 2, - 0 - }, - - // PT2262 - { - "2262 ", - "01F", "01F", - 32, 4, - { "10001000", "11101110", "10001110" }, - 12, "AAAAAAAAAAAAS", - "10000000000000000000000000000000", - 20000, 4, - 0 - }, - - // 16-bit ? - { - "16-bit ", - "01", "01", - 32, 8, - { "1110", "1000" }, // Opposite ? - 16, "AAAAAAAAAAAAAAAAS", - "100000000000000000000", - 25000, 50, - 0 // ? - }, - - // RT1527 - { - "1527 ", - "01", "01", - 128, 32, - { "1000", "1110" }, - 24, "SAAAAAAAAAAAAAAAAAAAADDDD", - "10000000000000000000000000000000", - 100000, 4, - 10 // ? - }, - - // HK526E - { - "526 ", - "01", "01", - 24, 8, - { "110", "100" }, - 12, "AAAAAAAAAAAA", - "", - 20000, 4, - 10 // ? - }, - - // HT12E - { - "12E ", - "01", "01", - 3, 1, - { "011", "001" }, - 12, "SAAAAAAAADDDD", - "0000000000000000000000000000000000001", - 3000, 4, - 10 // ? - }, - - // VD5026 13 bits ? - { - "5026 ", - "0123", "0123", - 128, 8, - { "1000000010000000", "1111111011111110", "1111111010000000", "1000000011111110" }, - 12, "SAAAAAAAAAAAA", - "000000000000000000000000000000000000000000000001", // ? - 100000, 4, - 10 // ? - }, - - // UM3750 - { - "UM3750 ", - "01", "01", - 96, 32, - { "011", "001" }, - 12, "SAAAAAAAAAAAA", - "1", - 100000, 4, - 0 // ? - }, - - // UM3758 - { - "UM3758 ", - "01F", "01", - 96, 16, - { "011011", "001001", "011001" }, - 18, "SAAAAAAAAAADDDDDDDD", - "1", - 160000, 4, - 10 // ? - }, - - // BA5104 - { - "BA5104 ", - "01", "01", - 3072, 768, - { "1000", "1110" }, - 9, "SDDAAAAAAA", - "", - 455000, 4, - 10 // ? - }, - - // MC145026 - { - "145026 ", - "01F", "01", - 16, 1, - { "0111111101111111", "0100000001000000", "0111111101000000" }, - 9, "SAAAAADDDD", - "000000000000000000", - 455000, 2, - 2 - }, - - // HT6*** TODO: Add individual variations - { - "HT6*** ", - "01F", "01", - 198, 33, - { "011011", "001001", "001011" }, - 18, "SAAAAAAAAAAAADDDDDD", - "0000000000000000000000000000000000001011001011001", - 80000, 3, - 10 // ? - }, - - // TC9148 - { - "TC9148 ", - "01", "01", - 48, 12, - { "1000", "1110", }, - 12, "AAAAAAAAAAAA", - "", - 455000, 3, - 10 // ? - } - }; - enum tx_modes { IDLE = 0, SINGLE, @@ -373,7 +189,7 @@ private: Message::ID::TXDone, [this](const Message* const p) { const auto message = *reinterpret_cast(p); - this->on_txdone(message.n); + this->on_txdone(message.progress); } }; }; diff --git a/firmware/application/ui_epar.cpp b/firmware/application/ui_epar.cpp deleted file mode 100644 index 07d1982dc..000000000 --- a/firmware/application/ui_epar.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. - * Copyright (C) 2016 Furrtek - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "ui_epar.hpp" - -#include "ch.h" -#include "hackrf_hal.hpp" - -#include "event_m0.hpp" -#include "ff.h" -#include "hackrf_gpio.hpp" -#include "portapack.hpp" -#include "radio.hpp" - -#include "hackrf_hal.hpp" -#include "portapack_shared_memory.hpp" -#include "portapack_persistent_memory.hpp" - -#include -#include - -using namespace portapack; - -namespace ui { - -void EPARView::focus() { - city_code.focus(); -} - -EPARView::~EPARView() { - transmitter_model.disable(); -} - -void EPARView::update_message() { - uint8_t c; - - // Start bit - epar_bits[0] = 1; - - // To binary - for (c = 0; c < 8; c++) - epar_bits[c + 1] = ((city_code.value() >> c) & 1); - - epar_bits[9] = options_group.selected_index_value() & 1; - epar_bits[10] = (options_group.selected_index_value() >> 1) & 1; - - if (checkbox_ra.value()) - epar_bits[11] = 1; // Bit 11 is relay 1 state - else - epar_bits[11] = 0; - - if (checkbox_rb.value()) - epar_bits[12] = 1; // Bit 12 is relay 2 state - else - epar_bits[12] = 0; - - // DEBUG - char debug_binary[14]; - for (c = 0; c < 13; c++) - debug_binary[c] = 0x30 + epar_bits[c]; - debug_binary[13] = 0; - - text_debug.set(debug_binary); -} - -void EPARView::journuit() { - chThdSleepMilliseconds(1000); - - // Invert relay states - checkbox_ra.set_value(~checkbox_ra.value()); - checkbox_rb.set_value(~checkbox_rb.value()); - - update_message(); - - shared_memory.transmit_done = false; - memcpy(shared_memory.epardata, epar_bits, 13); - transmitter_model.enable(); -} - -void EPARView::on_tuning_frequency_changed(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); -} - -EPARView::EPARView( - NavigationView& nav -) -{ - static constexpr Style style_val { - .font = font::fixed_8x16, - .background = Color::green(), - .foreground = Color::black(), - }; - - static constexpr Style style_cancel { - .font = font::fixed_8x16, - .background = Color::red(), - .foreground = Color::black(), - }; - - transmitter_model.set_baseband_configuration({ - .mode = 4, - .sampling_rate = 1536000, - .decimation_factor = 1, - }); - - add_children({ { - &text_city, - &city_code, - &text_group, - &options_group, - &checkbox_ra, - &checkbox_rb, - &excur, - &text_freq, - //&options_freq, - &field_frequency, - &progressbar, - &text_debug, - &button_transmit, - &checkbox_cligno, - &button_exit - } }); - - city_code.set_value(220); - options_group.set_selected_index(3); // TP - //options_freq.set_selected_index(6); // 5 ! DEBUG - - checkbox_ra.set_value(true); - checkbox_rb.set_value(true); - - excur.set_value(500); - shared_memory.excursion = 500; - excur.on_change = [this](int32_t v) { - (void)v; - shared_memory.excursion = excur.value(); - }; - - field_frequency.set_value(31387500); // 31.3805 receiver_model.tuning_frequency() - field_frequency.set_step(500); - field_frequency.on_change = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); - }; - field_frequency.on_edit = [this, &nav]() { - // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); - new_view->on_changed = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); - this->field_frequency.set_value(f); - }; - }; - - city_code.on_change = [this](int32_t v) { - (void)v; - EPARView::update_message(); - }; - options_group.on_change = [this](size_t n, OptionsField::value_t v) { - (void)n; - (void)v; - EPARView::update_message(); - }; - checkbox_ra.on_select = [this](Checkbox&) { - EPARView::update_message(); - }; - checkbox_rb.on_select = [this](Checkbox&) { - EPARView::update_message(); - }; - - button_transmit.set_style(&style_val); - - EPARView::update_message(); - - button_transmit.on_select = [this](Button&) { - if (txing == false) { - update_message(); - - EventDispatcher::message_map().unregister_handler(Message::ID::TXDone); - - EventDispatcher::message_map().register_handler(Message::ID::TXDone, - [this](Message* const p) { - const auto message = static_cast(p); - if (message->n == 100) { - transmitter_model.disable(); - progressbar.set_value(0); - if (checkbox_cligno.value() == false) { - txing = false; - button_transmit.set_style(&style_val); - button_transmit.set_text("START"); - } else { - journuit(); - } - } else { - progressbar.set_value(message->n * 2); // 100/52 - } - } - ); - - shared_memory.transmit_done = false; - memcpy(shared_memory.epardata, epar_bits, 13); - - transmitter_model.set_tuning_frequency(field_frequency.value()); - //transmitter_model.set_tuning_frequency(epar_freqs[options_freq.selected_index()]); - - txing = true; - button_transmit.set_style(&style_cancel); - button_transmit.set_text("Wait"); - transmitter_model.enable(); - } - }; - - button_exit.on_select = [&nav](Button&){ - nav.pop(); - }; - -} - -} /* namespace ui */ diff --git a/firmware/application/ui_epar.hpp b/firmware/application/ui_epar.hpp deleted file mode 100644 index a3ce96e54..000000000 --- a/firmware/application/ui_epar.hpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. - * Copyright (C) 2016 Furrtek - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "ui.hpp" -#include "ui_widget.hpp" -#include "ui_painter.hpp" -#include "ui_menu.hpp" -#include "ui_navigation.hpp" -#include "ui_font_fixed_8x16.hpp" -#include "ui_receiver.hpp" -#include "clock_manager.hpp" -#include "message.hpp" -#include "rf_path.hpp" -#include "max2837.hpp" -#include "volume.hpp" -#include "transmitter_model.hpp" -#include "receiver_model.hpp" - -namespace ui { - -class EPARView : public View { -public: - EPARView(NavigationView& nav); - ~EPARView(); - std::string title() const override { return "EPAR transmit"; }; - void journuit(); - - void talk(); - void update_message(); - void focus() override; - -private: - bool txing = false; - const rf::Frequency epar_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; - char epar_bits[13]; - void on_tuning_frequency_changed(rf::Frequency f); - - /* |012345678901234567890123456789| - * | Code ville: 000 | - * | Groupe: 00 | - * */ - - Text text_city { - { 6 * 8, 1 * 16, 11 * 8, 16 }, - "Code ville:" - }; - NumberField city_code { - { 18 * 8, 1 * 16 }, - 3, - { 0, 255 }, - 0, - ' ' - }; - - Text text_group { - { 10 * 8, 2 * 16, 7 * 8, 16 }, - "Groupe:" - }; - OptionsField options_group { - { 18 * 8, 2 * 16 }, - 4, - { - { "A ", 2 }, // See receiver PCB - { "B ", 1 }, - { "C ", 0 }, - { "TP", 3 } - } - }; - - Text text_freq { - { 5 * 8, 4 * 16, 10 * 8, 16 }, - "Frequence:" - }; - FrequencyField field_frequency { - { 16 * 8, 4 * 16 }, - }; - /*OptionsField options_freq { - { 16 * 8, 4 * 16}, - 7, - { - { "31.3250", 0 }, - { "31.3875", 1 }, - { "31.4375", 2 }, - { "31.4750", 3 }, - { "31.6875", 4 }, - { "31.9750", 5 }, - { "TEST 88", 6 } - } - };*/ - - Checkbox checkbox_ra { - { 7 * 8, 6 * 16 }, - 8, - "Relais 1" - }; - Checkbox checkbox_rb { - { 7 * 8, 8 * 16 }, - 8, - "Relais 2" - }; - - NumberField excur { - { 12 * 8, 10 * 16 }, - 4, - { 0, 5000 }, - 20, - ' ' - }; - - ProgressBar progressbar { - { 2 * 8, 12 * 16, 26 * 8, 20 }, - }; - - Text text_debug { - { 5 * 8, 14 * 16, 13 * 8, 16 }, - "-------------" - }; - - Button button_transmit { - { 2 * 8, 16 * 16, 64, 32 }, - "START" - }; - - Checkbox checkbox_cligno { - { 96, 16 * 16 + 4}, - 3, - "J/N" - }; - - Button button_exit { - { 21 * 8, 16 * 16, 64, 32 }, - "Exit" - }; -}; - -} /* namespace ui */ diff --git a/firmware/application/ui_freqman.cpp b/firmware/application/ui_freqman.cpp index c453ac230..8c518170e 100644 --- a/firmware/application/ui_freqman.cpp +++ b/firmware/application/ui_freqman.cpp @@ -22,8 +22,6 @@ #include "ui_freqman.hpp" -#include "ch.h" -#include "ff.h" #include "portapack.hpp" #include "event_m0.hpp" #include "portapack_shared_memory.hpp" @@ -35,13 +33,36 @@ using namespace portapack; namespace ui { void FrequencySaveView::focus() { - button_exit.focus(); + button_save_timestamp.focus(); } FrequencySaveView::FrequencySaveView( NavigationView& nav, const rf::Frequency value ) { + add_children({ { + &big_display, + &text_save, + &button_save_name, + &button_save_timestamp, + &button_cancel + } }); + + big_display.set(value); + + button_cancel.on_select = [this, &nav](Button&) { + nav.pop(); + }; +} + +void FrequencyLoadView::focus() { + button_exit.focus(); +} + +FrequencyLoadView::FrequencyLoadView( + NavigationView& nav, + const rf::Frequency value +) { add_children({ { &button_exit diff --git a/firmware/application/ui_freqman.hpp b/firmware/application/ui_freqman.hpp index 44f8419d4..402150313 100644 --- a/firmware/application/ui_freqman.hpp +++ b/firmware/application/ui_freqman.hpp @@ -37,6 +37,40 @@ public: std::string title() const override { return "Save frequency"; }; +private: + BigFrequency big_display { + { 4, 2 * 16, 28 * 8, 32 }, + 0 + }; + + Text text_save { + { 72, 124, 10 * 8, 16 }, + "Save with:", + }; + Button button_save_name { + { 72, 144, 96, 32 }, + "Name" + }; + Button button_save_timestamp { + { 72, 184, 96, 32 }, + "Timestamp" + }; + + Button button_cancel { + { 72, 264, 96, 32 }, + "Cancel" + }; +}; + +class FrequencyLoadView : public View { +public: + FrequencyLoadView(NavigationView& nav, const rf::Frequency value); + //~FrequencySaveView(); + + void focus() override; + + std::string title() const override { return "Load frequency"; }; + private: Button button_exit { { 72, 264, 96, 32 }, diff --git a/firmware/application/ui_handwrite.cpp b/firmware/application/ui_handwrite.cpp index 2173a6256..2ff568a53 100644 --- a/firmware/application/ui_handwrite.cpp +++ b/firmware/application/ui_handwrite.cpp @@ -22,11 +22,7 @@ #include "ui_handwrite.hpp" -#include "ch.h" - -#include "ff.h" #include "portapack.hpp" -#include "event_m0.hpp" #include "hackrf_hal.hpp" #include "portapack_shared_memory.hpp" @@ -43,17 +39,17 @@ void HandWriteView::paint(Painter& painter) { HandWriteView::HandWriteView( NavigationView& nav, char txt[], - uint8_t max_len -) { + size_t max_length +) : _max_length(max_length) +{ const char special_chars[5] = {'\'', '.', '?', '!', '='}; - _max_len = max_len; size_t n; // Handwriting alphabet definition here handwriting = &handwriting_unistroke; txtidx = strlen(txt); - memcpy(txtinput, txt, max_len + 1); + memcpy(txtinput, txt, _max_length + 1); n = txtidx; while (n && (txtinput[n - 1] == ' ')) { txtinput[--n] = 0; @@ -71,7 +67,7 @@ HandWriteView::HandWriteView( }; n = 0; - for(auto& button : num_buttons) { + for (auto& button : num_buttons) { add_child(&button); button.on_select = button_fn; button.set_parent_rect({ @@ -80,15 +76,15 @@ HandWriteView::HandWriteView( 24, 28 }); const std::string label { - (char)(n + 0x30) + (char)(n + '0') }; button.set_text(label); - button.id = n + 0x30; + button.id = n + '0'; n++; } n = 0; - for(auto& button : special_buttons) { + for (auto& button : special_buttons) { add_child(&button); button.on_select = button_fn; button.set_parent_rect({ @@ -114,9 +110,9 @@ HandWriteView::HandWriteView( } }; - button_ok.on_select = [this, &nav, txt, max_len](Button&) { - memcpy(txt, txtinput, max_len + 1); - on_changed(this->value()); + button_ok.on_select = [this, &nav, txt, max_length](Button&) { + memcpy(txt, txtinput, max_length + 1); + if (on_changed) on_changed(this->value()); nav.pop(); }; @@ -134,14 +130,13 @@ bool HandWriteView::on_touch(const TouchEvent event) { guess_letter(); } if (event.type == ui::TouchEvent::Type::Move) { - if (tracing) { + if (tracing) current_pos = event.point; - } } return true; } -void HandWriteView::clear_zone(Color color, bool flash) { +void HandWriteView::clear_zone(const Color color, const bool flash) { display.fill_rectangle( {{0, 32}, {240, 216}}, color @@ -149,6 +144,7 @@ void HandWriteView::clear_zone(Color color, bool flash) { if (flash) { flash_timer = 4; } else { + // Draw grid _painter->draw_rectangle( {{0, 32}, {80, 216}}, Color::grey() @@ -169,7 +165,7 @@ void HandWriteView::clear_zone(Color color, bool flash) { } void HandWriteView::guess_letter() { - uint8_t symbol, match, count, stroke_idx, stroke_data; + uint32_t symbol, match, count, stroke_idx, stroke_data; Condition cond; Direction dir; bool matched; @@ -212,7 +208,7 @@ void HandWriteView::guess_letter() { } else if ((dir & 0x0F) == 0x0F) { if ((dir & 0xF0) != (stroke_data & 0xF0)) break; } else { - if (dir != stroke_data) break; + if (dir != (int32_t)stroke_data) break; } } } @@ -231,7 +227,8 @@ void HandWriteView::guess_letter() { clear_zone(Color::green(), true); // Green flash } else { if (txtidx) { - txtinput[--txtidx] = 0; // Erase + txtidx--; + txtinput[txtidx] = 0; // Erase clear_zone(Color::yellow(), true); // Yellow flash } else { clear_zone(Color::red(), true); // Red flash @@ -386,6 +383,7 @@ void HandWriteView::on_show() { } char * HandWriteView::value() { + txtinput[txtidx] = 0; return txtinput; } @@ -395,10 +393,10 @@ void HandWriteView::on_button(Button& button) { } void HandWriteView::char_add(const char c) { - if (txtidx < _max_len) { - txtinput[txtidx] = c; - txtidx++; - } + if (txtidx >= _max_length) return; + + txtinput[txtidx] = c; + txtidx++; } void HandWriteView::update_text() { diff --git a/firmware/application/ui_handwrite.hpp b/firmware/application/ui_handwrite.hpp index c0db6e65d..056381add 100644 --- a/firmware/application/ui_handwrite.hpp +++ b/firmware/application/ui_handwrite.hpp @@ -26,10 +26,8 @@ #include "ui.hpp" #include "ui_widget.hpp" #include "ui_painter.hpp" -#include "ui_menu.hpp" #include "ui_navigation.hpp" #include "unistroke.hpp" -#include "message.hpp" namespace ui { @@ -37,20 +35,20 @@ class HandWriteView : public View { public: std::function on_changed; - HandWriteView(NavigationView& nav, char txt[], uint8_t max_len); + HandWriteView(NavigationView& nav, char txt[], size_t max_length); void paint(Painter& painter) override; void on_show() override; bool on_touch(const TouchEvent event) override; char * value(); - - void char_add(const char c); + std::string title() const override { return "Text entry"; }; + private: const HandWriting * handwriting; Painter * _painter; - uint8_t _max_len; + size_t _max_length; uint8_t dir_cnt = 0; uint8_t dir_prev; uint8_t flash_timer = 0; @@ -61,12 +59,16 @@ private: uint8_t sample_skip, move_wait; uint8_t stroke_list[8]; Point start_pos, current_pos, last_pos; - bool _lowercase = true; - char txtinput[25] = {0}; + bool _lowercase = false; + char txtinput[29] = { 0 }; // 28 chars max + void sample_pen(); void add_stroke(uint8_t dir); void guess_letter(); - void clear_zone(Color color, bool flash); + void clear_zone(const Color color, const bool flash); + void char_add(const char c); + void on_button(Button& button); + void update_text(); Text text_input { { 8, 0, 224, 16 } @@ -84,10 +86,6 @@ private: { 190, 270, 40, 28 }, "OK" }; - - void on_button(Button& button); - - void update_text(); MessageHandlerRegistration message_handler_sample { Message::ID::DisplayFrameSync, diff --git a/firmware/application/ui_jammer.cpp b/firmware/application/ui_jammer.cpp index a10c4cc40..fcf6290d0 100644 --- a/firmware/application/ui_jammer.cpp +++ b/firmware/application/ui_jammer.cpp @@ -118,7 +118,7 @@ JammerView::JammerView(NavigationView& nav) { .foreground = Color::grey(), }; - JammerRange * jammer_ranges = (JammerRange*)shared_memory.tx_data; + JammerRange * jammer_ranges = (JammerRange*)shared_memory.bb_data.data; add_children({ { &text_type, diff --git a/firmware/application/ui_lcr.cpp b/firmware/application/ui_lcr.cpp index 94428be2e..f5c0a1a47 100644 --- a/firmware/application/ui_lcr.cpp +++ b/firmware/application/ui_lcr.cpp @@ -259,7 +259,7 @@ void LCRView::start_tx(const bool scan) { transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); - memcpy(shared_memory.tx_data, lcr_message_data, 300); + memcpy(shared_memory.bb_data.data, lcr_message_data, 300); baseband::set_afsk_data( (153600 * 5) / portapack::persistent_memory::afsk_bitrate(), diff --git a/firmware/application/ui_lcr.hpp b/firmware/application/ui_lcr.hpp index 560a74fe6..e68ead94c 100644 --- a/firmware/application/ui_lcr.hpp +++ b/firmware/application/ui_lcr.hpp @@ -179,7 +179,7 @@ private: Message::ID::TXDone, [this](const Message* const p) { const auto message = *reinterpret_cast(p); - this->on_txdone(message.n); + this->on_txdone(message.progress); } }; }; diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index b6f19e6ae..57968b523 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -49,19 +49,20 @@ void MenuItemView::paint(Painter& painter) { const auto paint_style = (highlighted() && parent()->has_focus()) ? style().invert() : style(); const auto font_height = paint_style.font.line_height(); + + ui::Color final_item_color = (highlighted() && parent()->has_focus()) ? paint_style.foreground : item.color; + ui::Color final_bg_color = (highlighted() && parent()->has_focus()) ? item.color : paint_style.background; + + if (final_item_color.v == final_bg_color.v) final_item_color = paint_style.foreground; painter.fill_rectangle( r, - paint_style.background + final_bg_color ); - - ui::Color final_item_color = (highlighted() && parent()->has_focus()) ? ui::Color::black() : item.color; - - if (final_item_color.v == paint_style.background.v) final_item_color = paint_style.foreground; Style text_style { .font = paint_style.font, - .background = paint_style.background, + .background = final_bg_color, .foreground = final_item_color }; @@ -84,6 +85,7 @@ MenuView::MenuView() { arrow_more.set_parent_rect( { 216, 320 - 16 - 24, 16, 16 } ); arrow_more.set_focusable(false); + arrow_more.set_foreground(Color::black()); } MenuView::~MenuView() { @@ -115,7 +117,7 @@ void MenuView::update_items() { size_t i = 0; Coord y_pos; - if (MENU_MAX + offset_ < (children_.size() - 1)) + if ((children_.size() - 1) > MENU_MAX + offset_) more_ = true; else more_ = false; @@ -148,9 +150,8 @@ size_t MenuView::highlighted() const { } bool MenuView::set_highlighted(const size_t new_value) { - if( new_value >= (children_.size() - 1) ) { // Skip arrow widget + if( new_value >= (children_.size() - 1) ) // Skip arrow widget return false; - } if ((new_value > offset_) && ((new_value - offset_ + 1) >= MENU_MAX)) { // Shift MenuView up diff --git a/firmware/application/ui_menu.hpp b/firmware/application/ui_menu.hpp index 7e4264869..cfc22adc7 100644 --- a/firmware/application/ui_menu.hpp +++ b/firmware/application/ui_menu.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * diff --git a/firmware/application/ui_morse.cpp b/firmware/application/ui_morse.cpp new file mode 100644 index 000000000..04bf3307c --- /dev/null +++ b/firmware/application/ui_morse.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* +Keying speed: 60 or 75 PARIS +Continuous (Fox-oring) +12s transmit, 48s space (Sprint 1/5th) +60s transmit, 240s space (Classic 1/5 min) +60s transmit, 360s space (Classic 1/7 min) +*/ + +#include "ui_morse.hpp" + +#include "portapack.hpp" +#include "baseband_api.hpp" +#include "portapack_persistent_memory.hpp" + +#include +#include + +using namespace portapack; + +// TODO: TX power setting +// TODO: Live keying mode: Dit on left key, dah on right ? + +namespace ui { + +void MorseView::focus() { + button_transmit.focus(); +} + +MorseView::~MorseView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +void MorseView::paint(Painter& painter) { + (void)painter; +} + +void MorseView::generate_message(char * text) { + char ch; + size_t i, c; + uint8_t code; + uint8_t morse_message[256]; + + ToneDef * tone_defs = shared_memory.bb_data.tones_data.tone_defs; + + // TODO: OOB check on morse_message[] + + i = 0; + while ((ch = (*text++))) { + if ((ch >= 'a') && (ch <= 'z')) // Make uppercase + ch -= 32; + + if ((ch >= 'A') && (ch <= 'Z')) { + code = morse_ITU[ch - 'A' + 10]; + for (c = 0; c < (code & 7); c++) { + morse_message[i++] = (code << c) >> 7; // Dot/dash + morse_message[i++] = 2; // Silence + } + morse_message[i - 1] = 3; // Letter silence + } else if (ch == ' ') { + morse_message[i++] = 4; // Word silence + } + + } + + memcpy(shared_memory.bb_data.tones_data.message, morse_message, i); + + (*tone_defs).delta = MORSE_TONE_DELTA; // Dot + (*tone_defs++).duration = MORSE_DOT; + (*tone_defs).delta = MORSE_TONE_DELTA; // Dash + (*tone_defs++).duration = MORSE_DASH; + (*tone_defs).delta = 0; // 1 unit silence + (*tone_defs++).duration = MORSE_SPACE; + (*tone_defs).delta = 0; // 3 unit silence + (*tone_defs++).duration = MORSE_LETTER_SPACE; + (*tone_defs).delta = 0; // 7 unit silence + (*tone_defs++).duration = MORSE_WORD_SPACE; + + audio::set_rate(audio::Rate::Hz_24000); + baseband::set_tones_data(5000, 0, i, false, false); +} + +MorseView::MorseView( + NavigationView& nav +) +{ + add_children({ { + &options_foxhunt, + &button_transmit, + &button_exit + } }); + + button_transmit.on_select = [this](Button&){ + /*uint16_t c; + ui::Context context; + + make_frame(); + + shared_memory.afsk_samples_per_bit = 228000/persistent_memory::afsk_bitrate(); + shared_memory.afsk_phase_inc_mark = persistent_memory::afsk_mark_freq()*(65536*1024)/2280; + shared_memory.afsk_phase_inc_space = persistent_memory::afsk_space_freq()*(65536*1024)/2280; + + for (c = 0; c < 256; c++) { + shared_memory.lcrdata[c] = this->lcrframe[c]; + } + + shared_memory.afsk_transmit_done = false; + shared_memory.afsk_repeat = 5; // DEFAULT + + text_status.set("Send...");*/ + + //transmitter_model.enable(); + }; + + button_exit.on_select = [&nav](Button&){ + nav.pop(); + }; + +} + +} /* namespace ui */ diff --git a/firmware/application/ui_morse.hpp b/firmware/application/ui_morse.hpp new file mode 100644 index 000000000..a9ce4b7d5 --- /dev/null +++ b/firmware/application/ui_morse.hpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui.hpp" +#include "ui_widget.hpp" +#include "ui_navigation.hpp" +#include "ui_font_fixed_8x16.hpp" + +#include "message.hpp" +#include "volume.hpp" +#include "audio.hpp" +#include "transmitter_model.hpp" +//#include "receiver_model.hpp" +#include "portapack.hpp" + +#define MORSE_TONE_DELTA ((1536000 / 800) - 1) // 1536000/800 +#define MORSE_UNIT (76800 - 1) // 1536000*0.05 (50ms) +#define MORSE_DOT 1 * MORSE_UNIT +#define MORSE_DASH 3 * MORSE_UNIT +#define MORSE_SPACE 1 * MORSE_UNIT +#define MORSE_LETTER_SPACE 3 * MORSE_UNIT +#define MORSE_WORD_SPACE 7 * MORSE_UNIT + +namespace ui { + +class MorseView : public View { +public: + MorseView(NavigationView& nav); + ~MorseView(); + + void focus() override; + void paint(Painter& painter) override; + +private: + //rf::Frequency f; + + void generate_message(char * text); + + const char foxhunt_codes[11][3] = { + { 'M', 'O', 'E' }, + { 'M', 'O', 'I' }, + { 'M', 'O', 'S' }, + { 'M', 'O', 'H' }, + { 'M', 'O', '5' }, + { 'M', 'O', 'N' }, + { 'M', 'O', 'D' }, + { 'M', 'O', 'B' }, + { 'M', 'O', '6' }, + { 'M', 'O', 0 }, + { 'S', 0, 0 } + }; + + // 0=dot 1=dash + const uint8_t morse_ITU[36] = { + // Code Size + 0b11111101, // 0: 11111 101 + 0b01111101, // 1: 01111 101 + 0b00111101, // 2: 00111 101 + 0b00011101, // 3: 00011 101 + 0b00001101, // 4: 00001 101 + 0b00000101, // 5: 00000 101 + 0b10000101, // 6: 10000 101 + 0b11000101, // 7: 11000 101 + 0b11100101, // 8: 11100 101 + 0b11110101, // 9: 11110 101 + 0b01000010, // A: 01--- 010 + 0b10000100, // B: 1000- 100 + 0b10100100, // C: 1010- 100 + 0b10000011, // D: 100-- 011 + 0b00000001, // E: 0---- 001 + 0b00100100, // F: 0010- 100 + 0b11000011, // G: 110-- 011 + 0b00000100, // H: 0000- 100 + 0b00000010, // I: 00--- 010 + 0b01110100, // J: 0111- 100 + 0b10100011, // K: 101-- 011 + 0b01000100, // L: 0100- 100 + 0b11000010, // M: 11--- 010 + 0b10000010, // N: 10--- 010 + 0b11100011, // O: 111-- 011 + 0b01100100, // P: 0110- 100 .#-###-###.# ##.#-### ##.#-###.# ##.#.# ##.#.#.# = 48 units + 0b11010100, // Q: 1101- 100 60s: 1.25s/unit + 0b01000011, // R: 010-- 011 75s: 1.5625s/unit + 0b00000011, // S: 000-- 011 + 0b10000001, // T: 1---- 001 + 0b00100011, // U: 001-- 011 + 0b00010100, // V: 0001- 100 + 0b01100011, // W: 011-- 011 + 0b10010100, // X: 1001- 100 + 0b10110100, // Y: 1011- 100 + 0b11000100 // Z: 1100- 100 + }; + + const uint16_t morse_special[23] = { + // Code Size + 0b1010110000000110, // !: 101011- 110 + 0b0100100000000110, // ": 010010- 110 + 0, // # + 0b0001001000000111, // $: 0001001 111 + 0, // % + 0b0100000000000101, // &: 01000-- 101 + 0b0111100000000110, // ': 011110- 110 + 0b1011000000000101, // (: 10110-- 101 + 0b1011010000000110, // ): 101101- 110 + 0, // * + 0b0101000000000101, // +: 01010-- 101 + 0b1100110000000110, // ,: 110011- 110 + 0b1000010000000110, // -: 100001- 110 + 0b0101010000000110, // .: 010101- 110 + 0b1001000000000101, // /: 10010-- 101 + + 0b1110000000000110, // :: 111000- 110 + 0b1010100000000110, // ;: 101010- 110 + 0, // < + 0b1000100000000101, // =: 10001-- 101 + 0, // > + 0b0011000000000110, // ?: 001100- 110 + 0b0110100000000110, // @: 011010- 110 + + 0b0011010000000110 // _: 001101- 110 + }; + + const uint16_t prosigns[12] = { + // Code Size + 0b0001110000001001, // : 000111000 1001 + 0b0101000000000100, // : 0101----- 0100 + 0b0101000000000101, // : 01010---- 0101 + 0b0100000000000101, // : 01000---- 0101 + 0b1000100000000101, // : 10001---- 0101 + 0b1010100000000101, // : 10101---- 0101 + 0b0000000000001000, // : 00000000- 1000 + 0b1010000000000011, // : 101------ 0011 + 0b1011000000000101, // : 10110---- 0101 + 0b1001110000000110, // : 100111--- 0110 + 0b0001010000000110, // : 000101--- 0110 + 0b0001100000000101, // : 00010---- 0101 + }; + + OptionsField options_foxhunt { + { 4 * 8, 32 }, + 7, + { + { "0 (MOE)", 0 }, + { "1 (MOI)", 1 }, + { "2 (MOS)", 2 }, + { "3 (MOH)", 3 }, + { "4 (MO5)", 4 }, + { "5 (MON)", 5 }, + { "6 (MOD)", 6 }, + { "7 (MOB)", 7 }, + { "8 (MO6)", 8 }, + { "9 (MO)", 9 }, + { "10 (S)", 10 } + } + }; + + Text text_status { + { 172, 196, 64, 16 }, + "Ready" + }; + + Checkbox checkbox_am_a { + { 2 * 8, 68 }, + 4, + "TEST" + }; + + Button button_transmit { + { 24, 270, 48, 32 }, + "TX" + }; + + Button button_exit { + { 176, 270, 48, 32 }, + "Exit" + }; +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a366edd13..c535101c4 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -32,30 +32,30 @@ #include "bmp_modal_warning.hpp" #include "ui_about.hpp" -#include "ui_setup.hpp" -#include "ui_debug.hpp" - -#include "ui_numbers.hpp" -#include "ui_whipcalc.hpp" -#include "ui_closecall.hpp" -#include "ui_freqman.hpp" -#include "ui_nuoptix.hpp" -#include "ui_soundboard.hpp" -#include "ui_encoders.hpp" -#include "ui_rds.hpp" -#include "ui_xylos.hpp" -#include "ui_epar.hpp" -#include "ui_lcr.hpp" -#include "analog_audio_app.hpp" #include "ui_adsbtx.hpp" +#include "ui_closecall.hpp" +#include "ui_debug.hpp" +#include "ui_encoders.hpp" +#include "ui_freqman.hpp" #include "ui_jammer.hpp" +#include "ui_lcr.hpp" +#include "ui_morse.hpp" +#include "ui_numbers.hpp" +#include "ui_nuoptix.hpp" +#include "ui_rds.hpp" +#include "ui_setup.hpp" +#include "ui_soundboard.hpp" +#include "ui_whipcalc.hpp" +#include "ui_whistle.hpp" +#include "ui_bht_tx.hpp" + +#include "analog_audio_app.hpp" #include "ais_app.hpp" #include "ert_app.hpp" #include "tpms_app.hpp" #include "pocsag_app.hpp" #include "capture_app.hpp" -#include "ui_debug.hpp" #include "core_control.hpp" #include "file.hpp" @@ -66,28 +66,31 @@ namespace ui { /* SystemStatusView ******************************************************/ SystemStatusView::SystemStatusView() { - uint8_t cfg; - add_children({ { &button_back, &title, + &button_stealth, &button_textentry, &button_camera, &button_sleep, &sd_card_status_view, } }); - cfg = portapack::persistent_memory::ui_config_textentry(); - - if (!cfg) + if (portapack::persistent_memory::ui_config_textentry()) button_textentry.set_bitmap(&bitmap_keyboard); else button_textentry.set_bitmap(&bitmap_unistroke); + + if (portapack::persistent_memory::stealth_mode()) + button_stealth.set_foreground(ui::Color::green()); button_back.on_select = [this](Button&){ - if( this->on_back ) { + if (this->on_back) this->on_back(); - } + }; + + button_stealth.on_select = [this](ImageButton&) { + this->on_stealth(); }; button_textentry.on_select = [this](ImageButton&) { @@ -117,6 +120,20 @@ void SystemStatusView::set_title(const std::string new_value) { } } +void SystemStatusView::on_stealth() { + bool cfg; + + cfg = portapack::persistent_memory::stealth_mode(); + portapack::persistent_memory::set_stealth_mode(not cfg); + + if (!cfg) + button_stealth.set_foreground(ui::Color::green()); + else + button_stealth.set_foreground(ui::Color::light_grey()); + + button_stealth.set_dirty(); +} + void SystemStatusView::on_textentry() { uint8_t cfg; @@ -185,7 +202,7 @@ void NavigationView::pop_modal() { modal_view = nullptr; } - // Pop modal view and underlying app view + // Pop modal view + underlying app view if( view_stack.size() > 2 ) { free_view(); view_stack.pop_back(); @@ -221,8 +238,10 @@ void NavigationView::free_view() { void NavigationView::update_view() { const auto new_view = view_stack.back().get(); + add_child(new_view); new_view->set_parent_rect({ {0, 0}, size() }); + focus(); set_dirty(); @@ -271,14 +290,13 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { /* TransmitterCodedMenuView ******************************************************/ TransmitterCodedMenuView::TransmitterCodedMenuView(NavigationView& nav) { - add_items<8>({ { - { "ADS-B Mode S", ui::Color::yellow(), [&nav](){ nav.push(); } }, - { "BHT Epar", ui::Color::grey(), [&nav](){ nav.push(); } }, - { "BHT Xylos", ui::Color::green(), [&nav](){ nav.push(); } }, - { "Morse beacon", ui::Color::grey(), [&nav](){ nav.push(); } }, + add_items<7>({ { + { "ADS-B Mode S", ui::Color::orange(), [&nav](){ nav.push(); } }, + { "BHT EPAR/Xylos", ui::Color::yellow(), [&nav](){ nav.push(); } }, + { "Morse beacon", ui::Color::yellow(), [&nav](){ nav.push(); } }, { "Nuoptix DTMF timecode", ui::Color::green(), [&nav](){ nav.push(); } }, { "OOK remote encoders", ui::Color::green(), [&nav](){ nav.push(); } }, - { "RDS", ui::Color::orange(), [&nav](){ nav.push(); } }, + { "RDS", ui::Color::green(), [&nav](){ nav.push(); } }, { "TEDI/LCR AFSK", ui::Color::green(), [&nav](){ nav.push(); } }, } }); on_left = [&nav](){ nav.pop(); }; @@ -291,7 +309,7 @@ TransmitterAudioMenuView::TransmitterAudioMenuView(NavigationView& nav) { { "Soundboard", ui::Color::green(), [&nav](){ nav.push(); } }, { "Numbers station", ui::Color::green(), [&nav](){ nav.push(); } }, { "Microphone", ui::Color::grey(), [&nav](){ nav.push(); } }, - { "Whistle", ui::Color::grey(), [&nav](){ nav.push(); } }, + { "Whistle", ui::Color::yellow(), [&nav](){ nav.push(); } }, } }); on_left = [&nav](){ nav.pop(); }; } @@ -310,7 +328,7 @@ UtilitiesView::UtilitiesView(NavigationView& nav) { SystemMenuView::SystemMenuView(NavigationView& nav) { add_items<11>({ { - { "Play dead", ui::Color::red(), [&nav](){ nav.push(false); } }, + { "Play dead", ui::Color::red(), [&nav](){ nav.push(); } }, { "Receivers", ui::Color::cyan(), [&nav](){ nav.push(); } }, { "Capture", ui::Color::cyan(), [&nav](){ nav.push(); } }, { "Code transmitters", ui::Color::green(), [&nav](){ nav.push(); } }, @@ -324,6 +342,8 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { { "HackRF mode", ui::Color::white(), [&nav](){ nav.push(); } }, { "About", ui::Color::white(), [&nav](){ nav.push(); } } } }); + + set_highlighted(1); // Startup selection is "Receivers" } /* SystemView ************************************************************/ @@ -363,22 +383,16 @@ SystemView::SystemView( this->status_view.set_title(new_view.title()); }; - // Initial view. - // TODO: Restore from non-volatile memory? - - //if (persistent_memory::playing_dead() == 0x59) - // navigation_view.push(new PlayDeadView { navigation_view, true }); - //else - // navigation_view.push(new BMPView { navigation_view }); - - if (portapack::persistent_memory::ui_config() & 1) - navigation_view.push(); - else - //navigation_view.push(); - //navigation_view.push(); - //navigation_view.push(debugtxt, 20); - - navigation_view.push(); + // Initial view + if ((portapack::persistent_memory::playing_dead() == 0x5920C1DF) || // Enable code + (portapack::persistent_memory::ui_config() & 16)) { // Login option + navigation_view.push(); + } else { + if (portapack::persistent_memory::ui_config() & 1) + navigation_view.push(); + else + navigation_view.push(); + } } Context& SystemView::context() const { @@ -419,45 +433,56 @@ BMPView::BMPView(NavigationView& nav) { &button_done } }); - button_done.on_select = [this,&nav](Button&){ + button_done.on_select = [this, &nav](Button&){ nav.pop(); - nav.push(); }; } -void BMPView::paint(Painter& painter) { - (void)painter; - portapack::display.drawBMP({(240-185)/2, 0}, splash_bmp, false); +void BMPView::paint(Painter&) { + portapack::display.drawBMP({(240 - 185) / 2, 0}, splash_bmp, false); } /* PlayDeadView **********************************************************/ void PlayDeadView::focus() { - button_done.focus(); + button_seq_entry.focus(); } -PlayDeadView::PlayDeadView(NavigationView& nav, bool booting) { - _booting = booting; - portapack::persistent_memory::set_playing_dead(0x59); +void PlayDeadView::paint(Painter& painter) { + if (!(portapack::persistent_memory::ui_config() & 16)) { + // Blank the whole display + painter.fill_rectangle( + portapack::display.screen_rect(), + style().background + ); + } +} + +PlayDeadView::PlayDeadView(NavigationView& nav) { + portapack::persistent_memory::set_playing_dead(0x5920C1DF); // Enable add_children({ { &text_playdead1, &text_playdead2, - &button_done, + &text_playdead3, + &button_seq_entry, } }); - button_done.on_dir = [this,&nav](Button&, KeyEvent key){ - sequence = (sequence<<3) | static_cast::type>(key); + text_playdead3.hidden(true); + + button_seq_entry.on_dir = [this](Button&, KeyEvent key){ + sequence = (sequence << 3) | static_cast::type>(key); + return true; }; - button_done.on_select = [this,&nav](Button&){ + button_seq_entry.on_select = [this, &nav](Button&){ if (sequence == portapack::persistent_memory::playdead_sequence()) { - portapack::persistent_memory::set_playing_dead(0); - if (_booting) { - nav.pop(); - nav.push(); + portapack::persistent_memory::set_playing_dead(0x82175E23); // Disable + if (!(portapack::persistent_memory::ui_config() & 16)) { + text_playdead3.hidden(false); } else { nav.pop(); + nav.push(); } } else { sequence = 0; @@ -487,6 +512,7 @@ void NotImplementedView::focus() { } /* ModalMessageView ******************************************************/ + ModalMessageView::ModalMessageView( NavigationView& nav, const std::string& title, @@ -497,7 +523,6 @@ ModalMessageView::ModalMessageView( type_ { type }, on_choice_ { on_choice } { - add_child(&text_message); if (type == INFO) { @@ -537,8 +562,7 @@ ModalMessageView::ModalMessageView( text_message.set(message); } -void ModalMessageView::paint(Painter& painter) { - (void)painter; +void ModalMessageView::paint(Painter&) { portapack::display.drawBMP({96, 64}, modal_warning_bmp, false); } diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index a3e5b884b..8ee57bc19 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -61,31 +61,38 @@ private: //static constexpr auto back_text_disabled = " * "; Button button_back { - { 0 * 8, 0 * 16, 20, 16 }, + { 0 * 8, 0 * 16, 16, 16 }, "", //back_text_disabled, }; Text title { - { 3 * 8, 0, 16 * 8, 1 * 16 }, + { 20, 0, 16 * 8, 1 * 16 }, default_title, }; + ImageButton button_stealth { + { 152, 0, 2 * 8, 1 * 16 }, + &bitmap_stealth, + Color::light_grey(), + Color::black() + }; + ImageButton button_textentry { - { 164, 0, 2 * 8, 1 * 16 }, + { 170, 0, 2 * 8, 1 * 16 }, &bitmap_unistroke, Color::white(), Color::black() }; ImageButton button_camera { - { 184, 0, 2 * 8, 1 * 16 }, + { 188, 0, 2 * 8, 1 * 16 }, &bitmap_camera, Color::white(), Color::black() }; ImageButton button_sleep { - { 204, 0, 2 * 8, 1 * 16 }, + { 206, 0, 2 * 8, 1 * 16 }, &bitmap_sleep, Color::white(), Color::black() @@ -95,8 +102,9 @@ private: { 28 * 8, 0 * 16, 2 * 8, 1 * 16 } }; - void on_camera(); + void on_stealth(); void on_textentry(); + void on_camera(); }; class NavigationView : public View { @@ -144,7 +152,7 @@ public: class BMPView : public View { public: BMPView(NavigationView& nav); - void paint(Painter& painter) override; + void paint(Painter&) override; void focus() override; private: @@ -161,12 +169,14 @@ private: class PlayDeadView : public View { public: - PlayDeadView(NavigationView& nav, bool booting); + PlayDeadView(NavigationView& nav); + void focus() override; + void paint(Painter& painter) override; private: - bool _booting; uint32_t sequence = 0; + Text text_playdead1 { { 6 * 8, 7 * 16, 14 * 8, 16 }, "Firmware error" @@ -175,8 +185,12 @@ private: { 6 * 8, 9 * 16, 16 * 8, 16 }, "0x1400_0000 : 2C" }; + Text text_playdead3 { + { 6 * 8, 12 * 16, 16 * 8, 16 }, + "Please reset" + }; - Button button_done { + Button button_seq_entry { { 240, 0, 1, 1 }, "" }; @@ -296,11 +310,11 @@ public: const modal_t type, const std::function on_choice ); + void paint(Painter& painter) override; - void focus() override; - // std::string title() const override { return title_; }; + std::string title() const override { return title_; }; private: const std::string title_; diff --git a/firmware/application/ui_nuoptix.cpp b/firmware/application/ui_nuoptix.cpp index 11849f29c..0171b6df1 100644 --- a/firmware/application/ui_nuoptix.cpp +++ b/firmware/application/ui_nuoptix.cpp @@ -23,10 +23,8 @@ #include "ui_nuoptix.hpp" #include "ch.h" - -#include "lfsr_random.hpp" -#include "ui_alphanum.hpp" #include "portapack.hpp" +#include "lfsr_random.hpp" #include "string_format.hpp" #include "portapack_shared_memory.hpp" @@ -39,7 +37,12 @@ using namespace portapack; namespace ui { void NuoptixView::focus() { - number_timecode.focus(); + button_tx.focus(); +} + +NuoptixView::~NuoptixView() { + transmitter_model.disable(); + baseband::shutdown(); } void NuoptixView::on_tuning_frequency_changed(rf::Frequency f) { @@ -47,8 +50,9 @@ void NuoptixView::on_tuning_frequency_changed(rf::Frequency f) { } void NuoptixView::transmit(bool setup) { - uint8_t mod; + uint8_t mod, tone_code; uint8_t c; + uint8_t dtmf_message[6]; if (!tx_mode) { transmitter_model.disable(); @@ -56,7 +60,7 @@ void NuoptixView::transmit(bool setup) { } if (tx_mode == IMPROVISE) - timecode = lfsr_iterate(timecode) % 1999; // Should be 9999 but that would be one long audio track ! + timecode = lfsr_iterate(timecode) % 1999; // Could be 9999 but that would be one long audio track ! if (setup) { pbar.set_max(4); @@ -64,7 +68,7 @@ void NuoptixView::transmit(bool setup) { if (tx_mode == NORMAL) timecode = number_timecode.value(); else - timecode = 0125; + timecode = 0125; // TODO: Use RTC as seed ? transmitter_model.set_baseband_configuration({ .mode = 0, @@ -77,35 +81,63 @@ void NuoptixView::transmit(bool setup) { transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); - shared_memory.tx_data[0] = '*'; // "Pre-tone for restart" method #1 - shared_memory.tx_data[1] = 'A'; // "Restart" method #1 + dtmf_message[0] = '*'; // "Pre-tone for restart" method #1 + dtmf_message[1] = 'A'; // "Restart" method #1 } else { - shared_memory.tx_data[0] = '#'; - shared_memory.tx_data[1] = (timecode / 1000) % 10; + dtmf_message[0] = '#'; + dtmf_message[1] = (timecode / 1000) % 10; chThdSleepMilliseconds(92); // 141-49ms number_timecode.set_value(timecode); } pbar.set_value(0); - shared_memory.tx_data[2] = (timecode / 100) % 10; - shared_memory.tx_data[3] = (timecode / 10) % 10; - shared_memory.tx_data[4] = timecode % 10; + dtmf_message[2] = (timecode / 100) % 10; + dtmf_message[3] = (timecode / 10) % 10; + dtmf_message[4] = timecode % 10; mod = 0; for (c = 1; c < 5; c++) - if (shared_memory.tx_data[c] <= 9) - mod += shared_memory.tx_data[c]; + if (dtmf_message[c] <= 9) + mod += dtmf_message[c]; mod = 10 - (mod % 10); if (mod == 10) mod = 0; // Is this right ? + text_mod.set("Mod: " + to_string_dec_uint(mod)); - shared_memory.tx_data[5] = mod; + dtmf_message[5] = mod; - shared_memory.tx_data[6] = 0xFF; // End of message + for (c = 0; c < 6; c++) { + tone_code = dtmf_message[c]; + + if (tone_code == 'A') + tone_code = 10; + else if (tone_code == 'B') + tone_code = 11; + else if (tone_code == 'C') + tone_code = 12; + else if (tone_code == 'D') + tone_code = 13; + else if (tone_code == '#') + tone_code = 14; + else if (tone_code == '*') + tone_code = 15; + + shared_memory.bb_data.tones_data.message[c * 2] = tone_code; + shared_memory.bb_data.tones_data.message[c * 2 + 1] = 0xFF; // Silence + } - baseband::set_dtmf_data(number_bw.value(), 49, 49); // 49ms tone, 49ms space + for (c = 0; c < 16; c++) { + shared_memory.bb_data.tones_data.tone_defs[c * 2].delta = dtmf_deltas[c][0]; + shared_memory.bb_data.tones_data.tone_defs[c * 2].duration = NUOPTIX_TONE_LENGTH; + shared_memory.bb_data.tones_data.tone_defs[c * 2 + 1].delta = dtmf_deltas[c][1]; + shared_memory.bb_data.tones_data.tone_defs[c * 2 + 1].duration = NUOPTIX_TONE_LENGTH; + } + shared_memory.bb_data.tones_data.silence = NUOPTIX_TONE_LENGTH; // 49ms tone, 49ms space + + audio::set_rate(audio::Rate::Hz_24000); + baseband::set_tones_data(number_bw.value(), 0, 6 * 2, true, true); timecode++; } @@ -114,7 +146,7 @@ NuoptixView::NuoptixView( NavigationView& nav ) { - baseband::run_image(portapack::spi_flash::image_tag_dtmf_tx); + baseband::run_image(portapack::spi_flash::image_tag_tones); add_children({ { &field_frequency, @@ -129,7 +161,6 @@ NuoptixView::NuoptixView( &button_exit } }); - //check_loop.set_value(false); number_bw.set_value(15); number_timecode.set_value(1); @@ -174,9 +205,4 @@ NuoptixView::NuoptixView( }; } -NuoptixView::~NuoptixView() { - transmitter_model.disable(); - baseband::shutdown(); -} - } diff --git a/firmware/application/ui_nuoptix.hpp b/firmware/application/ui_nuoptix.hpp index 9fb2c7232..7d6bd3281 100644 --- a/firmware/application/ui_nuoptix.hpp +++ b/firmware/application/ui_nuoptix.hpp @@ -30,6 +30,20 @@ #include "ui_navigation.hpp" #include "ui_receiver.hpp" #include "message.hpp" +#include "volume.hpp" +#include "audio.hpp" + +#define DTMF_DELTA_COEF (43.691) // (65536*1024)/1536000 +#define DTMF_C0 (uint32_t)(1209 * DTMF_DELTA_COEF) +#define DTMF_C1 (uint32_t)(1336 * DTMF_DELTA_COEF) +#define DTMF_C2 (uint32_t)(1477 * DTMF_DELTA_COEF) +#define DTMF_C3 (uint32_t)(1633 * DTMF_DELTA_COEF) +#define DTMF_R0 (uint32_t)(697 * DTMF_DELTA_COEF) +#define DTMF_R1 (uint32_t)(770 * DTMF_DELTA_COEF) +#define DTMF_R2 (uint32_t)(852 * DTMF_DELTA_COEF) +#define DTMF_R3 (uint32_t)(941 * DTMF_DELTA_COEF) + +#define NUOPTIX_TONE_LENGTH 75264 // 1536000*0.049 namespace ui { @@ -50,7 +64,27 @@ private: }; tx_modes tx_mode = IDLE; - + + // 0123456789ABCD#* + const uint32_t dtmf_deltas[16][2] = { + { DTMF_C1, DTMF_R3 }, + { DTMF_C0, DTMF_R0 }, + { DTMF_C1, DTMF_R0 }, + { DTMF_C2, DTMF_R0 }, + { DTMF_C0, DTMF_R1 }, + { DTMF_C1, DTMF_R1 }, + { DTMF_C2, DTMF_R1 }, + { DTMF_C0, DTMF_R2 }, + { DTMF_C1, DTMF_R2 }, + { DTMF_C2, DTMF_R2 }, + { DTMF_C3, DTMF_R0 }, + { DTMF_C3, DTMF_R1 }, + { DTMF_C3, DTMF_R2 }, + { DTMF_C3, DTMF_R3 }, + { DTMF_C2, DTMF_R3 }, + { DTMF_C0, DTMF_R3 } + }; + void on_tuning_frequency_changed(rf::Frequency f); void transmit(bool setup); @@ -95,24 +129,18 @@ private: { 16, 236, 208, 16 } }; - /*Checkbox check_loop { - { 16, 274 }, - 4, - "Loop" - };*/ - Button button_tx { - { 70, 128, 100, 40 }, + { 64, 128, 112, 40 }, "TX" }; Button button_impro { - { 70, 184, 100, 40 }, + { 64, 184, 112, 40 }, "IMPROVISE" }; Button button_exit { - { 160, 270, 64, 32 }, + { 88, 270, 64, 32 }, "Exit" }; @@ -120,10 +148,10 @@ private: Message::ID::TXDone, [this](const Message* const p) { const auto message = *reinterpret_cast(p); - if (message.n == 0xFF) + if (message.progress == 0xFF) transmit(false); else - pbar.set_value(message.n); + pbar.set_value(message.progress); } }; }; diff --git a/firmware/application/ui_rds.cpp b/firmware/application/ui_rds.cpp index 61dff2a62..902777bf5 100644 --- a/firmware/application/ui_rds.cpp +++ b/firmware/application/ui_rds.cpp @@ -62,8 +62,8 @@ void RDSView::start_tx() { } void RDSView::paint(Painter& painter) { - char RadioTextA[17]; (void)painter; + char RadioTextA[17]; text_psn.set(PSN); @@ -81,25 +81,29 @@ RDSView::RDSView(NavigationView& nav) { strcpy(PSN, "TEST1234"); strcpy(RadioText, "Radiotext test ABCD1234"); - rds_flags.DI = false; - rds_flags.MS = false; - rds_flags.PI_code = 0x1337; - rds_flags.TA = false; - rds_flags.TP = true; - add_children({ { &field_frequency, + &text_pty, &options_pty, + &text_countrycode, &options_countrycode, + &text_coverage, &options_coverage, &text_tx, + &options_tx, + &check_mono_stereo, + &check_TA, + &check_TP, + &check_MS, + &text_pi_code, + &sym_pi_code, &button_editpsn, &text_psn, - &button_txpsn, &button_editradiotext, + &text_radiotext, &text_radiotexta, &text_radiotextb, - &button_txradiotext, + &button_tx, &button_exit } }); @@ -116,27 +120,72 @@ RDSView::RDSView(NavigationView& nav) { }; }; - options_countrycode.set_selected_index(18); // France - options_coverage.set_selected_index(0); // Local + check_TA.set_value(true); + check_TP.set_value(true); + + sym_pi_code.set_value(0, 0xF); + sym_pi_code.set_value(1, 0x3); + sym_pi_code.set_value(2, 0xE); + sym_pi_code.set_value(3, 0x0); + sym_pi_code.on_change = [this]() { + rds_flags.PI_code = sym_pi_code.value_hex_u64(); + }; options_pty.on_change = [this](size_t, int32_t v) { rds_flags.PTY = v; }; - options_pty.set_selected_index(0); // None + + options_countrycode.on_change = [this](size_t, int32_t) { + //rds_flags.PTY = v; + }; + options_countrycode.set_selected_index(18); // Baguette du fromage + + options_coverage.on_change = [this](size_t, int32_t) { + //rds_flags.PTY = v; + }; + options_coverage.set_selected_index(0); // Local + +<<<<<<< HEAD + button_editpsn.on_select = [this, &nav](Button&) { + textentry(nav, PSN, 8); + }; + button_tx.on_select = [this](Button&) { +======= + options_pty.on_change = [this](size_t, int32_t v) { + rds_flags.PTY = v; + }; button_editpsn.on_select = [this,&nav](Button&) { textentry(nav, PSN, 8); }; button_txpsn.on_select = [this](Button&) { +>>>>>>> d402a87... RDS radiotext and time group generators if (txing) { - button_txpsn.set_text("PSN"); - button_txradiotext.set_text("Radiotext"); transmitter_model.disable(); + button_tx.set_text("START"); txing = false; } else { +<<<<<<< HEAD + rds_flags.PI_code = sym_pi_code.value_hex_u64(); + rds_flags.PTY = options_pty.selected_index_value(); + rds_flags.DI = check_mono_stereo.value() ? 1 : 0; + rds_flags.TP = check_TP.value(); + rds_flags.TA = check_TA.value(); + rds_flags.MS = check_MS.value(); + + if (options_tx.selected_index() == 0) + message_length = gen_PSN(PSN, &rds_flags); + else if (options_tx.selected_index() == 1) + message_length = gen_RadioText(RadioText, 0, &rds_flags); + else + message_length = gen_ClockTime(&rds_flags, 2016, 12, 1, 9, 23, 2); + + button_tx.set_text("STOP"); +======= message_length = gen_PSN(PSN, &rds_flags); button_txpsn.set_text("STOP"); +>>>>>>> d402a87... RDS radiotext and time group generators txing = true; start_tx(); } @@ -145,6 +194,8 @@ RDSView::RDSView(NavigationView& nav) { button_editradiotext.on_select = [this, &nav](Button&){ textentry(nav, RadioText, 24); }; +<<<<<<< HEAD +======= button_txradiotext.on_select = [this](Button&){ if (txing) { button_txpsn.set_text("PSN"); @@ -158,6 +209,7 @@ RDSView::RDSView(NavigationView& nav) { start_tx(); } }; +>>>>>>> d402a87... RDS radiotext and time group generators button_exit.on_select = [&nav](Button&){ nav.pop(); diff --git a/firmware/application/ui_rds.hpp b/firmware/application/ui_rds.hpp index b8cee9d24..bcdc0ecb7 100644 --- a/firmware/application/ui_rds.hpp +++ b/firmware/application/ui_rds.hpp @@ -55,11 +55,15 @@ private: void on_tuning_frequency_changed(rf::Frequency f); FrequencyField field_frequency { - { 1 * 8, 1 * 16 }, + { 1 * 8, 4 }, }; + Text text_pty { + { 1 * 8, 16 + 8, 4 * 8, 16 }, + "PTY:" + }; OptionsField options_pty { - { 1 * 8, 2 * 16 }, + { 5 * 8, 16 + 8 }, 8, { { "None", 0 }, @@ -97,8 +101,12 @@ private: } }; + Text text_countrycode { + { 14 * 8, 16 + 8, 4 * 8, 16 }, + "CC:" + }; OptionsField options_countrycode { - { 1 * 8, 3 * 16 }, + { 17 * 8, 16 + 8 }, 11, { { "Albania", 9 }, @@ -166,12 +174,26 @@ private: } }; + Text text_pi_code { + { 1 * 8, 32 + 8, 3 * 8, 16 }, + "PI:" + }; + SymField sym_pi_code { + { 4 * 8, 32 + 8 }, + 4, + true + }; + + Text text_coverage { + { 13 * 8, 32 + 8, 9 * 8, 16 }, + "Cov:" + }; OptionsField options_coverage { - { 1 * 8, 4 * 16 }, - 13, + { 17 * 8, 32 + 8 }, + 12, { { "Local", 0 }, - { "International", 1 }, + { "Internat.", 1 }, { "National", 2 }, { "Sup-regional", 3 }, { "R11", 4 }, @@ -189,43 +211,73 @@ private: } }; - Text text_tx { - { 19 * 8, 4 * 16, 9 * 8, 16 }, - "Transmit:" + Checkbox check_mono_stereo { + { 1 * 8, 4 * 16 }, + 6, + "Stereo" + }; + Checkbox check_TA { + { 12 * 8, 4 * 16 }, + 2, + "TA" + }; + Checkbox check_TP { + { 18 * 8, 4 * 16 }, + 2, + "TP" + }; + Checkbox check_MS { + { 24 * 8, 4 * 16 }, + 2, + "MS" }; - Button button_editpsn { - { 2 * 8, 6 * 16, 64, 24 }, - "Set" - }; Text text_psn { - { 2 * 8, 15 * 8, 8 * 8, 16 }, - "TEST1234" + { 2 * 8, 6 * 16, 12 * 8, 16 }, + "PSN:" }; - Button button_txpsn { - { 19 * 8, 6 * 16, 10 * 8, 32 }, - "PSN" + Button button_editpsn { + { 22 * 8, 5 * 16 + 12, 48, 24 }, + "Set" }; - Button button_editradiotext { - { 2 * 8, 9 * 16, 64, 24 }, - "Set" + Text text_radiotext { + { 2 * 8, 8 * 16, 10 * 8, 16 }, + "RadioText:" }; Text text_radiotexta { - { 2 * 8, 21 * 8, 16 * 8, 16 }, - "Radiotext test !" + { 2 * 8, 9 * 16, 19 * 8, 16 }, + "-" }; Text text_radiotextb { - { 2 * 8, 23 * 8, 16 * 8, 16 }, - "--------" + { 2 * 8, 10 * 16, 19 * 8, 16 }, + "-" }; - Button button_txradiotext { - { 19 * 8, 9 * 16, 10 * 8, 32 }, - "Radiotext" + Button button_editradiotext { + { 22 * 8, 8 * 16 + 12, 48, 24 }, + "Set" }; + Text text_tx { + { 2 * 8, 14 * 16, 3 * 8, 16 }, + "TX:" + }; + OptionsField options_tx { + { 5 * 8, 14 * 16 }, + 11, + { + { "PSN", 0 }, + { "RadioText", 1 }, + { "Date & time", 2 } + } + }; + + Button button_tx { + { 3 * 8, 16 * 16, 80, 32 }, + "START" + }; Button button_exit { - { 72, 260, 96, 32 }, + { 19 * 8, 16 * 16, 64, 32 }, "Exit" }; }; diff --git a/firmware/application/ui_receiver.cpp b/firmware/application/ui_receiver.cpp index 4e928feca..19dc37a0a 100644 --- a/firmware/application/ui_receiver.cpp +++ b/firmware/application/ui_receiver.cpp @@ -150,12 +150,16 @@ FrequencyKeypadView::FrequencyKeypadView( add_children({ { &button_save, + &button_load, &button_close } }); button_save.on_select = [this, &nav](Button&) { nav.push(this->value()); }; + button_load.on_select = [this, &nav](Button&) { + nav.push(this->value()); + }; button_close.on_select = [this, &nav](Button&) { if( on_changed ) { diff --git a/firmware/application/ui_receiver.hpp b/firmware/application/ui_receiver.hpp index 280cc8537..3396aa656 100644 --- a/firmware/application/ui_receiver.hpp +++ b/firmware/application/ui_receiver.hpp @@ -204,11 +204,15 @@ private: std::array buttons; Button button_save { - { 0, button_h * 4 + button_h, button_w, button_h }, + { 0, button_h * 5, 60, button_h }, "Save" }; + Button button_load { + { 60, button_h * 5, 60, button_h }, + "Load" + }; Button button_close { - { button_w, button_h * 4 + button_h, button_w * 2, button_h }, + { 128, button_h * 5, 112, button_h }, "Done" }; diff --git a/firmware/application/ui_sd_card_status_view.cpp b/firmware/application/ui_sd_card_status_view.cpp index a0ed49b44..03394803b 100644 --- a/firmware/application/ui_sd_card_status_view.cpp +++ b/firmware/application/ui_sd_card_status_view.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * diff --git a/firmware/application/ui_sd_card_status_view.hpp b/firmware/application/ui_sd_card_status_view.hpp index 31388cfab..10ce8fd29 100644 --- a/firmware/application/ui_sd_card_status_view.hpp +++ b/firmware/application/ui_sd_card_status_view.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * diff --git a/firmware/application/ui_setup.cpp b/firmware/application/ui_setup.cpp index 5de60905a..7dd469718 100644 --- a/firmware/application/ui_setup.cpp +++ b/firmware/application/ui_setup.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -180,22 +181,24 @@ SetPlayDeadView::SetPlayDeadView(NavigationView& nav) { &text_sequence, &button_enter, &button_cancel - }}); + }}); - button_enter.on_select = [this,&nav](Button&){ - if (entermode == false) { + button_enter.on_select = [this, &nav](Button&){ + if (!entermode) { sequence = 0; - memset(sequence_txt,0,11); - text_sequence.set(""); keycount = 0; + memset(sequence_txt, '-', 10); + text_sequence.set(sequence_txt); entermode = true; button_cancel.hidden(true); + set_dirty(); } else { persistent_memory::set_playdead_sequence(sequence); nav.pop(); } }; - button_enter.on_dir = [this,&nav](Button&, KeyEvent key){ + + button_enter.on_dir = [this](Button&, KeyEvent key){ if ((entermode == true) && (keycount < 10)) { key_code = static_cast::type>(key); if (key_code == 0) @@ -207,25 +210,28 @@ SetPlayDeadView::SetPlayDeadView(NavigationView& nav) { else if (key_code == 3) sequence_txt[keycount] = 'U'; text_sequence.set(sequence_txt); - sequence = (sequence<<3) | key_code; + sequence = (sequence << 3) | key_code; keycount++; - + return true; } + return false; }; + button_cancel.on_select = [&nav](Button&){ nav.pop(); }; } void SetPlayDeadView::focus() { - button_enter.focus(); + button_cancel.focus(); } SetUIView::SetUIView(NavigationView& nav) { uint32_t ui_config; add_children({{ - &checkbox_showsplash, + &checkbox_login, &checkbox_bloff, &options_bloff, + &checkbox_showsplash, &button_ok }}); @@ -233,14 +239,18 @@ SetUIView::SetUIView(NavigationView& nav) { if (ui_config & 1) checkbox_showsplash.set_value(true); if (ui_config & 2) checkbox_bloff.set_value(true); + if (ui_config & 16) checkbox_login.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 |= (portapack::persistent_memory::ui_config_textentry() << 2); - ui_config |= (options_bloff.selected_index() << 5); + button_ok.on_select = [&nav, &ui_config, this](Button&) { + ui_config &= ~0b10011; + + if (checkbox_login.value()) { + portapack::persistent_memory::set_playing_dead(0x5920C1DF); // Enable + ui_config |= (1 << 4); + } + if (checkbox_showsplash.value()) ui_config |= (1 << 0); + if (checkbox_bloff.value()) ui_config |= (1 << 1); portapack::persistent_memory::set_ui_config(ui_config); nav.pop(); @@ -248,7 +258,7 @@ SetUIView::SetUIView(NavigationView& nav) { } void SetUIView::focus() { - checkbox_showsplash.focus(); + checkbox_login.focus(); } /*void ModInfoView::on_show() { diff --git a/firmware/application/ui_setup.hpp b/firmware/application/ui_setup.hpp index 2148f3e7f..e01010dc6 100644 --- a/firmware/application/ui_setup.hpp +++ b/firmware/application/ui_setup.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -253,20 +254,20 @@ public: void focus() override; private: - Checkbox checkbox_showsplash { - { 3 * 8, 2 * 16}, - 11, - "Show splash" + Checkbox checkbox_login { + { 3 * 8, 2 * 16 }, + 20, + "Login with play dead" }; Checkbox checkbox_bloff { - { 3 * 8, 4 * 16}, + { 3 * 8, 5 * 16 }, 20, "Backlight off after:" }; OptionsField options_bloff { - { 10 * 8, 5 * 16 + 4 }, + { 10 * 8, 6 * 16 + 4 }, 10, { { "5 seconds", 0 }, @@ -277,6 +278,12 @@ private: } }; + Checkbox checkbox_showsplash { + { 3 * 8, 8 * 16 }, + 11, + "Show splash" + }; + Button button_ok { { 72, 260, 96, 32 }, "OK" @@ -286,12 +293,14 @@ private: class SetPlayDeadView : public View { public: SetPlayDeadView(NavigationView& nav); + void focus() override; + private: bool entermode = false; uint32_t sequence = 0; uint8_t keycount, key_code; - char sequence_txt[11]; + char sequence_txt[11] = { 0 }; Text text_sequence { { 64, 32, 14 * 8, 16 }, diff --git a/firmware/application/ui_soundboard.cpp b/firmware/application/ui_soundboard.cpp index d196899b7..742cce112 100644 --- a/firmware/application/ui_soundboard.cpp +++ b/firmware/application/ui_soundboard.cpp @@ -271,6 +271,7 @@ SoundBoardView::SoundBoardView( const auto button_dir = [this](Button& button, const KeyEvent key) { this->change_page(button, key); + return false; }; size_t n = 0; diff --git a/firmware/application/ui_soundboard.hpp b/firmware/application/ui_soundboard.hpp index dd85822df..46b444e8a 100644 --- a/firmware/application/ui_soundboard.hpp +++ b/firmware/application/ui_soundboard.hpp @@ -152,7 +152,7 @@ private: }; Checkbox check_loop { - { 16, 274 }, + { 8, 274 }, 4, "Loop" }; diff --git a/firmware/application/ui_textentry.cpp b/firmware/application/ui_textentry.cpp index 83048e97c..be649267b 100644 --- a/firmware/application/ui_textentry.cpp +++ b/firmware/application/ui_textentry.cpp @@ -24,7 +24,7 @@ namespace ui { -bool textentry(NavigationView& nav, char * str, uint16_t max_length) { +bool textentry(NavigationView& nav, char * str, size_t max_length) { if (portapack::persistent_memory::ui_config_textentry() == 0) { auto an_view = nav.push(str, max_length); an_view->on_changed = [str, max_length](char * value) { diff --git a/firmware/application/ui_textentry.hpp b/firmware/application/ui_textentry.hpp index 98b86cd35..4b7998943 100644 --- a/firmware/application/ui_textentry.hpp +++ b/firmware/application/ui_textentry.hpp @@ -28,6 +28,6 @@ namespace ui { -bool textentry(NavigationView& nav, char * str, uint16_t max_length); +bool textentry(NavigationView& nav, char * str, size_t max_length); } /* namespace ui */ diff --git a/firmware/application/ui_whistle.cpp b/firmware/application/ui_whistle.cpp index 74f31096f..337133880 100644 --- a/firmware/application/ui_whistle.cpp +++ b/firmware/application/ui_whistle.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -22,14 +23,7 @@ #include "ui_whistle.hpp" #include "ui_receiver.hpp" -#include "ch.h" -#include "evtimer.h" - -#include "ff.h" -#include "hackrf_gpio.hpp" #include "portapack.hpp" -#include "radio.hpp" - #include "hackrf_hal.hpp" #include "portapack_shared_memory.hpp" #include "portapack_persistent_memory.hpp" @@ -46,41 +40,28 @@ void WhistleView::focus() { } WhistleView::~WhistleView() { - transmitter_model.disable(); + //transmitter_model.disable(); } void WhistleView::paint(Painter& painter) { (void)painter; } -void WhistleView::whistle_th(void *arg) { - Mailbox* mbox = (Mailbox *)arg; - chMBPost(mbox, 1, TIME_INFINITE); -} - Button WhistleView::button_scan = { { 76, 270, 72, 32 }, "SCAN" }; WhistleView::WhistleView( - NavigationView& nav, - TransmitterModel& transmitter_model -) : transmitter_model(transmitter_model) + NavigationView& nav +) { - Mailbox mbox; - msg_t mbox_buffer[3]; - chMBInit(&mbox, mbox_buffer, 3); - - transmitter_model.set_modulation(TX_TONE); - transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); - add_children({ { &button_transmit, &button_exit } }); - button_transmit.on_select = [this,&transmitter_model](Button&){ + button_transmit.on_select = [this](Button&){ /*uint16_t c; ui::Context context; @@ -99,7 +80,7 @@ WhistleView::WhistleView( text_status.set("Send...");*/ - transmitter_model.enable(); + //transmitter_model.enable(); }; button_exit.on_select = [&nav](Button&){ diff --git a/firmware/application/ui_whistle.hpp b/firmware/application/ui_whistle.hpp index f2d8d1ee2..f4552f9df 100644 --- a/firmware/application/ui_whistle.hpp +++ b/firmware/application/ui_whistle.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -22,21 +23,16 @@ #include "ui.hpp" #include "ui_widget.hpp" #include "ui_painter.hpp" -#include "ui_menu.hpp" #include "ui_navigation.hpp" #include "ui_font_fixed_8x16.hpp" -#include "clock_manager.hpp" #include "message.hpp" -#include "rf_path.hpp" -#include "max2837.hpp" -#include "volume.hpp" #include "transmitter_model.hpp" namespace ui { class WhistleView : public View { public: - WhistleView(NavigationView& nav, TransmitterModel& transmitter_model); + WhistleView(NavigationView& nav); ~WhistleView(); void focus() override; @@ -65,7 +61,6 @@ private: {{ 468225000, 468275000, 468325000 }, 458275000} }; rf::Frequency f; - TransmitterModel& transmitter_model; Text text_status { { 172, 196, 64, 16 }, diff --git a/firmware/application/ui_xylos.cpp b/firmware/application/ui_xylos.cpp deleted file mode 100644 index 22aa5f456..000000000 --- a/firmware/application/ui_xylos.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. - * Copyright (C) 2016 Furrtek - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "ui_xylos.hpp" -#include "ui_alphanum.hpp" - -#include "portapack.hpp" -#include "baseband_api.hpp" -//#include "audio.hpp" -#include "portapack_persistent_memory.hpp" - -#include -#include - -using namespace portapack; - -namespace ui { - -/* -void XylosRXView::talk() { - uint8_t c; - - xylos_voice_phrase[0] = XYLOS_VOICE_HEADER; // Header - for (c=0; c<4; c++) - xylos_voice_phrase[c+1] = XYLOS_VOICE_ZERO + ccir_received[c]; - xylos_voice_phrase[5] = XYLOS_VOICE_HEADER + 1; // City - xylos_voice_phrase[6] = XYLOS_VOICE_ZERO + ccir_received[4]; - xylos_voice_phrase[7] = XYLOS_VOICE_ZERO + ccir_received[5]; - xylos_voice_phrase[8] = XYLOS_VOICE_HEADER + 2; // Family - xylos_voice_phrase[9] = XYLOS_VOICE_ZERO + ccir_received[6]; - xylos_voice_phrase[10] = XYLOS_VOICE_HEADER + 3; // Subfamily - xylos_voice_phrase[11] = XYLOS_VOICE_ZERO + ccir_received[7]; - xylos_voice_phrase[12] = XYLOS_VOICE_HEADER + 4; // Address - xylos_voice_phrase[13] = XYLOS_VOICE_ZERO + ccir_received[8]; - xylos_voice_phrase[14] = XYLOS_VOICE_ZERO + ccir_received[9]; - xylos_voice_phrase[15] = XYLOS_VOICE_RELAYS; // Relays - for (c=0; c<4; c++) { - xylos_voice_phrase[(c*2)+16] = XYLOS_VOICE_ZERO + 1 + c; - xylos_voice_phrase[(c*2)+17] = XYLOS_VOICE_RELAYS + 1 + ccir_received[c+11]; - } - xylos_voice_phrase[24] = XYLOS_VOICE_TRAILER; // Trailer - for (c=0; c<4; c++) - xylos_voice_phrase[c+25] = XYLOS_VOICE_ZERO + ccir_received[c+16]; - xylos_voice_phrase[29] = 0xFF; -} - -void XylosRXView::focus() { - button_start.focus(); -} - -XylosRXView::~XylosRXView() { - receiver_model.disable(); -} - -void XylosRXView::on_show() { - //chVTSet(&vt, MS2ST(1000), do_something, NULL); -} - -XylosRXView::XylosRXView( - NavigationView& nav -) -{ - char ccirdebug[21] = { 0,0,0,0,1,8,1,10,10,10,11,1,1,2,0,11,0,0,0,0,0xFF }; - - memcpy(ccir_received, ccirdebug, 21); - - add_children({ { - &text_dbg, - &button_start, - &button_exit - } }); - - button_start.on_select = [this](Button&) { - talk(); - p_idx = 0; - }; - - button_exit.on_select = [&nav](Button&){ - nav.pop(); - }; - -} -*/ - - - -void XylosView::focus() { - options_ra.focus(); -} - -XylosView::~XylosView() { - transmitter_model.disable(); - baseband::shutdown(); -} - -void XylosView::generate_message() { - uint8_t c; - - // Init CCIR message - memcpy(ccir_message, ccir_base, 21); - - // Header - ccir_message[0] = (header_code_a.value() / 10) + 0x30; - ccir_message[1] = (header_code_a.value() % 10) + 0x30; - ccir_message[2] = (header_code_b.value() / 10) + 0x30; - ccir_message[3] = (header_code_b.value() % 10) + 0x30; - - // Addresses - ccir_message[4] = (city_code.value() / 10) + 0x30; - ccir_message[5] = (city_code.value() % 10) + 0x30; - ccir_message[6] = family_code.value() + 0x30; - - if (checkbox_wcsubfamily.value() == false) - ccir_message[7] = subfamily_code.value() + 0x30; - else - ccir_message[7] = 'A'; - - if (checkbox_wcid.value() == false) { - ccir_message[8] = (receiver_code.value() / 10) + 0x30; - ccir_message[9] = (receiver_code.value() % 10) + 0x30; - } else { - ccir_message[8] = 'A'; - ccir_message[9] = 'A'; - } - - // Commands - ccir_message[11] = options_ra.selected_index() + 0x30; - ccir_message[12] = options_rb.selected_index() + 0x30; - ccir_message[13] = options_rc.selected_index() + 0x30; - ccir_message[14] = options_rd.selected_index() + 0x30; - - // Get rid of repeats with E code - for (c = 1; c < 20; c++) - if (ccir_message[c] == ccir_message[c - 1]) ccir_message[c] = 'E'; - - // Display as text - text_message.set(ccir_message); - - ascii_to_ccir(ccir_message); -} - -void XylosView::start_tx() { - //audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); - - transmitter_model.set_tuning_frequency(xylos_freqs[options_freq.selected_index()]); - transmitter_model.set_baseband_configuration({ - .mode = 0, - .sampling_rate = 1536000U, - .decimation_factor = 1, - }); - transmitter_model.set_rf_amp(true); - transmitter_model.set_lna(40); - transmitter_model.set_vga(40); - transmitter_model.set_baseband_bandwidth(1750000); - transmitter_model.enable(); - - memcpy(shared_memory.tx_data, ccir_message, 21); - baseband::set_ccir_data(CCIR_TONELENGTH, 20); -} - - // ASCII to frequency LUT index -void XylosView::ascii_to_ccir(char *ascii) { - uint8_t c; - - for (c = 0; c < 20; c++) { - if (ascii[c] > '9') - ascii[c] -= 0x37; - else - ascii[c] -= 0x30; - } - - // EOM code for baseband - ascii[20] = 0xFF; -} - -void XylosView::on_txdone(const int n) { - size_t sr; - - if (tx_mode == TESTING) { - if (n == 25) { - transmitter_model.disable(); - - /*if (sequence_idx != 9) { - chThdSleepMilliseconds(15000); - memcpy(ccir_message, &xylos_sequence[sequence_idx][0], 21); - // ASCII to frequency LUT index - for (c=0; c<20; c++) { - if (ccir_message[c] > '9') - ccir_message[c] -= 0x37; - else - ccir_message[c] -= 0x30; - } - ccir_message[20] = 0xFF; - //memcpy(shared_memory.xylosdata, ccirmessage, 21); TODO !!! - - sequence_idx++; - tx_mode = TESTING; - transmitter_model.enable(); - } else {*/ - button_txtest.set_style(&style()); - button_txtest.set_text("TEST"); - tx_mode = IDLE; - //} - } - } else { - if (n == 25) { - //audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max); - transmitter_model.disable(); - progress.set_value(0); - - if (checkbox_cligno.value() == false) { - tx_mode = IDLE; - button_transmit.set_style(&style_val); - button_transmit.set_text("START"); - } else { - chThdSleepMilliseconds(tempo_cligno.value() * 1000); - - // Invert relay states - sr = options_ra.selected_index(); - if (sr > 0) options_ra.set_selected_index(sr ^ 3); - sr = options_rb.selected_index(); - if (sr > 0) options_rb.set_selected_index(sr ^ 3); - sr = options_rc.selected_index(); - if (sr > 0) options_rc.set_selected_index(sr ^ 3); - sr = options_rd.selected_index(); - if (sr > 0) options_rd.set_selected_index(sr ^ 3); - - generate_message(); - start_tx(); - } - } else { - progress.set_value(n); - } - } -} - -XylosView::XylosView(NavigationView& nav) { - (void)nav; - - baseband::run_image(portapack::spi_flash::image_tag_xylos); - - add_children({ { - &button_txtest, - &text_header, - &header_code_a, - &header_code_b, - &text_city, - &city_code, - &text_family, - &family_code, - &text_subfamily, - &subfamily_code, - &checkbox_wcsubfamily, - &text_receiver, - &receiver_code, - &checkbox_wcid, - &text_freq, - &options_freq, - &text_relais, - &options_ra, - &options_rb, - &options_rc, - &options_rd, - &progress, - &text_message, - &button_transmit, - &checkbox_cligno, - &tempo_cligno, - &text_cligno - } }); - - city_code.set_value(18); - family_code.set_value(1); - subfamily_code.set_value(1); - receiver_code.set_value(1); - header_code_a.set_value(0); - header_code_b.set_value(0); - options_freq.set_selected_index(5); - tempo_cligno.set_value(5); - - progress.set_max(20); - - options_ra.set_selected_index(1); // R1 OFF - - checkbox_wcsubfamily.set_value(true); - checkbox_wcid.set_value(true); - - header_code_a.on_change = [this](int32_t v) { - (void)v; - generate_message(); - }; - header_code_b.on_change = [this](int32_t v) { - (void)v; - generate_message(); - }; - city_code.on_change = [this](int32_t v) { - (void)v; - generate_message(); - }; - family_code.on_change = [this](int32_t v) { - (void)v; - generate_message(); - }; - subfamily_code.on_change = [this](int32_t v) { - (void)v; - generate_message(); - }; - receiver_code.on_change = [this](int32_t v) { - (void)v; - generate_message(); - }; - - checkbox_wcsubfamily.on_select = [this](Checkbox&) { - if (checkbox_wcsubfamily.value() == true) { - receiver_code.set_focusable(false); - text_subfamily.set_style(&style_grey); - } else { - receiver_code.set_focusable(true); - text_subfamily.set_style(&style()); - } - generate_message(); - }; - - checkbox_wcid.on_select = [this](Checkbox&) { - if (checkbox_wcid.value() == true) { - receiver_code.set_focusable(false); - text_receiver.set_style(&style_grey); - } else { - receiver_code.set_focusable(true); - text_receiver.set_style(&style()); - } - receiver_code.set_dirty(); - generate_message(); - }; - - options_ra.on_change = [this](size_t n, OptionsField::value_t v) { - (void)n; - (void)v; - generate_message(); - }; - options_rb.on_change = [this](size_t n, OptionsField::value_t v) { - (void)n; - (void)v; - generate_message(); - }; - options_rc.on_change = [this](size_t n, OptionsField::value_t v) { - (void)n; - (void)v; - generate_message(); - }; - options_rd.on_change = [this](size_t n, OptionsField::value_t v) { - (void)n; - (void)v; - generate_message(); - }; - - button_transmit.set_style(&style_val); - - generate_message(); - - // Transmission and tones testing - button_txtest.on_select = [this](Button&) { - // Tones going up in pitch - const uint8_t ccir_test[21] = { 11, 13, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 14, 12, 10, 12, 14, 0, 9, 0xFF }; - - if (tx_mode == IDLE) { - tx_mode = TESTING; - memcpy(ccir_message, ccir_test, 21); - //audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); - button_txtest.set_style(&style_cancel); - button_txtest.set_text("Wait"); - start_tx(); - } - }; - - // Sequence playback - /*button_txtest.on_select = [this](Button&) { - if (tx_mode == IDLE) { - tx_mode = TESTING; - sequence_idx = 0; - - memcpy(ccir_message, &xylos_sequence[sequence_idx][0], 21); - - ascii_to_ccir(ccir_message); - - sequence_idx++; - - button_txtest.set_style(&style_cancel); - button_txtest.set_text("Wait"); - start_tx(); - } - };*/ - - // Single transmit - button_transmit.on_select = [this,&nav](Button&) { - if (tx_mode == IDLE) { - /*auto modal_view = nav.push("TX", "TX ?", true); - modal_view->on_choice = [this](bool choice) { - if (choice) {*/ - // audio::headphone::set_volume(volume_t::decibel(90 - 99) + audio::headphone::volume_range().max); - tx_mode = SINGLE; - button_transmit.set_style(&style_cancel); - button_transmit.set_text("Wait"); - generate_message(); - start_tx(); - //} - //}; - } - }; -} - -} /* namespace ui */ diff --git a/firmware/application/ui_xylos.hpp b/firmware/application/ui_xylos.hpp deleted file mode 100644 index 3ddcb2b11..000000000 --- a/firmware/application/ui_xylos.hpp +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. - * Copyright (C) 2016 Furrtek - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "ui.hpp" -#include "ui_widget.hpp" -#include "ui_navigation.hpp" -#include "ui_font_fixed_8x16.hpp" - -#include "bmp_bulb_on.hpp" -#include "bmp_bulb_off.hpp" -#include "bmp_bulb_ignore.hpp" - -#include "message.hpp" -//#include "volume.hpp" -#include "transmitter_model.hpp" -//#include "receiver_model.hpp" -#include "portapack.hpp" - -#define CCIR_TONELENGTH (15360*2)-1 // 1536000/10/10 - -namespace ui { - -/* -#define XYLOS_VOICE_ZERO 0 -#define XYLOS_VOICE_HEADER 16 -#define XYLOS_VOICE_RELAYS 21 -#define XYLOS_VOICE_TRAILER 25 - -class XylosRXView : public View { -public: - XylosRXView(NavigationView& nav); - ~XylosRXView(); - - void talk(); - void on_show() override; - void focus() override; - - Text text_dbg { - { 5 * 8, 14 * 16, 20 * 8, 16 }, - "--------------------" - }; - - void do_something(void *p); - -private: - uint8_t p_idx; - const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; - uint8_t xylos_voice_phrase[32] = { 0xFF }; - const char * xylos_voice_filenames[26] = { "zero.wav", - "one.wav", - "two.wav", - "three.wav", - "four.wav", - "five.wav", - "six.wav", - "seven.wav", - "eight.wav", - "nine.wav", - "a.wav", - "b.wav", - "c.wav", - "d.wav", - "e.wav", - "f.wav", - "header.wav", - "city.wav", - "family.wav", - "subfamily.wav", - "address.wav", - "relays.wav", - "ignored.wav", - "off.wav", - "on.wav", - "trailer.wav" - }; - char ccir_received[21]; - - Text text_title { - { 1 * 8, 1 * 16, 11, 16 }, - "BH Xylos RX" - }; - - Text text_city { - { 4 * 8, 3 * 16, 11 * 8, 16 }, - "Code ville:" - }; - NumberField city_code { - { 16 * 8, 3 * 16 }, - 2, - { 0, 99 }, - 1, - ' ' - }; - - Text text_freq { - { 5 * 8, 9 * 16, 10 * 8, 16 }, - "Frequence:" - }; - OptionsField options_freq { - { 16 * 8, 9 * 16 }, - 7, - { - { "31.3250", 0 }, - { "31.3875", 1 }, - { "31.4375", 2 }, - { "31.4750", 3 }, - { "31.6875", 4 }, - { "31.9750", 5 }, - { "TEST 88", 6 } - } - }; - - Button button_start { - { 2 * 8, 16 * 16, 64, 32 }, - "START" - }; - - Button button_exit { - { 21 * 8, 16 * 16, 64, 32 }, - "Exit" - }; -};*/ - -class XylosView : public View { -public: - XylosView(NavigationView& nav); - ~XylosView(); - - void focus() override; - - std::string title() const override { return "Xylos transmit"; }; - -private: - enum tx_modes { - IDLE = 0, - SINGLE, - SEQUENCE, - TESTING - }; - - tx_modes tx_mode = IDLE; - - // 93.975 - // 94.1625 - // 94.3125 - // 94.425 - // 95.0625 - // 95.925 - const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; - - char ccir_message[21]; - - const char ccir_base[21] = "0000000000B0000B0000"; - - /* - const char xylos_sequence[9][21] = { - "0E0E18920EB1E10B0E0E", - "0E0E1890E0B0E12B0E0E", - "0E0E18920EB1E20B0E0E", - "0E0E18920EB1210B0E0E", - "0E0E18920EB1E10B0E0E", - "0E0E18920EB1E10B0E0E", - "0E0E181AEAB10E0B0E0E", - "0E01E81AEAB10E0B0E0E", - "0E03181AEAB10E0B0E0E" - };*/ - - unsigned int sequence_idx; - - void ascii_to_ccir(char *ascii); - void start_tx(); - void generate_message(); - void on_txdone(const int n); - - const Style style_val { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color::green(), - }; - const Style style_cancel { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color::red(), - }; - const Style style_grey { - .font = font::fixed_8x16, - .background = Color::black(), - .foreground = Color::grey(), - }; - - Text text_header { - { 8 * 8, 1 * 16, 7 * 8, 16 }, - "Header:" - }; - NumberField header_code_a { - { 16 * 8, 1 * 16 }, - 2, - { 0, 99 }, - 1, - '0' - }; - NumberField header_code_b { - { 18 * 8, 1 * 16 }, - 2, - { 0, 99 }, - 1, - '0' - }; - - Text text_city { - { 4 * 8, 2 * 16, 11 * 8, 16 }, - "Code ville:" - }; - NumberField city_code { - { 16 * 8, 2 * 16 }, - 2, - { 0, 99 }, - 1, - ' ' - }; - - Text text_family { - { 7 * 8, 3 * 16, 8 * 8, 16 }, - "Famille:" - }; - NumberField family_code { - { 16 * 8, 3 * 16 }, - 1, - { 0, 9 }, - 1, - ' ' - }; - - Text text_subfamily { - { 2 * 8, 4 * 16 + 4, 13 * 8, 16 }, - "Sous-famille:" - }; - NumberField subfamily_code { - { 16 * 8, 4 * 16 + 4 }, - 1, - { 0, 9 }, - 1, - ' ' - }; - Checkbox checkbox_wcsubfamily { - { 20 * 8, 4 * 16}, - 6, - "Toutes" - }; - - Text text_receiver { - { 2 * 8, 6 * 16, 13 * 8, 16 }, - "ID recepteur:" - }; - NumberField receiver_code { - { 16 * 8, 6 * 16 }, - 2, - { 0, 99 }, - 1, - '0' - }; - Checkbox checkbox_wcid { - { 20 * 8, 6 * 16 }, - 4, - "Tous" - }; - - Text text_freq { - { 6 * 8, 8 * 16, 10 * 8, 16 }, - "Frequence:" - }; - OptionsField options_freq { - { 17 * 8, 8 * 16}, - 7, - { - { "31.3250", 0 }, - { "31.3875", 1 }, - { "31.4375", 2 }, - { "31.4750", 3 }, - { "31.6875", 4 }, - { "31.9750", 5 }, - { "TEST 88", 6 } - } - }; - - Text text_relais { - { 8, 9 * 16 + 4, 7 * 8, 16 }, - "Relais:" - }; - - ImageOptionsField options_ra { - { 26, 166, 24, 24 }, - { - { &bulb_ignore_bmp[0], 0 }, - { &bulb_off_bmp[0], 1 }, - { &bulb_on_bmp[0], 2 } - } - }; - ImageOptionsField options_rb { - { 79, 166, 24, 24 }, - { - { &bulb_ignore_bmp[0], 0 }, - { &bulb_off_bmp[0], 1 }, - { &bulb_on_bmp[0], 2 } - } - }; - ImageOptionsField options_rc { - { 133, 166, 24, 24 }, - { - { &bulb_ignore_bmp[0], 0 }, - { &bulb_off_bmp[0], 1 }, - { &bulb_on_bmp[0], 2 } - } - }; - ImageOptionsField options_rd { - { 186, 166, 24, 24 }, - { - { &bulb_ignore_bmp[0], 0 }, - { &bulb_off_bmp[0], 1 }, - { &bulb_on_bmp[0], 2 } - } - }; - - ProgressBar progress { - { 5 * 8, 13 * 16, 20 * 8, 16 }, - }; - Text text_message { - { 5 * 8, 14 * 16, 20 * 8, 16 }, - "--------------------" - }; - - Button button_transmit { - { 2 * 8, 16 * 16, 64, 32 }, - "START" - }; - - Checkbox checkbox_cligno { - { 96, 16 * 16}, - 3, - "J/N" - }; - NumberField tempo_cligno { - { 104, 16 * 16 + 28 }, - 2, - { 1, 99 }, - 1, - ' ' - }; - Text text_cligno { - { 104 + 16, 16 * 16 + 28, 2 * 8, 16 }, - "s." - }; - - Button button_txtest { - { 20 * 8, 16 * 16, 64, 32 }, - "TEST" - }; - - MessageHandlerRegistration message_handler_tx_done { - Message::ID::TXDone, - [this](const Message* const p) { - const auto message = *reinterpret_cast(p); - this->on_txdone(message.n); - } - }; -}; - -} /* namespace ui */ diff --git a/firmware/application/ymdata.hpp b/firmware/application/ymdata.hpp index 45d69f797..a44e6f31f 100644 --- a/firmware/application/ymdata.hpp +++ b/firmware/application/ymdata.hpp @@ -1,4 +1,4 @@ -unsigned char ymdata_bin[] = { +const uint8_t ymdata_bin[] = { 0x00, 0x03, 0x1e, 0x00, 0xb4, 0x01, 0x3e, 0x02, 0x61, 0x05, 0xf7, 0x06, 0x6d, 0x08, 0xc2, 0x09, 0x68, 0x0a, 0x8d, 0x0c, 0x43, 0x0d, 0x9e, 0x0f, 0xef, 0x10, 0x01, 0x11, 0x0f, 0x11, 0x01, 0x64, 0x98, 0x3d, 0x82, 0xc8, diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index a81ba439e..a66aed373 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -375,19 +375,12 @@ DeclareTargets(PAFS afsk) #) #DeclareTargets(PEPR epar) -### Xylos +### Tones set(MODE_CPPSRC - proc_xylos.cpp + proc_tones.cpp ) -DeclareTargets(PXYL xylos) - -### DTMF TX - -set(MODE_CPPSRC - proc_dtmf_tx.cpp -) -DeclareTargets(PDTX dtmf_tx) +DeclareTargets(PTON tones) ### RDS diff --git a/firmware/baseband/audio_output.cpp b/firmware/baseband/audio_output.cpp index 8bb1520ac..dd06d3ea2 100644 --- a/firmware/baseband/audio_output.cpp +++ b/firmware/baseband/audio_output.cpp @@ -31,6 +31,12 @@ #include #include +void AudioOutput::configure( + const bool do_proc +) { + do_processing = do_proc; +} + void AudioOutput::configure( const iir_biquad_config_t& hpf_config, const iir_biquad_config_t& deemph_config, @@ -69,20 +75,25 @@ void AudioOutput::write( void AudioOutput::on_block( const buffer_f32_t& audio ) { - const auto audio_present_now = squelch.execute(audio); - - hpf.execute_in_place(audio); - deemph.execute_in_place(audio); - - audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0); - const bool audio_present = (audio_present_history != 0); + bool audio_present; - if( !audio_present ) { - for(size_t i=0; ifM&w4YDghx#AcwF4@C*J(A_PVNAp!7){vbvcOF;M#I{_miMgWr(lS=_3 z7limkFahwf`2&~`u>)vZXqZO?r~&Y~lYs#vlc)jc0S%Lp0w)0sleq#j0SlAu0y6;) IvmpaRAW3W@V*mgE delta 98 zcmV-o0G)vZXqZO?r~&Z1lZ62zlcWLc0SS|l0w)0oleq#j0SA-q0y6;$vmpaR EAfNFdT>t<8 diff --git a/firmware/baseband/baseband_tones.img b/firmware/baseband/baseband_tones.img new file mode 100644 index 0000000000000000000000000000000000000000..10220518c73ff10d0382939efb7b0f56f2992bcb GIT binary patch literal 11572 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 112) { // Stop - message.n = 200; + message.progress = 200; shared_memory.application_queue.push(message); configured = false; cur_bit = 0; diff --git a/firmware/baseband/proc_afsk.cpp b/firmware/baseband/proc_afsk.cpp index 8f0e86762..e3597d097 100644 --- a/firmware/baseband/proc_afsk.cpp +++ b/firmware/baseband/proc_afsk.cpp @@ -41,8 +41,8 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) { if (sample_count >= afsk_samples_per_bit) { if (configured) { - cur_byte = shared_memory.tx_data[byte_pos]; - ext_byte = shared_memory.tx_data[byte_pos + 1]; + cur_byte = shared_memory.bb_data.data[byte_pos]; + ext_byte = shared_memory.bb_data.data[byte_pos + 1]; if (!(cur_byte | ext_byte)) { // End of data @@ -50,16 +50,16 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) { // Repeat bit_pos = 0; byte_pos = 0; - cur_byte = shared_memory.tx_data[0]; - ext_byte = shared_memory.tx_data[1]; - message.n = repeat_counter + 1; + cur_byte = shared_memory.bb_data.data[0]; + ext_byte = shared_memory.bb_data.data[1]; + message.progress = repeat_counter + 1; shared_memory.application_queue.push(message); repeat_counter++; } else { // Stop cur_byte = 0; ext_byte = 0; - message.n = 0; + message.progress = 0; shared_memory.application_queue.push(message); configured = false; } diff --git a/firmware/baseband/proc_dtmf_tx.cpp b/firmware/baseband/proc_dtmf_tx.cpp index 9d9e57088..9af57f519 100644 --- a/firmware/baseband/proc_dtmf_tx.cpp +++ b/firmware/baseband/proc_dtmf_tx.cpp @@ -48,15 +48,15 @@ void DTMFTXProcessor::execute(const buffer_c8_t& buffer) { tone = true; timer = tone_length; - tone_code = shared_memory.tx_data[tone_idx]; + tone_code = shared_memory.bb_data.data[tone_idx]; if (tone_code == 0xFF) { - txdone_message.n = 0xFF; // End of list + txdone_message.done = true; // End of list shared_memory.application_queue.push(txdone_message); configured = false; tone = false; } else { - txdone_message.n = tone_idx; // New tone (progress) + txdone_message.progress = tone_idx; // New tone shared_memory.application_queue.push(txdone_message); tone_idx++; } @@ -99,7 +99,7 @@ void DTMFTXProcessor::on_message(const Message* const msg) { if (message.id == Message::ID::DTMFTXConfig) { // Translate DTMF message to index in DTMF frequencies table - tone_ptr = &shared_memory.tx_data[0]; + tone_ptr = &shared_memory.bb_data.data[0]; for (;;) { tone_code = *tone_ptr; if (tone_code == 0xFF) @@ -132,6 +132,8 @@ void DTMFTXProcessor::on_message(const Message* const msg) { tone_length = message.tone_length * 154; // 153.6 pause_length = message.pause_length * 154; // 153.6 as = 0; + txdone_message.progress = 0; + txdone_message.done = false; tone = false; timer = 0; tone_idx = 0; diff --git a/firmware/baseband/proc_jammer.cpp b/firmware/baseband/proc_jammer.cpp index f13e601a3..4e91476a1 100644 --- a/firmware/baseband/proc_jammer.cpp +++ b/firmware/baseband/proc_jammer.cpp @@ -87,7 +87,7 @@ void JammerProcessor::execute(const buffer_c8_t& buffer) { void JammerProcessor::on_message(const Message* const msg) { - jammer_ranges = (JammerRange*)shared_memory.tx_data; + jammer_ranges = (JammerRange*)shared_memory.bb_data.data; /*const auto message = *reinterpret_cast(msg); diff --git a/firmware/baseband/proc_ook.cpp b/firmware/baseband/proc_ook.cpp index eaca0da41..4ce4bc319 100644 --- a/firmware/baseband/proc_ook.cpp +++ b/firmware/baseband/proc_ook.cpp @@ -49,15 +49,15 @@ void OOKProcessor::execute(const buffer_c8_t& buffer) { if (repeat_counter < repeat) { // Repeat bit_pos = 0; - cur_bit = shared_memory.tx_data[0] & 0x80; - message.n = repeat_counter + 1; - shared_memory.application_queue.push(message); + cur_bit = shared_memory.bb_data.data[0] & 0x80; + txdone_message.progress = repeat_counter + 1; + shared_memory.application_queue.push(txdone_message); repeat_counter++; } else { // Stop cur_bit = 0; - message.n = 0; - shared_memory.application_queue.push(message); + txdone_message.done = true; + shared_memory.application_queue.push(txdone_message); configured = false; } pause_counter = 0; @@ -65,7 +65,7 @@ void OOKProcessor::execute(const buffer_c8_t& buffer) { pause_counter--; } } else { - cur_bit = (shared_memory.tx_data[bit_pos >> 3] << (bit_pos & 7)) & 0x80; + cur_bit = (shared_memory.bb_data.data[bit_pos >> 3] << (bit_pos & 7)) & 0x80; bit_pos++; } } @@ -108,6 +108,8 @@ void OOKProcessor::on_message(const Message* const p) { repeat_counter = 0; bit_pos = 0; cur_bit = 0; + txdone_message.progress = 0; + txdone_message.done = false; configured = true; } } diff --git a/firmware/baseband/proc_ook.hpp b/firmware/baseband/proc_ook.hpp index 652188737..43d914ada 100644 --- a/firmware/baseband/proc_ook.hpp +++ b/firmware/baseband/proc_ook.hpp @@ -52,7 +52,7 @@ private: uint32_t tone_phase, phase, sphase; int32_t tone_sample, sig, frq; - TXDoneMessage message; + TXDoneMessage txdone_message; }; #endif diff --git a/firmware/baseband/proc_rds.cpp b/firmware/baseband/proc_rds.cpp index c05b0b05e..2ddccde64 100644 --- a/firmware/baseband/proc_rds.cpp +++ b/firmware/baseband/proc_rds.cpp @@ -98,7 +98,7 @@ void RDSProcessor::execute(const buffer_c8_t& buffer) { void RDSProcessor::on_message(const Message* const msg) { if (msg->id == Message::ID::RDSConfigure) { const auto message = *reinterpret_cast(msg); - rdsdata = (uint32_t*)shared_memory.tx_data; + rdsdata = (uint32_t*)shared_memory.bb_data.data; message_length = message.length; configured = true; } diff --git a/firmware/baseband/proc_tones.cpp b/firmware/baseband/proc_tones.cpp new file mode 100644 index 000000000..a4d9e3c86 --- /dev/null +++ b/firmware/baseband/proc_tones.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "proc_tones.hpp" +#include "sine_table_int8.hpp" +#include "event_m4.hpp" + +#include + +// This is called at 1536000/2048 = 750Hz +void TonesProcessor::execute(const buffer_c8_t& buffer) { + + if (!configured) return; + + ai = 0; + + for (size_t i = 0; i < buffer.count; i++) { + + // Tone generation at full samplerate + if (silence_count) { + // Just occupy channel with carrier + silence_count--; + if (!silence_count) { + sample_count = 0; + tone_a_phase = 0; + tone_b_phase = 0; + } + tone_sample = 0; + re = 0; + im = 0; + } else { + if (!sample_count) { + digit = shared_memory.bb_data.tones_data.message[digit_pos++]; + if (digit_pos >= message_length) { + configured = false; + txdone_message.done = true; + shared_memory.application_queue.push(txdone_message); + } else { + txdone_message.progress = digit_pos; // Inform UI about progress + shared_memory.application_queue.push(txdone_message); + } + + if ((digit >= 32) || (tone_deltas[digit] == 0)) { + silence_count = shared_memory.bb_data.tones_data.silence; + } else { + if (!dual_tone) { + tone_a_delta = tone_deltas[digit]; + } else { + tone_a_delta = tone_deltas[digit << 1]; + tone_b_delta = tone_deltas[(digit << 1) + 1]; + } + sample_count = tone_durations[digit]; + } + } else { + sample_count--; + } + + // Ugly + if (digit >= 32) { + tone_sample = 0; + re = 0; + im = 0; + } else { + if (!dual_tone) { + tone_sample = (sine_table_i8[(tone_a_phase & 0x03FC0000) >> 18]); + tone_a_phase += tone_a_delta; + } else { + tone_sample = sine_table_i8[(tone_a_phase & 0x03FC0000) >> 18] >> 1; + tone_sample += sine_table_i8[(tone_b_phase & 0x03FC0000) >> 18] >> 1; + + tone_a_phase += tone_a_delta; + tone_b_phase += tone_b_delta; + } + + // FM + delta = tone_sample * fm_delta; + + phase += delta; + sphase = phase + (64 << 18); + + re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]); + im = (sine_table_i8[(phase & 0x03FC0000) >> 18]); + } + } + + // Headphone output sample generation: 1536000/24000 = 64 + if (audio_out) { + if (!as) { + as = 64; // 63 ? + audio_buffer.p[ai++] = tone_sample * 128; + } else { + as--; + } + } + + buffer.p[i] = {(int8_t)re, (int8_t)im}; + } + + if (audio_out) audio_output.write(audio_buffer); +} + +void TonesProcessor::on_message(const Message* const p) { + const auto message = *reinterpret_cast(p); + if (message.id == Message::ID::TonesConfigure) { + silence_count = message.pre_silence; // In samples + for (uint8_t c = 0; c < 32; c++) { + tone_deltas[c] = shared_memory.bb_data.tones_data.tone_defs[c].delta; + tone_durations[c] = shared_memory.bb_data.tones_data.tone_defs[c].duration; + } + message_length = message.tone_count; + fm_delta = message.fm_delta; + audio_out = message.audio_out; + dual_tone = message.dual_tone; + + if (audio_out) audio_output.configure(false); + + txdone_message.done = false; + txdone_message.progress = 0; + + digit_pos = 0; + tone_a_phase = 0; + tone_b_phase = 0; + as = 0; + + configured = true; + } +} + +int main() { + EventDispatcher event_dispatcher { std::make_unique() }; + event_dispatcher.run(); + return 0; +} diff --git a/firmware/baseband/proc_xylos.hpp b/firmware/baseband/proc_tones.hpp similarity index 51% rename from firmware/baseband/proc_xylos.hpp rename to firmware/baseband/proc_tones.hpp index 6d107dcbd..95c62a259 100644 --- a/firmware/baseband/proc_xylos.hpp +++ b/firmware/baseband/proc_tones.hpp @@ -20,18 +20,15 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __PROC_XYLOS_H__ -#define __PROC_XYLOS_H__ +#ifndef __PROC_TONES_H__ +#define __PROC_TONES_H__ +#include "portapack_shared_memory.hpp" #include "baseband_processor.hpp" #include "baseband_thread.hpp" +#include "audio_output.hpp" -//#include "audio_output.hpp" - -#define CCIR_PHASEINC (436.91/2) // (65536*1024)/1536000*10 -#define CCIR_SILENCE (122880)-1 // 400ms - -class XylosProcessor : public BasebandProcessor { +class TonesProcessor : public BasebandProcessor { public: void execute(const buffer_c8_t& buffer) override; @@ -42,37 +39,31 @@ private: BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit }; - const uint32_t ccir_phases[16] = { - (uint32_t)(1981*CCIR_PHASEINC), - (uint32_t)(1124*CCIR_PHASEINC), - (uint32_t)(1197*CCIR_PHASEINC), - (uint32_t)(1275*CCIR_PHASEINC), - (uint32_t)(1358*CCIR_PHASEINC), - (uint32_t)(1446*CCIR_PHASEINC), - (uint32_t)(1540*CCIR_PHASEINC), - (uint32_t)(1640*CCIR_PHASEINC), - (uint32_t)(1747*CCIR_PHASEINC), - (uint32_t)(1860*CCIR_PHASEINC), - (uint32_t)(2400*CCIR_PHASEINC), - (uint32_t)(930*CCIR_PHASEINC), - (uint32_t)(2247*CCIR_PHASEINC), - (uint32_t)(991*CCIR_PHASEINC), - (uint32_t)(2110*CCIR_PHASEINC), - (uint32_t)(1055*CCIR_PHASEINC) - }; + std::array audio; // 2048/64 + const buffer_s16_t audio_buffer { + (int16_t*)audio.data(), + sizeof(audio) / sizeof(int16_t) + }; - uint32_t samples_per_tone; - int8_t re, im; - uint8_t s, as = 0, ai; - uint8_t byte_pos = 0; - uint8_t digit = 0; - uint32_t sample_count = 0; - uint32_t tone_phase, phase, sphase; - int32_t tone_sample, delta; - bool silence = true; - TXDoneMessage message; + uint32_t tone_deltas[32]; + uint32_t tone_durations[32]; - //AudioOutput audio_output; + bool audio_out; + bool dual_tone; + uint32_t fm_delta; + uint32_t tone_a_phase, tone_b_phase; + uint32_t tone_a_delta, tone_b_delta; + uint8_t digit_pos; + uint8_t digit; + uint32_t silence_count, sample_count; + uint32_t message_length; + uint32_t phase, sphase; + int32_t tone_sample, delta; + int8_t re, im; + uint8_t as, ai; + + TXDoneMessage txdone_message; + AudioOutput audio_output; }; #endif diff --git a/firmware/baseband/proc_xylos.cpp b/firmware/baseband/proc_xylos.cpp deleted file mode 100644 index 1dae9151f..000000000 --- a/firmware/baseband/proc_xylos.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. - * Copyright (C) 2016 Furrtek - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "proc_xylos.hpp" -#include "portapack_shared_memory.hpp" -#include "sine_table_int8.hpp" -#include "event_m4.hpp" - -#include - -void XylosProcessor::execute(const buffer_c8_t& buffer) { - - // This is called at 1536000/2048 = 750Hz - - if (!configured) return; - - for (size_t i = 0; i= (5 - 1)) { - s = 0; - - if (silence) { - // Just occupy channel with carrier - if (sample_count >= CCIR_SILENCE) { - silence = false; - sample_count = samples_per_tone; - } else { - sample_count++; - } - } else { - if (sample_count >= samples_per_tone) { - digit = shared_memory.tx_data[byte_pos++]; - if ((digit == 0xFF) || (byte_pos >= 21)) { - configured = false; - message.n = 25; // End of message code - shared_memory.application_queue.push(message); - } else { - message.n = byte_pos; // Inform UI about progress (just as eye candy) - shared_memory.application_queue.push(message); - } - - sample_count = 0; - } else { - sample_count++; - } - - tone_phase += ccir_phases[digit]; - } - } else { - s++; - } - - if (silence) { - re = 0; - im = 0; - } else { - tone_sample = (sine_table_i8[(tone_phase & 0x03FC0000) >> 18]); - - // Audio preview sample generation: 1536000/48000 = 32 - /*if (as >= 31) { - as = 0; - audio[ai++] = sample * 128; - } else { - as++; - }*/ - - // FM - // 1<<18 = 262144 - // m = (262144 * BW) / 1536000 / 2 - delta = tone_sample * 853; // 10kHz BW - - phase += delta; - sphase = phase + (64 << 18); - - re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]); - im = (sine_table_i8[(phase & 0x03FC0000) >> 18]); - } - - buffer.p[i] = {(int8_t)re, (int8_t)im}; - } - - //audio_output.write(audio_buffer); -} - -void XylosProcessor::on_message(const Message* const p) { - const auto message = *reinterpret_cast(p); - if (message.id == Message::ID::CCIRConfigure) { - byte_pos = 0; - digit = 0; - samples_per_tone = message.samples_per_tone; - sample_count = samples_per_tone; - as = 0; - silence = true; - configured = true; - } -} - -int main() { - EventDispatcher event_dispatcher { std::make_unique() }; - event_dispatcher.run(); - return 0; -} diff --git a/firmware/bootstrap/bootstrap.bin b/firmware/bootstrap/bootstrap.bin index 784058649519f60fa99117504fa1874ae22ed336..c7875d1adddfe95c53051d1862b3219aa1aec096 100755 GIT binary patch delta 30 jcmaFDc!zO9hsXj3Fc7d|U=aBCoMC_b4~7pDmpA|bjn)cF delta 38 rcmcb^_=Isnhs+8FFc7d|U=aBCoMAuX7AB7tH^w~)?hN}U&T#+$+Vuplaydead_sequence = new_value; } +bool stealth_mode() { + return ((data->ui_config >> 3) & 1) ? true : false; +} + +void set_stealth_mode(const bool new_value) { + data->ui_config = (data->ui_config & ~0b1000) | ((new_value & 1) << 3); +} + uint32_t ui_config() { uint8_t bloff_value; @@ -210,7 +218,7 @@ uint16_t ui_config_bloff() { } void set_config_textentry(uint8_t new_value) { - data->ui_config = (data->ui_config & ~0b1100) | ((new_value & 1) << 2); + data->ui_config = (data->ui_config & ~0b100) | ((new_value & 1) << 2); } uint8_t ui_config_textentry() { diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 97b5ab2d4..c14bcaf03 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -65,6 +65,9 @@ void set_playing_dead(const uint32_t new_value); uint32_t playdead_sequence(); void set_playdead_sequence(const uint32_t new_value); +bool stealth_mode(); +void set_stealth_mode(const bool new_value); + uint32_t ui_config(); void set_ui_config(const uint32_t new_value); diff --git a/firmware/common/portapack_shared_memory.hpp b/firmware/common/portapack_shared_memory.hpp index 52283f5e9..4c08eac76 100644 --- a/firmware/common/portapack_shared_memory.hpp +++ b/firmware/common/portapack_shared_memory.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -25,6 +26,7 @@ #include #include +#include "portapack_shared_memory.hpp" #include "message_queue.hpp" struct JammerRange { @@ -34,6 +36,17 @@ struct JammerRange { uint32_t duration; }; +struct ToneDef { + uint32_t delta; + uint32_t duration; +}; + +struct ToneData { + ToneDef tone_defs[32]; + uint32_t silence; + uint8_t message[128]; +}; + /* NOTE: These structures must be located in the same location in both M4 and M0 binaries */ struct SharedMemory { static constexpr size_t application_queue_k = 11; @@ -47,8 +60,11 @@ struct SharedMemory { char m4_panic_msg[32] { 0 }; - // struct tx_data union for 9x JammerRange ? - uint8_t tx_data[512] { 0 }; + union { + ToneData tones_data; + JammerRange jammer_ranges[9]; + uint8_t data[512]; + } bb_data; }; extern SharedMemory& shared_memory; diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 9e7b23047..309c4c65e 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -77,10 +78,9 @@ constexpr image_tag_t image_tag_jammer { 'P', 'J', 'A', 'M' }; constexpr image_tag_t image_tag_audio_tx { 'P', 'A', 'T', 'X' }; constexpr image_tag_t image_tag_afsk { 'P', 'A', 'F', 'S' }; constexpr image_tag_t image_tag_epar { 'P', 'E', 'P', 'R' }; -constexpr image_tag_t image_tag_xylos { 'P', 'X', 'Y', 'L' }; +constexpr image_tag_t image_tag_tones { 'P', 'T', 'O', 'N' }; constexpr image_tag_t image_tag_rds { 'P', 'R', 'D', 'S' }; constexpr image_tag_t image_tag_ook { 'P', 'O', 'O', 'K' }; -constexpr image_tag_t image_tag_dtmf_tx { 'P', 'D', 'T', 'X' }; constexpr image_tag_t image_tag_adsb_tx { 'P', 'A', 'D', 'S' }; constexpr image_tag_t image_tag_hackrf { 'H', 'R', 'F', '1' }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 5525f9f40..14dbba3e6 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -250,6 +250,12 @@ void View::remove_child(Widget* const widget) { } } +void View::remove_children(const std::vector& children) { + for(auto child : children) { + remove_child(child); + } +} + const std::vector& View::children() const { return children_; } @@ -564,13 +570,17 @@ void Checkbox::set_text(const std::string value) { set_dirty(); } -/*std::string Checkbox::text() const { - return text_; -}*/ - -void Checkbox::set_value(const bool value) { +bool Checkbox::set_value(const bool value) { value_ = value; + + if( on_select ) { + on_select(*this); + return true; + } + set_dirty(); + + return false; } bool Checkbox::value() const { @@ -616,15 +626,8 @@ void Checkbox::paint(Painter& painter) { } bool Checkbox::on_key(const KeyEvent key) { - if( key == KeyEvent::Select ) { - value_ = not value_; - set_dirty(); - - if( on_select ) { - on_select(*this); - return true; - } - } + if( key == KeyEvent::Select ) + return set_value(not value_); return false; } @@ -714,8 +717,7 @@ bool Button::on_key(const KeyEvent key) { } } else { if( on_dir ) { - on_dir(*this, key); - return false; + return on_dir(*this, key); } } diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 49e3b66f0..6568e1b93 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -29,6 +29,7 @@ #include "ui_focus.hpp" #include "radio.hpp" +#include "portapack.hpp" #include "utility.hpp" #include @@ -161,6 +162,7 @@ public: void add_child(Widget* const widget); void add_children(const std::vector& children); void remove_child(Widget* const widget); + void remove_children(const std::vector& children); const std::vector& children() const override; virtual std::string title() const; @@ -264,7 +266,7 @@ public: void set_text(const std::string value); // std::string text() const; - void set_value(const bool value); + bool set_value(const bool value); bool value() const; void paint(Painter& painter) override; @@ -281,7 +283,7 @@ private: class Button : public Widget { public: std::function on_select; - std::function on_dir; + std::function on_dir; std::function on_highlight; Button(Rect parent_rect, std::string text); @@ -354,6 +356,11 @@ public: ImageOptionsField(Rect parent_rect, options_t options); + ImageOptionsField( + ) : ImageOptionsField { { }, { } } + { + } + void set_options(options_t new_options); size_t selected_index() const; diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index 34bb3c86a981f8f6f1ad0721bebeaa282a14300d..5216ce91ea56db1e7a27aa76beda4dd85b873e7b 100644 GIT binary patch delta 126771 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�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 Q`0_pNyPDH`uQxmY13nY%lmGw#