mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-23 14:29:23 -05:00
Merge 'upstream/master' - At least it builds...
This commit is contained in:
commit
5e40669cbc
@ -14,9 +14,9 @@ notifications:
|
||||
- "Firmware download : https://portapack-h1-builds.s3.amazonaws.com/%{repository_slug}/%{build_number}/%{build_number}.1/build/firmware/portapack-h1-firmware-%{commit}.tar.bz2"
|
||||
|
||||
before_script:
|
||||
- wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2
|
||||
- wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/6-2016q4/gcc-arm-none-eabi-6_2-2016q4-20161216-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2
|
||||
- tar -xf /tmp/gcc-arm.tar.bz2
|
||||
- export PATH=$PWD/gcc-arm-none-eabi-5_4-2016q2/bin:$PATH
|
||||
- export PATH=$PWD/gcc-arm-none-eabi-6_2-2016q4/bin:$PATH
|
||||
- export CC="arm-none-eabi-gcc"
|
||||
- export CXX="arm-none-eabi-g++"
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
project(firmware)
|
||||
|
||||
set(BASEBAND ${PROJECT_SOURCE_DIR}/baseband)
|
||||
set(COMMON ${PROJECT_SOURCE_DIR}/common)
|
||||
set(CHIBIOS ${PROJECT_SOURCE_DIR}/chibios)
|
||||
set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack)
|
||||
@ -27,7 +28,7 @@ set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack)
|
||||
set(HACKRF_FIRMWARE_FILENAME hackrf_one_usb_ram.dfu)
|
||||
set(HACKRF_FIRMWARE_IMAGE ${PROJECT_SOURCE_DIR}/${HACKRF_FIRMWARE_FILENAME})
|
||||
|
||||
set(HACKRF_CPLD_SVF_FILENAME hackrf_cpld_default.svf)
|
||||
set(HACKRF_CPLD_SVF_FILENAME hackrf_cpld_portapack.svf)
|
||||
set(HACKRF_CPLD_SVF_PATH ${PROJECT_SOURCE_DIR}/${HACKRF_CPLD_SVF_FILENAME})
|
||||
|
||||
set(EXTRACT_CPLD_DATA ${PROJECT_SOURCE_DIR}/tools/extract_cpld_data.py)
|
||||
@ -59,7 +60,7 @@ add_custom_target(
|
||||
|
||||
add_custom_target(
|
||||
program
|
||||
COMMAND dfu-util --device 1fc9:000c --download ${HACKRF_FIRMWARE_IMAGE} --reset
|
||||
COMMAND dfu-util --device 1fc9:000c --download ${HACKRF_FIRMWARE_IMAGE}
|
||||
COMMAND sleep 1s
|
||||
COMMAND hackrf_spiflash -w ${FIRMWARE_FILENAME}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FIRMWARE_FILENAME}
|
||||
|
@ -36,7 +36,7 @@ set(USE_OPT "-Os -g --specs=nano.specs")
|
||||
set(USE_COPT "-std=gnu99")
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
set(USE_CPPOPT "-Wl,-Map,foo.map -std=c++11 -fno-rtti -fno-exceptions")
|
||||
set(USE_CPPOPT "-std=c++14 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
||||
|
||||
# Enable this if you want the linker to remove unused code and data
|
||||
set(USE_LINK_GC yes)
|
||||
@ -131,6 +131,7 @@ set(CPPSRC
|
||||
rffc507x_spi.cpp
|
||||
max2837.cpp
|
||||
max5864.cpp
|
||||
${COMMON}/buffer.cpp
|
||||
debounce.cpp
|
||||
touch.cpp
|
||||
touch_adc.cpp
|
||||
@ -201,14 +202,15 @@ set(CPPSRC
|
||||
capture_app.cpp
|
||||
replay_app.cpp
|
||||
sd_card.cpp
|
||||
time.cpp
|
||||
rtc_time.cpp
|
||||
file.cpp
|
||||
filewriter.cpp
|
||||
wavfile.cpp
|
||||
log_file.cpp
|
||||
${COMMON}/png_writer.cpp
|
||||
${COMMON}/buffer_exchange.cpp
|
||||
capture_thread.cpp
|
||||
replay_thread.cpp
|
||||
io_file.cpp
|
||||
io_wave.cpp
|
||||
${COMMON}/manchester.cpp
|
||||
string_format.cpp
|
||||
temperature_logger.cpp
|
||||
@ -357,6 +359,7 @@ add_definitions(${DEFS})
|
||||
include_directories(. ${INCDIR})
|
||||
link_directories(${LLIBDIR})
|
||||
target_link_libraries(${PROJECT_NAME}.elf ${LIBS})
|
||||
target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_NAME}.bin
|
||||
|
@ -194,6 +194,33 @@ __/chibios-portapack/ext/fatfs/src/ff.c.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/chibios-portapack/ext/fatfs/src/ff.c.s
|
||||
.PHONY : __/chibios-portapack/ext/fatfs/src/ff.c.s
|
||||
|
||||
__/chibios-portapack/ext/fatfs/src/option/unicode.obj: __/chibios-portapack/ext/fatfs/src/option/unicode.c.obj
|
||||
|
||||
.PHONY : __/chibios-portapack/ext/fatfs/src/option/unicode.obj
|
||||
|
||||
# target to build an object file
|
||||
__/chibios-portapack/ext/fatfs/src/option/unicode.c.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/chibios-portapack/ext/fatfs/src/option/unicode.c.obj
|
||||
.PHONY : __/chibios-portapack/ext/fatfs/src/option/unicode.c.obj
|
||||
|
||||
__/chibios-portapack/ext/fatfs/src/option/unicode.i: __/chibios-portapack/ext/fatfs/src/option/unicode.c.i
|
||||
|
||||
.PHONY : __/chibios-portapack/ext/fatfs/src/option/unicode.i
|
||||
|
||||
# target to preprocess a source file
|
||||
__/chibios-portapack/ext/fatfs/src/option/unicode.c.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/chibios-portapack/ext/fatfs/src/option/unicode.c.i
|
||||
.PHONY : __/chibios-portapack/ext/fatfs/src/option/unicode.c.i
|
||||
|
||||
__/chibios-portapack/ext/fatfs/src/option/unicode.s: __/chibios-portapack/ext/fatfs/src/option/unicode.c.s
|
||||
|
||||
.PHONY : __/chibios-portapack/ext/fatfs/src/option/unicode.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
__/chibios-portapack/ext/fatfs/src/option/unicode.c.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/chibios-portapack/ext/fatfs/src/option/unicode.c.s
|
||||
.PHONY : __/chibios-portapack/ext/fatfs/src/option/unicode.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
|
||||
@ -2003,6 +2030,60 @@ __/common/ais_packet.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/ais_packet.cpp.s
|
||||
.PHONY : __/common/ais_packet.cpp.s
|
||||
|
||||
__/common/buffer.obj: __/common/buffer.cpp.obj
|
||||
|
||||
.PHONY : __/common/buffer.obj
|
||||
|
||||
# target to build an object file
|
||||
__/common/buffer.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/buffer.cpp.obj
|
||||
.PHONY : __/common/buffer.cpp.obj
|
||||
|
||||
__/common/buffer.i: __/common/buffer.cpp.i
|
||||
|
||||
.PHONY : __/common/buffer.i
|
||||
|
||||
# target to preprocess a source file
|
||||
__/common/buffer.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/buffer.cpp.i
|
||||
.PHONY : __/common/buffer.cpp.i
|
||||
|
||||
__/common/buffer.s: __/common/buffer.cpp.s
|
||||
|
||||
.PHONY : __/common/buffer.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
__/common/buffer.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/buffer.cpp.s
|
||||
.PHONY : __/common/buffer.cpp.s
|
||||
|
||||
__/common/buffer_exchange.obj: __/common/buffer_exchange.cpp.obj
|
||||
|
||||
.PHONY : __/common/buffer_exchange.obj
|
||||
|
||||
# target to build an object file
|
||||
__/common/buffer_exchange.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/buffer_exchange.cpp.obj
|
||||
.PHONY : __/common/buffer_exchange.cpp.obj
|
||||
|
||||
__/common/buffer_exchange.i: __/common/buffer_exchange.cpp.i
|
||||
|
||||
.PHONY : __/common/buffer_exchange.i
|
||||
|
||||
# target to preprocess a source file
|
||||
__/common/buffer_exchange.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/buffer_exchange.cpp.i
|
||||
.PHONY : __/common/buffer_exchange.cpp.i
|
||||
|
||||
__/common/buffer_exchange.s: __/common/buffer_exchange.cpp.s
|
||||
|
||||
.PHONY : __/common/buffer_exchange.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
__/common/buffer_exchange.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/__/common/buffer_exchange.cpp.s
|
||||
.PHONY : __/common/buffer_exchange.cpp.s
|
||||
|
||||
__/common/chibios_cpp.obj: __/common/chibios_cpp.cpp.obj
|
||||
|
||||
.PHONY : __/common/chibios_cpp.obj
|
||||
@ -3272,33 +3353,6 @@ file.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/file.cpp.s
|
||||
.PHONY : file.cpp.s
|
||||
|
||||
filewriter.obj: filewriter.cpp.obj
|
||||
|
||||
.PHONY : filewriter.obj
|
||||
|
||||
# target to build an object file
|
||||
filewriter.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/filewriter.cpp.obj
|
||||
.PHONY : filewriter.cpp.obj
|
||||
|
||||
filewriter.i: filewriter.cpp.i
|
||||
|
||||
.PHONY : filewriter.i
|
||||
|
||||
# target to preprocess a source file
|
||||
filewriter.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/filewriter.cpp.i
|
||||
.PHONY : filewriter.cpp.i
|
||||
|
||||
filewriter.s: filewriter.cpp.s
|
||||
|
||||
.PHONY : filewriter.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
filewriter.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/filewriter.cpp.s
|
||||
.PHONY : filewriter.cpp.s
|
||||
|
||||
freqman.obj: freqman.cpp.obj
|
||||
|
||||
.PHONY : freqman.obj
|
||||
@ -3353,6 +3407,60 @@ hackrf_cpld_data.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/hackrf_cpld_data.cpp.s
|
||||
.PHONY : hackrf_cpld_data.cpp.s
|
||||
|
||||
io_file.obj: io_file.cpp.obj
|
||||
|
||||
.PHONY : io_file.obj
|
||||
|
||||
# target to build an object file
|
||||
io_file.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/io_file.cpp.obj
|
||||
.PHONY : io_file.cpp.obj
|
||||
|
||||
io_file.i: io_file.cpp.i
|
||||
|
||||
.PHONY : io_file.i
|
||||
|
||||
# target to preprocess a source file
|
||||
io_file.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/io_file.cpp.i
|
||||
.PHONY : io_file.cpp.i
|
||||
|
||||
io_file.s: io_file.cpp.s
|
||||
|
||||
.PHONY : io_file.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
io_file.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/io_file.cpp.s
|
||||
.PHONY : io_file.cpp.s
|
||||
|
||||
io_wave.obj: io_wave.cpp.obj
|
||||
|
||||
.PHONY : io_wave.obj
|
||||
|
||||
# target to build an object file
|
||||
io_wave.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/io_wave.cpp.obj
|
||||
.PHONY : io_wave.cpp.obj
|
||||
|
||||
io_wave.i: io_wave.cpp.i
|
||||
|
||||
.PHONY : io_wave.i
|
||||
|
||||
# target to preprocess a source file
|
||||
io_wave.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/io_wave.cpp.i
|
||||
.PHONY : io_wave.cpp.i
|
||||
|
||||
io_wave.s: io_wave.cpp.s
|
||||
|
||||
.PHONY : io_wave.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
io_wave.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/io_wave.cpp.s
|
||||
.PHONY : io_wave.cpp.s
|
||||
|
||||
irq_controls.obj: irq_controls.cpp.obj
|
||||
|
||||
.PHONY : irq_controls.obj
|
||||
@ -3866,6 +3974,33 @@ rffc507x_spi.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/rffc507x_spi.cpp.s
|
||||
.PHONY : rffc507x_spi.cpp.s
|
||||
|
||||
rtc_time.obj: rtc_time.cpp.obj
|
||||
|
||||
.PHONY : rtc_time.obj
|
||||
|
||||
# target to build an object file
|
||||
rtc_time.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/rtc_time.cpp.obj
|
||||
.PHONY : rtc_time.cpp.obj
|
||||
|
||||
rtc_time.i: rtc_time.cpp.i
|
||||
|
||||
.PHONY : rtc_time.i
|
||||
|
||||
# target to preprocess a source file
|
||||
rtc_time.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/rtc_time.cpp.i
|
||||
.PHONY : rtc_time.cpp.i
|
||||
|
||||
rtc_time.s: rtc_time.cpp.s
|
||||
|
||||
.PHONY : rtc_time.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
rtc_time.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/rtc_time.cpp.s
|
||||
.PHONY : rtc_time.cpp.s
|
||||
|
||||
sd_card.obj: sd_card.cpp.obj
|
||||
|
||||
.PHONY : sd_card.obj
|
||||
@ -4028,33 +4163,6 @@ temperature_logger.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/temperature_logger.cpp.s
|
||||
.PHONY : temperature_logger.cpp.s
|
||||
|
||||
time.obj: time.cpp.obj
|
||||
|
||||
.PHONY : time.obj
|
||||
|
||||
# target to build an object file
|
||||
time.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/time.cpp.obj
|
||||
.PHONY : time.cpp.obj
|
||||
|
||||
time.i: time.cpp.i
|
||||
|
||||
.PHONY : time.i
|
||||
|
||||
# target to preprocess a source file
|
||||
time.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/time.cpp.i
|
||||
.PHONY : time.cpp.i
|
||||
|
||||
time.s: time.cpp.s
|
||||
|
||||
.PHONY : time.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
time.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/time.cpp.s
|
||||
.PHONY : time.cpp.s
|
||||
|
||||
touch.obj: touch.cpp.obj
|
||||
|
||||
.PHONY : touch.obj
|
||||
@ -5108,33 +5216,6 @@ 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
|
||||
wavfile.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/wavfile.cpp.obj
|
||||
.PHONY : wavfile.cpp.obj
|
||||
|
||||
wavfile.i: wavfile.cpp.i
|
||||
|
||||
.PHONY : wavfile.i
|
||||
|
||||
# target to preprocess a source file
|
||||
wavfile.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/wavfile.cpp.i
|
||||
.PHONY : wavfile.cpp.i
|
||||
|
||||
wavfile.s: wavfile.cpp.s
|
||||
|
||||
.PHONY : wavfile.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
wavfile.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/wavfile.cpp.s
|
||||
.PHONY : wavfile.cpp.s
|
||||
|
||||
# Help Target
|
||||
help:
|
||||
@echo "The following are some of the valid targets for this Makefile:"
|
||||
@ -5151,6 +5232,9 @@ help:
|
||||
@echo "... __/chibios-portapack/ext/fatfs/src/ff.obj"
|
||||
@echo "... __/chibios-portapack/ext/fatfs/src/ff.i"
|
||||
@echo "... __/chibios-portapack/ext/fatfs/src/ff.s"
|
||||
@echo "... __/chibios-portapack/ext/fatfs/src/option/unicode.obj"
|
||||
@echo "... __/chibios-portapack/ext/fatfs/src/option/unicode.i"
|
||||
@echo "... __/chibios-portapack/ext/fatfs/src/option/unicode.s"
|
||||
@echo "... __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.obj"
|
||||
@echo "... __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.i"
|
||||
@echo "... __/chibios-portapack/os/hal/platforms/LPC43xx/gpt_lld.s"
|
||||
@ -5352,6 +5436,12 @@ help:
|
||||
@echo "... __/common/ais_packet.obj"
|
||||
@echo "... __/common/ais_packet.i"
|
||||
@echo "... __/common/ais_packet.s"
|
||||
@echo "... __/common/buffer.obj"
|
||||
@echo "... __/common/buffer.i"
|
||||
@echo "... __/common/buffer.s"
|
||||
@echo "... __/common/buffer_exchange.obj"
|
||||
@echo "... __/common/buffer_exchange.i"
|
||||
@echo "... __/common/buffer_exchange.s"
|
||||
@echo "... __/common/chibios_cpp.obj"
|
||||
@echo "... __/common/chibios_cpp.i"
|
||||
@echo "... __/common/chibios_cpp.s"
|
||||
@ -5493,15 +5583,18 @@ help:
|
||||
@echo "... file.obj"
|
||||
@echo "... file.i"
|
||||
@echo "... file.s"
|
||||
@echo "... filewriter.obj"
|
||||
@echo "... filewriter.i"
|
||||
@echo "... filewriter.s"
|
||||
@echo "... freqman.obj"
|
||||
@echo "... freqman.i"
|
||||
@echo "... freqman.s"
|
||||
@echo "... hackrf_cpld_data.obj"
|
||||
@echo "... hackrf_cpld_data.i"
|
||||
@echo "... hackrf_cpld_data.s"
|
||||
@echo "... io_file.obj"
|
||||
@echo "... io_file.i"
|
||||
@echo "... io_file.s"
|
||||
@echo "... io_wave.obj"
|
||||
@echo "... io_wave.i"
|
||||
@echo "... io_wave.s"
|
||||
@echo "... irq_controls.obj"
|
||||
@echo "... irq_controls.i"
|
||||
@echo "... irq_controls.s"
|
||||
@ -5559,6 +5652,9 @@ help:
|
||||
@echo "... rffc507x_spi.obj"
|
||||
@echo "... rffc507x_spi.i"
|
||||
@echo "... rffc507x_spi.s"
|
||||
@echo "... rtc_time.obj"
|
||||
@echo "... rtc_time.i"
|
||||
@echo "... rtc_time.s"
|
||||
@echo "... sd_card.obj"
|
||||
@echo "... sd_card.i"
|
||||
@echo "... sd_card.s"
|
||||
@ -5577,9 +5673,6 @@ help:
|
||||
@echo "... temperature_logger.obj"
|
||||
@echo "... temperature_logger.i"
|
||||
@echo "... temperature_logger.s"
|
||||
@echo "... time.obj"
|
||||
@echo "... time.i"
|
||||
@echo "... time.s"
|
||||
@echo "... touch.obj"
|
||||
@echo "... touch.i"
|
||||
@echo "... touch.s"
|
||||
@ -5697,9 +5790,6 @@ help:
|
||||
@echo "... ui_whistle.obj"
|
||||
@echo "... ui_whistle.i"
|
||||
@echo "... ui_whistle.s"
|
||||
@echo "... wavfile.obj"
|
||||
@echo "... wavfile.i"
|
||||
@echo "... wavfile.s"
|
||||
.PHONY : help
|
||||
|
||||
|
||||
|
@ -185,40 +185,13 @@ void AISRecentEntry::update(const ais::Packet& packet) {
|
||||
|
||||
namespace ui {
|
||||
|
||||
static const std::array<std::pair<std::string, size_t>, 2> ais_columns { {
|
||||
{ "MMSI", 9 },
|
||||
{ "Name/Call", 20 },
|
||||
} };
|
||||
|
||||
template<>
|
||||
void RecentEntriesView<AISRecentEntries>::draw_header(
|
||||
void RecentEntriesTable<AISRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style
|
||||
) {
|
||||
auto x = 0;
|
||||
for(const auto& column : ais_columns) {
|
||||
const auto width = column.second;
|
||||
auto text = column.first;
|
||||
if( width > text.length() ) {
|
||||
text.append(width - text.length(), ' ');
|
||||
}
|
||||
|
||||
painter.draw_string({ x, target_rect.pos.y }, style, text);
|
||||
x += (width * 8) + 8;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void RecentEntriesView<AISRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style,
|
||||
const bool is_selected
|
||||
) {
|
||||
const auto& draw_style = is_selected ? style.invert() : style;
|
||||
|
||||
std::string line = ais::format::mmsi(entry.mmsi) + " ";
|
||||
if( !entry.name.empty() ) {
|
||||
line += entry.name;
|
||||
@ -227,13 +200,13 @@ void RecentEntriesView<AISRecentEntries>::draw(
|
||||
}
|
||||
|
||||
line.resize(target_rect.width() / 8, ' ');
|
||||
painter.draw_string(target_rect.pos, draw_style, line);
|
||||
painter.draw_string(target_rect.location(), style, line);
|
||||
}
|
||||
|
||||
AISRecentEntryDetailView::AISRecentEntryDetailView() {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&button_done,
|
||||
} });
|
||||
});
|
||||
|
||||
button_done.on_select = [this](const ui::Button&) {
|
||||
if( this->on_close ) {
|
||||
@ -291,7 +264,7 @@ void AISRecentEntryDetailView::set_entry(const AISRecentEntry& entry) {
|
||||
AISAppView::AISAppView(NavigationView&) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_ais);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&label_channel,
|
||||
&options_channel,
|
||||
&field_rf_amp,
|
||||
@ -301,7 +274,7 @@ AISAppView::AISAppView(NavigationView&) {
|
||||
&channel,
|
||||
&recent_entries_view,
|
||||
&recent_entry_detail_view,
|
||||
} });
|
||||
});
|
||||
|
||||
recent_entry_detail_view.hidden(true);
|
||||
|
||||
@ -315,7 +288,6 @@ AISAppView::AISAppView(NavigationView&) {
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
1,
|
||||
});
|
||||
|
||||
options_channel.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
@ -332,7 +304,7 @@ AISAppView::AISAppView(NavigationView&) {
|
||||
|
||||
logger = std::make_unique<AISLogger>();
|
||||
if( logger ) {
|
||||
logger->append("ais.txt");
|
||||
logger->append(u"ais.txt");
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,12 +330,13 @@ void AISAppView::on_packet(const ais::Packet& packet) {
|
||||
logger->on_packet(packet);
|
||||
}
|
||||
|
||||
const auto updated_entry = recent.on_packet(packet.source_id(), packet);
|
||||
auto& entry = ::on_packet(recent, packet.source_id());
|
||||
entry.update(packet);
|
||||
recent_entries_view.set_dirty();
|
||||
|
||||
// TODO: Crude hack, should be a more formal listener arrangement...
|
||||
if( updated_entry.key() == recent_entry_detail_view.entry().key() ) {
|
||||
recent_entry_detail_view.set_entry(updated_entry);
|
||||
if( entry.key() == recent_entry_detail_view.entry().key() ) {
|
||||
recent_entry_detail_view.set_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,8 @@ using namespace lpc43xx;
|
||||
|
||||
struct AISPosition {
|
||||
rtc::RTC timestamp { };
|
||||
ais::Latitude latitude;
|
||||
ais::Longitude longitude;
|
||||
ais::Latitude latitude { };
|
||||
ais::Longitude longitude { };
|
||||
ais::RateOfTurn rate_of_turn { -128 };
|
||||
ais::SpeedOverGround speed_over_ground { 1023 };
|
||||
ais::CourseOverGround course_over_ground { 3600 };
|
||||
@ -78,6 +78,9 @@ struct AISRecentEntry {
|
||||
AISRecentEntry(
|
||||
const ais::MMSI& mmsi
|
||||
) : mmsi { mmsi },
|
||||
name { },
|
||||
call_sign { },
|
||||
destination { },
|
||||
last_position { },
|
||||
received_count { 0 },
|
||||
navigational_status { -1 }
|
||||
@ -91,18 +94,18 @@ struct AISRecentEntry {
|
||||
void update(const ais::Packet& packet);
|
||||
};
|
||||
|
||||
using AISRecentEntries = RecentEntries<ais::Packet, AISRecentEntry>;
|
||||
using AISRecentEntries = RecentEntries<AISRecentEntry>;
|
||||
|
||||
class AISLogger {
|
||||
public:
|
||||
Optional<File::Error> append(const std::string& filename) {
|
||||
Optional<File::Error> append(const std::filesystem::path& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void on_packet(const ais::Packet& packet);
|
||||
|
||||
private:
|
||||
LogFile log_file;
|
||||
LogFile log_file { };
|
||||
};
|
||||
|
||||
namespace ui {
|
||||
@ -111,7 +114,7 @@ using AISRecentEntriesView = RecentEntriesView<AISRecentEntries>;
|
||||
|
||||
class AISRecentEntryDetailView : public View {
|
||||
public:
|
||||
std::function<void(void)> on_close;
|
||||
std::function<void(void)> on_close { };
|
||||
|
||||
AISRecentEntryDetailView();
|
||||
|
||||
@ -122,7 +125,7 @@ public:
|
||||
void paint(Painter&) override;
|
||||
|
||||
private:
|
||||
AISRecentEntry entry_;
|
||||
AISRecentEntry entry_ { };
|
||||
|
||||
Button button_done {
|
||||
{ 72, 216, 96, 24 },
|
||||
@ -158,11 +161,15 @@ private:
|
||||
static constexpr uint32_t sampling_rate = 2457600;
|
||||
static constexpr uint32_t baseband_bandwidth = 1750000;
|
||||
|
||||
AISRecentEntries recent;
|
||||
std::unique_ptr<AISLogger> logger;
|
||||
AISRecentEntries recent { };
|
||||
std::unique_ptr<AISLogger> logger { };
|
||||
|
||||
AISRecentEntriesView recent_entries_view { recent };
|
||||
AISRecentEntryDetailView recent_entry_detail_view;
|
||||
const RecentEntriesColumns columns { {
|
||||
{ "MMSI", 9 },
|
||||
{ "Name/Call", 20 },
|
||||
} };
|
||||
AISRecentEntriesView recent_entries_view { columns, recent };
|
||||
AISRecentEntryDetailView recent_entry_detail_view { };
|
||||
|
||||
static constexpr auto header_height = 1 * 16;
|
||||
|
||||
|
@ -44,10 +44,10 @@ AMOptionsView::AMOptionsView(
|
||||
{
|
||||
set_style(style);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&label_config,
|
||||
&options_config,
|
||||
} });
|
||||
});
|
||||
|
||||
options_config.set_selected_index(receiver_model.am_configuration());
|
||||
options_config.on_change = [this](size_t n, OptionsField::value_t) {
|
||||
@ -63,10 +63,10 @@ NBFMOptionsView::NBFMOptionsView(
|
||||
{
|
||||
set_style(style);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&label_config,
|
||||
&options_config,
|
||||
} });
|
||||
});
|
||||
|
||||
options_config.set_selected_index(receiver_model.nbfm_configuration());
|
||||
options_config.on_change = [this](size_t n, OptionsField::value_t) {
|
||||
@ -79,7 +79,7 @@ NBFMOptionsView::NBFMOptionsView(
|
||||
AnalogAudioView::AnalogAudioView(
|
||||
NavigationView& nav
|
||||
) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&rssi,
|
||||
&channel,
|
||||
&audio,
|
||||
@ -90,7 +90,7 @@ AnalogAudioView::AnalogAudioView(
|
||||
&field_volume,
|
||||
&record_view,
|
||||
&waterfall,
|
||||
} });
|
||||
});
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
@ -161,7 +161,7 @@ void AnalogAudioView::on_hide() {
|
||||
void AnalogAudioView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), static_cast<ui::Dim>(new_parent_rect.height() - header_height) };
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
|
||||
|
@ -139,14 +139,14 @@ private:
|
||||
' ',
|
||||
};
|
||||
|
||||
std::unique_ptr<Widget> options_widget;
|
||||
std::unique_ptr<Widget> options_widget { };
|
||||
|
||||
RecordView record_view {
|
||||
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
||||
"AUD_????", RecordView::FileType::WAV, 4096, 4
|
||||
u"AUD_????", RecordView::FileType::WAV, 4096, 4
|
||||
};
|
||||
|
||||
spectrum::WaterfallWidget waterfall;
|
||||
spectrum::WaterfallWidget waterfall { };
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
|
||||
|
@ -225,4 +225,14 @@ void capture_stop() {
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void replay_start(CaptureConfig* const config) {
|
||||
CaptureConfigMessage message { config };
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void replay_stop() {
|
||||
CaptureConfigMessage message { nullptr };
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
} /* namespace baseband */
|
||||
|
@ -75,6 +75,8 @@ void spectrum_streaming_stop();
|
||||
|
||||
void capture_start(CaptureConfig* const config);
|
||||
void capture_stop();
|
||||
void replay_start(CaptureConfig* const config);
|
||||
void replay_stop();
|
||||
|
||||
} /* namespace baseband */
|
||||
|
||||
|
@ -27,25 +27,12 @@ using namespace hackrf::one;
|
||||
namespace baseband {
|
||||
|
||||
void CPLD::init() {
|
||||
set_decimation_by(1);
|
||||
gpios_baseband_decimation[0].output();
|
||||
gpios_baseband_decimation[1].output();
|
||||
gpios_baseband_decimation[2].output();
|
||||
|
||||
set_q_invert(false);
|
||||
gpio_baseband_q_invert.output();
|
||||
set_invert(false);
|
||||
gpio_baseband_invert.output();
|
||||
}
|
||||
|
||||
void CPLD::set_decimation_by(const uint8_t n) {
|
||||
const uint8_t skip_n = n - 1;
|
||||
const uint8_t value = skip_n ^ 7;
|
||||
gpios_baseband_decimation[0].write(value & 1);
|
||||
gpios_baseband_decimation[1].write(value & 2);
|
||||
gpios_baseband_decimation[2].write(value & 4);
|
||||
}
|
||||
|
||||
void CPLD::set_q_invert(const bool invert) {
|
||||
gpio_baseband_q_invert.write(invert);
|
||||
void CPLD::set_invert(const bool invert) {
|
||||
gpio_baseband_invert.write(invert);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,8 +30,7 @@ class CPLD {
|
||||
public:
|
||||
void init();
|
||||
|
||||
void set_decimation_by(const uint8_t n);
|
||||
void set_q_invert(const bool invert);
|
||||
void set_invert(const bool invert);
|
||||
|
||||
private:
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ namespace ui {
|
||||
CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_capture);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&rssi,
|
||||
&channel,
|
||||
&field_frequency,
|
||||
@ -44,7 +44,7 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
&field_vga,
|
||||
&record_view,
|
||||
&waterfall,
|
||||
} });
|
||||
});
|
||||
|
||||
field_frequency.set_value(target_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
@ -74,7 +74,6 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
1,
|
||||
});
|
||||
|
||||
record_view.set_sampling_rate(sampling_rate / 8);
|
||||
@ -99,7 +98,7 @@ void CaptureAppView::on_hide() {
|
||||
void CaptureAppView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), static_cast<ui::Dim>(new_parent_rect.height() - header_height) };
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
|
||||
|
@ -89,10 +89,10 @@ private:
|
||||
|
||||
RecordView record_view {
|
||||
{ 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
"BBD_????", RecordView::FileType::RawS16, 16384, 3
|
||||
u"BBD_????", RecordView::FileType::RawS16, 16384, 3
|
||||
};
|
||||
|
||||
spectrum::WaterfallWidget waterfall;
|
||||
spectrum::WaterfallWidget waterfall { };
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
@ -22,60 +22,22 @@
|
||||
#include "capture_thread.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "buffer_exchange.hpp"
|
||||
|
||||
// StreamOutput ///////////////////////////////////////////////////////////
|
||||
|
||||
class StreamOutput {
|
||||
public:
|
||||
StreamOutput(CaptureConfig* const config);
|
||||
~StreamOutput();
|
||||
|
||||
size_t available() {
|
||||
return fifo_buffers_full->len();
|
||||
struct BasebandCapture {
|
||||
BasebandCapture(CaptureConfig* const config) {
|
||||
baseband::capture_start(config);
|
||||
}
|
||||
|
||||
StreamBuffer* get_buffer() {
|
||||
StreamBuffer* p { nullptr };
|
||||
fifo_buffers_full->out(p);
|
||||
return p;
|
||||
~BasebandCapture() {
|
||||
baseband::capture_stop();
|
||||
}
|
||||
|
||||
bool release_buffer(StreamBuffer* const p) {
|
||||
p->empty();
|
||||
return fifo_buffers_empty->in(p);
|
||||
}
|
||||
|
||||
static FIFO<StreamBuffer*>* fifo_buffers_empty;
|
||||
static FIFO<StreamBuffer*>* fifo_buffers_full;
|
||||
|
||||
private:
|
||||
CaptureConfig* const config;
|
||||
};
|
||||
|
||||
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_empty = nullptr;
|
||||
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_full = nullptr;
|
||||
|
||||
StreamOutput::StreamOutput(
|
||||
CaptureConfig* const config
|
||||
) : config { config }
|
||||
{
|
||||
baseband::capture_start(config);
|
||||
fifo_buffers_empty = config->fifo_buffers_empty;
|
||||
fifo_buffers_full = config->fifo_buffers_full;
|
||||
}
|
||||
|
||||
StreamOutput::~StreamOutput() {
|
||||
fifo_buffers_full = nullptr;
|
||||
fifo_buffers_empty = nullptr;
|
||||
baseband::capture_stop();
|
||||
}
|
||||
|
||||
// CaptureThread //////////////////////////////////////////////////////////
|
||||
|
||||
Thread* CaptureThread::thread = nullptr;
|
||||
|
||||
CaptureThread::CaptureThread(
|
||||
std::unique_ptr<Writer> writer,
|
||||
std::unique_ptr<stream::Writer> writer,
|
||||
size_t write_size,
|
||||
size_t buffer_count,
|
||||
std::function<void()> success_callback,
|
||||
@ -92,23 +54,11 @@ CaptureThread::CaptureThread(
|
||||
CaptureThread::~CaptureThread() {
|
||||
if( thread ) {
|
||||
chThdTerminate(thread);
|
||||
chEvtSignal(thread, event_mask_loop_wake);
|
||||
chThdWait(thread);
|
||||
thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureThread::check_fifo_isr() {
|
||||
// TODO: Prevent over-signalling by transmitting a set of
|
||||
// flags from the baseband core.
|
||||
const auto fifo = StreamOutput::fifo_buffers_full;
|
||||
if( fifo ) {
|
||||
if( !fifo->is_empty() ) {
|
||||
chEvtSignalI(thread, event_mask_loop_wake);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg_t CaptureThread::static_fn(void* arg) {
|
||||
auto obj = static_cast<CaptureThread*>(arg);
|
||||
const auto error = obj->run();
|
||||
@ -123,19 +73,17 @@ msg_t CaptureThread::static_fn(void* arg) {
|
||||
}
|
||||
|
||||
Optional<File::Error> CaptureThread::run() {
|
||||
StreamOutput stream { &config };
|
||||
BasebandCapture capture { &config };
|
||||
BufferExchange buffers { &config };
|
||||
|
||||
while( !chThdShouldTerminate() ) {
|
||||
if( stream.available() ) {
|
||||
auto buffer = stream.get_buffer();
|
||||
auto write_result = writer->write(buffer->data(), buffer->size());
|
||||
if( write_result.is_error() ) {
|
||||
return write_result.error();
|
||||
}
|
||||
stream.release_buffer(buffer);
|
||||
} else {
|
||||
chEvtWaitAny(event_mask_loop_wake);
|
||||
auto buffer = buffers.get();
|
||||
auto write_result = writer->write(buffer->data(), buffer->size());
|
||||
if( write_result.is_error() ) {
|
||||
return write_result.error();
|
||||
}
|
||||
buffer->empty();
|
||||
buffers.put(buffer);
|
||||
}
|
||||
|
||||
return { };
|
||||
|
@ -26,23 +26,17 @@
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "io.hpp"
|
||||
#include "optional.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
virtual File::Result<size_t> write(const void* const buffer, const size_t bytes) = 0;
|
||||
virtual ~Writer() = default;
|
||||
};
|
||||
|
||||
class CaptureThread {
|
||||
public:
|
||||
CaptureThread(
|
||||
std::unique_ptr<Writer> writer,
|
||||
std::unique_ptr<stream::Writer> writer,
|
||||
size_t write_size,
|
||||
size_t buffer_count,
|
||||
std::function<void()> success_callback,
|
||||
@ -50,20 +44,21 @@ public:
|
||||
);
|
||||
~CaptureThread();
|
||||
|
||||
CaptureThread(const CaptureThread&) = delete;
|
||||
CaptureThread(CaptureThread&&) = delete;
|
||||
CaptureThread& operator=(const CaptureThread&) = delete;
|
||||
CaptureThread& operator=(CaptureThread&&) = delete;
|
||||
|
||||
const CaptureConfig& state() const {
|
||||
return config;
|
||||
}
|
||||
|
||||
static void check_fifo_isr();
|
||||
|
||||
private:
|
||||
static constexpr auto event_mask_loop_wake = EVENT_MASK(0);
|
||||
|
||||
CaptureConfig config;
|
||||
std::unique_ptr<Writer> writer;
|
||||
std::unique_ptr<stream::Writer> writer;
|
||||
std::function<void()> success_callback;
|
||||
std::function<void(File::Error)> error_callback;
|
||||
static Thread* thread;
|
||||
Thread* thread { nullptr };
|
||||
|
||||
static msg_t static_fn(void* arg);
|
||||
|
||||
|
@ -219,7 +219,7 @@ constexpr ClockControl::Type si5351_clock_control_ms_src_clkin = ClockControl::M
|
||||
|
||||
constexpr ClockControls si5351_clock_control_common {
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Fractional | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Invert | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_8mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_8mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
mask_t mask;
|
||||
mask_t mask { };
|
||||
};
|
||||
|
||||
#endif/*__DIRTY_REGISTERS_H__*/
|
||||
|
@ -75,42 +75,13 @@ void ERTRecentEntry::update(const ert::Packet& packet) {
|
||||
|
||||
namespace ui {
|
||||
|
||||
static const std::array<std::pair<std::string, size_t>, 4> ert_columns { {
|
||||
{ "ID", 10 },
|
||||
{ "Tp", 2 },
|
||||
{ "Consumpt", 10 },
|
||||
{ "Cnt", 3 },
|
||||
} };
|
||||
|
||||
template<>
|
||||
void RecentEntriesView<ERTRecentEntries>::draw_header(
|
||||
void RecentEntriesTable<ERTRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style
|
||||
) {
|
||||
auto x = 0;
|
||||
for(const auto& column : ert_columns) {
|
||||
const auto width = column.second;
|
||||
auto text = column.first;
|
||||
if( width > text.length() ) {
|
||||
text.append(width - text.length(), ' ');
|
||||
}
|
||||
|
||||
painter.draw_string({ x, target_rect.pos.y }, style, text);
|
||||
x += (width * 8) + 8;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void RecentEntriesView<ERTRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style,
|
||||
const bool is_selected
|
||||
) {
|
||||
const auto& draw_style = is_selected ? style.invert() : style;
|
||||
|
||||
std::string line = ert::format::id(entry.id) + " " + ert::format::commodity_type(entry.commodity_type) + " " + ert::format::consumption(entry.last_consumption);
|
||||
|
||||
if( entry.received_count > 999 ) {
|
||||
@ -120,19 +91,19 @@ void RecentEntriesView<ERTRecentEntries>::draw(
|
||||
}
|
||||
|
||||
line.resize(target_rect.width() / 8, ' ');
|
||||
painter.draw_string(target_rect.pos, draw_style, line);
|
||||
painter.draw_string(target_rect.location(), style, line);
|
||||
}
|
||||
|
||||
ERTAppView::ERTAppView(NavigationView&) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_ert);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&field_rf_amp,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&rssi,
|
||||
&recent_entries_view,
|
||||
} });
|
||||
});
|
||||
|
||||
radio::enable({
|
||||
initial_target_frequency,
|
||||
@ -142,12 +113,11 @@ ERTAppView::ERTAppView(NavigationView&) {
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
1,
|
||||
});
|
||||
|
||||
logger = std::make_unique<ERTLogger>();
|
||||
if( logger ) {
|
||||
logger->append("ert.txt");
|
||||
logger->append(u"ert.txt");
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,7 +142,8 @@ void ERTAppView::on_packet(const ert::Packet& packet) {
|
||||
}
|
||||
|
||||
if( packet.crc_ok() ) {
|
||||
recent.on_packet({ packet.id(), packet.commodity_type() }, packet);
|
||||
auto& entry = ::on_packet(recent, ERTRecentEntry::Key { packet.id(), packet.commodity_type() });
|
||||
entry.update(packet);
|
||||
recent_entries_view.set_dirty();
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ struct ERTRecentEntry {
|
||||
|
||||
size_t received_count { 0 };
|
||||
|
||||
ert::Consumption last_consumption;
|
||||
ert::Consumption last_consumption { };
|
||||
|
||||
ERTRecentEntry(
|
||||
const Key& key
|
||||
@ -90,17 +90,17 @@ struct ERTRecentEntry {
|
||||
|
||||
class ERTLogger {
|
||||
public:
|
||||
Optional<File::Error> append(const std::string& filename) {
|
||||
Optional<File::Error> append(const std::filesystem::path& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void on_packet(const ert::Packet& packet);
|
||||
|
||||
private:
|
||||
LogFile log_file;
|
||||
LogFile log_file { };
|
||||
};
|
||||
|
||||
using ERTRecentEntries = RecentEntries<ert::Packet, ERTRecentEntry>;
|
||||
using ERTRecentEntries = RecentEntries<ERTRecentEntry>;
|
||||
|
||||
namespace ui {
|
||||
|
||||
@ -126,10 +126,16 @@ public:
|
||||
std::string title() const override { return "ERT"; };
|
||||
|
||||
private:
|
||||
ERTRecentEntries recent;
|
||||
std::unique_ptr<ERTLogger> logger;
|
||||
ERTRecentEntries recent { };
|
||||
std::unique_ptr<ERTLogger> logger { };
|
||||
|
||||
ERTRecentEntriesView recent_entries_view { recent };
|
||||
const RecentEntriesColumns columns { {
|
||||
{ "ID", 10 },
|
||||
{ "Tp", 2 },
|
||||
{ "Consumpt", 10 },
|
||||
{ "Cnt", 3 },
|
||||
} };
|
||||
ERTRecentEntriesView recent_entries_view { columns, recent };
|
||||
|
||||
static constexpr auto header_height = 1 * 16;
|
||||
|
||||
|
@ -25,14 +25,14 @@
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
#include "sd_card.hpp"
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
#include "message.hpp"
|
||||
#include "message_queue.hpp"
|
||||
|
||||
#include "irq_controls.hpp"
|
||||
|
||||
#include "capture_thread.hpp"
|
||||
#include "buffer_exchange.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
@ -49,7 +49,7 @@ CH_IRQ_HANDLER(M4Core_IRQHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
chSysLockFromIsr();
|
||||
CaptureThread::check_fifo_isr();
|
||||
BufferExchange::handle_isr();
|
||||
EventDispatcher::check_fifo_isr();
|
||||
chSysUnlockFromIsr();
|
||||
|
||||
@ -86,7 +86,7 @@ public:
|
||||
|
||||
private:
|
||||
using MapType = std::array<MessageHandler, toUType(Message::ID::MAX)>;
|
||||
MapType map_;
|
||||
MapType map_ { };
|
||||
};
|
||||
|
||||
static MessageHandlerMap message_map;
|
||||
@ -235,7 +235,7 @@ void EventDispatcher::handle_rtc_tick() {
|
||||
portapack::bl_tick_counter++;
|
||||
}
|
||||
|
||||
time::on_tick_second();
|
||||
rtc_time::on_tick_second();
|
||||
}
|
||||
|
||||
ui::Widget* EventDispatcher::touch_widget(ui::Widget* const w, ui::TouchEvent event) {
|
||||
|
@ -49,6 +49,11 @@ public:
|
||||
ui::Context& context
|
||||
);
|
||||
|
||||
EventDispatcher(const EventDispatcher&) = delete;
|
||||
EventDispatcher(EventDispatcher&&) = delete;
|
||||
EventDispatcher& operator=(const EventDispatcher&) = delete;
|
||||
EventDispatcher& operator=(EventDispatcher&&) = delete;
|
||||
|
||||
void run();
|
||||
static void request_stop();
|
||||
|
||||
@ -94,7 +99,7 @@ private:
|
||||
|
||||
static Thread* thread_event_loop;
|
||||
|
||||
touch::Manager touch_manager;
|
||||
touch::Manager touch_manager { };
|
||||
ui::Widget* const top_widget;
|
||||
ui::Painter painter;
|
||||
ui::Context& context;
|
||||
|
@ -2,10 +2,10 @@
|
||||
#include "ch.h"
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 64180 /* Revision ID */
|
||||
#define _FFCONF 80186 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
@ -22,8 +22,8 @@
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: All basic functions are enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
|
||||
/ f_truncate() and f_rename() function are removed.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
||||
/ are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
@ -38,8 +38,8 @@
|
||||
|
||||
|
||||
#define _USE_FIND 1
|
||||
/* This option switches filtered directory read feature and related functions,
|
||||
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
|
||||
#define _USE_MKFS 0
|
||||
@ -47,7 +47,16 @@
|
||||
|
||||
|
||||
#define _USE_FASTSEEK 1
|
||||
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_EXPAND 0
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_CHMOD 0
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
#define _USE_LABEL 0
|
||||
@ -56,8 +65,7 @@
|
||||
|
||||
|
||||
#define _USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable)
|
||||
/ To enable it, also _FS_TINY need to be set to 1. */
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
@ -93,30 +101,32 @@
|
||||
*/
|
||||
|
||||
|
||||
#define _USE_LFN 0
|
||||
#define _USE_LFN 2
|
||||
#define _MAX_LFN 255
|
||||
/* The _USE_LFN option switches the LFN feature.
|
||||
/* The _USE_LFN switches the support of long file name (LFN).
|
||||
/
|
||||
/ 0: Disable LFN feature. _MAX_LFN has no effect.
|
||||
/ 0: Disable support of LFN. _MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
|
||||
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
|
||||
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added
|
||||
/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
|
||||
/ It should be set 255 to support full featured LFN operations.
|
||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||
/ ff_memfree(), must be added to the project. */
|
||||
|
||||
|
||||
#define _LFN_UNICODE 0
|
||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
|
||||
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
|
||||
/ to 1. This option also affects behavior of string I/O functions. */
|
||||
#define _LFN_UNICODE 1
|
||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
|
||||
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
||||
/ This option also affects behavior of string I/O functions. */
|
||||
|
||||
|
||||
#define _STRF_ENCODE 3
|
||||
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
||||
/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
|
||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||
/
|
||||
/ 0: ANSI/OEM
|
||||
@ -124,17 +134,16 @@
|
||||
/ 2: UTF-16BE
|
||||
/ 3: UTF-8
|
||||
/
|
||||
/ When _LFN_UNICODE is 0, this option has no effect. */
|
||||
/ This option has no effect when _LFN_UNICODE == 0. */
|
||||
|
||||
|
||||
#define _FS_RPATH 0
|
||||
/* This option configures relative path feature.
|
||||
/* This option configures support of relative path.
|
||||
/
|
||||
/ 0: Disable relative path feature and remove related functions.
|
||||
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
||||
/ 2: f_getcwd() function is available in addition to 1.
|
||||
/
|
||||
/ Note that directory items read via f_readdir() are affected by this option. */
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
@ -146,8 +155,8 @@
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
|
||||
/* _STR_VOLUME_ID option switches string volume ID feature.
|
||||
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
|
||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
|
||||
@ -155,11 +164,12 @@
|
||||
|
||||
|
||||
#define _MULTI_PARTITION 0
|
||||
/* This option switches multi-partition feature. By default (0), each logical drive
|
||||
/ number is bound to the same physical drive number and only an FAT volume found on
|
||||
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
|
||||
/ each logical drive number is bound to arbitrary physical drive and partition
|
||||
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
|
||||
/* This option switches support of multi-partition on a physical drive.
|
||||
/ By default (0), each logical drive number is bound to the same physical drive
|
||||
/ number and only an FAT volume found on the physical drive will be mounted.
|
||||
/ When multi-partition is enabled (1), each logical drive number can be bound to
|
||||
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
||||
/ funciton will be available. */
|
||||
|
||||
|
||||
#define _MIN_SS 512
|
||||
@ -173,8 +183,8 @@
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
|
||||
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
|
||||
/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
|
||||
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
@ -197,46 +207,51 @@
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||
/ data transfer. */
|
||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||
|
||||
|
||||
#define _FS_EXFAT 0
|
||||
/* This option switches support of exFAT file system in addition to the traditional
|
||||
/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
|
||||
/ Note that enabling exFAT discards C89 compatibility. */
|
||||
|
||||
|
||||
#define _FS_NORTC 0
|
||||
#define _NORTC_MON 1
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2015
|
||||
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
||||
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
||||
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
||||
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
||||
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
||||
#define _NORTC_YEAR 2016
|
||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
|
||||
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to get current time form real-time clock. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
|
||||
|
||||
|
||||
#define _FS_LOCK 0
|
||||
/* The _FS_LOCK option switches file lock feature to control duplicated file open
|
||||
/* The option _FS_LOCK switches file lock function to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock feature. To avoid volume corruption, application program
|
||||
/ 0: Disable file lock function. To avoid volume corruption, application program
|
||||
/ should avoid illegal open, remove and rename to the open objects.
|
||||
/ >0: Enable file lock feature. The value defines how many files/sub-directories
|
||||
/ >0: Enable file lock function. The value defines how many files/sub-directories
|
||||
/ can be opened simultaneously under file lock control. Note that the file
|
||||
/ lock feature is independent of re-entrancy. */
|
||||
/ lock control is independent of re-entrancy. */
|
||||
|
||||
|
||||
#define _FS_REENTRANT 1
|
||||
#define _FS_TIMEOUT 1000
|
||||
#define _SYNC_t Semaphore *
|
||||
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
|
||||
/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
|
||||
/ module itself. Note that regardless of this option, file access to different
|
||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||
/ to the same volume is under control of this feature.
|
||||
/ to the same volume is under control of this function.
|
||||
/
|
||||
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
|
||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||
@ -250,30 +265,4 @@
|
||||
/ included somewhere in the scope of ff.c. */
|
||||
|
||||
|
||||
#define _WORD_ACCESS 0
|
||||
/* The _WORD_ACCESS option is an only platform dependent option. It defines
|
||||
/ which access method is used to the word data on the FAT volume.
|
||||
/
|
||||
/ 0: Byte-by-byte access. Always compatible with all platforms.
|
||||
/ 1: Word access. Do not choose this unless under both the following conditions.
|
||||
/
|
||||
/ * Address misaligned memory access is always allowed to ALL instructions.
|
||||
/ * Byte order on the memory is little-endian.
|
||||
/
|
||||
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
||||
/ Following table shows allowable settings of some type of processors.
|
||||
/
|
||||
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
|
||||
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
|
||||
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1
|
||||
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
|
||||
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2
|
||||
/ PIC18 0/1 SH-2 0 *1 M16C 0/1
|
||||
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
|
||||
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
|
||||
/
|
||||
/ *1:Big-endian.
|
||||
/ *2:Unaligned memory access is not supported.
|
||||
/ *3:Some compilers generate LDM/STM for mem_cpy function.
|
||||
*/
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
@ -23,16 +23,11 @@
|
||||
#include "file.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */
|
||||
static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected.");
|
||||
#define FR_DISK_FULL (0x100)
|
||||
#define FR_EOF (0x101)
|
||||
#define FR_BAD_SEEK (0x102)
|
||||
#define FR_UNEXPECTED (0x103)
|
||||
|
||||
Optional<File::Error> File::open_fatfs(const std::string& filename, BYTE mode) {
|
||||
auto result = f_open(&f, filename.c_str(), mode);
|
||||
Optional<File::Error> File::open_fatfs(const std::filesystem::path& filename, BYTE mode) {
|
||||
auto result = f_open(&f, reinterpret_cast<const TCHAR*>(filename.c_str()), mode);
|
||||
if( result == FR_OK ) {
|
||||
if( mode & FA_OPEN_ALWAYS ) {
|
||||
const auto result = f_lseek(&f, f_size(&f));
|
||||
@ -49,15 +44,15 @@ Optional<File::Error> File::open_fatfs(const std::string& filename, BYTE mode) {
|
||||
}
|
||||
}
|
||||
|
||||
Optional<File::Error> File::open(const std::string& filename) {
|
||||
Optional<File::Error> File::open(const std::filesystem::path& filename) {
|
||||
return open_fatfs(filename, FA_READ);
|
||||
}
|
||||
|
||||
Optional<File::Error> File::append(const std::string& filename) {
|
||||
Optional<File::Error> File::append(const std::filesystem::path& filename) {
|
||||
return open_fatfs(filename, FA_WRITE | FA_OPEN_ALWAYS);
|
||||
}
|
||||
|
||||
Optional<File::Error> File::create(const std::string& filename) {
|
||||
Optional<File::Error> File::create(const std::filesystem::path& filename) {
|
||||
return open_fatfs(filename, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
}
|
||||
|
||||
@ -65,7 +60,7 @@ File::~File() {
|
||||
f_close(&f);
|
||||
}
|
||||
|
||||
File::Result<size_t> File::read(void* const data, const size_t bytes_to_read) {
|
||||
File::Result<File::Size> File::read(void* const data, const Size bytes_to_read) {
|
||||
UINT bytes_read = 0;
|
||||
const auto result = f_read(&f, data, bytes_to_read, &bytes_read);
|
||||
if( result == FR_OK ) {
|
||||
@ -75,12 +70,12 @@ File::Result<size_t> File::read(void* const data, const size_t bytes_to_read) {
|
||||
}
|
||||
}
|
||||
|
||||
File::Result<size_t> File::write(const void* const data, const size_t bytes_to_write) {
|
||||
File::Result<File::Size> File::write(const void* const data, const Size bytes_to_write) {
|
||||
UINT bytes_written = 0;
|
||||
const auto result = f_write(&f, data, bytes_to_write, &bytes_written);
|
||||
if( result == FR_OK ) {
|
||||
if( bytes_to_write == bytes_written ) {
|
||||
return { static_cast<size_t>(bytes_written) };
|
||||
return { static_cast<File::Size>(bytes_written) };
|
||||
} else {
|
||||
return Error { FR_DISK_FULL };
|
||||
}
|
||||
@ -89,7 +84,7 @@ File::Result<size_t> File::write(const void* const data, const size_t bytes_to_w
|
||||
}
|
||||
}
|
||||
|
||||
File::Result<uint64_t> File::seek(const uint64_t new_position) {
|
||||
File::Result<File::Offset> File::seek(const Offset new_position) {
|
||||
/* NOTE: Returns *old* position, not new position */
|
||||
const auto old_position = f_tell(&f);
|
||||
const auto result = f_lseek(&f, new_position);
|
||||
@ -99,7 +94,7 @@ File::Result<uint64_t> File::seek(const uint64_t new_position) {
|
||||
if( f_tell(&f) != new_position ) {
|
||||
return { static_cast<Error>(FR_BAD_SEEK) };
|
||||
}
|
||||
return { static_cast<uint64_t>(old_position) };
|
||||
return { static_cast<File::Offset>(old_position) };
|
||||
}
|
||||
|
||||
Optional<File::Error> File::write_line(const std::string& s) {
|
||||
@ -125,11 +120,11 @@ Optional<File::Error> File::sync() {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string find_last_file_matching_pattern(const std::string& pattern) {
|
||||
std::string last_match;
|
||||
for(const auto& entry : std::filesystem::directory_iterator("", pattern.c_str())) {
|
||||
static std::filesystem::path find_last_file_matching_pattern(const std::filesystem::path& pattern) {
|
||||
std::filesystem::path last_match;
|
||||
for(const auto& entry : std::filesystem::directory_iterator(u"", pattern)) {
|
||||
if( std::filesystem::is_regular_file(entry.status()) ) {
|
||||
const auto match = entry.path();
|
||||
const auto& match = entry.path();
|
||||
if( match > last_match ) {
|
||||
last_match = match;
|
||||
}
|
||||
@ -138,18 +133,12 @@ static std::string find_last_file_matching_pattern(const std::string& pattern) {
|
||||
return last_match;
|
||||
}
|
||||
|
||||
std::string remove_filename_extension(const std::string& filename) {
|
||||
const auto extension_index = filename.find_last_of('.');
|
||||
return filename.substr(0, extension_index);
|
||||
}
|
||||
|
||||
static std::string increment_filename_stem_ordinal(const std::string& filename_stem) {
|
||||
std::string result { filename_stem };
|
||||
|
||||
auto it = result.rbegin();
|
||||
static std::filesystem::path increment_filename_stem_ordinal(std::filesystem::path path) {
|
||||
auto t = path.replace_extension().native();
|
||||
auto it = t.rbegin();
|
||||
|
||||
// Increment decimal number before the extension.
|
||||
for(; it != result.rend(); ++it) {
|
||||
for(; it != t.rend(); ++it) {
|
||||
const auto c = *it;
|
||||
if( c < '0' ) {
|
||||
return { };
|
||||
@ -163,36 +152,35 @@ static std::string increment_filename_stem_ordinal(const std::string& filename_s
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return t;
|
||||
}
|
||||
|
||||
std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern) {
|
||||
const auto filename = find_last_file_matching_pattern(filename_stem_pattern + ".*");
|
||||
auto filename_stem = remove_filename_extension(filename);
|
||||
if( filename_stem.empty() ) {
|
||||
filename_stem = filename_stem_pattern;
|
||||
std::replace(std::begin(filename_stem), std::end(filename_stem), '?', '0');
|
||||
std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_pattern) {
|
||||
const auto next_filename = find_last_file_matching_pattern(filename_pattern.replace_extension(u".*"));
|
||||
if( next_filename.empty() ) {
|
||||
auto pattern_s = filename_pattern.replace_extension().native();
|
||||
std::replace(std::begin(pattern_s), std::end(pattern_s), '?', '0');
|
||||
return pattern_s;
|
||||
} else {
|
||||
filename_stem = increment_filename_stem_ordinal(filename_stem);
|
||||
return increment_filename_stem_ordinal(next_filename);
|
||||
}
|
||||
return filename_stem;
|
||||
}
|
||||
|
||||
std::vector<std::string> scan_root_files(const std::string& directory, const std::string& extension) {
|
||||
std::vector<std::string> file_list { };
|
||||
std::string fname;
|
||||
std::vector<std::filesystem::path> scan_root_files(const TCHAR* directory, const std::string& extension) {
|
||||
std::vector<std::filesystem::path> file_list { };
|
||||
std::filesystem::path file_path;
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
static FILINFO fno;
|
||||
|
||||
res = f_opendir(&dir, directory.c_str());
|
||||
res = f_opendir(&dir, directory);
|
||||
if (res == FR_OK) {
|
||||
for (;;) {
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res != FR_OK || fno.fname[0] == 0) break;
|
||||
fname.assign(fno.fname);
|
||||
if (fname.find(extension) != std::string::npos)
|
||||
file_list.push_back(fname);
|
||||
file_path = fno.fname;
|
||||
if (file_path.extension().string() == extension)
|
||||
file_list.push_back(file_path);
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
@ -233,12 +221,67 @@ std::string filesystem_error::what() const {
|
||||
}
|
||||
}
|
||||
|
||||
path path::extension() const {
|
||||
const auto t = filename().native();
|
||||
const auto index = t.find_last_of(u'.');
|
||||
if( index == t.npos ) {
|
||||
return { };
|
||||
} else {
|
||||
return t.substr(index);
|
||||
}
|
||||
}
|
||||
|
||||
path path::filename() const {
|
||||
const auto index = _s.find_last_of(preferred_separator);
|
||||
if( index == _s.npos ) {
|
||||
return _s;
|
||||
} else {
|
||||
return _s.substr(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
path path::stem() const {
|
||||
const auto t = filename().native();
|
||||
const auto index = t.find_last_of(u'.');
|
||||
if( index == t.npos ) {
|
||||
return t;
|
||||
} else {
|
||||
return t.substr(0, index);
|
||||
}
|
||||
}
|
||||
|
||||
std::string path::string() const {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<path::value_type>, path::value_type> conv;
|
||||
return conv.to_bytes(native());
|
||||
}
|
||||
|
||||
path& path::replace_extension(const path& replacement) {
|
||||
const auto t = extension().native();
|
||||
_s.erase(_s.size() - t.size());
|
||||
if( !replacement._s.empty() ) {
|
||||
if( replacement._s.front() != u'.' ) {
|
||||
_s += u'.';
|
||||
}
|
||||
_s += replacement._s;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator<(const path& lhs, const path& rhs) {
|
||||
return lhs.native() < rhs.native();
|
||||
}
|
||||
|
||||
bool operator>(const path& lhs, const path& rhs) {
|
||||
return lhs.native() > rhs.native();
|
||||
}
|
||||
|
||||
directory_iterator::directory_iterator(
|
||||
const char* path,
|
||||
const char* wild
|
||||
) {
|
||||
std::filesystem::path path,
|
||||
std::filesystem::path wild
|
||||
) : pattern { wild }
|
||||
{
|
||||
impl = std::make_shared<Impl>();
|
||||
const auto result = f_findfirst(&impl->dir, &impl->filinfo, path, wild);
|
||||
const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast<const TCHAR*>(path.c_str()), reinterpret_cast<const TCHAR*>(pattern.c_str()));
|
||||
if( result != FR_OK ) {
|
||||
impl.reset();
|
||||
// TODO: Throw exception if/when I enable exceptions...
|
||||
@ -253,6 +296,10 @@ directory_iterator& directory_iterator::operator++() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool is_directory(const file_status s) {
|
||||
return (s & AM_DIR);
|
||||
}
|
||||
|
||||
bool is_regular_file(const file_status s) {
|
||||
return !(s & AM_DIR);
|
||||
}
|
||||
@ -260,7 +307,7 @@ bool is_regular_file(const file_status s) {
|
||||
space_info space(const path& p) {
|
||||
DWORD free_clusters { 0 };
|
||||
FATFS* fs;
|
||||
if( f_getfree(p.c_str(), &free_clusters, &fs) == FR_OK ) {
|
||||
if( f_getfree(reinterpret_cast<const TCHAR*>(p.c_str()), &free_clusters, &fs) == FR_OK ) {
|
||||
#if _MAX_SS != _MIN_SS
|
||||
static_assert(false, "FatFs not configured for fixed sector size");
|
||||
#else
|
||||
|
@ -35,18 +35,11 @@
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
std::string remove_filename_extension(const std::string& filename);
|
||||
std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern);
|
||||
std::vector<std::string> scan_root_files(const std::string& directory, const std::string& extension);
|
||||
|
||||
namespace std {
|
||||
namespace filesystem {
|
||||
|
||||
struct filesystem_error {
|
||||
constexpr filesystem_error(
|
||||
) : err { FR_OK }
|
||||
{
|
||||
}
|
||||
constexpr filesystem_error() = default;
|
||||
|
||||
constexpr filesystem_error(
|
||||
FRESULT fatfs_error
|
||||
@ -67,12 +60,111 @@ struct filesystem_error {
|
||||
std::string what() const;
|
||||
|
||||
private:
|
||||
uint32_t err;
|
||||
uint32_t err { FR_OK };
|
||||
};
|
||||
|
||||
using path = std::string;
|
||||
struct path {
|
||||
using string_type = std::u16string;
|
||||
using value_type = string_type::value_type;
|
||||
|
||||
static constexpr value_type preferred_separator = u'/';
|
||||
|
||||
path(
|
||||
) : _s { }
|
||||
{
|
||||
}
|
||||
|
||||
path(
|
||||
const path& p
|
||||
) : _s { p._s }
|
||||
{
|
||||
}
|
||||
|
||||
path(
|
||||
path&& p
|
||||
) : _s { std::move(p._s) }
|
||||
{
|
||||
}
|
||||
|
||||
template<class Source>
|
||||
path(
|
||||
const Source& source
|
||||
) : path { std::begin(source), std::end(source) }
|
||||
{
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
path(
|
||||
InputIt first,
|
||||
InputIt last
|
||||
) : _s { first, last }
|
||||
{
|
||||
}
|
||||
|
||||
path(
|
||||
const char16_t* const s
|
||||
) : _s { s }
|
||||
{
|
||||
}
|
||||
|
||||
path(
|
||||
const TCHAR* const s
|
||||
) : _s { reinterpret_cast<const std::filesystem::path::value_type*>(s) }
|
||||
{
|
||||
}
|
||||
|
||||
path& operator=(const path& p) {
|
||||
_s = p._s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
path& operator=(path&& p) {
|
||||
_s = std::move(p._s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
path extension() const;
|
||||
path filename() const;
|
||||
path stem() const;
|
||||
|
||||
bool empty() const {
|
||||
return _s.empty();
|
||||
}
|
||||
|
||||
const value_type* c_str() const {
|
||||
return native().c_str();
|
||||
}
|
||||
|
||||
const string_type& native() const {
|
||||
return _s;
|
||||
}
|
||||
|
||||
std::string string() const;
|
||||
|
||||
path& operator+=(const path& p) {
|
||||
_s += p._s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
path& operator+=(const string_type& str) {
|
||||
_s += str;
|
||||
return *this;
|
||||
}
|
||||
|
||||
path& replace_extension(const path& replacement = path());
|
||||
|
||||
private:
|
||||
string_type _s;
|
||||
};
|
||||
|
||||
bool operator<(const path& lhs, const path& rhs);
|
||||
bool operator>(const path& lhs, const path& rhs);
|
||||
|
||||
using file_status = BYTE;
|
||||
|
||||
static_assert(sizeof(path::value_type) == 2, "sizeof(std::filesystem::path::value_type) != 2");
|
||||
static_assert(sizeof(path::value_type) == sizeof(TCHAR), "FatFs TCHAR size != std::filesystem::path::value_type");
|
||||
|
||||
struct space_info {
|
||||
static_assert(sizeof(std::uintmax_t) >= 8, "std::uintmax_t too small (<uint64_t)");
|
||||
|
||||
@ -86,7 +178,11 @@ struct directory_entry : public FILINFO {
|
||||
return fattrib;
|
||||
}
|
||||
|
||||
const std::string path() const noexcept { return fname; };
|
||||
std::uintmax_t size() const {
|
||||
return fsize;
|
||||
};
|
||||
|
||||
const std::filesystem::path path() const noexcept { return { fname }; };
|
||||
};
|
||||
|
||||
class directory_iterator {
|
||||
@ -99,7 +195,8 @@ class directory_iterator {
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<Impl> impl;
|
||||
std::shared_ptr<Impl> impl { };
|
||||
const path pattern { };
|
||||
|
||||
friend bool operator!=(const directory_iterator& lhs, const directory_iterator& rhs);
|
||||
|
||||
@ -111,8 +208,8 @@ public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
directory_iterator() noexcept { };
|
||||
directory_iterator(const char* path, const char* wild);
|
||||
|
||||
directory_iterator(std::filesystem::path path, std::filesystem::path wild);
|
||||
|
||||
~directory_iterator() { }
|
||||
|
||||
directory_iterator& operator++();
|
||||
@ -128,6 +225,7 @@ inline directory_iterator end(const directory_iterator&) noexcept { return { };
|
||||
|
||||
inline bool operator!=(const directory_iterator& lhs, const directory_iterator& rhs) { return lhs.impl != rhs.impl; };
|
||||
|
||||
bool is_directory(const file_status s);
|
||||
bool is_regular_file(const file_status s);
|
||||
|
||||
space_info space(const path& p);
|
||||
@ -135,8 +233,23 @@ space_info space(const path& p);
|
||||
} /* namespace filesystem */
|
||||
} /* namespace std */
|
||||
|
||||
std::vector<std::filesystem::path> scan_root_files(const TCHAR* directory, const std::string& extension);
|
||||
std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern);
|
||||
|
||||
/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */
|
||||
static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected.");
|
||||
|
||||
/* Dangerous to expose these, as FatFs native error values are byte-sized. However,
|
||||
* my filesystem_error implemetation is fine with it. */
|
||||
#define FR_DISK_FULL (0x100)
|
||||
#define FR_EOF (0x101)
|
||||
#define FR_BAD_SEEK (0x102)
|
||||
#define FR_UNEXPECTED (0x103)
|
||||
|
||||
class File {
|
||||
public:
|
||||
using Size = uint64_t;
|
||||
using Offset = uint64_t;
|
||||
using Error = std::filesystem::filesystem_error;
|
||||
|
||||
template<typename T>
|
||||
@ -197,17 +310,17 @@ public:
|
||||
File& operator=(const File&) = delete;
|
||||
|
||||
// TODO: Return Result<>.
|
||||
Optional<Error> open(const std::string& filename);
|
||||
Optional<Error> append(const std::string& filename);
|
||||
Optional<Error> create(const std::string& filename);
|
||||
Optional<Error> open(const std::filesystem::path& filename);
|
||||
Optional<Error> append(const std::filesystem::path& filename);
|
||||
Optional<Error> create(const std::filesystem::path& filename);
|
||||
|
||||
Result<size_t> read(void* const data, const size_t bytes_to_read);
|
||||
Result<size_t> write(const void* const data, const size_t bytes_to_write);
|
||||
Result<Size> read(void* const data, const Size bytes_to_read);
|
||||
Result<Size> write(const void* const data, const Size bytes_to_write);
|
||||
|
||||
Result<uint64_t> seek(const uint64_t new_position);
|
||||
Result<Offset> seek(const uint64_t Offset);
|
||||
|
||||
template<size_t N>
|
||||
Result<size_t> write(const std::array<uint8_t, N>& data) {
|
||||
Result<Size> write(const std::array<uint8_t, N>& data) {
|
||||
return write(data.data(), N);
|
||||
}
|
||||
|
||||
@ -217,9 +330,9 @@ public:
|
||||
Optional<Error> sync();
|
||||
|
||||
private:
|
||||
FIL f;
|
||||
FIL f { };
|
||||
|
||||
Optional<Error> open_fatfs(const std::string& filename, BYTE mode);
|
||||
Optional<Error> open_fatfs(const std::filesystem::path& filename, BYTE mode);
|
||||
};
|
||||
|
||||
#endif/*__FILE_H__*/
|
||||
|
40
firmware/application/io.hpp
Normal file
40
firmware/application/io.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "file.hpp"
|
||||
|
||||
namespace stream {
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
virtual File::Result<File::Size> read(void* const buffer, const File::Size bytes) = 0;
|
||||
virtual ~Reader() = default;
|
||||
};
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
virtual File::Result<File::Size> write(const void* const buffer, const File::Size bytes) = 0;
|
||||
virtual ~Writer() = default;
|
||||
};
|
||||
|
||||
} /* namespace stream */
|
@ -19,25 +19,20 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "filewriter.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
|
||||
Optional<File::Error> FileWriter::create(const std::string& filename) {
|
||||
return file.create(filename);
|
||||
File::Result<File::Size> FileReader::read(void* const buffer, const File::Size bytes) {
|
||||
auto read_result = file.read(buffer, bytes) ;
|
||||
if( read_result.is_ok() ) {
|
||||
bytes_read += read_result.value();
|
||||
}
|
||||
return read_result;
|
||||
}
|
||||
|
||||
File::Result<size_t> FileWriter::write(const void* const buffer, const size_t bytes) {
|
||||
File::Result<File::Size> FileWriter::write(const void* const buffer, const File::Size bytes) {
|
||||
auto write_result = file.write(buffer, bytes) ;
|
||||
if( write_result.is_ok() ) {
|
||||
bytes_written += write_result.value();
|
||||
}
|
||||
return write_result;
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -19,22 +19,32 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FILEWRITER_H__
|
||||
#define __FILEWRITER_H__
|
||||
#pragma once
|
||||
|
||||
#include "ui_widget.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
#include "capture_thread.hpp"
|
||||
#include "signal.hpp"
|
||||
#include "file.hpp"
|
||||
#include "optional.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
class FileReader : public stream::Reader {
|
||||
public:
|
||||
FileReader() = default;
|
||||
|
||||
FileReader(const FileReader&) = delete;
|
||||
FileReader& operator=(const FileReader&) = delete;
|
||||
FileReader(FileReader&& file) = delete;
|
||||
FileReader& operator=(FileReader&&) = delete;
|
||||
|
||||
File::Result<File::Size> read(void* const buffer, const File::Size bytes) override;
|
||||
|
||||
class FileWriter : public Writer {
|
||||
protected:
|
||||
File file { };
|
||||
uint64_t bytes_read { 0 };
|
||||
};
|
||||
|
||||
class FileWriter : public stream::Writer {
|
||||
public:
|
||||
FileWriter() = default;
|
||||
|
||||
@ -43,15 +53,15 @@ public:
|
||||
FileWriter(FileWriter&& file) = delete;
|
||||
FileWriter& operator=(FileWriter&&) = delete;
|
||||
|
||||
Optional<File::Error> create(const std::string& filename);
|
||||
|
||||
File::Result<size_t> write(const void* const buffer, const size_t bytes) override;
|
||||
Optional<File::Error> create(const std::filesystem::path& filename) {
|
||||
return file.create(filename);
|
||||
}
|
||||
|
||||
File::Result<File::Size> write(const void* const buffer, const File::Size bytes) override;
|
||||
|
||||
protected:
|
||||
File file;
|
||||
File file { };
|
||||
uint64_t bytes_written { 0 };
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__FILEWRITER_H__*/
|
||||
using RawFileWriter = FileWriter;
|
@ -20,33 +20,22 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "wavfile.hpp"
|
||||
#include "io_wave.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "file.hpp"
|
||||
#include "time.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
|
||||
int WAVFileReader::open(const std::string& filename) {
|
||||
if (filename == last_filename) {
|
||||
int WAVFileReader::open(const std::filesystem::path& path) {
|
||||
if (path.string() == last_path.string()) {
|
||||
rewind();
|
||||
return 1; // Already open
|
||||
}
|
||||
|
||||
auto error = file.open(filename);
|
||||
auto error = file.open(path);
|
||||
|
||||
if (!error.is_valid()) {
|
||||
file.read((void*)&header, sizeof(header));
|
||||
|
||||
// TODO: Check validity here
|
||||
|
||||
last_filename = filename;
|
||||
last_path = path;
|
||||
data_start = header.fmt.cksize + 28; // Skip "data" and cksize
|
||||
|
||||
data_size_ = header.data.cksize;
|
||||
@ -98,13 +87,11 @@ uint16_t WAVFileReader::bits_per_sample() {
|
||||
return header.fmt.wBitsPerSample;
|
||||
}
|
||||
|
||||
WAVFileWriter::~WAVFileWriter() {
|
||||
update_header();
|
||||
}
|
||||
|
||||
Optional<File::Error> WAVFileWriter::create(
|
||||
const std::string& filename
|
||||
const std::filesystem::path& filename,
|
||||
size_t sampling_rate
|
||||
) {
|
||||
sampling_rate = sampling_rate;
|
||||
const auto create_error = FileWriter::create(filename);
|
||||
if( create_error.is_valid() ) {
|
||||
return create_error;
|
||||
@ -114,7 +101,7 @@ Optional<File::Error> WAVFileWriter::create(
|
||||
}
|
||||
|
||||
Optional<File::Error> WAVFileWriter::update_header() {
|
||||
header.set_data_size(bytes_written);
|
||||
header_t header { sampling_rate, bytes_written };
|
||||
const auto seek_0_result = file.seek(0);
|
||||
if( seek_0_result.is_error() ) {
|
||||
return seek_0_result.error();
|
||||
@ -130,5 +117,3 @@ Optional<File::Error> WAVFileWriter::update_header() {
|
||||
}
|
||||
return { };
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@ -20,18 +20,66 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __WAVFILE_H__
|
||||
#define __WAVFILE_H__
|
||||
#pragma once
|
||||
|
||||
#include "filewriter.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "optional.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
struct fmt_pcm_t {
|
||||
constexpr fmt_pcm_t(
|
||||
const uint32_t sampling_rate
|
||||
) : nSamplesPerSec { sampling_rate },
|
||||
nAvgBytesPerSec { nSamplesPerSec * nBlockAlign }
|
||||
{
|
||||
}
|
||||
|
||||
class WAVFileReader {
|
||||
private:
|
||||
uint8_t ckID[4] { 'f', 'm', 't', ' ' };
|
||||
uint32_t cksize { 16 };
|
||||
uint16_t wFormatTag { 0x0001 };
|
||||
uint16_t nChannels { 1 };
|
||||
uint32_t nSamplesPerSec;
|
||||
uint32_t nAvgBytesPerSec;
|
||||
uint16_t nBlockAlign { 2 };
|
||||
uint16_t wBitsPerSample { 16 };
|
||||
};
|
||||
|
||||
struct data_t {
|
||||
constexpr data_t(
|
||||
const uint32_t size
|
||||
) : cksize { size }
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t ckID[4] { 'd', 'a', 't', 'a' };
|
||||
uint32_t cksize { 0 };
|
||||
};
|
||||
|
||||
struct header_t {
|
||||
constexpr header_t(
|
||||
const uint32_t sampling_rate,
|
||||
const uint32_t data_chunk_size
|
||||
) : cksize { sizeof(header_t) + data_chunk_size - 8 },
|
||||
fmt { sampling_rate },
|
||||
data { data_chunk_size }
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t riff_id[4] { 'R', 'I', 'F', 'F' };
|
||||
uint32_t cksize { 0 };
|
||||
uint8_t wave_id[4] { 'W', 'A', 'V', 'E' };
|
||||
fmt_pcm_t fmt;
|
||||
data_t data;
|
||||
};
|
||||
|
||||
class WAVFileReader : public FileReader {
|
||||
public:
|
||||
WAVFileReader() = default;
|
||||
|
||||
@ -42,7 +90,7 @@ public:
|
||||
|
||||
virtual ~WAVFileReader() = default;
|
||||
|
||||
int open(const std::string& filename);
|
||||
int open(const std::filesystem::path& path);
|
||||
void rewind();
|
||||
uint32_t ms_duration();
|
||||
size_t read(void * const data, const size_t bytes_to_read);
|
||||
@ -53,13 +101,6 @@ public:
|
||||
uint16_t bits_per_sample();
|
||||
|
||||
private:
|
||||
File file;
|
||||
uint32_t data_start;
|
||||
uint32_t bytes_per_sample;
|
||||
uint32_t data_size_;
|
||||
uint32_t sample_rate_;
|
||||
std::string last_filename = "";
|
||||
|
||||
struct fmt_pcm_t {
|
||||
uint8_t ckID[4]; // fmt
|
||||
uint32_t cksize;
|
||||
@ -85,81 +126,36 @@ private:
|
||||
};
|
||||
|
||||
header_t header;
|
||||
};
|
||||
|
||||
File file;
|
||||
uint32_t data_start;
|
||||
uint32_t bytes_per_sample;
|
||||
uint32_t data_size_;
|
||||
uint32_t sample_rate_;
|
||||
std::filesystem::path last_path { };
|
||||
};
|
||||
|
||||
class WAVFileWriter : public FileWriter {
|
||||
public:
|
||||
WAVFileWriter(
|
||||
size_t sampling_rate
|
||||
) : header { sampling_rate }
|
||||
{
|
||||
}
|
||||
WAVFileWriter() = default;
|
||||
|
||||
WAVFileWriter(const WAVFileWriter&) = delete;
|
||||
WAVFileWriter& operator=(const WAVFileWriter&) = delete;
|
||||
WAVFileWriter(WAVFileWriter&&) = delete;
|
||||
WAVFileWriter& operator=(WAVFileWriter&&) = delete;
|
||||
|
||||
~WAVFileWriter();
|
||||
~WAVFileWriter() {
|
||||
update_header();
|
||||
}
|
||||
|
||||
Optional<File::Error> create(const std::string& filename);
|
||||
Optional<File::Error> create(
|
||||
const std::filesystem::path& filename,
|
||||
size_t sampling_rate
|
||||
);
|
||||
|
||||
private:
|
||||
struct fmt_pcm_t {
|
||||
constexpr fmt_pcm_t(
|
||||
const uint32_t sampling_rate
|
||||
) : nSamplesPerSec { sampling_rate },
|
||||
nAvgBytesPerSec { nSamplesPerSec * nBlockAlign }
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t ckID[4] { 'f', 'm', 't', ' ' };
|
||||
const uint32_t cksize { 16 };
|
||||
const uint16_t wFormatTag { 0x0001 };
|
||||
const uint16_t nChannels { 1 };
|
||||
const uint32_t nSamplesPerSec;
|
||||
const uint32_t nAvgBytesPerSec;
|
||||
const uint16_t nBlockAlign { 2 };
|
||||
const uint16_t wBitsPerSample { 16 };
|
||||
};
|
||||
|
||||
struct data_t {
|
||||
void set_size(const uint32_t value) {
|
||||
cksize = value;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t ckID[4] { 'd', 'a', 't', 'a' };
|
||||
uint32_t cksize { 0 };
|
||||
};
|
||||
|
||||
struct header_t {
|
||||
constexpr header_t(
|
||||
const uint32_t sampling_rate
|
||||
) : fmt { sampling_rate }
|
||||
{
|
||||
}
|
||||
|
||||
void set_data_size(const uint32_t value) {
|
||||
data.set_size(value);
|
||||
cksize = sizeof(header_t) + value - 8;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t riff_id[4] { 'R', 'I', 'F', 'F' };
|
||||
uint32_t cksize { 0 };
|
||||
const uint8_t wave_id[4] { 'W', 'A', 'V', 'E' };
|
||||
fmt_pcm_t fmt;
|
||||
data_t data;
|
||||
};
|
||||
|
||||
header_t header;
|
||||
uint32_t sampling_rate { 0 };
|
||||
uint32_t bytes_written { 0 };
|
||||
|
||||
Optional<File::Error> update_header();
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__WAVFILE_H__*/
|
@ -31,14 +31,14 @@ using namespace lpc43xx;
|
||||
|
||||
class LogFile {
|
||||
public:
|
||||
Optional<File::Error> append(const std::string& filename) {
|
||||
Optional<File::Error> append(const std::filesystem::path& filename) {
|
||||
return file.append(filename);
|
||||
}
|
||||
|
||||
Optional<File::Error> write_entry(const rtc::RTC& datetime, const std::string& entry);
|
||||
|
||||
private:
|
||||
File file;
|
||||
File file { };
|
||||
|
||||
Optional<File::Error> write_line(const std::string& message);
|
||||
};
|
||||
|
@ -55,6 +55,18 @@ static uint_fast8_t gain_ordinal(const int8_t db) {
|
||||
|
||||
} /* namespace vga */
|
||||
|
||||
namespace tx {
|
||||
|
||||
static uint_fast8_t gain_ordinal(const int8_t db) {
|
||||
const auto db_sat = gain_db_range.clip(db);
|
||||
uint8_t value = db_sat & 0x0f;
|
||||
value = (db_sat >= 16) ? (value | 0x20) : value;
|
||||
value = (db_sat >= 32) ? (value | 0x10) : value;
|
||||
return (value & 0b111111) ^ 0b111111;
|
||||
}
|
||||
|
||||
} /* namespace tx */
|
||||
|
||||
namespace filter {
|
||||
|
||||
static uint_fast8_t bandwidth_ordinal(const uint32_t bandwidth) {
|
||||
@ -170,8 +182,8 @@ reg_t MAX2837::read(const Register reg) {
|
||||
return read(toUType(reg));
|
||||
}
|
||||
|
||||
void MAX2837::set_tx_vga_gain(const int_fast8_t value) {
|
||||
_map.r.tx_gain.TXVGA_GAIN_SPI = value;
|
||||
void MAX2837::set_tx_vga_gain(const int_fast8_t db) {
|
||||
_map.r.tx_gain.TXVGA_GAIN_SPI = tx::gain_ordinal(db);
|
||||
_dirty[Register::TX_GAIN] = 1;
|
||||
flush();
|
||||
}
|
||||
@ -230,6 +242,34 @@ bool MAX2837::set_frequency(const rf::Frequency lo_frequency) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void MAX2837::set_rx_lo_iq_calibration(const size_t v) {
|
||||
_map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1;
|
||||
_dirty[Register::RX_TOP_RX_BIAS] = 1;
|
||||
_map.r.rxrf_2.iqerr_trim = v;
|
||||
_dirty[Register::RXRF_2] = 1;
|
||||
flush();
|
||||
}
|
||||
|
||||
void MAX2837::set_rx_bias_trim(const size_t v) {
|
||||
_map.r.rx_top_rx_bias.EN_Bias_Trim = 1;
|
||||
_map.r.rx_top_rx_bias.BIAS_TRIM_SPI = v;
|
||||
_dirty[Register::RX_TOP_RX_BIAS] = 1;
|
||||
flush();
|
||||
}
|
||||
|
||||
void MAX2837::set_vco_bias(const size_t v) {
|
||||
_map.r.vco_cfg.VCO_BIAS_SPI_EN = 1;
|
||||
_map.r.vco_cfg.VCO_BIAS_SPI = v;
|
||||
_dirty[Register::VCO_CFG] = 1;
|
||||
flush();
|
||||
}
|
||||
|
||||
void MAX2837::set_rx_buff_vcm(const size_t v) {
|
||||
_map.r.lpf_3_vga_1.BUFF_VCM = v;
|
||||
_dirty[Register::LPF_3_VGA_1] = 1;
|
||||
flush();
|
||||
}
|
||||
|
||||
reg_t MAX2837::temp_sense() {
|
||||
if( !_map.r.rx_top.ts_en ) {
|
||||
_map.r.rx_top.ts_en = 1;
|
||||
|
@ -83,6 +83,14 @@ constexpr int8_t gain_db_step = 2;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
namespace tx {
|
||||
|
||||
constexpr range_t<int8_t> gain_db_range { 0, 47 };
|
||||
constexpr int8_t gain_db_step = 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
namespace filter {
|
||||
|
||||
constexpr std::array<uint32_t, 16> bandwidths {
|
||||
@ -829,7 +837,7 @@ public:
|
||||
void init();
|
||||
void set_mode(const Mode mode);
|
||||
|
||||
void set_tx_vga_gain(const int_fast8_t value);
|
||||
void set_tx_vga_gain(const int_fast8_t db);
|
||||
void set_lna_gain(const int_fast8_t db);
|
||||
void set_vga_gain(const int_fast8_t db);
|
||||
void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum);
|
||||
@ -876,6 +884,11 @@ public:
|
||||
|
||||
bool set_frequency(const rf::Frequency lo_frequency);
|
||||
|
||||
void set_rx_lo_iq_calibration(const size_t v);
|
||||
void set_rx_bias_trim(const size_t v);
|
||||
void set_vco_bias(const size_t v);
|
||||
void set_rx_buff_vcm(const size_t v);
|
||||
|
||||
reg_t temp_sense();
|
||||
|
||||
reg_t read(const address_t reg_num);
|
||||
@ -884,7 +897,7 @@ private:
|
||||
spi::arbiter::Target& _target;
|
||||
|
||||
RegisterMap _map { initial_register_values };
|
||||
DirtyRegisters<Register, reg_count> _dirty;
|
||||
DirtyRegisters<Register, reg_count> _dirty { };
|
||||
|
||||
void flush_one(const Register reg);
|
||||
|
||||
|
@ -104,7 +104,7 @@ void POCSAGAppView::update_freq(rf::Frequency f) {
|
||||
POCSAGAppView::POCSAGAppView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_pocsag);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&rssi,
|
||||
&channel,
|
||||
&options_freq,
|
||||
@ -113,7 +113,7 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&console
|
||||
} });
|
||||
});
|
||||
|
||||
radio::enable({
|
||||
tuning_frequency(),
|
||||
@ -122,8 +122,7 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
|
||||
rf::Direction::Receive,
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
1,
|
||||
static_cast<int8_t>(receiver_model.vga())
|
||||
});
|
||||
|
||||
options_freq.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
|
@ -126,7 +126,7 @@ bool set_tuning_frequency(const rf::Frequency frequency) {
|
||||
const auto result_second_if = second_if.set_frequency(tuning_config.second_lo_frequency);
|
||||
|
||||
rf_path.set_band(tuning_config.rf_path_band);
|
||||
baseband_cpld.set_q_invert(tuning_config.baseband_q_invert);
|
||||
baseband_cpld.set_invert(tuning_config.baseband_invert);
|
||||
|
||||
return result_second_if;
|
||||
} else {
|
||||
@ -146,6 +146,10 @@ void set_vga_gain(const int_fast8_t db) {
|
||||
second_if.set_vga_gain(db);
|
||||
}
|
||||
|
||||
void set_tx_gain(const int_fast8_t db) {
|
||||
second_if.set_tx_vga_gain(db);
|
||||
}
|
||||
|
||||
void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum) {
|
||||
second_if.set_lpf_rf_bandwidth(bandwidth_minimum);
|
||||
}
|
||||
@ -154,10 +158,6 @@ void set_baseband_rate(const uint32_t rate) {
|
||||
portapack::clock_manager.set_sampling_frequency(rate);
|
||||
}
|
||||
|
||||
void set_baseband_decimation_by(const size_t n) {
|
||||
baseband_cpld.set_decimation_by(n);
|
||||
}
|
||||
|
||||
void set_antenna_bias(const bool on) {
|
||||
/* Pull MOSFET gate low to turn on antenna bias. */
|
||||
first_if.set_gpo1(on ? 0 : 1);
|
||||
@ -181,7 +181,6 @@ void configure(Configuration configuration) {
|
||||
set_lna_gain(configuration.lna_gain);
|
||||
set_vga_gain(configuration.vga_gain);
|
||||
set_baseband_rate(configuration.baseband_rate);
|
||||
set_baseband_decimation_by(configuration.baseband_decimation);
|
||||
set_baseband_filter_bandwidth(configuration.baseband_filter_bandwidth);
|
||||
set_direction(configuration.direction);
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ struct Configuration {
|
||||
bool rf_amp;
|
||||
int8_t lna_gain;
|
||||
int8_t vga_gain;
|
||||
uint8_t baseband_decimation;
|
||||
};
|
||||
|
||||
void init();
|
||||
@ -47,9 +46,9 @@ bool set_tuning_frequency(const rf::Frequency frequency);
|
||||
void set_rf_amp(const bool rf_amp);
|
||||
void set_lna_gain(const int_fast8_t db);
|
||||
void set_vga_gain(const int_fast8_t db);
|
||||
void set_tx_gain(const int_fast8_t db);
|
||||
void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum);
|
||||
void set_baseband_rate(const uint32_t rate);
|
||||
void set_baseband_decimation_by(const size_t n);
|
||||
void set_antenna_bias(const bool on);
|
||||
|
||||
void enable(Configuration configuration);
|
||||
|
@ -117,6 +117,15 @@ void ReceiverModel::set_vga(int32_t v_db) {
|
||||
update_vga();
|
||||
}
|
||||
|
||||
int32_t ReceiverModel::tx_gain() const {
|
||||
return tx_gain_db_;
|
||||
}
|
||||
|
||||
void ReceiverModel::set_tx_gain(int32_t v_db) {
|
||||
tx_gain_db_ = v_db;
|
||||
update_tx_gain();
|
||||
}
|
||||
|
||||
uint32_t ReceiverModel::sampling_rate() const {
|
||||
return sampling_rate_;
|
||||
}
|
||||
@ -144,11 +153,6 @@ void ReceiverModel::set_headphone_volume(volume_t v) {
|
||||
update_headphone_volume();
|
||||
}
|
||||
|
||||
uint32_t ReceiverModel::baseband_oversampling() const {
|
||||
// TODO: Rename decimation_factor.
|
||||
return decimation_factor_;
|
||||
}
|
||||
|
||||
void ReceiverModel::enable() {
|
||||
enabled_ = true;
|
||||
radio::set_direction(rf::Direction::Receive);
|
||||
@ -157,6 +161,7 @@ void ReceiverModel::enable() {
|
||||
update_rf_amp();
|
||||
update_lna();
|
||||
update_vga();
|
||||
update_tx_gain();
|
||||
update_baseband_bandwidth();
|
||||
update_sampling_rate();
|
||||
update_modulation();
|
||||
@ -206,6 +211,10 @@ void ReceiverModel::update_vga() {
|
||||
radio::set_vga_gain(vga_gain_db_);
|
||||
}
|
||||
|
||||
void ReceiverModel::update_tx_gain() {
|
||||
radio::set_tx_gain(tx_gain_db_);
|
||||
}
|
||||
|
||||
void ReceiverModel::set_am_configuration(const size_t n) {
|
||||
if( n < am_configs.size() ) {
|
||||
am_config_index = n;
|
||||
@ -233,9 +242,8 @@ void ReceiverModel::update_sampling_rate() {
|
||||
// protocols that need quick RX/TX turn-around.
|
||||
|
||||
// Disabling baseband while changing sampling rates seems like a good idea...
|
||||
radio::set_baseband_rate(sampling_rate() * baseband_oversampling());
|
||||
radio::set_baseband_rate(sampling_rate());
|
||||
update_tuning_frequency();
|
||||
radio::set_baseband_decimation_by(baseband_oversampling());
|
||||
}
|
||||
|
||||
void ReceiverModel::update_headphone_volume() {
|
||||
|
@ -81,6 +81,9 @@ public:
|
||||
int32_t vga() const;
|
||||
void set_vga(int32_t v_db);
|
||||
|
||||
int32_t tx_gain() const;
|
||||
void set_tx_gain(int32_t v_db);
|
||||
|
||||
uint32_t sampling_rate() const;
|
||||
void set_sampling_rate(uint32_t v);
|
||||
|
||||
@ -90,8 +93,6 @@ public:
|
||||
volume_t headphone_volume() const;
|
||||
void set_headphone_volume(volume_t v);
|
||||
|
||||
uint32_t baseband_oversampling() const;
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
@ -112,9 +113,9 @@ private:
|
||||
int32_t lna_gain_db_ { 32 };
|
||||
uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum };
|
||||
int32_t vga_gain_db_ { 32 };
|
||||
int32_t tx_gain_db_ { 47 };
|
||||
Mode mode_ { Mode::NarrowbandFMAudio };
|
||||
uint32_t sampling_rate_ { 3072000 };
|
||||
size_t decimation_factor_ { 1 };
|
||||
size_t am_config_index = 0;
|
||||
size_t nbfm_config_index = 0;
|
||||
size_t wfm_config_index = 0;
|
||||
@ -128,6 +129,7 @@ private:
|
||||
void update_lna();
|
||||
void update_baseband_bandwidth();
|
||||
void update_vga();
|
||||
void update_tx_gain();
|
||||
void update_sampling_rate();
|
||||
void update_headphone_volume();
|
||||
|
||||
|
@ -20,3 +20,42 @@
|
||||
*/
|
||||
|
||||
#include "recent_entries.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
RecentEntriesColumns::RecentEntriesColumns(
|
||||
const std::initializer_list<RecentEntriesColumn> columns
|
||||
) : _columns { columns }
|
||||
{
|
||||
}
|
||||
|
||||
RecentEntriesHeader::RecentEntriesHeader(
|
||||
const RecentEntriesColumns& columns
|
||||
) : _columns { columns }
|
||||
{
|
||||
}
|
||||
|
||||
void RecentEntriesHeader::paint(Painter& painter) {
|
||||
const auto r = screen_rect();
|
||||
const auto& parent_style = style();
|
||||
|
||||
const Style style {
|
||||
.font = parent_style.font,
|
||||
.background = Color::blue(),
|
||||
.foreground = parent_style.foreground,
|
||||
};
|
||||
|
||||
auto p = r.location();
|
||||
for(const auto& column : _columns) {
|
||||
const auto width = column.second;
|
||||
auto text = column.first;
|
||||
if( width > text.length() ) {
|
||||
text.append(width - text.length(), ' ');
|
||||
}
|
||||
|
||||
painter.draw_string(p, style, text);
|
||||
p += { static_cast<Coord>((width * 8) + 8), 0 };
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
@ -33,99 +33,103 @@
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
template<class Packet, class Entry>
|
||||
class RecentEntries {
|
||||
public:
|
||||
using EntryType = Entry;
|
||||
using Key = typename Entry::Key;
|
||||
using ContainerType = std::list<Entry>;
|
||||
using const_reference = typename ContainerType::const_reference;
|
||||
using const_iterator = typename ContainerType::const_iterator;
|
||||
using RangeType = std::pair<const_iterator, const_iterator>;
|
||||
|
||||
const Entry& on_packet(const Key key, const Packet& packet) {
|
||||
auto matching_recent = find(key);
|
||||
if( matching_recent != std::end(entries) ) {
|
||||
// Found within. Move to front of list, increment counter.
|
||||
entries.push_front(*matching_recent);
|
||||
entries.erase(matching_recent);
|
||||
} else {
|
||||
entries.emplace_front(key);
|
||||
truncate_entries();
|
||||
}
|
||||
template<class Entry>
|
||||
using RecentEntries = std::list<Entry>;
|
||||
|
||||
auto& entry = entries.front();
|
||||
entry.update(packet);
|
||||
template<typename ContainerType, typename Key>
|
||||
typename ContainerType::const_iterator find(const ContainerType& entries, const Key key) {
|
||||
return std::find_if(
|
||||
std::begin(entries), std::end(entries),
|
||||
[key](typename ContainerType::const_reference e) { return e.key() == key; }
|
||||
);
|
||||
}
|
||||
|
||||
return entry;
|
||||
template<typename ContainerType>
|
||||
static void truncate_entries(ContainerType& entries, const size_t entries_max = 64) {
|
||||
while(entries.size() > entries_max) {
|
||||
entries.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContainerType, typename Key>
|
||||
typename ContainerType::reference on_packet(ContainerType& entries, const Key key) {
|
||||
auto matching_recent = find(entries, key);
|
||||
if( matching_recent != std::end(entries) ) {
|
||||
// Found within. Move to front of list, increment counter.
|
||||
entries.push_front(*matching_recent);
|
||||
entries.erase(matching_recent);
|
||||
} else {
|
||||
entries.emplace_front(key);
|
||||
truncate_entries(entries);
|
||||
}
|
||||
|
||||
const_reference front() const {
|
||||
return entries.front();
|
||||
return entries.front();
|
||||
}
|
||||
|
||||
template<typename ContainerType>
|
||||
static std::pair<typename ContainerType::const_iterator, typename ContainerType::const_iterator> range_around(
|
||||
const ContainerType& entries,
|
||||
typename ContainerType::const_iterator item,
|
||||
const size_t count
|
||||
) {
|
||||
auto start = item;
|
||||
auto end = item;
|
||||
size_t i = 0;
|
||||
|
||||
// Move start iterator toward first entry.
|
||||
while( (start != std::begin(entries)) && (i < count / 2) ) {
|
||||
std::advance(start, -1);
|
||||
i++;
|
||||
}
|
||||
|
||||
const_iterator find(const Key key) const {
|
||||
return std::find_if(
|
||||
std::begin(entries), std::end(entries),
|
||||
[key](const Entry& e) { return e.key() == key; }
|
||||
);
|
||||
// Move end iterator toward last entry.
|
||||
while( (end != std::end(entries)) && (i < count) ) {
|
||||
std::advance(end, 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return entries.begin();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return entries.end();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return entries.empty();
|
||||
}
|
||||
|
||||
RangeType range_around(
|
||||
const_iterator item, const size_t count
|
||||
) const {
|
||||
auto start = item;
|
||||
auto end = item;
|
||||
size_t i = 0;
|
||||
|
||||
// Move start iterator toward first entry.
|
||||
while( (start != std::begin(entries)) && (i < count / 2) ) {
|
||||
std::advance(start, -1);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Move end iterator toward last entry.
|
||||
while( (end != std::end(entries)) && (i < count) ) {
|
||||
std::advance(end, 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
return { start, end };
|
||||
}
|
||||
|
||||
private:
|
||||
ContainerType entries;
|
||||
const size_t entries_max = 64;
|
||||
|
||||
void truncate_entries() {
|
||||
while(entries.size() > entries_max) {
|
||||
entries.pop_back();
|
||||
}
|
||||
}
|
||||
};
|
||||
return { start, end };
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
|
||||
template<class Entries>
|
||||
class RecentEntriesView : public View {
|
||||
using RecentEntriesColumn = std::pair<std::string, size_t>;
|
||||
|
||||
class RecentEntriesColumns {
|
||||
public:
|
||||
using Entry = typename Entries::EntryType;
|
||||
using ContainerType = std::vector<RecentEntriesColumn>;
|
||||
|
||||
std::function<void(const Entry& entry)> on_select;
|
||||
RecentEntriesColumns(
|
||||
const std::initializer_list<RecentEntriesColumn> columns
|
||||
);
|
||||
|
||||
RecentEntriesView(
|
||||
ContainerType::const_iterator begin() const { return std::begin(_columns); }
|
||||
ContainerType::const_iterator end() const { return std::end(_columns); }
|
||||
|
||||
private:
|
||||
const ContainerType _columns;
|
||||
};
|
||||
|
||||
class RecentEntriesHeader : public Widget {
|
||||
public:
|
||||
RecentEntriesHeader(
|
||||
const RecentEntriesColumns& columns
|
||||
);
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
const RecentEntriesColumns& _columns;
|
||||
};
|
||||
|
||||
template<class Entries>
|
||||
class RecentEntriesTable : public Widget {
|
||||
public:
|
||||
using Entry = typename Entries::value_type;
|
||||
|
||||
std::function<void(const Entry& entry)> on_select { };
|
||||
|
||||
RecentEntriesTable(
|
||||
Entries& recent
|
||||
) : recent { recent }
|
||||
{
|
||||
@ -136,30 +140,22 @@ public:
|
||||
const auto r = screen_rect();
|
||||
const auto& s = style();
|
||||
|
||||
Rect target_rect { r.pos, { r.width(), s.font.line_height() }};
|
||||
Rect target_rect { r.location(), { r.width(), s.font.line_height() }};
|
||||
const size_t visible_item_count = r.height() / s.font.line_height();
|
||||
|
||||
const Style style_header {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::blue(),
|
||||
.foreground = Color::white(),
|
||||
};
|
||||
|
||||
draw_header(target_rect, painter, style_header);
|
||||
target_rect.pos.y += target_rect.height();
|
||||
|
||||
auto selected = recent.find(selected_key);
|
||||
auto selected = find(recent, selected_key);
|
||||
if( selected == std::end(recent) ) {
|
||||
selected = std::begin(recent);
|
||||
}
|
||||
|
||||
auto range = recent.range_around(selected, visible_item_count);
|
||||
auto range = range_around(recent, selected, visible_item_count);
|
||||
|
||||
for(auto p = range.first; p != range.second; p++) {
|
||||
const auto& entry = *p;
|
||||
const auto is_selected_key = (selected_key == entry.key());
|
||||
draw(entry, target_rect, painter, s, (has_focus() && is_selected_key));
|
||||
target_rect.pos.y += target_rect.height();
|
||||
const auto item_style = (has_focus() && is_selected_key) ? s.invert() : s;
|
||||
draw(entry, target_rect, painter, item_style);
|
||||
target_rect += { 0, target_rect.height() };
|
||||
}
|
||||
|
||||
painter.fill_rectangle(
|
||||
@ -176,7 +172,7 @@ public:
|
||||
bool on_key(const ui::KeyEvent event) override {
|
||||
if( event == ui::KeyEvent::Select ) {
|
||||
if( on_select ) {
|
||||
const auto selected = recent.find(selected_key);
|
||||
const auto selected = find(recent, selected_key);
|
||||
if( selected != std::end(recent) ) {
|
||||
on_select(*selected);
|
||||
return true;
|
||||
@ -197,7 +193,7 @@ private:
|
||||
EntryKey selected_key = Entry::invalid_key;
|
||||
|
||||
void advance(const int32_t amount) {
|
||||
auto selected = recent.find(selected_key);
|
||||
auto selected = find(recent, selected_key);
|
||||
if( selected == std::end(recent) ) {
|
||||
if( recent.empty() ) {
|
||||
selected_key = Entry::invalid_key;
|
||||
@ -222,21 +218,61 @@ private:
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void draw_header(
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style
|
||||
);
|
||||
|
||||
void draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style,
|
||||
const bool is_selected
|
||||
const Style& style
|
||||
);
|
||||
};
|
||||
|
||||
template<class Entries>
|
||||
class RecentEntriesView : public View {
|
||||
public:
|
||||
using Entry = typename Entries::value_type;
|
||||
|
||||
std::function<void(const Entry& entry)> on_select { };
|
||||
|
||||
RecentEntriesView(
|
||||
const RecentEntriesColumns& columns,
|
||||
Entries& recent
|
||||
) : _header { columns },
|
||||
_table { recent }
|
||||
{
|
||||
add_children({
|
||||
&_header,
|
||||
&_table,
|
||||
});
|
||||
|
||||
_table.on_select = [this](const Entry& entry) { if( this->on_select ) { this->on_select(entry); } };
|
||||
}
|
||||
|
||||
void set_parent_rect(const Rect new_parent_rect) override {
|
||||
constexpr Dim scale_height = 16;
|
||||
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
_header.set_parent_rect({ 0, 0, new_parent_rect.width(), scale_height });
|
||||
_table.set_parent_rect({
|
||||
0, scale_height,
|
||||
new_parent_rect.width(),
|
||||
new_parent_rect.height() - scale_height
|
||||
});
|
||||
}
|
||||
|
||||
void paint(Painter&) override {
|
||||
// Children completely cover this View, do not paint.
|
||||
// TODO: What happens here shouldn't matter if I do proper damage detection!
|
||||
}
|
||||
|
||||
void on_focus() override {
|
||||
_table.focus();
|
||||
}
|
||||
|
||||
private:
|
||||
RecentEntriesHeader _header;
|
||||
RecentEntriesTable<Entries> _table;
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__RECENT_ENTRIES_H__*/
|
||||
|
@ -35,7 +35,7 @@ namespace ui {
|
||||
ReplayAppView::ReplayAppView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_replay);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&channel,
|
||||
&field_frequency,
|
||||
&field_frequency_step,
|
||||
@ -44,7 +44,7 @@ ReplayAppView::ReplayAppView(NavigationView& nav) {
|
||||
&field_vga,
|
||||
&replay_view,
|
||||
&waterfall,
|
||||
} });
|
||||
});
|
||||
|
||||
field_frequency.set_value(target_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
@ -73,8 +73,7 @@ ReplayAppView::ReplayAppView(NavigationView& nav) {
|
||||
rf::Direction::Transmit,
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
1,
|
||||
static_cast<int8_t>(receiver_model.vga())
|
||||
});
|
||||
|
||||
replay_view.set_sampling_rate(sampling_rate / 8);
|
||||
|
@ -23,60 +23,22 @@
|
||||
#include "replay_thread.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "buffer_exchange.hpp"
|
||||
|
||||
// StreamOutput ///////////////////////////////////////////////////////////
|
||||
|
||||
class StreamOutput {
|
||||
public:
|
||||
StreamOutput(CaptureConfig* const config);
|
||||
~StreamOutput();
|
||||
|
||||
size_t available() {
|
||||
return fifo_buffers_full->len();
|
||||
struct BasebandReplay {
|
||||
BasebandReplay(CaptureConfig* const config) {
|
||||
baseband::replay_start(config);
|
||||
}
|
||||
|
||||
StreamBuffer* get_buffer() {
|
||||
StreamBuffer* p { nullptr };
|
||||
fifo_buffers_full->out(p);
|
||||
return p;
|
||||
~BasebandReplay() {
|
||||
baseband::replay_stop();
|
||||
}
|
||||
|
||||
bool release_buffer(StreamBuffer* const p) {
|
||||
p->empty();
|
||||
return fifo_buffers_empty->in(p);
|
||||
}
|
||||
|
||||
static FIFO<StreamBuffer*>* fifo_buffers_empty;
|
||||
static FIFO<StreamBuffer*>* fifo_buffers_full;
|
||||
|
||||
private:
|
||||
CaptureConfig* const config;
|
||||
};
|
||||
|
||||
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_empty = nullptr;
|
||||
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_full = nullptr;
|
||||
|
||||
StreamOutput::StreamOutput(
|
||||
CaptureConfig* const config
|
||||
) : config { config }
|
||||
{
|
||||
baseband::capture_start(config);
|
||||
fifo_buffers_empty = config->fifo_buffers_empty;
|
||||
fifo_buffers_full = config->fifo_buffers_full;
|
||||
}
|
||||
|
||||
StreamOutput::~StreamOutput() {
|
||||
fifo_buffers_full = nullptr;
|
||||
fifo_buffers_empty = nullptr;
|
||||
baseband::capture_stop();
|
||||
}
|
||||
|
||||
// CaptureThread //////////////////////////////////////////////////////////
|
||||
|
||||
Thread* ReplayThread::thread = nullptr;
|
||||
// ReplayThread ///////////////////////////////////////////////////////////
|
||||
|
||||
ReplayThread::ReplayThread(
|
||||
std::unique_ptr<Reader> reader,
|
||||
std::unique_ptr<stream::Reader> reader,
|
||||
size_t read_size,
|
||||
size_t buffer_count,
|
||||
std::function<void()> success_callback,
|
||||
@ -93,23 +55,11 @@ ReplayThread::ReplayThread(
|
||||
ReplayThread::~ReplayThread() {
|
||||
if( thread ) {
|
||||
chThdTerminate(thread);
|
||||
chEvtSignal(thread, event_mask_loop_wake);
|
||||
chThdWait(thread);
|
||||
thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ReplayThread::check_fifo_isr() {
|
||||
// TODO: Prevent over-signalling by transmitting a set of
|
||||
// flags from the baseband core.
|
||||
const auto fifo = StreamOutput::fifo_buffers_full;
|
||||
if( fifo ) {
|
||||
if( !fifo->is_empty() ) {
|
||||
chEvtSignalI(thread, event_mask_loop_wake);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg_t ReplayThread::static_fn(void* arg) {
|
||||
auto obj = static_cast<ReplayThread*>(arg);
|
||||
const auto error = obj->run();
|
||||
@ -124,19 +74,16 @@ msg_t ReplayThread::static_fn(void* arg) {
|
||||
}
|
||||
|
||||
Optional<File::Error> ReplayThread::run() {
|
||||
StreamOutput stream { &config };
|
||||
BasebandReplay replay { &config };
|
||||
BufferExchange buffers { &config };
|
||||
|
||||
while( !chThdShouldTerminate() ) {
|
||||
if( stream.available() ) {
|
||||
auto buffer = stream.get_buffer();
|
||||
auto read_result = reader->reader(buffer->data(), buffer->size());
|
||||
if( read_result.is_error() ) {
|
||||
return read_result.error();
|
||||
}
|
||||
stream.release_buffer(buffer);
|
||||
} else {
|
||||
chEvtWaitAny(event_mask_loop_wake);
|
||||
auto buffer = buffers.get();
|
||||
auto read_result = reader->read(buffer->data(), buffer->size());
|
||||
if( read_result.is_error() ) {
|
||||
return read_result.error();
|
||||
}
|
||||
buffers.put(buffer);
|
||||
}
|
||||
|
||||
return { };
|
||||
|
@ -27,23 +27,17 @@
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "io.hpp"
|
||||
#include "optional.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
virtual File::Result<size_t> read(const void* const buffer, const size_t bytes) = 0;
|
||||
virtual ~Reader() = default;
|
||||
};
|
||||
|
||||
class ReplayThread {
|
||||
public:
|
||||
ReplayThread(
|
||||
std::unique_ptr<Reader> reader,
|
||||
std::unique_ptr<stream::Reader> reader,
|
||||
size_t read_size,
|
||||
size_t buffer_count,
|
||||
std::function<void()> success_callback,
|
||||
@ -51,20 +45,21 @@ public:
|
||||
);
|
||||
~ReplayThread();
|
||||
|
||||
const ReplayConfig& state() const {
|
||||
ReplayThread(const ReplayThread&) = delete;
|
||||
ReplayThread(ReplayThread&&) = delete;
|
||||
ReplayThread& operator=(const ReplayThread&) = delete;
|
||||
ReplayThread& operator=(ReplayThread&&) = delete;
|
||||
|
||||
const CaptureConfig& state() const {
|
||||
return config;
|
||||
}
|
||||
|
||||
static void check_fifo_isr();
|
||||
|
||||
private:
|
||||
static constexpr auto event_mask_loop_wake = EVENT_MASK(0);
|
||||
|
||||
ReplayConfig config;
|
||||
std::unique_ptr<Reader> reader;
|
||||
CaptureConfig config;
|
||||
std::unique_ptr<stream::Reader> reader;
|
||||
std::function<void()> success_callback;
|
||||
std::function<void(File::Error)> error_callback;
|
||||
static Thread* thread;
|
||||
Thread* thread { nullptr };
|
||||
|
||||
static msg_t static_fn(void* arg);
|
||||
|
||||
|
@ -92,9 +92,9 @@ struct Config {
|
||||
lp(band == Band::Low),
|
||||
amp_bypass(!amplify),
|
||||
tx_amp((direction == Direction::Transmit) && amplify),
|
||||
not_tx_amp(!((direction == Direction::Transmit) && amplify)),
|
||||
not_tx_amp(!tx_amp),
|
||||
rx_amp((direction == Direction::Receive) && amplify),
|
||||
not_rx_amp(!((direction == Direction::Receive) && amplify))
|
||||
not_rx_amp(!rx_amp)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -813,10 +813,10 @@ public:
|
||||
reg_t read(const address_t reg_num);
|
||||
|
||||
private:
|
||||
spi::SPI _bus;
|
||||
spi::SPI _bus { };
|
||||
|
||||
RegisterMap _map { default_hackrf_one };
|
||||
DirtyRegisters<Register, reg_count> _dirty;
|
||||
DirtyRegisters<Register, reg_count> _dirty { };
|
||||
|
||||
void write(const address_t reg_num, const reg_t value);
|
||||
|
||||
|
@ -19,9 +19,9 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
namespace time {
|
||||
namespace rtc_time {
|
||||
|
||||
Signal<> signal_tick_second;
|
||||
|
||||
@ -29,4 +29,4 @@ void on_tick_second() {
|
||||
signal_tick_second.emit();
|
||||
}
|
||||
|
||||
} /* namespace time */
|
||||
} /* namespace rtc_time */
|
@ -19,17 +19,17 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __TIME_H__
|
||||
#define __TIME_H__
|
||||
#ifndef __RTC_TIME_H__
|
||||
#define __RTC_TIME_H__
|
||||
|
||||
#include "signal.hpp"
|
||||
|
||||
namespace time {
|
||||
namespace rtc_time {
|
||||
|
||||
extern Signal<> signal_tick_second;
|
||||
|
||||
void on_tick_second();
|
||||
|
||||
} /* namespace time */
|
||||
} /* namespace rtc_time */
|
||||
|
||||
#endif/*__TIME_H__*/
|
||||
#endif/*__RTC_TIME_H__*/
|
@ -36,7 +36,7 @@ bool card_present = false;
|
||||
Status status_ { Status::NotPresent };
|
||||
|
||||
FRESULT mount() {
|
||||
return f_mount(&fs, "", 0);
|
||||
return f_mount(&fs, reinterpret_cast<const TCHAR*>(_T("")), 0);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
@ -168,7 +168,7 @@ struct Inputs {
|
||||
const uint32_t f_clkin;
|
||||
const uint32_t clkin_div;
|
||||
|
||||
constexpr uint32_t f_clkin_out() {
|
||||
constexpr uint32_t f_clkin_out() const {
|
||||
return f_clkin / clkin_div;
|
||||
}
|
||||
};
|
||||
@ -181,23 +181,23 @@ struct PLL {
|
||||
const uint32_t b;
|
||||
const uint32_t c;
|
||||
|
||||
constexpr uint32_t f_vco() {
|
||||
constexpr uint32_t f_vco() const {
|
||||
return f_in * (a + (float)b / (float)c);
|
||||
}
|
||||
|
||||
constexpr uint32_t p1() {
|
||||
constexpr uint32_t p1() const {
|
||||
return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512;
|
||||
}
|
||||
|
||||
constexpr uint32_t p2() {
|
||||
constexpr uint32_t p2() const {
|
||||
return 128 * b - c * (uint32_t)(128 * (float)b / (float)c);
|
||||
}
|
||||
|
||||
constexpr uint32_t p3() {
|
||||
constexpr uint32_t p3() const {
|
||||
return c;
|
||||
}
|
||||
|
||||
constexpr PLLReg reg(const uint8_t pll_n) {
|
||||
constexpr PLLReg reg(const uint8_t pll_n) const {
|
||||
return {
|
||||
uint8_t(26 + (pll_n * 8)),
|
||||
uint8_t((p3() >> 8) & 0xff),
|
||||
@ -224,23 +224,23 @@ struct MultisynthFractional {
|
||||
const uint32_t c;
|
||||
const uint32_t r_div;
|
||||
|
||||
constexpr uint32_t p1() {
|
||||
constexpr uint32_t p1() const {
|
||||
return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512;
|
||||
}
|
||||
|
||||
constexpr uint32_t p2() {
|
||||
constexpr uint32_t p2() const {
|
||||
return 128 * b - c * (uint32_t)(128 * (float)b / (float)c);
|
||||
}
|
||||
|
||||
constexpr uint32_t p3() {
|
||||
constexpr uint32_t p3() const {
|
||||
return c;
|
||||
}
|
||||
|
||||
constexpr uint32_t f_out() {
|
||||
constexpr uint32_t f_out() const {
|
||||
return f_src / (a + (float)b / (float)c) / (1 << r_div);
|
||||
}
|
||||
|
||||
constexpr MultisynthFractionalReg reg(const uint8_t multisynth_n) {
|
||||
constexpr MultisynthFractionalReg reg(const uint8_t multisynth_n) const {
|
||||
return {
|
||||
uint8_t(42 + (multisynth_n * 8)),
|
||||
uint8_t((p3() >> 8) & 0xFF),
|
||||
@ -260,11 +260,11 @@ struct MultisynthInteger {
|
||||
const uint32_t a;
|
||||
const uint32_t r_div;
|
||||
|
||||
constexpr uint8_t p1() {
|
||||
constexpr uint8_t p1() const {
|
||||
return a;
|
||||
}
|
||||
|
||||
constexpr uint32_t f_out() {
|
||||
constexpr uint32_t f_out() const {
|
||||
return f_src / a / (1 << r_div);
|
||||
}
|
||||
};
|
||||
|
@ -78,7 +78,7 @@ private:
|
||||
|
||||
using EntryType = std::unique_ptr<CallbackEntry>;
|
||||
|
||||
std::list<EntryType> entries;
|
||||
std::list<EntryType> entries { };
|
||||
SignalToken next_token = 1;
|
||||
};
|
||||
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
std::vector<sample_t> history() const;
|
||||
|
||||
private:
|
||||
std::array<sample_t, 128> samples;
|
||||
std::array<sample_t, 128> samples { };
|
||||
|
||||
static constexpr size_t sample_interval = 5;
|
||||
size_t sample_phase = 0;
|
||||
|
@ -73,10 +73,7 @@ ui::Point Calibration::translate(const DigitizerPoint& p) const {
|
||||
const int32_t y = (d * p.x + e * p.y + f) / k;
|
||||
const auto x_clipped = x_range.clip(x);
|
||||
const auto y_clipped = y_range.clip(y);
|
||||
return {
|
||||
static_cast<ui::Coord>(x_clipped),
|
||||
static_cast<ui::Coord>(y_clipped)
|
||||
};
|
||||
return { x_clipped, y_clipped };
|
||||
}
|
||||
|
||||
const Calibration default_calibration() {
|
||||
|
@ -128,12 +128,12 @@ struct Calibration {
|
||||
const std::array<DigitizerPoint, 3>& s,
|
||||
const std::array<ui::Point, 3>& d
|
||||
) : k { (s[0].x - s[2].x) * (s[1].y - s[2].y) - (s[1].x - s[2].x) * (s[0].y - s[2].y) },
|
||||
a { (d[0].x - d[2].x) * (s[1].y - s[2].y) - (d[1].x - d[2].x) * (s[0].y - s[2].y) },
|
||||
b { (s[0].x - s[2].x) * (d[1].x - d[2].x) - (d[0].x - d[2].x) * (s[1].x - s[2].x) },
|
||||
c { s[0].y * (s[2].x * d[1].x - s[1].x * d[2].x) + s[1].y * (s[0].x * d[2].x - s[2].x * d[0].x) + s[2].y * (s[1].x * d[0].x - s[0].x * d[1].x) },
|
||||
d { (d[0].y - d[2].y) * (s[1].y - s[2].y) - (d[1].y - d[2].y) * (s[0].y - s[2].y) },
|
||||
e { (s[0].x - s[2].x) * (d[1].y - d[2].y) - (d[0].y - d[2].y) * (s[1].x - s[2].x) },
|
||||
f { s[0].y * (s[2].x * d[1].y - s[1].x * d[2].y) + s[1].y * (s[0].x * d[2].y - s[2].x * d[0].y) + s[2].y * (s[1].x * d[0].y - s[0].x * d[1].y) }
|
||||
a { (d[0].x() - d[2].x()) * (s[1].y - s[2].y) - (d[1].x() - d[2].x()) * (s[0].y - s[2].y) },
|
||||
b { (s[0].x - s[2].x) * (d[1].x() - d[2].x()) - (d[0].x() - d[2].x()) * (s[1].x - s[2].x) },
|
||||
c { s[0].y * (s[2].x * d[1].x() - s[1].x * d[2].x()) + s[1].y * (s[0].x * d[2].x() - s[2].x * d[0].x()) + s[2].y * (s[1].x * d[0].x() - s[0].x * d[1].x()) },
|
||||
d { (d[0].y() - d[2].y()) * (s[1].y - s[2].y) - (d[1].y() - d[2].y()) * (s[0].y - s[2].y) },
|
||||
e { (s[0].x - s[2].x) * (d[1].y() - d[2].y()) - (d[0].y() - d[2].y()) * (s[1].x - s[2].x) },
|
||||
f { s[0].y * (s[2].x * d[1].y() - s[1].x * d[2].y()) + s[1].y * (s[0].x * d[2].y() - s[2].x * d[0].y()) + s[2].y * (s[1].x * d[0].y() - s[0].x * d[1].y()) }
|
||||
{
|
||||
}
|
||||
|
||||
@ -154,13 +154,7 @@ const Calibration default_calibration();
|
||||
template<size_t N>
|
||||
class Filter {
|
||||
public:
|
||||
constexpr Filter(
|
||||
) : history(),
|
||||
history_history { 0 },
|
||||
accumulator { 0 },
|
||||
n { 0 }
|
||||
{
|
||||
}
|
||||
constexpr Filter() = default;
|
||||
|
||||
void reset() {
|
||||
history.fill(0);
|
||||
@ -177,7 +171,7 @@ public:
|
||||
history_history = (history_history << 1) | 1U;
|
||||
}
|
||||
|
||||
uint32_t value() const {
|
||||
int32_t value() const {
|
||||
return accumulator / N;
|
||||
}
|
||||
|
||||
@ -196,10 +190,10 @@ public:
|
||||
private:
|
||||
static constexpr uint32_t history_history_mask { (1U << N) - 1 };
|
||||
|
||||
std::array<sample_t, N> history;
|
||||
uint32_t history_history;
|
||||
uint32_t accumulator;
|
||||
size_t n;
|
||||
std::array<sample_t, N> history { };
|
||||
uint32_t history_history { 0 };
|
||||
int32_t accumulator { 0 };
|
||||
size_t n { 0 };
|
||||
|
||||
bool history_valid() const {
|
||||
return (history_history & history_history_mask) == history_history_mask;
|
||||
@ -208,7 +202,7 @@ private:
|
||||
|
||||
class Manager {
|
||||
public:
|
||||
std::function<void(ui::TouchEvent)> on_event;
|
||||
std::function<void(ui::TouchEvent)> on_event { };
|
||||
|
||||
void feed(const Frame& frame);
|
||||
|
||||
@ -224,8 +218,8 @@ private:
|
||||
|
||||
// Ensure filter length is equal or less than touch_count_threshold,
|
||||
// or coordinates from the last touch will be in the initial averages.
|
||||
Filter<touch_count_threshold> filter_x;
|
||||
Filter<touch_count_threshold> filter_y;
|
||||
Filter<touch_count_threshold> filter_x { };
|
||||
Filter<touch_count_threshold> filter_y { };
|
||||
|
||||
//Debounce touch_debounce;
|
||||
|
||||
|
@ -57,14 +57,14 @@ constexpr lpc43xx::adc::Config adc0_config {
|
||||
};
|
||||
|
||||
void init() {
|
||||
adc0.clock_enable();
|
||||
adc0.interrupts_disable();
|
||||
adc0.power_up(adc0_config);
|
||||
adc0.interrupts_enable(adc0_interrupt_mask);
|
||||
adc0::clock_enable();
|
||||
adc0::interrupts_disable();
|
||||
adc0::power_up(adc0_config);
|
||||
adc0::interrupts_enable(adc0_interrupt_mask);
|
||||
}
|
||||
|
||||
void start() {
|
||||
adc0.start_burst();
|
||||
adc0::start_burst();
|
||||
}
|
||||
|
||||
// static constexpr bool monitor_overruns_and_not_dones = false;
|
||||
|
@ -95,44 +95,13 @@ void TPMSRecentEntry::update(const tpms::Reading& reading) {
|
||||
|
||||
namespace ui {
|
||||
|
||||
static const std::array<std::pair<std::string, size_t>, 6> tpms_columns { {
|
||||
{ "Tp", 2 },
|
||||
{ "ID", 8 },
|
||||
{ "kPa", 3 },
|
||||
{ "C", 3 },
|
||||
{ "Cnt", 3 },
|
||||
{ "Fl", 2 },
|
||||
} };
|
||||
|
||||
template<>
|
||||
void RecentEntriesView<TPMSRecentEntries>::draw_header(
|
||||
void RecentEntriesTable<TPMSRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style
|
||||
) {
|
||||
auto x = 0;
|
||||
for(const auto& column : tpms_columns) {
|
||||
const auto width = column.second;
|
||||
auto text = column.first;
|
||||
if( width > text.length() ) {
|
||||
text.append(width - text.length(), ' ');
|
||||
}
|
||||
|
||||
painter.draw_string({ x, target_rect.pos.y }, style, text);
|
||||
x += (width * 8) + 8;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void RecentEntriesView<TPMSRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style,
|
||||
const bool is_selected
|
||||
) {
|
||||
const auto& draw_style = is_selected ? style.invert() : style;
|
||||
|
||||
std::string line = tpms::format::type(entry.type) + " " + tpms::format::id(entry.id);
|
||||
|
||||
if( entry.last_pressure.is_valid() ) {
|
||||
@ -160,13 +129,13 @@ void RecentEntriesView<TPMSRecentEntries>::draw(
|
||||
}
|
||||
|
||||
line.resize(target_rect.width() / 8, ' ');
|
||||
painter.draw_string(target_rect.pos, draw_style, line);
|
||||
painter.draw_string(target_rect.location(), style, line);
|
||||
}
|
||||
|
||||
TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tpms);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&rssi,
|
||||
&channel,
|
||||
&options_band,
|
||||
@ -174,7 +143,7 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&recent_entries_view,
|
||||
} });
|
||||
});
|
||||
|
||||
radio::enable({
|
||||
tuning_frequency(),
|
||||
@ -184,7 +153,6 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
1,
|
||||
});
|
||||
|
||||
options_band.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
@ -194,7 +162,7 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
|
||||
logger = std::make_unique<TPMSLogger>();
|
||||
if( logger ) {
|
||||
logger->append("tpms.txt");
|
||||
logger->append(u"tpms.txt");
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,7 +189,8 @@ void TPMSAppView::on_packet(const tpms::Packet& packet) {
|
||||
const auto reading_opt = packet.reading();
|
||||
if( reading_opt.is_valid() ) {
|
||||
const auto reading = reading_opt.value();
|
||||
recent.on_packet({ reading.type(), reading.id() }, reading);
|
||||
auto& entry = ::on_packet(recent, TPMSRecentEntry::Key { reading.type(), reading.id() });
|
||||
entry.update(reading);
|
||||
recent_entries_view.set_dirty();
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ struct TPMSRecentEntry {
|
||||
|
||||
size_t received_count { 0 };
|
||||
|
||||
Optional<Pressure> last_pressure;
|
||||
Optional<Temperature> last_temperature;
|
||||
Optional<tpms::Flags> last_flags;
|
||||
Optional<Pressure> last_pressure { };
|
||||
Optional<Temperature> last_temperature { };
|
||||
Optional<tpms::Flags> last_flags { };
|
||||
|
||||
TPMSRecentEntry(
|
||||
const Key& key
|
||||
@ -72,18 +72,18 @@ struct TPMSRecentEntry {
|
||||
void update(const tpms::Reading& reading);
|
||||
};
|
||||
|
||||
using TPMSRecentEntries = RecentEntries<tpms::Reading, TPMSRecentEntry>;
|
||||
using TPMSRecentEntries = RecentEntries<TPMSRecentEntry>;
|
||||
|
||||
class TPMSLogger {
|
||||
public:
|
||||
Optional<File::Error> append(const std::string& filename) {
|
||||
Optional<File::Error> append(const std::filesystem::path& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void on_packet(const tpms::Packet& packet, const uint32_t target_frequency);
|
||||
|
||||
private:
|
||||
LogFile log_file;
|
||||
LogFile log_file { };
|
||||
};
|
||||
|
||||
namespace ui {
|
||||
@ -150,10 +150,18 @@ private:
|
||||
{ 18 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
TPMSRecentEntries recent;
|
||||
std::unique_ptr<TPMSLogger> logger;
|
||||
TPMSRecentEntries recent { };
|
||||
std::unique_ptr<TPMSLogger> logger { };
|
||||
|
||||
TPMSRecentEntriesView recent_entries_view { recent };
|
||||
const RecentEntriesColumns columns { {
|
||||
{ "Tp", 2 },
|
||||
{ "ID", 8 },
|
||||
{ "kPa", 3 },
|
||||
{ "C", 3 },
|
||||
{ "Cnt", 3 },
|
||||
{ "Fl", 2 },
|
||||
} };
|
||||
TPMSRecentEntriesView recent_entries_view { columns, recent };
|
||||
|
||||
uint32_t target_frequency_ = initial_target_frequency;
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
using namespace hackrf::one;
|
||||
using namespace portapack;
|
||||
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "event_m0.hpp"
|
||||
#include "radio.hpp"
|
||||
#include "audio.hpp"
|
||||
@ -80,12 +80,12 @@ void TransmitterModel::set_vga(int32_t v_db) {
|
||||
}
|
||||
|
||||
uint32_t TransmitterModel::sampling_rate() const {
|
||||
return baseband_configuration.sampling_rate;
|
||||
return sampling_rate_;
|
||||
}
|
||||
|
||||
uint32_t TransmitterModel::baseband_oversampling() const {
|
||||
// TODO: Rename decimation_factor.
|
||||
return baseband_configuration.decimation_factor;
|
||||
void TransmitterModel::set_sampling_rate(uint32_t v) {
|
||||
sampling_rate_ = v;
|
||||
update_sampling_rate();
|
||||
}
|
||||
|
||||
void TransmitterModel::on_tick_second() {
|
||||
@ -101,10 +101,10 @@ void TransmitterModel::enable() {
|
||||
update_lna();
|
||||
update_vga();
|
||||
update_baseband_bandwidth();
|
||||
update_baseband_configuration();
|
||||
update_sampling_rate();
|
||||
|
||||
led_tx.on();
|
||||
signal_token_tick_second = time::signal_tick_second += [this]() {
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
if (portapack::persistent_memory::stealth_mode())
|
||||
@ -118,7 +118,7 @@ void TransmitterModel::disable() {
|
||||
// Some happens in ReceiverModel, some inside radio namespace.
|
||||
radio::disable();
|
||||
|
||||
time::signal_tick_second -= signal_token_tick_second;
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
led_tx.off();
|
||||
}
|
||||
|
||||
@ -142,18 +142,16 @@ void TransmitterModel::update_vga() {
|
||||
radio::set_vga_gain(vga_gain_db_);
|
||||
}
|
||||
|
||||
void TransmitterModel::set_baseband_configuration(const BasebandConfiguration config) {
|
||||
baseband_configuration = config;
|
||||
update_baseband_configuration();
|
||||
void TransmitterModel::update_tx_gain() {
|
||||
radio::set_tx_gain(tx_gain_db_);
|
||||
}
|
||||
|
||||
void TransmitterModel::update_baseband_configuration() {
|
||||
void TransmitterModel::update_sampling_rate() {
|
||||
// TODO: Move more low-level radio control stuff to M4. It'll enable tighter
|
||||
// synchronization for things like wideband (sweeping) spectrum analysis, and
|
||||
// protocols that need quick RX/TX turn-around.
|
||||
|
||||
// Disabling baseband while changing sampling rates seems like a good idea...
|
||||
radio::set_baseband_rate(sampling_rate() * baseband_oversampling());
|
||||
radio::set_baseband_rate(sampling_rate());
|
||||
update_tuning_frequency();
|
||||
radio::set_baseband_decimation_by(baseband_oversampling());
|
||||
}
|
||||
|
@ -49,17 +49,15 @@ public:
|
||||
|
||||
int32_t vga() const;
|
||||
void set_vga(int32_t v_db);
|
||||
|
||||
int32_t tx_gain() const;
|
||||
void set_tx_gain(int32_t v_db);
|
||||
|
||||
uint32_t sampling_rate() const;
|
||||
|
||||
uint32_t modulation() const;
|
||||
|
||||
uint32_t baseband_oversampling() const;
|
||||
void set_sampling_rate(uint32_t v);
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void set_baseband_configuration(const BasebandConfiguration config);
|
||||
|
||||
private:
|
||||
bool enabled_ { false };
|
||||
@ -67,20 +65,17 @@ private:
|
||||
int32_t lna_gain_db_ { 0 };
|
||||
uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum };
|
||||
int32_t vga_gain_db_ { 8 };
|
||||
BasebandConfiguration baseband_configuration {
|
||||
.mode = 0,
|
||||
.sampling_rate = 3072000,
|
||||
.decimation_factor = 1,
|
||||
};
|
||||
SignalToken signal_token_tick_second;
|
||||
int32_t tx_gain_db_ { 47 };
|
||||
uint32_t sampling_rate_ { 3072000 };
|
||||
SignalToken signal_token_tick_second { };
|
||||
|
||||
void update_tuning_frequency();
|
||||
void update_rf_amp();
|
||||
void update_lna();
|
||||
void update_baseband_bandwidth();
|
||||
void update_vga();
|
||||
void update_modulation();
|
||||
void update_baseband_configuration();
|
||||
void update_tx_gain();
|
||||
void update_sampling_rate();
|
||||
void on_tick_second();
|
||||
};
|
||||
|
||||
|
@ -49,8 +49,8 @@ constexpr rf::Frequency high_band_second_lo_frequency(const rf::Frequency target
|
||||
Config low_band(const rf::Frequency target_frequency) {
|
||||
const rf::Frequency first_lo_frequency = target_frequency + low_band_second_lo_frequency(target_frequency);
|
||||
const rf::Frequency second_lo_frequency = first_lo_frequency - target_frequency;
|
||||
const bool baseband_q_invert = true;
|
||||
return { first_lo_frequency, second_lo_frequency, rf::path::Band::Low, baseband_q_invert };
|
||||
const bool baseband_invert = true;
|
||||
return { first_lo_frequency, second_lo_frequency, rf::path::Band::Low, baseband_invert };
|
||||
}
|
||||
|
||||
Config mid_band(const rf::Frequency target_frequency) {
|
||||
@ -60,8 +60,8 @@ Config mid_band(const rf::Frequency target_frequency) {
|
||||
Config high_band(const rf::Frequency target_frequency) {
|
||||
const rf::Frequency first_lo_frequency = target_frequency - high_band_second_lo_frequency(target_frequency);
|
||||
const rf::Frequency second_lo_frequency = target_frequency - first_lo_frequency;
|
||||
const bool baseband_q_invert = false;
|
||||
return { first_lo_frequency, second_lo_frequency, rf::path::Band::High, baseband_q_invert };
|
||||
const bool baseband_invert = false;
|
||||
return { first_lo_frequency, second_lo_frequency, rf::path::Band::High, baseband_invert };
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
@ -33,7 +33,7 @@ struct Config {
|
||||
) : first_lo_frequency(0),
|
||||
second_lo_frequency(0),
|
||||
rf_path_band(rf::path::Band::Mid),
|
||||
baseband_q_invert(false)
|
||||
baseband_invert(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -41,11 +41,11 @@ struct Config {
|
||||
rf::Frequency first_lo_frequency,
|
||||
rf::Frequency second_lo_frequency,
|
||||
rf::path::Band rf_path_band,
|
||||
bool baseband_q_invert
|
||||
bool baseband_invert
|
||||
) : first_lo_frequency(first_lo_frequency),
|
||||
second_lo_frequency(second_lo_frequency),
|
||||
rf_path_band(rf_path_band),
|
||||
baseband_q_invert(baseband_q_invert)
|
||||
baseband_invert(baseband_invert)
|
||||
{
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ struct Config {
|
||||
const rf::Frequency first_lo_frequency;
|
||||
const rf::Frequency second_lo_frequency;
|
||||
const rf::path::Band rf_path_band;
|
||||
const bool baseband_q_invert;
|
||||
const bool baseband_invert;
|
||||
};
|
||||
|
||||
Config create(const rf::Frequency target_frequency);
|
||||
|
@ -52,7 +52,7 @@ void AboutView::update() {
|
||||
} else {
|
||||
// Find a free text widget
|
||||
for (c = 0; c < 10; c++)
|
||||
if (text_line[c].screen_pos().y >= 200) break;
|
||||
if (text_line[c].screen_pos().y() >= 200) break;
|
||||
|
||||
if (c < 10) {
|
||||
flag = credits[credits_index].flag & 0x3F;
|
||||
@ -106,13 +106,13 @@ void AboutView::update() {
|
||||
|
||||
// Scroll text lines
|
||||
for (c = 0; c < 10; c++) {
|
||||
y_val = text_line[c].screen_pos().y - 16;
|
||||
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].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() }});
|
||||
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);
|
||||
@ -134,11 +134,11 @@ AboutView::AboutView(
|
||||
{
|
||||
//uint8_t p, c;
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_cpld_hackrf,
|
||||
&text_cpld_hackrf_status,
|
||||
&button_ok,
|
||||
} });
|
||||
});
|
||||
|
||||
for (auto& text : text_line) {
|
||||
text.set("");
|
||||
|
@ -101,7 +101,7 @@ private:
|
||||
{"", "MMXVI", END}
|
||||
};
|
||||
|
||||
std::array<Text, 10> text_line;
|
||||
std::array<Text, 10> text_line { };
|
||||
|
||||
Text text_cpld_hackrf {
|
||||
{ 0, 252, 11*8, 16 },
|
||||
|
@ -84,11 +84,7 @@ void ADSBTxView::generate_frame() {
|
||||
|
||||
void ADSBTxView::start_tx() {
|
||||
transmitter_model.set_tuning_frequency(452000000); // FOR TESTING - DEBUG
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 2000000U, // Good ?
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(2000000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -121,7 +117,7 @@ ADSBTxView::ADSBTxView(NavigationView& nav) {
|
||||
|
||||
// http://openflights.org
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_format,
|
||||
&options_format,
|
||||
&text_icaolabel,
|
||||
@ -141,7 +137,7 @@ ADSBTxView::ADSBTxView(NavigationView& nav) {
|
||||
&text_frame_a,
|
||||
&text_frame_b,
|
||||
&button_transmit
|
||||
} });
|
||||
});
|
||||
|
||||
options_format.set_by_value(17); // Mode S
|
||||
|
||||
|
@ -36,10 +36,10 @@ AFSKRXView::AFSKRXView(
|
||||
NavigationView& nav
|
||||
)
|
||||
{
|
||||
add_children({ {
|
||||
add_children({
|
||||
&button_done,
|
||||
&text_rx
|
||||
} } );
|
||||
});
|
||||
|
||||
button_done.on_select = [&nav](Button&){
|
||||
nav.pop();
|
||||
|
@ -68,7 +68,7 @@ AFSKSetupView::AFSKSetupView(
|
||||
uint8_t rpt;
|
||||
size_t i;
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_setfreq,
|
||||
&button_setfreq,
|
||||
&text_bps,
|
||||
@ -84,7 +84,7 @@ AFSKSetupView::AFSKSetupView(
|
||||
&text_format,
|
||||
&options_format,
|
||||
&button_save
|
||||
} });
|
||||
});
|
||||
|
||||
for (i = 0; i < AFSK_MODES_COUNT; i++)
|
||||
format_options.emplace_back(std::make_pair(afsk_formats[i].fullname, i));
|
||||
|
@ -66,12 +66,12 @@ AlphanumView::AlphanumView(
|
||||
txtidx--;
|
||||
}
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_input,
|
||||
&button_lowercase,
|
||||
&raw_char,
|
||||
&button_ok
|
||||
} });
|
||||
});
|
||||
|
||||
const auto button_fn = [this](Button& button) {
|
||||
this->on_button(button);
|
||||
@ -124,11 +124,11 @@ AlphanumView::AlphanumView(
|
||||
void AlphanumView::move_cursor() {
|
||||
Point cursor_pos;
|
||||
|
||||
cursor_pos.x = text_input.screen_rect().pos.x + (txtidx * 8);
|
||||
cursor_pos.y = text_input.screen_rect().pos.y + 16;
|
||||
cursor_pos = {text_input.screen_rect().location().x() + (txtidx * 8),
|
||||
text_input.screen_rect().location().y() + 16};
|
||||
|
||||
portapack::display.fill_rectangle(
|
||||
{{text_input.screen_rect().pos.x, cursor_pos.y}, {text_input.screen_rect().size.w, 4}},
|
||||
{{text_input.screen_rect().location().x(), cursor_pos.y()}, {text_input.screen_rect().size().width(), 4}},
|
||||
Color::black()
|
||||
);
|
||||
portapack::display.fill_rectangle(
|
||||
|
@ -37,6 +37,12 @@ public:
|
||||
std::function<void(char *)> on_changed;
|
||||
|
||||
AlphanumView(NavigationView& nav, char txt[], size_t max_length);
|
||||
|
||||
AlphanumView(const AlphanumView&) = delete;
|
||||
AlphanumView(AlphanumView&&) = delete;
|
||||
AlphanumView& operator=(const AlphanumView&) = delete;
|
||||
AlphanumView& operator=(AlphanumView&&) = delete;
|
||||
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void focus() override;
|
||||
|
@ -38,37 +38,25 @@ void Audio::paint(Painter& painter) {
|
||||
const range_t<int> x_max_range { x_rms + 1, r.width() };
|
||||
const auto x_max = x_max_range.clip((max_db_ - db_min) * r.width() / db_delta);
|
||||
|
||||
const Rect r0 {
|
||||
static_cast<ui::Coord>(r.left()), r.top(),
|
||||
static_cast<ui::Dim>(x_rms), r.height()
|
||||
};
|
||||
const Rect r0 { r.left(), r.top(), x_rms, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r0,
|
||||
Color::green()
|
||||
);
|
||||
|
||||
const Rect r1 {
|
||||
static_cast<ui::Coord>(r.left() + x_rms), r.top(),
|
||||
1, r.height()
|
||||
};
|
||||
const Rect r1 { r.left() + x_rms, r.top(), 1, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r1,
|
||||
Color::black()
|
||||
);
|
||||
|
||||
const Rect r2 {
|
||||
static_cast<ui::Coord>(r.left() + x_rms + 1), r.top(),
|
||||
static_cast<ui::Dim>(x_max - (x_rms + 1)), r.height()
|
||||
};
|
||||
const Rect r2 { r.left() + x_rms + 1, r.top(), x_max - (x_rms + 1), r.height() };
|
||||
painter.fill_rectangle(
|
||||
r2,
|
||||
Color::red()
|
||||
);
|
||||
|
||||
const Rect r3 {
|
||||
static_cast<ui::Coord>(r.left() + x_max), r.top(),
|
||||
static_cast<ui::Dim>(r.width() - x_max), r.height()
|
||||
};
|
||||
const Rect r3 { r.left() + x_max, r.top(), r.width() - x_max, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r3,
|
||||
Color::black()
|
||||
|
@ -52,12 +52,12 @@ AudioTXView::AudioTXView(
|
||||
{
|
||||
transmitter_model.set_tuning_frequency(92200000);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_title,
|
||||
&field_frequency,
|
||||
&button_transmit,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
|
@ -34,9 +34,9 @@ namespace ui {
|
||||
/* BasebandStatsView *****************************************************/
|
||||
|
||||
BasebandStatsView::BasebandStatsView() {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_stats,
|
||||
} });
|
||||
});
|
||||
}
|
||||
|
||||
static std::string ticks_to_percent_string(const uint32_t ticks) {
|
||||
|
@ -64,11 +64,7 @@ void BHTView::start_tx() {
|
||||
generate_message();
|
||||
|
||||
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_sampling_rate(1536000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -125,7 +121,7 @@ BHTView::BHTView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
//baseband::run_image(portapack::spi_flash::image_tag_encoders);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&options_mode,
|
||||
&text_header,
|
||||
&header_code_a,
|
||||
@ -152,7 +148,7 @@ BHTView::BHTView(NavigationView& nav) {
|
||||
&checkbox_cligno,
|
||||
&tempo_cligno,
|
||||
&text_cligno
|
||||
} });
|
||||
});
|
||||
|
||||
options_mode.set_selected_index(0); // Start up in Xy mode
|
||||
header_code_a.set_value(0);
|
||||
@ -175,7 +171,7 @@ BHTView::BHTView(NavigationView& nav) {
|
||||
|
||||
if (_mode) {
|
||||
// EP layout
|
||||
remove_children({ {
|
||||
remove_children({
|
||||
&text_header,
|
||||
&header_code_a,
|
||||
&header_code_b,
|
||||
@ -191,19 +187,19 @@ BHTView::BHTView(NavigationView& nav) {
|
||||
&checkbox_wcid,
|
||||
&relay_states[2],
|
||||
&relay_states[3]
|
||||
} });
|
||||
add_children({ {
|
||||
});
|
||||
add_children({
|
||||
&city_code_ep,
|
||||
&family_code_ep
|
||||
} });
|
||||
});
|
||||
set_dirty();
|
||||
} else {
|
||||
// Xy layout
|
||||
remove_children({ {
|
||||
remove_children({
|
||||
&city_code_ep,
|
||||
&family_code_ep
|
||||
} });
|
||||
add_children({ {
|
||||
});
|
||||
add_children({
|
||||
&text_header,
|
||||
&header_code_a,
|
||||
&header_code_b,
|
||||
@ -219,7 +215,7 @@ BHTView::BHTView(NavigationView& nav) {
|
||||
&checkbox_wcid,
|
||||
&relay_states[2],
|
||||
&relay_states[3]
|
||||
} });
|
||||
});
|
||||
set_dirty();
|
||||
};
|
||||
generate_message();
|
||||
|
@ -36,28 +36,19 @@ void Channel::paint(Painter& painter) {
|
||||
const range_t<int> x_max_range { 0, r.width() - 1 };
|
||||
const auto x_max = x_max_range.clip((max_db_ - db_min) * r.width() / db_delta);
|
||||
|
||||
const Rect r0 {
|
||||
static_cast<ui::Coord>(r.left()), r.top(),
|
||||
static_cast<ui::Dim>(x_max), r.height()
|
||||
};
|
||||
const Rect r0 { r.left(), r.top(), x_max, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r0,
|
||||
Color::blue()
|
||||
);
|
||||
|
||||
const Rect r1 {
|
||||
static_cast<ui::Coord>(r.left() + x_max), r.top(),
|
||||
1, r.height()
|
||||
};
|
||||
const Rect r1 { r.left() + x_max, r.top(), 1, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r1,
|
||||
Color::white()
|
||||
);
|
||||
|
||||
const Rect r2 {
|
||||
static_cast<ui::Coord>(r.left() + x_max + 1), r.top(),
|
||||
static_cast<ui::Dim>(r.width() - (x_max + 1)), r.height()
|
||||
};
|
||||
const Rect r2 { r.left() + x_max + 1, r.top(), r.width() - (x_max + 1), r.height() };
|
||||
painter.fill_rectangle(
|
||||
r2,
|
||||
Color::black()
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "ui_closecall.hpp"
|
||||
#include "msgpack.hpp"
|
||||
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "event_m0.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
@ -42,7 +42,7 @@ void CloseCallView::focus() {
|
||||
}
|
||||
|
||||
CloseCallView::~CloseCallView() {
|
||||
time::signal_tick_second -= signal_token_tick_second;
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
@ -301,7 +301,7 @@ CloseCallView::CloseCallView(
|
||||
{
|
||||
baseband::run_image(portapack::spi_flash::image_tag_closecall);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_labels_a,
|
||||
&text_labels_b,
|
||||
&text_labels_c,
|
||||
@ -318,7 +318,7 @@ CloseCallView::CloseCallView(
|
||||
&text_debug,
|
||||
&big_display,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
text_labels_a.set_style(&style_grey);
|
||||
text_labels_b.set_style(&style_grey);
|
||||
@ -380,7 +380,7 @@ CloseCallView::CloseCallView(
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
signal_token_tick_second = time::signal_tick_second += [this]() {
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace ui {
|
||||
/* DebugMemoryView *******************************************************/
|
||||
|
||||
DebugMemoryView::DebugMemoryView(NavigationView& nav) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_title,
|
||||
&text_label_m0_core_free,
|
||||
&text_label_m0_core_free_value,
|
||||
@ -44,7 +44,7 @@ DebugMemoryView::DebugMemoryView(NavigationView& nav) {
|
||||
&text_label_m0_heap_fragments,
|
||||
&text_label_m0_heap_fragments_value,
|
||||
&button_done
|
||||
} });
|
||||
});
|
||||
|
||||
const auto m0_core_free = chCoreStatus();
|
||||
text_label_m0_core_free_value.set(to_string_dec_uint(m0_core_free, 5));
|
||||
@ -135,11 +135,11 @@ Coord TemperatureWidget::screen_y(
|
||||
/* TemperatureView *******************************************************/
|
||||
|
||||
TemperatureView::TemperatureView(NavigationView& nav) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_title,
|
||||
&temperature_widget,
|
||||
&button_done,
|
||||
} });
|
||||
});
|
||||
|
||||
button_done.on_select = [&nav](Button&){ nav.pop(); };
|
||||
}
|
||||
@ -164,7 +164,7 @@ void RegistersWidget::update() {
|
||||
}
|
||||
|
||||
void RegistersWidget::paint(Painter& painter) {
|
||||
const Coord left = (size().w - config.row_width()) / 2;
|
||||
const Coord left = (size().width() - config.row_width()) / 2;
|
||||
|
||||
draw_legend(left, painter);
|
||||
draw_values(left, painter);
|
||||
@ -219,12 +219,12 @@ RegistersView::RegistersView(
|
||||
std::function<uint32_t(const size_t register_number)>&& reader
|
||||
) : registers_widget { std::move(config), std::move(reader) }
|
||||
{
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_title,
|
||||
®isters_widget,
|
||||
&button_update,
|
||||
&button_done,
|
||||
} });
|
||||
});
|
||||
|
||||
button_update.on_select = [this](Button&){
|
||||
this->registers_widget.update();
|
||||
@ -285,10 +285,10 @@ DebugLCRView::DebugLCRView(NavigationView& nav, std::string lcr_string, uint8_t
|
||||
|
||||
std::string debug_text;
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&console,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
for(const auto c : lcr_string) {
|
||||
if ((c < 32) || (c > 126))
|
||||
|
@ -193,7 +193,7 @@ public:
|
||||
void focus();
|
||||
|
||||
private:
|
||||
Text text_title;
|
||||
Text text_title { };
|
||||
|
||||
RegistersWidget registers_widget;
|
||||
|
||||
|
@ -189,11 +189,7 @@ void EncodersView::start_tx(const bool scan) {
|
||||
|
||||
ook_bitstream_length = n;
|
||||
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 2280000U,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(2280000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -307,7 +303,7 @@ EncodersView::EncodersView(NavigationView& nav) {
|
||||
// Default encoder def
|
||||
encoder_def = &encoder_defs[0];
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&field_frequency,
|
||||
&text_enctype,
|
||||
&options_enctype,
|
||||
@ -330,7 +326,7 @@ EncodersView::EncodersView(NavigationView& nav) {
|
||||
&text_status,
|
||||
&progress,
|
||||
&button_transmit
|
||||
} });
|
||||
});
|
||||
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
field_frequency.set_step(50000);
|
||||
|
@ -37,7 +37,7 @@ void FrequencySaveView::on_save_name(NavigationView& nav) {
|
||||
nav.pop();
|
||||
}
|
||||
void FrequencySaveView::on_save_timestamp(NavigationView& nav) {
|
||||
frequencies.push_back({ value_, "", text_timestamp.text() });
|
||||
frequencies.push_back({ value_, "", str_timestamp });
|
||||
nav.pop();
|
||||
}
|
||||
|
||||
@ -50,12 +50,13 @@ void FrequencySaveView::focus() {
|
||||
|
||||
void FrequencySaveView::on_tick_second() {
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
text_timestamp.set(to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " +
|
||||
to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0'));
|
||||
str_timestamp = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " +
|
||||
to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
|
||||
text_timestamp.set(str_timestamp);
|
||||
}
|
||||
|
||||
FrequencySaveView::~FrequencySaveView() {
|
||||
time::signal_tick_second -= signal_token_tick_second;
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
save_freqman_file(frequencies);
|
||||
}
|
||||
|
||||
@ -71,18 +72,18 @@ FrequencySaveView::FrequencySaveView(
|
||||
if (!create_freqman_file(freqs_file)) error = true;
|
||||
}
|
||||
|
||||
signal_token_tick_second = time::signal_tick_second += [this]() {
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&big_display,
|
||||
&text_save,
|
||||
&button_save_name,
|
||||
&button_save_timestamp,
|
||||
&text_timestamp,
|
||||
&button_cancel
|
||||
} });
|
||||
});
|
||||
|
||||
on_tick_second();
|
||||
|
||||
@ -130,10 +131,10 @@ FrequencyLoadView::FrequencyLoadView(
|
||||
{
|
||||
error = !load_freqman_file(frequencies);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&menu_view,
|
||||
&button_cancel
|
||||
} });
|
||||
});
|
||||
|
||||
setup_list();
|
||||
|
||||
@ -196,13 +197,13 @@ FreqManView::FreqManView(
|
||||
{
|
||||
error = !load_freqman_file(frequencies);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&menu_view,
|
||||
&button_edit_freq,
|
||||
&button_edit_desc,
|
||||
&button_del,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
setup_list();
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "freqman.hpp"
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@ -47,6 +47,7 @@ private:
|
||||
char desc_buffer[32] = { 0 };
|
||||
rtc::RTC datetime;
|
||||
rf::Frequency value_;
|
||||
std::string str_timestamp { };
|
||||
|
||||
void on_save_name(NavigationView& nav);
|
||||
void on_save_timestamp(NavigationView& nav);
|
||||
|
@ -56,11 +56,11 @@ HandWriteView::HandWriteView(
|
||||
txtidx--;
|
||||
}
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_input,
|
||||
&button_case,
|
||||
&button_ok
|
||||
} });
|
||||
});
|
||||
|
||||
const auto button_fn = [this](Button& button) {
|
||||
this->on_button(button);
|
||||
@ -263,12 +263,12 @@ void HandWriteView::sample_pen() {
|
||||
if (!(sample_skip & 15)) {
|
||||
Point cursor_pos;
|
||||
|
||||
cursor_pos.x = text_input.screen_rect().pos.x + (txtidx * 8);
|
||||
cursor_pos.y = text_input.screen_rect().pos.y + 16 - 4;
|
||||
cursor_pos = {text_input.screen_rect().location().x() + (txtidx * 8),
|
||||
text_input.screen_rect().location().y() + 16 - 4};
|
||||
|
||||
if (cursor) {
|
||||
display.fill_rectangle(
|
||||
{cursor_pos, {text_input.screen_rect().size.w - cursor_pos.x, 4}},
|
||||
{cursor_pos, {text_input.screen_rect().size().width() - cursor_pos.x(), 4}},
|
||||
Color::black()
|
||||
);
|
||||
} else {
|
||||
@ -290,12 +290,12 @@ void HandWriteView::sample_pen() {
|
||||
if (move_wait) {
|
||||
move_wait--; // ~100ms delay to get rid of jitter from touch start
|
||||
} else {
|
||||
diff_x = current_pos.x - last_pos.x;
|
||||
diff_y = current_pos.y - last_pos.y;
|
||||
diff_x = current_pos.x() - last_pos.x();
|
||||
diff_y = current_pos.y() - last_pos.y();
|
||||
|
||||
if (current_pos.y <= 240) {
|
||||
if (current_pos.y() <= 240) {
|
||||
display.fill_rectangle(
|
||||
{{current_pos.x, current_pos.y}, {4, 4}},
|
||||
{{current_pos.x(), current_pos.y()}, {4, 4}},
|
||||
Color::grey()
|
||||
);
|
||||
}
|
||||
|
@ -36,6 +36,11 @@ public:
|
||||
std::function<void(char *)> on_changed;
|
||||
|
||||
HandWriteView(NavigationView& nav, char txt[], size_t max_length);
|
||||
|
||||
HandWriteView(const HandWriteView&) = delete;
|
||||
HandWriteView(HandWriteView&&) = delete;
|
||||
HandWriteView& operator=(const HandWriteView&) = delete;
|
||||
HandWriteView& operator=(HandWriteView&&) = delete;
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void on_show() override;
|
||||
|
@ -120,7 +120,7 @@ JammerView::JammerView(NavigationView& nav) {
|
||||
|
||||
JammerRange * jammer_ranges = (JammerRange*)shared_memory.bb_data.data;
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_type,
|
||||
&options_modulation,
|
||||
&text_sweep,
|
||||
@ -137,7 +137,7 @@ JammerView::JammerView(NavigationView& nav) {
|
||||
&text_info3,
|
||||
&button_transmit,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
const auto button_freq_fn = [this, &nav](Button& button) {
|
||||
uint16_t id = button.id;
|
||||
@ -255,11 +255,7 @@ JammerView::JammerView(NavigationView& nav) {
|
||||
button_transmit.set_text("STOP");
|
||||
|
||||
//transmitter_model.set_tuning_frequency(433920000); // TODO
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000U,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(1536000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
transmitter_model.enable();
|
||||
|
@ -120,7 +120,7 @@ void LCRView::paint(Painter& painter) {
|
||||
style_orange,
|
||||
litteral[i]
|
||||
);
|
||||
offset.y += 32;
|
||||
offset += { 0, 32 };
|
||||
}
|
||||
|
||||
button_setrgsb.set_text(rgsb);
|
||||
@ -248,11 +248,7 @@ void LCRView::start_tx(const bool scan) {
|
||||
}
|
||||
|
||||
transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(1536000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -282,7 +278,7 @@ LCRView::LCRView(NavigationView& nav) {
|
||||
|
||||
strcpy(rgsb, &scan_list[0].addresses[0]);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_recap,
|
||||
&options_ec,
|
||||
&button_setrgsb,
|
||||
@ -295,7 +291,7 @@ LCRView::LCRView(NavigationView& nav) {
|
||||
&options_scanlist,
|
||||
&button_scan,
|
||||
&button_clear
|
||||
} });
|
||||
});
|
||||
|
||||
options_scanlist.set_selected_index(0);
|
||||
|
||||
|
@ -148,11 +148,11 @@ LoadModuleView::LoadModuleView(
|
||||
)
|
||||
{
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_info,
|
||||
&text_infob,
|
||||
&button_ok
|
||||
} });
|
||||
});
|
||||
|
||||
_hash = hash;
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "ui_menu.hpp"
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@ -62,7 +62,7 @@ void MenuItemView::paint(Painter& painter) {
|
||||
|
||||
if (item.bitmap) {
|
||||
painter.draw_bitmap(
|
||||
{ r.pos.x + 4, r.pos.y + 4 },
|
||||
{ r.location().x() + 4, r.location().y() + 4 },
|
||||
*item.bitmap,
|
||||
final_item_color,
|
||||
final_bg_color
|
||||
@ -76,7 +76,7 @@ void MenuItemView::paint(Painter& painter) {
|
||||
};
|
||||
|
||||
painter.draw_string(
|
||||
{ r.pos.x + 26, r.pos.y + (r.size.h - font_height) / 2 },
|
||||
{ r.location().x() + 26, r.location().y() + (r.size().height() - font_height) / 2 },
|
||||
text_style,
|
||||
item.text
|
||||
);
|
||||
@ -90,7 +90,7 @@ MenuView::MenuView(
|
||||
{
|
||||
set_focusable(true);
|
||||
|
||||
signal_token_tick_second = time::signal_tick_second += [this]() {
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
|
||||
@ -101,7 +101,7 @@ MenuView::MenuView(
|
||||
}
|
||||
|
||||
MenuView::~MenuView() {
|
||||
time::signal_tick_second -= signal_token_tick_second;
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
}
|
||||
|
||||
void MenuView::on_tick_second() {
|
||||
@ -126,7 +126,7 @@ void MenuView::add_item(const MenuItem item) {
|
||||
void MenuView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
displayed_max_ = new_parent_rect.size.h / 24;
|
||||
displayed_max_ = new_parent_rect.size().height() / 24;
|
||||
arrow_more.set_parent_rect( { 228, (Coord)(displayed_max_ * item_height), 8, 8 } );
|
||||
|
||||
update_items();
|
||||
@ -147,9 +147,9 @@ void MenuView::update_items() {
|
||||
y_pos = (i - offset_ - 1) * item_height;
|
||||
child->set_parent_rect({
|
||||
{ 0, y_pos },
|
||||
{ size().w, (Coord)item_height }
|
||||
{ size().width(), (Coord)item_height }
|
||||
});
|
||||
if ((y_pos < 0) || (y_pos > (Coord)(screen_rect().size.h - item_height)))
|
||||
if ((y_pos < 0) || (y_pos > (Coord)(screen_rect().size().height() - item_height)))
|
||||
child->hidden(true);
|
||||
else
|
||||
child->hidden(false);
|
||||
|
@ -98,11 +98,7 @@ void MorseView::generate_message(char * text) {
|
||||
(*tone_defs++).duration = MORSE_WORD_SPACE;
|
||||
|
||||
transmitter_model.set_tuning_frequency(81800000);
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000U,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(1536000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -121,12 +117,12 @@ MorseView::MorseView(
|
||||
NavigationView& nav
|
||||
)
|
||||
{
|
||||
add_children({ {
|
||||
add_children({
|
||||
&checkbox_foxhunt,
|
||||
&options_foxhunt,
|
||||
&button_transmit,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
button_transmit.on_select = [this](Button&){
|
||||
//char strtest[] = "TEST";
|
||||
|
@ -67,7 +67,7 @@ namespace ui {
|
||||
/* SystemStatusView ******************************************************/
|
||||
|
||||
SystemStatusView::SystemStatusView() {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&button_back,
|
||||
&title,
|
||||
&button_stealth,
|
||||
@ -75,7 +75,7 @@ SystemStatusView::SystemStatusView() {
|
||||
&button_camera,
|
||||
&button_sleep,
|
||||
&sd_card_status_view,
|
||||
} });
|
||||
});
|
||||
|
||||
if (!portapack::persistent_memory::ui_config_textentry())
|
||||
button_textentry.set_bitmap(&bitmap_keyboard);
|
||||
@ -148,18 +148,18 @@ void SystemStatusView::on_textentry() {
|
||||
}
|
||||
|
||||
void SystemStatusView::on_camera() {
|
||||
const auto filename_stem = next_filename_stem_matching_pattern("SCR_????");
|
||||
if( filename_stem.empty() ) {
|
||||
auto path = next_filename_stem_matching_pattern(u"SCR_????");
|
||||
if( path.empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
PNGWriter png;
|
||||
auto create_error = png.create(filename_stem + ".PNG");
|
||||
auto create_error = png.create(path.replace_extension(u".PNG"));
|
||||
if( create_error.is_valid() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0; i<320; i++) {
|
||||
for(int i=0; i<320; i++) {
|
||||
std::array<ColorRGB888, 240> row;
|
||||
portapack::display.read_pixels({ 0, i, 240, 1 }, row);
|
||||
png.write_scanline(row);
|
||||
@ -420,10 +420,10 @@ void BMPView::focus() {
|
||||
}
|
||||
|
||||
BMPView::BMPView(NavigationView& nav) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_info,
|
||||
&button_done
|
||||
} });
|
||||
});
|
||||
|
||||
button_done.on_select = [this, &nav](Button&){
|
||||
nav.pop();
|
||||
@ -438,11 +438,11 @@ void BMPView::paint(Painter&) {
|
||||
/* WipeSDView ************************************************************/
|
||||
|
||||
WipeSDView::WipeSDView(NavigationView& nav) : nav_ (nav) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_info,
|
||||
&progress,
|
||||
&dummy
|
||||
} });
|
||||
});
|
||||
}
|
||||
|
||||
WipeSDView::~WipeSDView() {
|
||||
@ -495,12 +495,12 @@ PlayDeadView::PlayDeadView(NavigationView& nav) {
|
||||
|
||||
portapack::persistent_memory::set_playing_dead(0x5920C1DF); // Enable
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_playdead1,
|
||||
&text_playdead2,
|
||||
&text_playdead3,
|
||||
&button_seq_entry,
|
||||
} });
|
||||
});
|
||||
|
||||
// Seed from RTC
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
@ -535,10 +535,10 @@ NotImplementedView::NotImplementedView(NavigationView& nav) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_title,
|
||||
&button_done,
|
||||
} });
|
||||
});
|
||||
}
|
||||
|
||||
void NotImplementedView::focus() {
|
||||
@ -566,10 +566,10 @@ ModalMessageView::ModalMessageView(
|
||||
nav.pop();
|
||||
};
|
||||
} else if (type == YESNO) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&button_yes,
|
||||
&button_no
|
||||
} });
|
||||
});
|
||||
|
||||
button_yes.on_select = [this, &nav](Button&){
|
||||
if (on_choice_) on_choice_(true);
|
||||
@ -580,10 +580,10 @@ ModalMessageView::ModalMessageView(
|
||||
nav.pop();
|
||||
};
|
||||
} else if (type == YESCANCEL) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&button_yes,
|
||||
&button_no
|
||||
} });
|
||||
});
|
||||
|
||||
button_yes.on_select = [this, &nav](Button&){
|
||||
if (on_choice_) on_choice_(true);
|
||||
|
@ -55,7 +55,7 @@ enum modal_t {
|
||||
|
||||
class SystemStatusView : public View {
|
||||
public:
|
||||
std::function<void(void)> on_back;
|
||||
std::function<void(void)> on_back { };
|
||||
|
||||
SystemStatusView();
|
||||
|
||||
@ -116,12 +116,14 @@ private:
|
||||
|
||||
class NavigationView : public View {
|
||||
public:
|
||||
std::function<void(const View&)> on_view_changed;
|
||||
std::function<void(const View&)> on_view_changed { };
|
||||
|
||||
NavigationView() { }
|
||||
NavigationView() = default;
|
||||
|
||||
NavigationView(const NavigationView&) = delete;
|
||||
NavigationView(NavigationView&&) = delete;
|
||||
NavigationView& operator=(const NavigationView&) = delete;
|
||||
NavigationView& operator=(NavigationView&&) = delete;
|
||||
|
||||
bool is_top() const;
|
||||
|
||||
@ -141,7 +143,7 @@ public:
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<View>> view_stack;
|
||||
std::vector<std::unique_ptr<View>> view_stack { };
|
||||
Widget* modal_view { nullptr };
|
||||
|
||||
Widget* view() const;
|
||||
@ -300,8 +302,8 @@ public:
|
||||
Context& context() const override;
|
||||
|
||||
private:
|
||||
SystemStatusView status_view;
|
||||
NavigationView navigation_view;
|
||||
SystemStatusView status_view { };
|
||||
NavigationView navigation_view { };
|
||||
Context& context_;
|
||||
};
|
||||
|
||||
|
@ -121,11 +121,7 @@ void NumbersStationView::start_tx() {
|
||||
|
||||
prepare_audio();
|
||||
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(1536000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -176,7 +172,7 @@ NumbersStationView::NumbersStationView(
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_title,
|
||||
&field_frequency,
|
||||
&number_bw,
|
||||
@ -185,7 +181,7 @@ NumbersStationView::NumbersStationView(
|
||||
&check_armed,
|
||||
&button_tx_now,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
number_bw.set_value(75);
|
||||
check_armed.set_value(false);
|
||||
@ -207,12 +203,12 @@ NumbersStationView::NumbersStationView(
|
||||
check_armed.on_select = [this](Checkbox&) {
|
||||
if (check_armed.value()) {
|
||||
armed_blink = false;
|
||||
signal_token_tick_second = time::signal_tick_second += [this]() {
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
} else {
|
||||
check_armed.set_style(&style());
|
||||
time::signal_tick_second -= signal_token_tick_second;
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -28,12 +28,12 @@
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "message.hpp"
|
||||
#include "wavfile.hpp"
|
||||
#include "io_wave.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
|
@ -74,11 +74,7 @@ void NuoptixView::transmit(bool setup) {
|
||||
timecode = number_timecode.value();
|
||||
}
|
||||
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000U,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(1536000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -152,7 +148,7 @@ NuoptixView::NuoptixView(
|
||||
{
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&field_frequency,
|
||||
&number_bw,
|
||||
&text_kHz,
|
||||
@ -163,7 +159,7 @@ NuoptixView::NuoptixView(
|
||||
&button_tx,
|
||||
&button_impro,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
number_bw.set_value(15);
|
||||
number_timecode.set_value(1);
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "baseband_api.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "message.hpp"
|
||||
#include "volume.hpp"
|
||||
#include "audio.hpp"
|
||||
|
@ -47,11 +47,7 @@ RDSView::~RDSView() {
|
||||
}
|
||||
|
||||
void RDSView::start_tx() {
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 2280000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_sampling_rate(2280000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
@ -81,7 +77,7 @@ RDSView::RDSView(NavigationView& nav) {
|
||||
strcpy(PSN, "TEST1234");
|
||||
strcpy(RadioText, "Radiotext test ABCD1234");
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&field_frequency,
|
||||
&text_pty,
|
||||
&options_pty,
|
||||
@ -105,7 +101,7 @@ RDSView::RDSView(NavigationView& nav) {
|
||||
&text_radiotextb,
|
||||
&button_tx,
|
||||
&button_exit
|
||||
} });
|
||||
});
|
||||
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
field_frequency.set_step(50000); // 50kHz steps
|
||||
|
@ -148,11 +148,11 @@ FrequencyKeypadView::FrequencyKeypadView(
|
||||
n++;
|
||||
}
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&button_save,
|
||||
&button_load,
|
||||
&button_close
|
||||
} });
|
||||
});
|
||||
|
||||
button_save.on_select = [this, &nav](Button&) {
|
||||
nav.push<FrequencySaveView>(this->value());
|
||||
@ -257,12 +257,12 @@ FrequencyOptionsView::FrequencyOptionsView(
|
||||
this->on_reference_ppm_correction_changed(v);
|
||||
};
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_step,
|
||||
&field_step,
|
||||
&field_ppm,
|
||||
&text_ppm,
|
||||
} });
|
||||
});
|
||||
}
|
||||
|
||||
void FrequencyOptionsView::set_step(rf::Frequency f) {
|
||||
@ -313,10 +313,10 @@ RadioGainOptionsView::RadioGainOptionsView(
|
||||
{
|
||||
set_style(style);
|
||||
|
||||
add_children({ {
|
||||
add_children({
|
||||
&label_rf_amp,
|
||||
&field_rf_amp,
|
||||
} });
|
||||
});
|
||||
}
|
||||
|
||||
/* LNAGainField **********************************************************/
|
||||
@ -369,4 +369,29 @@ void VGAGainField::on_focus() {
|
||||
}
|
||||
}
|
||||
|
||||
/* TXGainField **********************************************************/
|
||||
|
||||
TXGainField::TXGainField(
|
||||
Point parent_pos
|
||||
) : NumberField {
|
||||
parent_pos, 2,
|
||||
{ max2837::tx::gain_db_range.minimum, max2837::tx::gain_db_range.maximum },
|
||||
max2837::tx::gain_db_step,
|
||||
' ',
|
||||
}
|
||||
{
|
||||
set_value(receiver_model.tx_gain());
|
||||
|
||||
on_change = [](int32_t v) {
|
||||
receiver_model.set_tx_gain(v);
|
||||
};
|
||||
}
|
||||
|
||||
void TXGainField::on_focus() {
|
||||
//Widget::on_focus();
|
||||
if( on_show_options ) {
|
||||
on_show_options();
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
@ -38,9 +38,9 @@ namespace ui {
|
||||
|
||||
class FrequencyField : public Widget {
|
||||
public:
|
||||
std::function<void(rf::Frequency)> on_change;
|
||||
std::function<void(void)> on_edit;
|
||||
std::function<void(void)> on_show_options;
|
||||
std::function<void(rf::Frequency)> on_change { };
|
||||
std::function<void(void)> on_edit { };
|
||||
std::function<void(void)> on_show_options { };
|
||||
|
||||
using range_t = rf::FrequencyRange;
|
||||
|
||||
@ -61,7 +61,7 @@ public:
|
||||
private:
|
||||
const size_t length_;
|
||||
const range_t range;
|
||||
rf::Frequency value_;
|
||||
rf::Frequency value_ { 0 };
|
||||
rf::Frequency step { 25000 };
|
||||
|
||||
rf::Frequency clamp_value(rf::Frequency value);
|
||||
@ -135,8 +135,8 @@ public:
|
||||
private:
|
||||
using array_type = std::array<char, N>;
|
||||
|
||||
array_type s;
|
||||
Justify justify;
|
||||
array_type s { };
|
||||
Justify justify { Justify::Left };
|
||||
|
||||
template<typename Iterator>
|
||||
void remove_zeros(Iterator begin, Iterator end) {
|
||||
@ -174,7 +174,7 @@ private:
|
||||
|
||||
class FrequencyKeypadView : public View {
|
||||
public:
|
||||
std::function<void(rf::Frequency)> on_changed;
|
||||
std::function<void(rf::Frequency)> on_changed { };
|
||||
|
||||
FrequencyKeypadView(
|
||||
NavigationView& nav,
|
||||
@ -201,7 +201,7 @@ private:
|
||||
{ 0, 4, 240, 16 }
|
||||
};
|
||||
|
||||
std::array<Button, 12> buttons;
|
||||
std::array<Button, 12> buttons { };
|
||||
|
||||
Button button_save {
|
||||
{ 0, button_h * 5, 60, button_h },
|
||||
@ -265,8 +265,8 @@ public:
|
||||
|
||||
class FrequencyOptionsView : public View {
|
||||
public:
|
||||
std::function<void(rf::Frequency)> on_change_step;
|
||||
std::function<void(int32_t)> on_change_reference_ppm_correction;
|
||||
std::function<void(rf::Frequency)> on_change_step { };
|
||||
std::function<void(int32_t)> on_change_reference_ppm_correction { };
|
||||
|
||||
FrequencyOptionsView(const Rect parent_rect, const Style* const style);
|
||||
|
||||
@ -322,7 +322,7 @@ private:
|
||||
|
||||
class LNAGainField : public NumberField {
|
||||
public:
|
||||
std::function<void(void)> on_show_options;
|
||||
std::function<void(void)> on_show_options { };
|
||||
|
||||
LNAGainField(Point parent_pos);
|
||||
|
||||
@ -331,13 +331,22 @@ public:
|
||||
|
||||
class VGAGainField : public NumberField {
|
||||
public:
|
||||
std::function<void(void)> on_show_options;
|
||||
std::function<void(void)> on_show_options { };
|
||||
|
||||
VGAGainField(Point parent_pos);
|
||||
|
||||
void on_focus() override;
|
||||
};
|
||||
|
||||
class TXGainField : public NumberField {
|
||||
public:
|
||||
std::function<void(void)> on_show_options { };
|
||||
|
||||
TXGainField(Point parent_pos);
|
||||
|
||||
void on_focus() override;
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__UI_RECEIVER_H__*/
|
||||
|
@ -22,11 +22,12 @@
|
||||
#include "ui_record_view.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "message.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "time.hpp"
|
||||
#include "io_file.hpp"
|
||||
#include "io_wave.hpp"
|
||||
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
#include "utility.hpp"
|
||||
@ -35,9 +36,27 @@ using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void RecordView::toggle_pwmrssi() {
|
||||
pwmrssi_enabled = !pwmrssi_enabled;
|
||||
|
||||
// Send to RSSI widget
|
||||
const PWMRSSIConfigureMessage message {
|
||||
pwmrssi_enabled,
|
||||
1000,
|
||||
0
|
||||
};
|
||||
shared_memory.application_queue.push(message);
|
||||
|
||||
if( !pwmrssi_enabled ) {
|
||||
button_pwmrssi.set_foreground(Color::orange());
|
||||
} else {
|
||||
button_pwmrssi.set_foreground(Color::green());
|
||||
}
|
||||
}
|
||||
|
||||
RecordView::RecordView(
|
||||
const Rect parent_rect,
|
||||
std::string filename_stem_pattern,
|
||||
std::filesystem::path filename_stem_pattern,
|
||||
const FileType file_type,
|
||||
const size_t write_size,
|
||||
const size_t buffer_count
|
||||
@ -47,14 +66,14 @@ RecordView::RecordView(
|
||||
write_size { write_size },
|
||||
buffer_count { buffer_count }
|
||||
{
|
||||
add_children({ {
|
||||
add_children({
|
||||
&rect_background,
|
||||
&button_pwmrssi,
|
||||
&button_record,
|
||||
&text_record_filename,
|
||||
&text_record_dropped,
|
||||
&text_time_available,
|
||||
} });
|
||||
});
|
||||
|
||||
rect_background.set_parent_rect({ { 0, 0 }, size() });
|
||||
|
||||
@ -66,13 +85,13 @@ RecordView::RecordView(
|
||||
this->toggle();
|
||||
};
|
||||
|
||||
signal_token_tick_second = time::signal_tick_second += [this]() {
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
}
|
||||
|
||||
RecordView::~RecordView() {
|
||||
time::signal_tick_second -= signal_token_tick_second;
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
}
|
||||
|
||||
void RecordView::focus() {
|
||||
@ -106,24 +125,6 @@ void RecordView::toggle() {
|
||||
}
|
||||
}
|
||||
|
||||
void RecordView::toggle_pwmrssi() {
|
||||
pwmrssi_enabled = !pwmrssi_enabled;
|
||||
|
||||
// Send to RSSI widget
|
||||
const PWMRSSIConfigureMessage message {
|
||||
pwmrssi_enabled,
|
||||
1000,
|
||||
0
|
||||
};
|
||||
shared_memory.application_queue.push(message);
|
||||
|
||||
if( !pwmrssi_enabled ) {
|
||||
button_pwmrssi.set_foreground(Color::orange());
|
||||
} else {
|
||||
button_pwmrssi.set_foreground(Color::green());
|
||||
}
|
||||
}
|
||||
|
||||
void RecordView::start() {
|
||||
stop();
|
||||
|
||||
@ -134,21 +135,17 @@ void RecordView::start() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto filename_stem = next_filename_stem_matching_pattern(filename_stem_pattern);
|
||||
if( filename_stem.empty() ) {
|
||||
auto base_path = next_filename_stem_matching_pattern(filename_stem_pattern);
|
||||
if( base_path.empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<Writer> writer;
|
||||
std::unique_ptr<stream::Writer> writer;
|
||||
switch(file_type) {
|
||||
case FileType::WAV:
|
||||
{
|
||||
auto p = std::make_unique<WAVFileWriter>(
|
||||
sampling_rate
|
||||
);
|
||||
auto create_error = p->create(
|
||||
filename_stem + ".WAV"
|
||||
);
|
||||
auto p = std::make_unique<WAVFileWriter>();
|
||||
auto create_error = p->create(base_path.replace_extension(u".WAV"), sampling_rate);
|
||||
if( create_error.is_valid() ) {
|
||||
handle_error(create_error.value());
|
||||
} else {
|
||||
@ -159,16 +156,14 @@ void RecordView::start() {
|
||||
|
||||
case FileType::RawS16:
|
||||
{
|
||||
const auto metadata_file_error = write_metadata_file(filename_stem + ".TXT");
|
||||
const auto metadata_file_error = write_metadata_file(base_path.replace_extension(u".TXT"));
|
||||
if( metadata_file_error.is_valid() ) {
|
||||
handle_error(metadata_file_error.value());
|
||||
return;
|
||||
}
|
||||
|
||||
auto p = std::make_unique<FileWriter>();
|
||||
auto create_error = p->create(
|
||||
filename_stem + ".C16"
|
||||
);
|
||||
auto p = std::make_unique<RawFileWriter>();
|
||||
auto create_error = p->create(base_path.replace_extension(u".C16"));
|
||||
if( create_error.is_valid() ) {
|
||||
handle_error(create_error.value());
|
||||
} else {
|
||||
@ -182,7 +177,7 @@ void RecordView::start() {
|
||||
};
|
||||
|
||||
if( writer ) {
|
||||
text_record_filename.set(filename_stem);
|
||||
text_record_filename.set(base_path.replace_extension().string());
|
||||
button_record.set_bitmap(&bitmap_stop);
|
||||
capture_thread = std::make_unique<CaptureThread>(
|
||||
std::move(writer),
|
||||
@ -210,7 +205,7 @@ void RecordView::stop() {
|
||||
update_status_display();
|
||||
}
|
||||
|
||||
Optional<File::Error> RecordView::write_metadata_file(const std::string& filename) {
|
||||
Optional<File::Error> RecordView::write_metadata_file(const std::filesystem::path& filename) {
|
||||
File file;
|
||||
const auto create_error = file.create(filename);
|
||||
if( create_error.is_valid() ) {
|
||||
@ -244,7 +239,7 @@ void RecordView::update_status_display() {
|
||||
}
|
||||
|
||||
if( sampling_rate ) {
|
||||
const auto space_info = std::filesystem::space("");
|
||||
const auto space_info = std::filesystem::space(u"");
|
||||
const uint32_t bytes_per_second = file_type == FileType::WAV ? (sampling_rate * 2) : (sampling_rate * 4);
|
||||
const uint32_t available_seconds = space_info.free / bytes_per_second;
|
||||
const uint32_t seconds = available_seconds % 60;
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#include "capture_thread.hpp"
|
||||
#include "signal.hpp"
|
||||
#include "wavfile.hpp"
|
||||
|
||||
#include "bitmap.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
@ -37,7 +37,7 @@ namespace ui {
|
||||
|
||||
class RecordView : public View {
|
||||
public:
|
||||
std::function<void(std::string)> on_error;
|
||||
std::function<void(std::string)> on_error { };
|
||||
|
||||
enum FileType {
|
||||
RawS16 = 2,
|
||||
@ -46,7 +46,7 @@ public:
|
||||
|
||||
RecordView(
|
||||
const Rect parent_rect,
|
||||
std::string filename_stem_pattern,
|
||||
std::filesystem::path filename_stem_pattern,
|
||||
FileType file_type,
|
||||
const size_t write_size,
|
||||
const size_t buffer_count
|
||||
@ -65,7 +65,7 @@ public:
|
||||
private:
|
||||
void toggle();
|
||||
void toggle_pwmrssi();
|
||||
Optional<File::Error> write_metadata_file(const std::string& filename);
|
||||
Optional<File::Error> write_metadata_file(const std::filesystem::path& filename);
|
||||
|
||||
void on_tick_second();
|
||||
void update_status_display();
|
||||
@ -74,12 +74,12 @@ private:
|
||||
void handle_error(const File::Error error);
|
||||
|
||||
bool pwmrssi_enabled = false;
|
||||
const std::string filename_stem_pattern;
|
||||
const std::filesystem::path filename_stem_pattern;
|
||||
const FileType file_type;
|
||||
const size_t write_size;
|
||||
const size_t buffer_count;
|
||||
size_t sampling_rate { 0 };
|
||||
SignalToken signal_token_tick_second;
|
||||
SignalToken signal_token_tick_second { };
|
||||
|
||||
Rectangle rect_background {
|
||||
Color::black()
|
||||
@ -114,7 +114,7 @@ private:
|
||||
"",
|
||||
};
|
||||
|
||||
std::unique_ptr<CaptureThread> capture_thread;
|
||||
std::unique_ptr<CaptureThread> capture_thread { };
|
||||
|
||||
MessageHandlerRegistration message_handler_capture_thread_error {
|
||||
Message::ID::CaptureThreadDone,
|
||||
|
@ -27,7 +27,8 @@
|
||||
#include "portapack_shared_memory.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "time.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
#include "utility.hpp"
|
||||
@ -38,22 +39,22 @@ namespace ui {
|
||||
|
||||
ReplayView::ReplayView(
|
||||
const Rect parent_rect,
|
||||
std::string filename_stem_pattern,
|
||||
std::string filename,
|
||||
const FileType file_type,
|
||||
const size_t read_size,
|
||||
const size_t buffer_count
|
||||
) : View { parent_rect },
|
||||
filename_stem_pattern { filename_stem_pattern },
|
||||
filename { filename },
|
||||
file_type { file_type },
|
||||
read_size { read_size },
|
||||
buffer_count { buffer_count }
|
||||
{
|
||||
add_children({ {
|
||||
add_children({
|
||||
&rect_background,
|
||||
&button_record,
|
||||
&text_replay_filename,
|
||||
&text_time_seek,
|
||||
} });
|
||||
});
|
||||
|
||||
rect_background.set_parent_rect({ { 0, 0 }, size() });
|
||||
|
||||
@ -61,13 +62,13 @@ ReplayView::ReplayView(
|
||||
this->toggle();
|
||||
};
|
||||
|
||||
signal_token_tick_second = time::signal_tick_second += [this]() {
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
}
|
||||
|
||||
ReplayView::~ReplayView() {
|
||||
time::signal_tick_second -= signal_token_tick_second;
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
}
|
||||
|
||||
void ReplayView::focus() {
|
||||
@ -109,24 +110,10 @@ void ReplayView::start() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto filename_stem = next_filename_stem_matching_pattern(filename_stem_pattern);
|
||||
if( filename_stem.empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<Reader> reader;
|
||||
auto p = std::make_unique<FileReader>();
|
||||
auto create_error = p->create(
|
||||
filename_stem + ".C16"
|
||||
);
|
||||
if( create_error.is_valid() ) {
|
||||
handle_error(create_error.value());
|
||||
} else {
|
||||
reader = std::move(p);
|
||||
}
|
||||
auto reader = std::make_unique<FileReader>();
|
||||
|
||||
if( reader ) {
|
||||
text_replay_filename.set(filename_stem);
|
||||
text_replay_filename.set(filename.string());
|
||||
button_record.set_bitmap(&bitmap_stop);
|
||||
replay_thread = std::make_unique<ReplayThread>(
|
||||
std::move(reader),
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
|
||||
ReplayView(
|
||||
const Rect parent_rect,
|
||||
std::string filename_stem_pattern,
|
||||
std::string filename,
|
||||
FileType file_type,
|
||||
const size_t read_size,
|
||||
const size_t buffer_count
|
||||
@ -71,8 +71,7 @@ private:
|
||||
void handle_replay_thread_done(const File::Error error);
|
||||
void handle_error(const File::Error error);
|
||||
|
||||
bool pwmrssi_enabled = false;
|
||||
const std::string filename_stem_pattern;
|
||||
const std::filesystem::path filename;
|
||||
const FileType file_type;
|
||||
const size_t read_size;
|
||||
const size_t buffer_count;
|
||||
|
@ -45,46 +45,31 @@ void RSSI::paint(Painter& painter) {
|
||||
const range_t<int> x_max_range { x_avg + 1, r.width() };
|
||||
const auto x_max = x_max_range.clip((max_ - raw_min) * r.width() / raw_delta);
|
||||
|
||||
const Rect r0 {
|
||||
static_cast<ui::Coord>(r.left()), r.top(),
|
||||
static_cast<ui::Dim>(x_min), r.height()
|
||||
};
|
||||
const Rect r0 { r.left(), r.top(), x_min, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r0,
|
||||
Color::blue()
|
||||
);
|
||||
|
||||
const Rect r1 {
|
||||
static_cast<ui::Coord>(r.left() + x_min), r.top(),
|
||||
static_cast<ui::Dim>(x_avg - x_min), r.height()
|
||||
};
|
||||
const Rect r1 { r.left() + x_min, r.top(), x_avg - x_min, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r1,
|
||||
Color::red()
|
||||
);
|
||||
|
||||
const Rect r2 {
|
||||
static_cast<ui::Coord>(r.left() + x_avg), r.top(),
|
||||
1, r.height()
|
||||
};
|
||||
const Rect r2 { r.left() + x_avg, r.top(), 1, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r2,
|
||||
Color::white()
|
||||
);
|
||||
|
||||
const Rect r3 {
|
||||
static_cast<ui::Coord>(r.left() + x_avg + 1), r.top(),
|
||||
static_cast<ui::Dim>(x_max - (x_avg + 1)), r.height()
|
||||
};
|
||||
const Rect r3 { r.left() + x_avg + 1, r.top(), x_max - (x_avg + 1), r.height() };
|
||||
painter.fill_rectangle(
|
||||
r3,
|
||||
Color::red()
|
||||
);
|
||||
|
||||
const Rect r4 {
|
||||
static_cast<ui::Coord>(r.left() + x_max), r.top(),
|
||||
static_cast<ui::Dim>(r.width() - x_max), r.height()
|
||||
};
|
||||
const Rect r4 { r.left() + x_max, r.top(), r.width() - x_max, r.height() };
|
||||
painter.fill_rectangle(
|
||||
r4,
|
||||
Color::black()
|
||||
|
@ -51,19 +51,19 @@ public:
|
||||
halrtcnt_t write_duration_min { 0 };
|
||||
halrtcnt_t write_duration_max { 0 };
|
||||
halrtcnt_t write_test_duration { 0 };
|
||||
size_t write_bytes { 0 };
|
||||
File::Size write_bytes { 0 };
|
||||
size_t write_count { 0 };
|
||||
|
||||
halrtcnt_t read_duration_min { 0 };
|
||||
halrtcnt_t read_duration_max { 0 };
|
||||
halrtcnt_t read_test_duration { 0 };
|
||||
size_t read_bytes { 0 };
|
||||
File::Size read_bytes { 0 };
|
||||
size_t read_count { 0 };
|
||||
};
|
||||
|
||||
SDCardTestThread(
|
||||
) {
|
||||
thread = chThdCreateFromHeap(NULL, 2048, NORMALPRIO + 10, SDCardTestThread::static_fn, this);
|
||||
thread = chThdCreateFromHeap(NULL, 3072, NORMALPRIO + 10, SDCardTestThread::static_fn, this);
|
||||
}
|
||||
|
||||
Result result() const {
|
||||
@ -80,13 +80,13 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t write_size = 16384;
|
||||
static constexpr size_t bytes_to_write = 16 * 1024 * 1024;
|
||||
static constexpr size_t bytes_to_read = bytes_to_write;
|
||||
static constexpr File::Size write_size = 16384;
|
||||
static constexpr File::Size bytes_to_write = 16 * 1024 * 1024;
|
||||
static constexpr File::Size bytes_to_read = bytes_to_write;
|
||||
|
||||
static Thread* thread;
|
||||
volatile Result _result { Result::Incomplete };
|
||||
Stats _stats;
|
||||
Stats _stats { };
|
||||
|
||||
static msg_t static_fn(void* arg) {
|
||||
auto obj = static_cast<SDCardTestThread*>(arg);
|
||||
@ -95,7 +95,7 @@ private:
|
||||
}
|
||||
|
||||
Result run() {
|
||||
const std::string filename { "_PPTEST_.DAT" };
|
||||
const std::filesystem::path filename { u"_PPTEST_.DAT" };
|
||||
|
||||
const auto write_result = write(filename);
|
||||
if( write_result != Result::OK ) {
|
||||
@ -115,7 +115,7 @@ private:
|
||||
return read_result;
|
||||
}
|
||||
|
||||
f_unlink(filename.c_str());
|
||||
f_unlink(reinterpret_cast<const TCHAR*>(filename.c_str()));
|
||||
|
||||
if( _stats.read_bytes < bytes_to_read ) {
|
||||
return Result::FailReadIncomplete;
|
||||
@ -128,7 +128,7 @@ private:
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
Result write(const std::string& filename) {
|
||||
Result write(const std::filesystem::path& filename) {
|
||||
const auto buffer = std::make_unique<std::array<uint8_t, write_size>>();
|
||||
if( !buffer ) {
|
||||
return Result::FailHeap;
|
||||
@ -175,7 +175,7 @@ private:
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
Result read(const std::string& filename) {
|
||||
Result read(const std::filesystem::path& filename) {
|
||||
const auto buffer = std::make_unique<std::array<uint8_t, write_size>>();
|
||||
if( !buffer ) {
|
||||
return Result::FailHeap;
|
||||
@ -230,7 +230,7 @@ Thread* SDCardTestThread::thread { nullptr };
|
||||
namespace ui {
|
||||
|
||||
SDCardDebugView::SDCardDebugView(NavigationView& nav) {
|
||||
add_children({ {
|
||||
add_children({
|
||||
&text_title,
|
||||
&text_csd_title,
|
||||
&text_csd_value_3,
|
||||
@ -257,7 +257,7 @@ SDCardDebugView::SDCardDebugView(NavigationView& nav) {
|
||||
&text_test_read_rate_value,
|
||||
&button_test,
|
||||
&button_ok,
|
||||
} });
|
||||
});
|
||||
|
||||
button_test.on_select = [this](Button&){ this->on_test(); };
|
||||
button_ok.on_select = [&nav](Button&){ nav.pop(); };
|
||||
@ -365,7 +365,7 @@ static std::string format_ticks_as_ms(const halrtcnt_t value) {
|
||||
return format_3dot3_string(us);
|
||||
}
|
||||
|
||||
static std::string format_bytes_per_ticks_as_mib(const size_t bytes, const halrtcnt_t ticks) {
|
||||
static std::string format_bytes_per_ticks_as_mib(const File::Size bytes, const halrtcnt_t ticks) {
|
||||
const uint32_t bps = uint64_t(bytes) * halGetCounterFrequency() / ticks;
|
||||
const uint32_t kbps = bps / 1000U;
|
||||
return format_3dot3_string(kbps);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user