Merge 'upstream/master' - At least it builds...

This commit is contained in:
furrtek 2017-01-16 03:45:44 +00:00
commit 5e40669cbc
298 changed files with 8122 additions and 4685 deletions

View File

@ -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++"

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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:
};

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 { };

View File

@ -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);

View File

@ -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,

View File

@ -58,7 +58,7 @@ public:
}
private:
mask_t mask;
mask_t mask { };
};
#endif/*__DIRTY_REGISTERS_H__*/

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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 ---*/

View File

@ -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

View File

@ -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__*/

View 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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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__*/

View File

@ -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);
};

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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() {

View File

@ -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();

View File

@ -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 */

View File

@ -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__*/

View File

@ -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);

View File

@ -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 { };

View File

@ -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);

View File

@ -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)
{
}

View File

@ -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);

View File

@ -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 */

View File

@ -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__*/

View File

@ -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 */

View File

@ -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);
}
};

View File

@ -78,7 +78,7 @@ private:
using EntryType = std::unique_ptr<CallbackEntry>;
std::list<EntryType> entries;
std::list<EntryType> entries { };
SignalToken next_token = 1;
};

View File

@ -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;

View File

@ -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() {

View File

@ -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;

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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());
}

View File

@ -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();
};

View File

@ -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 */

View File

@ -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);

View File

@ -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("");

View File

@ -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 },

View File

@ -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

View File

@ -36,10 +36,10 @@ AFSKRXView::AFSKRXView(
NavigationView& nav
)
{
add_children({ {
add_children({
&button_done,
&text_rx
} } );
});
button_done.on_select = [&nav](Button&){
nav.pop();

View File

@ -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));

View File

@ -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(

View File

@ -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;

View File

@ -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()

View File

@ -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());

View File

@ -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) {

View File

@ -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();

View File

@ -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()

View File

@ -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();
};

View File

@ -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,
&registers_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))

View File

@ -193,7 +193,7 @@ public:
void focus();
private:
Text text_title;
Text text_title { };
RegistersWidget registers_widget;

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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()
);
}

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -148,11 +148,11 @@ LoadModuleView::LoadModuleView(
)
{
add_children({ {
add_children({
&text_info,
&text_infob,
&button_ok
} });
});
_hash = hash;

View File

@ -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);

View File

@ -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";

View File

@ -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);

View File

@ -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_;
};

View File

@ -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;
}
};

View File

@ -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 {

View File

@ -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);

View File

@ -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"

View File

@ -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

View File

@ -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 */

View File

@ -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__*/

View File

@ -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;

View File

@ -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,

View File

@ -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),

View File

@ -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;

View File

@ -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()

View File

@ -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