From aabae17eeaa24e87ae0e201c2e2dd626916e44eb Mon Sep 17 00:00:00 2001 From: HTotoo Date: Thu, 18 Apr 2024 12:20:48 +0200 Subject: [PATCH 01/28] BMP initial --- firmware/application/CMakeLists.txt | 1 + .../external/extsensors/ui_extsensors.cpp | 8 + .../external/extsensors/ui_extsensors.hpp | 1 + firmware/application/file.cpp | 4 + firmware/application/file.hpp | 1 + firmware/common/bmpfile.cpp | 207 ++++++++++++++++++ firmware/common/bmpfile.hpp | 42 ++++ 7 files changed, 264 insertions(+) create mode 100644 firmware/common/bmpfile.cpp create mode 100644 firmware/common/bmpfile.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 8fab990e5..c686c0d8e 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -177,6 +177,7 @@ set(CPPSRC ${COMMON}/utility.cpp ${COMMON}/wm8731.cpp ${COMMON}/performance_counter.cpp + ${COMMON}/bmpfile.cpp app_settings.cpp audio.cpp baseband_api.cpp diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp index 572effe65..4f7a303cc 100644 --- a/firmware/application/external/extsensors/ui_extsensors.cpp +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -40,6 +40,14 @@ ExtSensorsView::ExtSensorsView(NavigationView& nav) &text_orientation, &text_envl1, &text_envl2}); + BMPFile bmp; + auto ret = bmp.create("/SCREENSHOTS/tmp.bmp", 500, 100); + text_envl1.set(to_string_dec_int(ret)); + text_envl2.set(to_string_dec_int(bmp.getbpr())); + + // Color c = Color::red(); + // bmp.write_next_px(c); + bmp.close(); } ExtSensorsView::~ExtSensorsView() { diff --git a/firmware/application/external/extsensors/ui_extsensors.hpp b/firmware/application/external/extsensors/ui_extsensors.hpp index e068ff6d2..5dfd2a568 100644 --- a/firmware/application/external/extsensors/ui_extsensors.hpp +++ b/firmware/application/external/extsensors/ui_extsensors.hpp @@ -33,6 +33,7 @@ #include "ui_record_view.hpp" #include "app_settings.hpp" #include "utility.hpp" +#include "bmpfile.hpp" using namespace ui; diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 0964b0dac..de7d4220e 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -70,6 +70,10 @@ File::~File() { f_close(&f); } +void File::close() { + f_close(&f); +} + File::Result File::read(void* data, Size bytes_to_read) { UINT bytes_read = 0; const auto result = f_read(&f, data, bytes_to_read, &bytes_read); diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index ae602f48f..889e86470 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -332,6 +332,7 @@ class File { // TODO: Return Result<>. Optional open(const std::filesystem::path& filename, bool read_only = true, bool create = false); + void close(); Optional append(const std::filesystem::path& filename); Optional create(const std::filesystem::path& filename); diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp new file mode 100644 index 000000000..7e02822d4 --- /dev/null +++ b/firmware/common/bmpfile.cpp @@ -0,0 +1,207 @@ + +#include "bmpfile.hpp" + +BMPFile::~BMPFile() { + close(); +} + +// closes file +void BMPFile::close() { + is_opened = false; + bmpimage.close(); +} + +// creates a new bmp file. for now, hardcoded to 3 byte colour depth +bool BMPFile::create(const std::filesystem::path& file, uint32_t x, uint32_t y) { + is_opened = false; + is_read_ony = true; + bmpimage.close(); // if already open, close before open a new + if (file_exists(file)) return false; + auto result = bmpimage.open(file, false, true); + if (!result.value().ok()) return false; + file_pos = 0; + byte_per_row = (x * 3 % 4 == 0) ? x * 3 : (x * 3 + (4 - ((x * 3) % 4))); // with padding + bmpimage.seek(file_pos); + bmp_header.signature = 0x4D42; + bmp_header.planes = 1; + bmp_header.compression = 0; + bmp_header.bpp = 24; // 3 byte depth + bmp_header.width = x; + bmp_header.height = 0; // for now, will expand + bmp_header.image_data = 0x36; + bmp_header.BIH_size = 0x28; + bmp_header.h_res = 100; + bmp_header.v_res = 100; + byte_per_px = 3; + type = 1; + bmp_header.size = sizeof(bmp_header) + bmp_header.height * byte_per_row; // with padding! --will update later with expand + bmp_header.data_size = bmp_header.size - sizeof(bmp_header_t); + bmp_header.colors_count = 0; + bmp_header.icolors_count = 0; + + bmpimage.write(&bmp_header, sizeof(bmp_header_t)); + file_pos = bmp_header.image_data; + is_opened = true; + is_read_ony = false; + if (!expand_y(y)) return false; // will fill with 0, and update header data + seek(0, 0); + return true; +} + +// opens the file and parses header data. return true on success +bool BMPFile::open(const std::filesystem::path& file, bool readonly) { + is_opened = false; + is_read_ony = true; + bmpimage.close(); // if already open, close before open a new + + auto result = bmpimage.open(file, readonly, false); + if (!result.is_valid()) return false; + file_pos = 0; + bmpimage.seek(file_pos); + auto read_size = bmpimage.read(&bmp_header, sizeof(bmp_header_t)); + if (!((bmp_header.signature == 0x4D42) && // "BM" Signature + (bmp_header.planes == 1) && // Seems always to be 1 + (bmp_header.compression == 0 || bmp_header.compression == 3))) { // No compression + return false; + } + char buffer[257]; + switch (bmp_header.bpp) { + case 16: + file_pos = 0x36; + memset(buffer, 0, 16); + bmpimage.read(buffer, 16); + byte_per_px = 2; + if (buffer[1] == 0x7C) + type = 3; // A1R5G5B5 + else + type = 0; // R5G6B5 + break; + case 24: + type = 1; + byte_per_px = 3; + break; + case 32: + default: + type = 2; + byte_per_px = 4; + break; + } + byte_per_row = (bmp_header.width * byte_per_px % 4 == 0) ? bmp_header.width * byte_per_px : (bmp_header.width * byte_per_px + (4 - ((bmp_header.width * byte_per_px) % 4))); + file_pos = bmp_header.image_data; + is_opened = true; + is_read_ony = readonly; + currx = 0; + curry = 0; + return true; +} + +// jumps to next pixel. false on the end +bool BMPFile::advance_curr_px(uint32_t num = 1) { + if (curry >= bmp_header.height) return false; + uint32_t rowsToAdvance = (currx + num) / bmp_header.width; + uint32_t nx = (currx + num) % bmp_header.width; + uint32_t ny = curry + rowsToAdvance; + if (ny >= bmp_header.height) { + return false; + } + seek(nx, ny); + return true; +} + +// reads next px, then advance the pos (and seek). return false on last px +bool BMPFile::read_next_px(ui::Color& px) { + if (!is_opened) return false; + uint8_t buffer[4]; + auto res = bmpimage.read(buffer, byte_per_px); + if (res.is_error()) return false; + switch (type) { + case 0: // R5G6B5 + case 3: // A1R5G5B5 + if (!type) + px = ui::Color((uint16_t)buffer[0] | ((uint16_t)buffer[1] << 8)); + else + px = ui::Color(((uint16_t)buffer[0] & 0x1F) | ((uint16_t)buffer[0] & 0xE0) << 1 | ((uint16_t)buffer[1] & 0x7F) << 9); + break; + case 1: // 24 + default: + px = ui::Color(buffer[2], buffer[1], buffer[0]); + + break; + case 2: // 32 + px = ui::Color(buffer[2], buffer[1], buffer[0]); + break; + } + return advance_curr_px(); +} + +// writes a color data to the current position, and advances 1 px. true on success, false on error +bool BMPFile::write_next_px(ui::Color& px) { + if (!is_opened) return false; + if (is_read_ony) return false; + uint8_t buffer[4]; + switch (type) { + case 0: // R5G6B5 + case 3: // A1R5G5B5 + if (!type) { + buffer[0] = (px.r() << 3) | (px.g() >> 3); // todo test in future + buffer[1] = (px.g() << 5) | px.b(); + } else { + buffer[0] = (1 << 7) | (px.r() << 2) | (px.g() >> 3); // todo test in future + buffer[1] = (px.g() << 5) | px.b(); + } + break; + case 1: // 24 + default: + buffer[2] = px.r(); + buffer[1] = px.g(); + buffer[0] = px.b(); + break; + case 2: // 32 + buffer[2] = px.r(); + buffer[1] = px.g(); + buffer[0] = px.b(); + buffer[3] = 255; + break; + } + auto res = bmpimage.write(buffer, byte_per_px); + if (res.is_error()) return false; + advance_curr_px(); + return true; +} + +// positions in the file to the given pixel. 0 based indexing +bool BMPFile::seek(uint32_t x, uint32_t y) { + if (!is_opened) return false; + if (x >= bmp_header.width) return false; + if (y >= bmp_header.height) return false; + file_pos = bmp_header.image_data; // nav to start pos. + file_pos += y * byte_per_row; + file_pos += x * byte_per_px; + bmpimage.seek(file_pos); + currx = x; + curry = y; + return true; +} + +// expands the image with a delta (y) +bool BMPFile::expand_y_delta(uint32_t delta_y) { + return expand_y(bmp_header.height + delta_y); +} + +// expands the image to a new y size. +bool BMPFile::expand_y(uint32_t new_y) { + if (!is_opened) return false; // not yet opened + if (new_y < bmp_header.height) return true; // already bigger + if (is_read_ony) return false; // can't expand + size_t old_fp = file_pos; + uint32_t delta = (new_y - bmp_header.height) * byte_per_row; + bmp_header.size += delta; + bmp_header.data_size += delta; + bmp_header.height = new_y; + bmpimage.seek(0); + bmpimage.write(&bmp_header, sizeof(bmp_header)); // overwrite header + bmpimage.seek(bmp_header.size); // seek to new end + file_pos = old_fp; // restore pointer + bmpimage.seek(file_pos); + return true; +} \ No newline at end of file diff --git a/firmware/common/bmpfile.hpp b/firmware/common/bmpfile.hpp new file mode 100644 index 000000000..167c3aa45 --- /dev/null +++ b/firmware/common/bmpfile.hpp @@ -0,0 +1,42 @@ +#ifndef __BMPFILE__H +#define __BMPFILE__H + +#include +#include + +#include "file.hpp" +#include "bmp.hpp" +#include "ui.hpp" + +class BMPFile { + public: + ~BMPFile(); + bool open(const std::filesystem::path& file, bool readonly); + bool create(const std::filesystem::path& file, uint32_t x, uint32_t y); + void close(); + bool seek(uint32_t x, uint32_t y); + bool expand_y(uint32_t new_y); + bool expand_y_delta(uint32_t delta_y); + uint32_t getbpr() { return byte_per_row; }; + + bool read_next_px(ui::Color& px); + bool write_next_px(ui::Color& px); + + private: + bool advance_curr_px(uint32_t num); + bool is_opened = false; + bool is_read_ony = true; + File bmpimage{}; + size_t file_pos = 0; + bmp_header_t bmp_header{}; + uint8_t type = 0; + uint8_t byte_per_px = 1; + uint32_t byte_per_row = 0; + + uint32_t currx = 0; + uint32_t curry = 0; + + int8_t zoom_factor = 1; // + zoom in, - zoom out. +}; + +#endif \ No newline at end of file From c790a0c1ec23ebe9dbc807220c5cfd4478d67ec8 Mon Sep 17 00:00:00 2001 From: "E.T" Date: Wed, 17 Apr 2024 14:21:16 +0200 Subject: [PATCH 02/28] Add vscode debug configuration as a template (#2109) --- .vscode/launch.json | 148 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..cc3c84aea --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,148 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) JTAG probe", + "type": "cppdbg", + "request": "launch", + "miDebuggerPath": "arm-none-eabi-gdb", + "targetArchitecture": "arm", + "program": "${workspaceRoot}/build/firmware/baseband/baseband_adsbrx.elf", + "cwd": "${workspaceRoot}", + "setupCommands": [ + // use logging for troubleshooting + //{"text": "set logging file ${workspaceRoot}/build/arm-none-eabi-gdb.log"}, + //{"text": "set logging on"}, + { + "text": "file '${workspaceRoot}/build/firmware/baseband/baseband_adsbrx.elf'" + }, + { + "text": "target extended-remote /dev/ttyACM0" + }, + { + "text": "monitor swdp_scan" + }, + { + "text": "attach 1" + }, + ], + "launchCompleteCommand": "None", + "externalConsole": false, + }, + { + "name": "(gdb) OpenOCD m4 baseband", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceRoot}/build/firmware/baseband/baseband_sd_over_usb.elf", + "args": [], + "cwd": "${workspaceRoot}", + // "environment": [ + // { + // "name": "PATH", + // "value": "${env:PATH}" + // } + // ], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "arm-none-eabi-gdb", + "targetArchitecture": "arm", + "debugServerPath": "openocd", + "debugServerArgs": "-f interface/ftdi/um232h.cfg -f target/lpc4350.cfg -c \"gdb_breakpoint_override hard\"", + "serverStarted": "Listening on port [0-9]+ for gdb connections", + "filterStderr": true, + "filterStdout": false, + "launchCompleteCommand": "None", + "postRemoteConnectCommands": [ + { + "description": "Target Remote Device on Port 3333", + "text": "target extended-remote :3333", + "ignoreFailures": false + }, + { + "description": "Respect Hardware Limitations", + "text": "set remote hardware-watchpoint-limit 2", + "ignoreFailures": false + }, + { + "description": "Respect Hardware Limitations", + "text": "set remote hardware-breakpoint-limit 4", + "ignoreFailures": false + }, + { + "description": "Shutdown GDB Server on GDB Detach", + "text": "monitor [target current] configure -event gdb-detach { shutdown }", + "ignoreFailures": false + }, + ], + "stopAtConnect": false, + "logging": { + "exceptions": true, + "engineLogging": false, + "moduleLoad": true, + "programOutput": true, + "trace": false, + "traceResponse": false + }, + "useExtendedRemote": true + }, + { + "name": "(gdb) OpenOCD m0 application", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceRoot}/build/firmware/application/application.elf", + "args": [], + "cwd": "${workspaceRoot}", + // "environment": [ + // { + // "name": "PATH", + // "value": "${env:PATH}" + // } + // ], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "arm-none-eabi-gdb", + "targetArchitecture": "arm", + "debugServerPath": "openocd", + "debugServerArgs": "-f interface/ftdi/um232h.cfg -f target/lpc4350.cfg -c \"gdb_breakpoint_override hard\"", + "serverStarted": "Listening on port [0-9]+ for gdb connections", + "filterStderr": true, + "filterStdout": false, + "launchCompleteCommand": "None", + "postRemoteConnectCommands": [ + { + "description": "Target Remote Device on Port 3334", + "text": "target extended-remote :3334", + "ignoreFailures": false + }, + { + "description": "Respect Hardware Limitations", + "text": "set remote hardware-watchpoint-limit 1", + "ignoreFailures": false + }, + { + "description": "Respect Hardware Limitations", + "text": "set remote hardware-breakpoint-limit 2", + "ignoreFailures": false + }, + { + "description": "Shutdown GDB Server on GDB Detach", + "text": "monitor [target current] configure -event gdb-detach { shutdown }", + "ignoreFailures": false + }, + ], + "stopAtConnect": false, + "logging": { + "exceptions": true, + "engineLogging": false, + "moduleLoad": true, + "programOutput": true, + "trace": false, + "traceResponse": false + }, + "useExtendedRemote": true + }, + ] +} \ No newline at end of file From d4192b076b3d5bc54fdaa173a3477c139fed9345 Mon Sep 17 00:00:00 2001 From: sommermorgentraum <24917424+zxkmm@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:10:34 +0800 Subject: [PATCH 03/28] usb serial debug interface & usb serial async msg (#2111) * add serial_debug * not use OSS * add path print * add string print and vec * clean up * clean up * format * add an async blocking bool * add an async blocking bool - comment * protect the unexpected tx * naming * remove demo code --- firmware/application/CMakeLists.txt | 1 + firmware/application/apps/ui_sstvtx.cpp | 1 - firmware/application/portapack.cpp | 2 + firmware/application/portapack.hpp | 2 + firmware/application/usb_serial_asyncmsg.hpp | 154 +++++++++++++++++++ firmware/application/usb_serial_shell.cpp | 18 +++ 6 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 firmware/application/usb_serial_asyncmsg.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index c686c0d8e..42ee253c2 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -226,6 +226,7 @@ set(CPPSRC tone_key.cpp transmitter_model.cpp tuning.cpp + usb_serial_asyncmsg.hpp hw/debounce.cpp hw/encoder.cpp hw/max2837.cpp diff --git a/firmware/application/apps/ui_sstvtx.cpp b/firmware/application/apps/ui_sstvtx.cpp index 7358a854a..d6e8ca084 100644 --- a/firmware/application/apps/ui_sstvtx.cpp +++ b/firmware/application/apps/ui_sstvtx.cpp @@ -156,7 +156,6 @@ void SSTVTXView::start_tx() { // The baseband SSTV TX code (proc_sstv) has a 2-scanline buffer. It is preloaded before // TX start, and asks for fill-up when a new scanline starts being read. This should // leave enough time for the code in prepare_scanline() before it ends. - scanline_counter = 0; prepare_scanline(); // Preload one scanline diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index 7a88b57f5..6010c6044 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -617,4 +617,6 @@ void setEventDispatcherToUSBSerial(EventDispatcher* evt) { usb_serial.setEventDispatcher(evt); } +bool async_tx_enabled = false; // this is for serial tx things, globally + } /* namespace portapack */ diff --git a/firmware/application/portapack.hpp b/firmware/application/portapack.hpp index 24eae598c..f9f23d6e1 100644 --- a/firmware/application/portapack.hpp +++ b/firmware/application/portapack.hpp @@ -81,4 +81,6 @@ void setEventDispatcherToUSBSerial(EventDispatcher* evt); Backlight* backlight(); +extern bool async_tx_enabled; // this is for serial tx things, globally + } /* namespace portapack */ diff --git a/firmware/application/usb_serial_asyncmsg.hpp b/firmware/application/usb_serial_asyncmsg.hpp new file mode 100644 index 000000000..588694076 --- /dev/null +++ b/firmware/application/usb_serial_asyncmsg.hpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 Furrtek + * Copyleft (ɔ) 2024 zxkmm with the GPL license + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef USB_SERIAL_AYNCMSG_HPP +#define USB_SERIAL_AYNCMSG_HPP + +#include +#include +#include +#include +#include "usb_serial_device_to_host.h" + +class UsbSerialAsyncmsg { + public: + template + static void asyncmsg(const STRINGCOVER& data); + + template + static void asyncmsg(const std::vector& data); +}; + +/*Notes: + * - Don't use MayhemHub since it currently not support real time serial output + * - If you don't use this class linker will drop it so it won't use any space + * - so delete all debug things before you push your code to production + * - use this client to filter only PP devices: https://github.com/zxkmm/Pyserial-Demo-portapack + * - usage: + * #include "usb_serial_debug_bridge.hpp" + * UsbSerialAsyncmsg::asyncmsg("Hello PP"); + * */ + +/// value +// to_string_bin/ to_string_decimal/ to_string_hex/ to_string_hex_array/ to_string_dec_uint/ to_string_dec_int etc seems usellss so i didn't add them here + +template <> +// usage: UsbSerialAsyncmsg::asyncmsg(num); +void UsbSerialAsyncmsg::asyncmsg(const int64_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +template <> +void UsbSerialAsyncmsg::asyncmsg(const int32_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +template <> +void UsbSerialAsyncmsg::asyncmsg(const int16_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +template <> +void UsbSerialAsyncmsg::asyncmsg(const int8_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +template <> +void UsbSerialAsyncmsg::asyncmsg(const uint8_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +template <> +void UsbSerialAsyncmsg::asyncmsg(const uint16_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +template <> +void UsbSerialAsyncmsg::asyncmsg(const uint32_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +template <> +void UsbSerialAsyncmsg::asyncmsg(const uint64_t& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); +} + +/// fs things + +template <> +// usage: UsbSerialAsyncmsg::asyncmsg(path); +void UsbSerialAsyncmsg::asyncmsg(const std::filesystem::path& data) { + if (!portapack::async_tx_enabled) { + return; + } + std::string path_str = data.string(); + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", path_str.c_str()); +} + +/// string +template <> +// usage: UsbSerialAsyncmsg::asyncmsg(str); +void UsbSerialAsyncmsg::asyncmsg(const std::string& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", data.c_str()); +} + +/// vec worker +// ussgae: UsbSerialAsyncmsg::asyncmsg(vec); +template +void UsbSerialAsyncmsg::asyncmsg(const std::vector& data) { + if (!portapack::async_tx_enabled) { + return; + } + for (const auto& item : data) { + asyncmsg(item); + } +} + +#endif // USB_SERIAL_AYNCMSG_HPP diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 3964e6ed4..e260b8b87 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -1131,6 +1131,23 @@ static void cmd_sendpocsag(BaseSequentialStream* chp, int argc, char* argv[]) { chprintf(chp, "ok\r\n"); } +static void cmd_asyncmsg(BaseSequentialStream* chp, int argc, char* argv[]) { + const char* usage = "usage: asyncmsg x, x can be enable or disable\r\n"; + if (argc != 1) { + chprintf(chp, usage); + return; + } + if (strcmp(argv[0], "disable") == 0) { + portapack::async_tx_enabled = false; + chprintf(chp, "ok\r\n"); + } else if (strcmp(argv[0], "enable") == 0) { + portapack::async_tx_enabled = true; + chprintf(chp, "ok\r\n"); + } else { + chprintf(chp, usage); + } +} + static const ShellCommand commands[] = { {"reboot", cmd_reboot}, {"dfu", cmd_dfu}, @@ -1162,6 +1179,7 @@ static const ShellCommand commands[] = { {"pmemreset", cmd_pmemreset}, {"settingsreset", cmd_settingsreset}, {"sendpocsag", cmd_sendpocsag}, + {"asyncmsg", cmd_asyncmsg}, {NULL, NULL}}; static const ShellConfig shell_cfg1 = { From d691a186e5dde0c624b9c12e9f97cc24512fe086 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Thu, 18 Apr 2024 13:29:06 +0200 Subject: [PATCH 04/28] fix bottom-up format, and add auto extend, .. --- .../external/extsensors/ui_extsensors.cpp | 12 ++++++---- firmware/application/file.cpp | 4 ++++ firmware/application/file.hpp | 1 + firmware/common/bmp.hpp | 2 +- firmware/common/bmpfile.cpp | 24 ++++++++++++------- firmware/common/bmpfile.hpp | 2 ++ 6 files changed, 32 insertions(+), 13 deletions(-) diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp index 4f7a303cc..910c3b441 100644 --- a/firmware/application/external/extsensors/ui_extsensors.cpp +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -41,12 +41,16 @@ ExtSensorsView::ExtSensorsView(NavigationView& nav) &text_envl1, &text_envl2}); BMPFile bmp; - auto ret = bmp.create("/SCREENSHOTS/tmp.bmp", 500, 100); + auto ret = bmp.create("/SCREENSHOTS/tmp.bmp", 50, 10); text_envl1.set(to_string_dec_int(ret)); text_envl2.set(to_string_dec_int(bmp.getbpr())); - - // Color c = Color::red(); - // bmp.write_next_px(c); + Color c = Color::red(); + for (int i = 0; i < 1000; i++) { + if (i % 3 == 0) c = Color::red(); + if (i % 3 == 1) c = Color::green(); + if (i % 3 == 2) c = Color::blue(); + bmp.write_next_px(c); + } bmp.close(); } diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index de7d4220e..dae33f01c 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -102,6 +102,10 @@ File::Offset File::tell() const { return f_tell(&f); } +File::Result File::eof() { + return f_eof(&f); +} + File::Result File::seek(Offset new_position) { /* NOTE: Returns *old* position, not new position */ const auto old_position = tell(); diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 889e86470..3a9e1d522 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -343,6 +343,7 @@ class File { Result seek(uint64_t Offset); Result truncate(); Size size() const; + Result eof(); template Result write(const std::array& data) { diff --git a/firmware/common/bmp.hpp b/firmware/common/bmp.hpp index 1b6a3fbc8..6218e1b41 100644 --- a/firmware/common/bmp.hpp +++ b/firmware/common/bmp.hpp @@ -29,7 +29,7 @@ struct bmp_header_t { uint32_t image_data; uint32_t BIH_size; uint32_t width; - uint32_t height; + int32_t height; uint16_t planes; uint16_t bpp; uint32_t compression; diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index 7e02822d4..765cb0a10 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -1,6 +1,11 @@ #include "bmpfile.hpp" +// fix height info +uint32_t BMPFile::get_real_height() { + return bmp_header.height >= 0 ? (uint32_t)bmp_header.height : (uint32_t)(-1 * bmp_header.height); +} + BMPFile::~BMPFile() { close(); } @@ -34,7 +39,7 @@ bool BMPFile::create(const std::filesystem::path& file, uint32_t x, uint32_t y) bmp_header.v_res = 100; byte_per_px = 3; type = 1; - bmp_header.size = sizeof(bmp_header) + bmp_header.height * byte_per_row; // with padding! --will update later with expand + bmp_header.size = sizeof(bmp_header) + get_real_height() * byte_per_row; // with padding! --will update later with expand bmp_header.data_size = bmp_header.size - sizeof(bmp_header_t); bmp_header.colors_count = 0; bmp_header.icolors_count = 0; @@ -97,11 +102,11 @@ bool BMPFile::open(const std::filesystem::path& file, bool readonly) { // jumps to next pixel. false on the end bool BMPFile::advance_curr_px(uint32_t num = 1) { - if (curry >= bmp_header.height) return false; + if (curry >= get_real_height()) return false; uint32_t rowsToAdvance = (currx + num) / bmp_header.width; uint32_t nx = (currx + num) % bmp_header.width; uint32_t ny = curry + rowsToAdvance; - if (ny >= bmp_header.height) { + if (ny >= get_real_height()) { return false; } seek(nx, ny); @@ -138,6 +143,9 @@ bool BMPFile::read_next_px(ui::Color& px) { bool BMPFile::write_next_px(ui::Color& px) { if (!is_opened) return false; if (is_read_ony) return false; + if (bmpimage.eof()) { + expand_y_delta(1); + } uint8_t buffer[4]; switch (type) { case 0: // R5G6B5 @@ -173,7 +181,7 @@ bool BMPFile::write_next_px(ui::Color& px) { bool BMPFile::seek(uint32_t x, uint32_t y) { if (!is_opened) return false; if (x >= bmp_header.width) return false; - if (y >= bmp_header.height) return false; + if (y >= get_real_height()) return false; file_pos = bmp_header.image_data; // nav to start pos. file_pos += y * byte_per_row; file_pos += x * byte_per_px; @@ -185,19 +193,19 @@ bool BMPFile::seek(uint32_t x, uint32_t y) { // expands the image with a delta (y) bool BMPFile::expand_y_delta(uint32_t delta_y) { - return expand_y(bmp_header.height + delta_y); + return expand_y(get_real_height() + delta_y); } // expands the image to a new y size. bool BMPFile::expand_y(uint32_t new_y) { if (!is_opened) return false; // not yet opened - if (new_y < bmp_header.height) return true; // already bigger + if (new_y < get_real_height()) return true; // already bigger if (is_read_ony) return false; // can't expand size_t old_fp = file_pos; - uint32_t delta = (new_y - bmp_header.height) * byte_per_row; + uint32_t delta = (new_y - get_real_height()) * byte_per_row; bmp_header.size += delta; bmp_header.data_size += delta; - bmp_header.height = new_y; + bmp_header.height = -1 * new_y; //-1*, so no bottom-up structure needed. easier to expand. bmpimage.seek(0); bmpimage.write(&bmp_header, sizeof(bmp_header)); // overwrite header bmpimage.seek(bmp_header.size); // seek to new end diff --git a/firmware/common/bmpfile.hpp b/firmware/common/bmpfile.hpp index 167c3aa45..81a4de68d 100644 --- a/firmware/common/bmpfile.hpp +++ b/firmware/common/bmpfile.hpp @@ -23,9 +23,11 @@ class BMPFile { bool write_next_px(ui::Color& px); private: + uint32_t get_real_height(); bool advance_curr_px(uint32_t num); bool is_opened = false; bool is_read_ony = true; + File bmpimage{}; size_t file_pos = 0; bmp_header_t bmp_header{}; From cdee25779a075ef152fe524de68b027e2c04d9ff Mon Sep 17 00:00:00 2001 From: HTotoo Date: Thu, 18 Apr 2024 14:09:07 +0200 Subject: [PATCH 05/28] bmp write --- .../external/extsensors/ui_extsensors.cpp | 13 +++++++----- firmware/common/bmpfile.cpp | 20 ++++++++----------- firmware/common/bmpfile.hpp | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp index 910c3b441..332bdadf1 100644 --- a/firmware/application/external/extsensors/ui_extsensors.cpp +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -45,11 +45,14 @@ ExtSensorsView::ExtSensorsView(NavigationView& nav) text_envl1.set(to_string_dec_int(ret)); text_envl2.set(to_string_dec_int(bmp.getbpr())); Color c = Color::red(); - for (int i = 0; i < 1000; i++) { - if (i % 3 == 0) c = Color::red(); - if (i % 3 == 1) c = Color::green(); - if (i % 3 == 2) c = Color::blue(); - bmp.write_next_px(c); + for (uint32_t cy = 0; cy < 100; cy++) { + if (cy >= bmp.get_real_height()) bmp.expand_y_delta(1); + for (int x = 0; x < 50; x++) { + if (x % 3 == 0) c = Color::red(); + if (x % 3 == 1) c = Color::green(); + if (x % 3 == 2) c = Color::blue(); + bmp.write_next_px(c); + } } bmp.close(); } diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index 765cb0a10..4f715394b 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -143,9 +143,6 @@ bool BMPFile::read_next_px(ui::Color& px) { bool BMPFile::write_next_px(ui::Color& px) { if (!is_opened) return false; if (is_read_ony) return false; - if (bmpimage.eof()) { - expand_y_delta(1); - } uint8_t buffer[4]; switch (type) { case 0: // R5G6B5 @@ -196,20 +193,19 @@ bool BMPFile::expand_y_delta(uint32_t delta_y) { return expand_y(get_real_height() + delta_y); } -// expands the image to a new y size. +// expands the image to a new y size. also seek's t it's begining bool BMPFile::expand_y(uint32_t new_y) { - if (!is_opened) return false; // not yet opened - if (new_y < get_real_height()) return true; // already bigger - if (is_read_ony) return false; // can't expand - size_t old_fp = file_pos; - uint32_t delta = (new_y - get_real_height()) * byte_per_row; + if (!is_opened) return false; // not yet opened + uint32_t old_height = get_real_height(); + if (new_y < old_height) return true; // already bigger + if (is_read_ony) return false; // can't expand + uint32_t delta = (new_y - old_height) * byte_per_row; bmp_header.size += delta; bmp_header.data_size += delta; bmp_header.height = -1 * new_y; //-1*, so no bottom-up structure needed. easier to expand. bmpimage.seek(0); bmpimage.write(&bmp_header, sizeof(bmp_header)); // overwrite header - bmpimage.seek(bmp_header.size); // seek to new end - file_pos = old_fp; // restore pointer - bmpimage.seek(file_pos); + bmpimage.seek(bmp_header.size); // seek to new end to expand + seek(0, curry + 1); // seek back to the original position return true; } \ No newline at end of file diff --git a/firmware/common/bmpfile.hpp b/firmware/common/bmpfile.hpp index 81a4de68d..26a16ce22 100644 --- a/firmware/common/bmpfile.hpp +++ b/firmware/common/bmpfile.hpp @@ -21,9 +21,9 @@ class BMPFile { bool read_next_px(ui::Color& px); bool write_next_px(ui::Color& px); + uint32_t get_real_height(); private: - uint32_t get_real_height(); bool advance_curr_px(uint32_t num); bool is_opened = false; bool is_read_ony = true; From 7d3823934f362fa77079f95f9951d5edf1a6e53b Mon Sep 17 00:00:00 2001 From: HTotoo Date: Thu, 18 Apr 2024 14:13:18 +0200 Subject: [PATCH 06/28] Minor additions --- firmware/common/bmpfile.cpp | 12 ++++++++++++ firmware/common/bmpfile.hpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index 4f715394b..ffe3ab214 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -3,9 +3,21 @@ // fix height info uint32_t BMPFile::get_real_height() { + if (!is_opened) return 0; return bmp_header.height >= 0 ? (uint32_t)bmp_header.height : (uint32_t)(-1 * bmp_header.height); } +// get bmp width +uint32_t BMPFile::get_width() { + if (!is_opened) return 0; + return bmp_header.width; +} + +// get if the rows are bottom up (for most bmp), or up to bottom (negative height, we use it for write) +bool BMPFile::is_bottomup() { + return (bmp_header.height >= 0); +} + BMPFile::~BMPFile() { close(); } diff --git a/firmware/common/bmpfile.hpp b/firmware/common/bmpfile.hpp index 26a16ce22..286c68bdc 100644 --- a/firmware/common/bmpfile.hpp +++ b/firmware/common/bmpfile.hpp @@ -22,6 +22,8 @@ class BMPFile { bool read_next_px(ui::Color& px); bool write_next_px(ui::Color& px); uint32_t get_real_height(); + uint32_t get_width(); + bool is_bottomup(); private: bool advance_curr_px(uint32_t num); From 9b5410c6e5b284687f9a483cf1291bf1f7277d9b Mon Sep 17 00:00:00 2001 From: HTotoo Date: Thu, 18 Apr 2024 14:35:31 +0200 Subject: [PATCH 07/28] Minor --- firmware/common/bmpfile.cpp | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index ffe3ab214..57df34b1a 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -125,7 +125,7 @@ bool BMPFile::advance_curr_px(uint32_t num = 1) { return true; } -// reads next px, then advance the pos (and seek). return false on last px +// reads next px, then advance the pos (and seek). return false on error bool BMPFile::read_next_px(ui::Color& px) { if (!is_opened) return false; uint8_t buffer[4]; @@ -148,7 +148,8 @@ bool BMPFile::read_next_px(ui::Color& px) { px = ui::Color(buffer[2], buffer[1], buffer[0]); break; } - return advance_curr_px(); + advance_curr_px(); + return true; } // writes a color data to the current position, and advances 1 px. true on success, false on error @@ -191,21 +192,30 @@ bool BMPFile::seek(uint32_t x, uint32_t y) { if (!is_opened) return false; if (x >= bmp_header.width) return false; if (y >= get_real_height()) return false; - file_pos = bmp_header.image_data; // nav to start pos. - file_pos += y * byte_per_row; - file_pos += x * byte_per_px; - bmpimage.seek(file_pos); - currx = x; - curry = y; + if (!BMPFile::is_bottomup()) { + file_pos = bmp_header.image_data; // nav to start pos. + file_pos += y * byte_per_row; + file_pos += x * byte_per_px; + bmpimage.seek(file_pos); + currx = x; + curry = y; + } else { + file_pos = bmp_header.image_data; // nav to start pos. + file_pos += (bmp_header.height - y) * byte_per_row; + file_pos += x * byte_per_px; + bmpimage.seek(file_pos); + currx = x; + curry = y; + } return true; } -// expands the image with a delta (y) +// expands the image with a delta (y). also seek's t it's begining. in bottumup format, it should be used carefully! bool BMPFile::expand_y_delta(uint32_t delta_y) { return expand_y(get_real_height() + delta_y); } -// expands the image to a new y size. also seek's t it's begining +// expands the image to a new y size. also seek's t it's begining. in bottumup format, it should be used carefully! bool BMPFile::expand_y(uint32_t new_y) { if (!is_opened) return false; // not yet opened uint32_t old_height = get_real_height(); @@ -218,6 +228,10 @@ bool BMPFile::expand_y(uint32_t new_y) { bmpimage.seek(0); bmpimage.write(&bmp_header, sizeof(bmp_header)); // overwrite header bmpimage.seek(bmp_header.size); // seek to new end to expand - seek(0, curry + 1); // seek back to the original position + if (is_bottomup()) { + seek(0, new_y - old_height); // seek to the new chunk begin + } else { + seek(0, curry + 1); // seek to the begin of the new chunk + } return true; } \ No newline at end of file From 52d401ec194be1fc960e708e0513765ad636b089 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Thu, 18 Apr 2024 14:37:16 +0200 Subject: [PATCH 08/28] overwrite on create --- firmware/common/bmpfile.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index 57df34b1a..30176b3ee 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -33,7 +33,9 @@ bool BMPFile::create(const std::filesystem::path& file, uint32_t x, uint32_t y) is_opened = false; is_read_ony = true; bmpimage.close(); // if already open, close before open a new - if (file_exists(file)) return false; + if (file_exists(file)) { + delete_file(file); // overwrite + } auto result = bmpimage.open(file, false, true); if (!result.value().ok()) return false; file_pos = 0; From 57f4ef8a0f0d3da7238e7317ed736fe5483f9de1 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Thu, 18 Apr 2024 15:05:05 +0200 Subject: [PATCH 09/28] Tmp --- firmware/application/CMakeLists.txt | 1 + firmware/application/ui/ui_bmpview.cpp | 21 +++++++++++ firmware/application/ui/ui_bmpview.hpp | 48 ++++++++++++++++++++++++++ firmware/common/bmp.hpp | 2 +- firmware/common/bmpfile.cpp | 20 +++++++++++ firmware/common/bmpfile.hpp | 23 ++++++++++-- 6 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 firmware/application/ui/ui_bmpview.cpp create mode 100644 firmware/application/ui/ui_bmpview.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 42ee253c2..05aca93c5 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -261,6 +261,7 @@ set(CPPSRC ui/ui_textentry.cpp ui/ui_tone_key.cpp ui/ui_transmitter.cpp + ui/ui_bmpview.cpp apps/acars_app.cpp apps/ais_app.cpp apps/analog_audio_app.cpp diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp new file mode 100644 index 000000000..3e5548a6f --- /dev/null +++ b/firmware/application/ui/ui_bmpview.cpp @@ -0,0 +1,21 @@ +#include "ui_bmpview.hpp" + +void BMPView::set_zoom(int8_t new_zoom) { + zoom = new_zoom; + set_dirty(); +} +int8_t BMPView::get_zoom() { + return zoom; +} + +BMPView::BMPView(Rect parent_rect) + : Widget{parent_rect} { +} + +void BMPView::paint(Painter& painter) {} +void BMPView::on_focus() {} + +void BMPView::on_blur() {} +bool BMPView::on_key(const KeyEvent key) {} +bool BMPView::on_encoder(EncoderEvent delta) {} +bool BMPView::on_keyboard(const KeyboardEvent event) {} \ No newline at end of file diff --git a/firmware/application/ui/ui_bmpview.hpp b/firmware/application/ui/ui_bmpview.hpp new file mode 100644 index 000000000..74cefc1f6 --- /dev/null +++ b/firmware/application/ui/ui_bmpview.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 HTotoo + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UIBMPVIEW_H__ +#define __UIBMPVIEW_H__ + +#include "ui.hpp" +#include "ui_widget.hpp" + +class BMPView : public Widget { + public: + BMPView(Rect parent_rect); + BMPView(const BMPView& other) = delete; + BMPView& operator=(const BMPView& other) = delete; + + void paint(Painter& painter) override; + void on_focus() override; + void on_blur() override; + bool on_key(const KeyEvent key) override; + bool on_encoder(EncoderEvent delta) override; + bool on_keyboard(const KeyboardEvent event) override; + + void set_zoom(int8_t new_zoom); + int8_t get_zoom(); + + private: + int8_t zoom = 1; // positive = zoom in, negative = zoom out 0-invalid 1- no zoom +}; + +#endif \ No newline at end of file diff --git a/firmware/common/bmp.hpp b/firmware/common/bmp.hpp index 6218e1b41..dd032fb66 100644 --- a/firmware/common/bmp.hpp +++ b/firmware/common/bmp.hpp @@ -29,7 +29,7 @@ struct bmp_header_t { uint32_t image_data; uint32_t BIH_size; uint32_t width; - int32_t height; + int32_t height; // can be negative, to signal the bottom-up or reserve status uint16_t planes; uint16_t bpp; uint32_t compression; diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index 30176b3ee..d452918dd 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2024 HTotoo + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ #include "bmpfile.hpp" diff --git a/firmware/common/bmpfile.hpp b/firmware/common/bmpfile.hpp index 286c68bdc..fa1b3901d 100644 --- a/firmware/common/bmpfile.hpp +++ b/firmware/common/bmpfile.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2024 HTotoo + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + #ifndef __BMPFILE__H #define __BMPFILE__H @@ -39,8 +60,6 @@ class BMPFile { uint32_t currx = 0; uint32_t curry = 0; - - int8_t zoom_factor = 1; // + zoom in, - zoom out. }; #endif \ No newline at end of file From c9b69e098fa13f61effbc467ba46bc20957c1f9d Mon Sep 17 00:00:00 2001 From: HTotoo Date: Fri, 19 Apr 2024 15:27:33 +0200 Subject: [PATCH 10/28] Basic view - WIP --- .../external/extsensors/ui_extsensors.cpp | 24 +--- .../external/extsensors/ui_extsensors.hpp | 4 +- firmware/application/ui/ui_bmpview.cpp | 136 ++++++++++++++++-- firmware/application/ui/ui_bmpview.hpp | 23 ++- firmware/common/bmpfile.cpp | 12 +- firmware/common/bmpfile.hpp | 3 +- 6 files changed, 164 insertions(+), 38 deletions(-) diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp index 332bdadf1..74162240a 100644 --- a/firmware/application/external/extsensors/ui_extsensors.cpp +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -29,32 +29,20 @@ using namespace ui; namespace ui::external_app::extsensors { void ExtSensorsView::focus() { - text_info.focus(); + text_envl1.focus(); } ExtSensorsView::ExtSensorsView(NavigationView& nav) : nav_{nav} { - add_children({&labels, + /*add_children({&labels, &text_info, &text_gps, &text_orientation, &text_envl1, - &text_envl2}); - BMPFile bmp; - auto ret = bmp.create("/SCREENSHOTS/tmp.bmp", 50, 10); - text_envl1.set(to_string_dec_int(ret)); - text_envl2.set(to_string_dec_int(bmp.getbpr())); - Color c = Color::red(); - for (uint32_t cy = 0; cy < 100; cy++) { - if (cy >= bmp.get_real_height()) bmp.expand_y_delta(1); - for (int x = 0; x < 50; x++) { - if (x % 3 == 0) c = Color::red(); - if (x % 3 == 1) c = Color::green(); - if (x % 3 == 2) c = Color::blue(); - bmp.write_next_px(c); - } - } - bmp.close(); + &text_envl2, &bmpv});*/ + add_children({&text_envl1, + &text_envl2, &bmpv}); + bmpv.load_bmp("/SCREENSHOTS/splash.bmp"); } ExtSensorsView::~ExtSensorsView() { diff --git a/firmware/application/external/extsensors/ui_extsensors.hpp b/firmware/application/external/extsensors/ui_extsensors.hpp index 5dfd2a568..3c98529d4 100644 --- a/firmware/application/external/extsensors/ui_extsensors.hpp +++ b/firmware/application/external/extsensors/ui_extsensors.hpp @@ -33,7 +33,7 @@ #include "ui_record_view.hpp" #include "app_settings.hpp" #include "utility.hpp" -#include "bmpfile.hpp" +#include "ui_bmpview.hpp" using namespace ui; @@ -66,6 +66,8 @@ class ExtSensorsView : public View { Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"}; Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"}; + BMPViewer bmpv{{0, 100, 200, 100}}; + void on_any(); void on_gps(const GPSPosDataMessage* msg); diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index 3e5548a6f..76fa9ebdc 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -1,21 +1,139 @@ #include "ui_bmpview.hpp" +#include "portapack.hpp" -void BMPView::set_zoom(int8_t new_zoom) { +bool BMPViewer::load_bmp(const std::filesystem::path& file) { + if (!bmp.open(file, true)) return false; + // todo calc default zoom level to fit screen, and min / max zoom too + zoom_fit = 1; + reset_pos(); + set_dirty(); + return true; +} + +void BMPViewer::set_zoom(int8_t new_zoom) { + if (new_zoom == 0) new_zoom = 1; + if (new_zoom > max_zoom) new_zoom = max_zoom; + if (new_zoom < min_zoom) new_zoom = min_zoom; zoom = new_zoom; set_dirty(); } -int8_t BMPView::get_zoom() { + +// reads a lint from the bmp's bx, by coordinate to the line that's size is cnt. according to zoom +void BMPViewer::get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt) { + if (!bmp.is_loaded()) return; + for (uint32_t x = 0; x < cnt; x++) { + uint32_t targetx = (zoom < 0) ? bx + x * -1 * zoom : bx + x / zoom; // todo fix zoom out! + if (!bmp.seek(targetx, by)) { + line[x] = Color::white(); // can't seek there + } else { + bmp.read_next_px(line[x], false); + } + } +} + +void BMPViewer::paint(Painter& painter) { + if (!bmp.is_loaded()) { + painter.draw_string({48, 24}, ui::Styles::white, "Can't load BMP"); + return; + } + // get where i can paint + auto rect = screen_rect(); + auto d_height = rect.height(); + auto d_width = rect.width(); + + // get the bmp's size + // auto b_width = bmp.get_width(); + // auto b_height = bmp.get_real_height(); + + uint32_t by = cy; // we start to read from there + ui::Color* line = new ui::Color[d_width]; + for (int32_t y = 0; y < d_height; y++) { + by = cy + ((zoom < 0) ? -1 * zoom : y / (int32_t)zoom); + get_line(line, cx, by, d_width); + + // todo optimize, not to read again and again the same.. + portapack::display.draw_pixels({rect.left(), rect.top() + y, d_width, 1}, line, d_width); + } + delete line; +} + +int8_t BMPViewer::get_zoom() { return zoom; } -BMPView::BMPView(Rect parent_rect) +BMPViewer::BMPViewer(Rect parent_rect) + : Widget{parent_rect} { +} + +BMPViewer::BMPViewer(Rect parent_rect, const std::filesystem::path& file) : Widget{parent_rect} { + load_bmp(file); +} + +void BMPViewer::on_focus() {} + +void BMPViewer::on_blur() { + set_dirty(); } -void BMPView::paint(Painter& painter) {} -void BMPView::on_focus() {} +void BMPViewer::reset_pos() { + if (!bmp.is_loaded()) return; + cx = 0; + cy = 0; + zoom = zoom_fit; + set_dirty(); +} + +bool BMPViewer::on_key(const KeyEvent key) { + if (key == KeyEvent::Up) { + if (cy <= 0) return false; + // todo move up + } + if (key == KeyEvent::Down) { + if (cy >= 100) return false; // todo limit + // todo move down + } + if (key == KeyEvent::Left) { + if (cx <= 0) return false; + // todo move left + } + if (key == KeyEvent::Right) { + if (cx >= 100) return false; // todo limit + // todo move right + } + if (key == KeyEvent::Select) { + reset_pos(); + return true; + } + return false; +} + +bool BMPViewer::on_encoder(EncoderEvent delta) { + if (delta > 0) { + set_zoom(zoom + 1); // 0 handled in set_zoom + return true; + } + if (delta > 0) { + if (zoom == 1) // not 0, but -1 + set_zoom(-1); + else + set_zoom(zoom - 1); // decrease + return true; + } + return false; +} -void BMPView::on_blur() {} -bool BMPView::on_key(const KeyEvent key) {} -bool BMPView::on_encoder(EncoderEvent delta) {} -bool BMPView::on_keyboard(const KeyboardEvent event) {} \ No newline at end of file +bool BMPViewer::on_keyboard(const KeyboardEvent event) { + if (event == '+') { + set_zoom(zoom + 1); + return true; + } + if (event == '-') { + if (zoom == 1) // not 0, but -1 + set_zoom(-1); + else + set_zoom(zoom - 1); // decrease + return true; + } + return false; +} \ No newline at end of file diff --git a/firmware/application/ui/ui_bmpview.hpp b/firmware/application/ui/ui_bmpview.hpp index 74cefc1f6..5a80bfb8c 100644 --- a/firmware/application/ui/ui_bmpview.hpp +++ b/firmware/application/ui/ui_bmpview.hpp @@ -24,12 +24,17 @@ #include "ui.hpp" #include "ui_widget.hpp" +#include "bmpfile.hpp" +#include "ui_styles.hpp" -class BMPView : public Widget { +class BMPViewer : public Widget { public: - BMPView(Rect parent_rect); - BMPView(const BMPView& other) = delete; - BMPView& operator=(const BMPView& other) = delete; + BMPViewer(Rect parent_rect); + BMPViewer(Rect parent_rect, const std::filesystem::path& file); + BMPViewer(const BMPViewer& other) = delete; + BMPViewer& operator=(const BMPViewer& other) = delete; + + bool load_bmp(const std::filesystem::path& file); void paint(Painter& painter) override; void on_focus() override; @@ -38,11 +43,19 @@ class BMPView : public Widget { bool on_encoder(EncoderEvent delta) override; bool on_keyboard(const KeyboardEvent event) override; + void reset_pos(); void set_zoom(int8_t new_zoom); int8_t get_zoom(); private: - int8_t zoom = 1; // positive = zoom in, negative = zoom out 0-invalid 1- no zoom + void get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt); + BMPFile bmp{}; + int8_t zoom = 1; // positive = zoom in, negative = zoom out 0-invalid 1- no zoom + int8_t zoom_fit = 1; // if this value is set, the image will fit the screen the most + int8_t max_zoom = 20; // will be calculated on load + int8_t min_zoom = -20; + uint32_t cx = 0; // current top-left coordinate + uint32_t cy = 0; }; #endif \ No newline at end of file diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index d452918dd..3a6de2e8a 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -21,6 +21,10 @@ #include "bmpfile.hpp" +bool BMPFile::is_loaded() { + return is_opened; +} + // fix height info uint32_t BMPFile::get_real_height() { if (!is_opened) return 0; @@ -94,7 +98,7 @@ bool BMPFile::open(const std::filesystem::path& file, bool readonly) { bmpimage.close(); // if already open, close before open a new auto result = bmpimage.open(file, readonly, false); - if (!result.is_valid()) return false; + if (!result.value().ok()) return false; file_pos = 0; bmpimage.seek(file_pos); auto read_size = bmpimage.read(&bmp_header, sizeof(bmp_header_t)); @@ -148,7 +152,7 @@ bool BMPFile::advance_curr_px(uint32_t num = 1) { } // reads next px, then advance the pos (and seek). return false on error -bool BMPFile::read_next_px(ui::Color& px) { +bool BMPFile::read_next_px(ui::Color& px, bool seek = true) { if (!is_opened) return false; uint8_t buffer[4]; auto res = bmpimage.read(buffer, byte_per_px); @@ -170,7 +174,7 @@ bool BMPFile::read_next_px(ui::Color& px) { px = ui::Color(buffer[2], buffer[1], buffer[0]); break; } - advance_curr_px(); + if (seek) advance_curr_px(); return true; } @@ -223,7 +227,7 @@ bool BMPFile::seek(uint32_t x, uint32_t y) { curry = y; } else { file_pos = bmp_header.image_data; // nav to start pos. - file_pos += (bmp_header.height - y) * byte_per_row; + file_pos += (get_real_height() - y) * byte_per_row; file_pos += x * byte_per_px; bmpimage.seek(file_pos); currx = x; diff --git a/firmware/common/bmpfile.hpp b/firmware/common/bmpfile.hpp index fa1b3901d..821af9eac 100644 --- a/firmware/common/bmpfile.hpp +++ b/firmware/common/bmpfile.hpp @@ -35,12 +35,13 @@ class BMPFile { bool open(const std::filesystem::path& file, bool readonly); bool create(const std::filesystem::path& file, uint32_t x, uint32_t y); void close(); + bool is_loaded(); bool seek(uint32_t x, uint32_t y); bool expand_y(uint32_t new_y); bool expand_y_delta(uint32_t delta_y); uint32_t getbpr() { return byte_per_row; }; - bool read_next_px(ui::Color& px); + bool read_next_px(ui::Color& px, bool seek); bool write_next_px(ui::Color& px); uint32_t get_real_height(); uint32_t get_width(); From fd14a2817028335e1a35bbf2e6ed733653b7c8f4 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 11:08:22 +0200 Subject: [PATCH 11/28] debug --- firmware/application/ui/ui_bmpview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index 76fa9ebdc..bc9d3b310 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -1,4 +1,5 @@ #include "ui_bmpview.hpp" +#include "usb_serial_asyncmsg.hpp" #include "portapack.hpp" bool BMPViewer::load_bmp(const std::filesystem::path& file) { @@ -15,6 +16,8 @@ void BMPViewer::set_zoom(int8_t new_zoom) { if (new_zoom > max_zoom) new_zoom = max_zoom; if (new_zoom < min_zoom) new_zoom = min_zoom; zoom = new_zoom; + UsbSerialAsyncmsg::asyncmsg("New zoom: "); + UsbSerialAsyncmsg::asyncmsg(zoom); set_dirty(); } From 53242439ebd0aa3479c03ab36bcf607b0133bd7b Mon Sep 17 00:00:00 2001 From: sommermorgentraum <24917424+zxkmm@users.noreply.github.com> Date: Sat, 20 Apr 2024 18:31:57 +0800 Subject: [PATCH 12/28] add literal str print in asyncmsg (#2113) * add literal str print in asyncmsg * remove debug things * accept suggestion per gull * fix documentary --- .gitignore | 1 + firmware/application/usb_serial_asyncmsg.hpp | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 52f03525b..d7ab86ca3 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ .dep/ /build* CMakeFiles/ +cmake-build-debug/ # Debugging .gdbinit* diff --git a/firmware/application/usb_serial_asyncmsg.hpp b/firmware/application/usb_serial_asyncmsg.hpp index 588694076..17b22f84a 100644 --- a/firmware/application/usb_serial_asyncmsg.hpp +++ b/firmware/application/usb_serial_asyncmsg.hpp @@ -37,6 +37,8 @@ class UsbSerialAsyncmsg { template static void asyncmsg(const std::vector& data); + + static void asyncmsg(const char* data); // string literal }; /*Notes: @@ -45,15 +47,16 @@ class UsbSerialAsyncmsg { * - so delete all debug things before you push your code to production * - use this client to filter only PP devices: https://github.com/zxkmm/Pyserial-Demo-portapack * - usage: - * #include "usb_serial_debug_bridge.hpp" + * portapack::async_tx_enabled = true; // note that use this when debugging, unless the msg would be forbidden. but don't use this in production, since it's not real async and multiple serial transmittions will broken each other. if this class is used in other scene in the future, just use command to cover (protect your serial tramsnitton) in your extern thing: asyncmsg enable --- your cmd --- asyncmsg disable + * #include "usb_serial_asyncmsg.cpp" * UsbSerialAsyncmsg::asyncmsg("Hello PP"); * */ /// value // to_string_bin/ to_string_decimal/ to_string_hex/ to_string_hex_array/ to_string_dec_uint/ to_string_dec_int etc seems usellss so i didn't add them here +// usage: UsbSerialAsyncmsg::asyncmsg(num); template <> -// usage: UsbSerialAsyncmsg::asyncmsg(num); void UsbSerialAsyncmsg::asyncmsg(const int64_t& data) { if (!portapack::async_tx_enabled) { return; @@ -130,6 +133,8 @@ void UsbSerialAsyncmsg::asyncmsg(const std::filesystem::p } /// string + +// string obj template <> // usage: UsbSerialAsyncmsg::asyncmsg(str); void UsbSerialAsyncmsg::asyncmsg(const std::string& data) { @@ -139,6 +144,15 @@ void UsbSerialAsyncmsg::asyncmsg(const std::string& data) { chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", data.c_str()); } +// string literal AKA char[] +// usage: UsbSerialAsyncmsg::asyncmsg("abc"); +void UsbSerialAsyncmsg::asyncmsg(const char* data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", data); +} + /// vec worker // ussgae: UsbSerialAsyncmsg::asyncmsg(vec); template From 4652b3702815197773a0accea437e069db357acd Mon Sep 17 00:00:00 2001 From: Totoo Date: Sat, 20 Apr 2024 14:26:54 +0200 Subject: [PATCH 13/28] Fix bug (#2114) --- firmware/application/string_format.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/application/string_format.cpp b/firmware/application/string_format.cpp index 8a061cb1e..fefbc16fe 100644 --- a/firmware/application/string_format.cpp +++ b/firmware/application/string_format.cpp @@ -159,6 +159,7 @@ std::string to_string_decimal(float decimal, int8_t precision) { double fractional_part; std::string result; + if (precision > 9) precision = 9; // we will convert to uin32_t, and that is the max it can hold. fractional_part = modf(decimal, &integer_part) * pow(10, precision); From ab6e740fdd8b62232da8921b71b2f0934839909c Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 21 Apr 2024 01:34:55 -0500 Subject: [PATCH 14/28] Disable Back button during Touch Calibration (#2115) --- firmware/application/apps/ui_touch_calibration.cpp | 10 ++++++++++ firmware/application/apps/ui_touch_calibration.hpp | 7 ++++++- firmware/application/main.cpp | 3 +++ firmware/application/ui_navigation.cpp | 7 +++++++ firmware/application/ui_navigation.hpp | 2 ++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/firmware/application/apps/ui_touch_calibration.cpp b/firmware/application/apps/ui_touch_calibration.cpp index fa91e07c5..3ee3a9637 100644 --- a/firmware/application/apps/ui_touch_calibration.cpp +++ b/firmware/application/apps/ui_touch_calibration.cpp @@ -26,6 +26,8 @@ #include "portapack_persistent_memory.hpp" using namespace portapack; +extern ui::SystemView* system_view_ptr; + namespace ui { TouchCalibrationView::TouchCalibrationView( @@ -40,6 +42,7 @@ TouchCalibrationView::TouchCalibrationView( &image_verify_1, &image_verify_2, &label_calibrate, + &label_calibrate_2, &label_verify, &label_success, &label_failure, @@ -51,6 +54,12 @@ TouchCalibrationView::TouchCalibrationView( button_ok.on_select = [this](Button&) { this->on_ok(); }; set_phase(Phase::Calibrate0); + + system_view_ptr->get_status_view()->set_back_hidden(true); +} + +TouchCalibrationView::~TouchCalibrationView() { + system_view_ptr->get_status_view()->set_back_hidden(false); } void TouchCalibrationView::focus() { @@ -70,6 +79,7 @@ void TouchCalibrationView::update_target() { image_verify_2.hidden(phase != Phase::Verify2); label_calibrate.hidden(!phase_calibrate); + label_calibrate_2.hidden(!phase_calibrate && !phase_verify); label_verify.hidden(!phase_verify); label_success.hidden(phase != Phase::Success); label_failure.hidden(phase != Phase::Failure); diff --git a/firmware/application/apps/ui_touch_calibration.hpp b/firmware/application/apps/ui_touch_calibration.hpp index f64bca1d6..18b848ace 100644 --- a/firmware/application/apps/ui_touch_calibration.hpp +++ b/firmware/application/apps/ui_touch_calibration.hpp @@ -31,6 +31,7 @@ namespace ui { class TouchCalibrationView : public View { public: TouchCalibrationView(NavigationView& nav); + ~TouchCalibrationView(); void focus() override; @@ -110,9 +111,13 @@ class TouchCalibrationView : public View { Color::black()}; Text label_calibrate{ - {16, 5 * 16, 26 * 8, 1 * 16}, + {2 * 8, 5 * 16, 26 * 8, 1 * 16}, "Touch targets to calibrate"}; + Text label_calibrate_2{ + {1 * 8, 6 * 16, 28 * 8, 1 * 16}, + "(hold position using stylus)"}; + Text label_verify{ {28, 5 * 16, 23 * 8, 1 * 16}, "Touch targets to verify"}; diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 4ec395cb3..cff6762fc 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -144,6 +144,7 @@ Continuous (Fox-oring) #include "rffc507x.hpp" /* c/m, avoiding initial short ON Ant_DC_Bias pulse, from cold reset */ rffc507x::RFFC507x first_if; +ui::SystemView* system_view_ptr; static void event_loop() { static ui::Context context; @@ -151,6 +152,8 @@ static void event_loop() { context, portapack::display.screen_rect()}; + system_view_ptr = &system_view; + EventDispatcher event_dispatcher{&system_view, context}; static MessageHandlerRegistration message_handler_display_sleep{ Message::ID::DisplaySleep, diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 67c586363..2f36d98de 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -422,6 +422,10 @@ void SystemStatusView::set_back_enabled(bool new_value) { } } +void SystemStatusView::set_back_hidden(bool new_value) { + button_back.hidden(new_value); +} + void SystemStatusView::set_title_image_enabled(bool new_value) { if (new_value) { add_child(&button_title); @@ -896,6 +900,9 @@ Context& SystemView::context() const { NavigationView* SystemView::get_navigation_view() { return &navigation_view; } +SystemStatusView* SystemView::get_status_view() { + return &status_view; +} void SystemView::toggle_overlay() { static uint8_t last_perf_counter_status = shared_memory.request_m4_performance_counter; diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 8144efd48..801e2a35f 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -185,6 +185,7 @@ class SystemStatusView : public View { SystemStatusView(NavigationView& nav); void set_back_enabled(bool new_value); + void set_back_hidden(bool new_value); void set_title_image_enabled(bool new_value); void set_title(const std::string new_value); @@ -378,6 +379,7 @@ class SystemView : public View { void paint_overlay(); NavigationView* get_navigation_view(); + SystemStatusView* get_status_view(); private: uint8_t overlay_active{0}; From 1fb77824311f24978e084c187ca079661ba96746 Mon Sep 17 00:00:00 2001 From: jLynx Date: Sun, 21 Apr 2024 20:44:47 +1200 Subject: [PATCH 15/28] ADS1100 (#2116) * WIP * WIP * WIP * Corrected name * WIP * WIP * WIP * WIP * Added new calc * WIP * WIP * WIP * WIP * WIP * WIP * Added debug serial lines * WIP * Fixed issue * Fixed calculation issue * Added voltage to performance DFU menu * Added padding function and added voltage to perf menu * Clean up * Refactor * Fixed linting * Hides voltage if PP does not conatin IC * WIP showing battery % * made the percentage a int * Added % to header * Removed test UI * Removed comment * Added fix for precision too large * Added fix for precision too large * Linting --- firmware/application/CMakeLists.txt | 1 + firmware/application/apps/ui_dfu_menu.cpp | 11 +- firmware/application/apps/ui_dfu_menu.hpp | 5 +- firmware/application/portapack.cpp | 3 + firmware/application/portapack.hpp | 3 + firmware/application/string_format.cpp | 25 +++++ firmware/application/string_format.hpp | 1 + firmware/common/ads1110.cpp | 130 ++++++++++++++++++++++ firmware/common/ads1110.hpp | 58 ++++++++++ 9 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 firmware/common/ads1110.cpp create mode 100644 firmware/common/ads1110.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 05aca93c5..44a077813 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -176,6 +176,7 @@ set(CPPSRC ${COMMON}/ui_language.cpp ${COMMON}/utility.cpp ${COMMON}/wm8731.cpp + ${COMMON}/ads1110.cpp ${COMMON}/performance_counter.cpp ${COMMON}/bmpfile.cpp app_settings.cpp diff --git a/firmware/application/apps/ui_dfu_menu.cpp b/firmware/application/apps/ui_dfu_menu.cpp index 63efe41ff..887a33f05 100644 --- a/firmware/application/apps/ui_dfu_menu.cpp +++ b/firmware/application/apps/ui_dfu_menu.cpp @@ -41,6 +41,11 @@ DfuMenu::DfuMenu(NavigationView& nav) &text_info_line_8, &text_info_line_9, &text_info_line_10}); + + if (portapack::battery_ads1110.isDetected()) { + add_child(&voltage_label); + add_child(&text_info_line_11); + } } void DfuMenu::paint(Painter& painter) { @@ -48,6 +53,8 @@ void DfuMenu::paint(Painter& painter) { size_t m0_fragmented_free_space = 0; const auto m0_fragments = chHeapStatus(NULL, &m0_fragmented_free_space); + auto lines = (portapack::battery_ads1110.isDetected() ? 11 : 10) + 2; + text_info_line_1.set(to_string_dec_uint(chCoreStatus(), 6)); text_info_line_2.set(to_string_dec_uint(m0_fragmented_free_space, 6)); text_info_line_3.set(to_string_dec_uint(m0_fragments, 6)); @@ -58,9 +65,11 @@ void DfuMenu::paint(Painter& painter) { text_info_line_8.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6)); text_info_line_9.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6)); text_info_line_10.set(to_string_dec_uint(chTimeNow() / 1000, 6)); + if (portapack::battery_ads1110.isDetected()) { + text_info_line_11.set(to_string_decimal_padding(portapack::battery_ads1110.readVoltage(), 3, 6)); + } constexpr auto margin = 5; - constexpr auto lines = 10 + 2; painter.fill_rectangle( {{6 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin}, diff --git a/firmware/application/apps/ui_dfu_menu.hpp b/firmware/application/apps/ui_dfu_menu.hpp index 9729bcb71..91e3f6eea 100644 --- a/firmware/application/apps/ui_dfu_menu.hpp +++ b/firmware/application/apps/ui_dfu_menu.hpp @@ -58,7 +58,9 @@ class DfuMenu : public View { {{6 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "M4 stack:", Color::dark_cyan()}, {{6 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "M4 cpu %:", Color::dark_cyan()}, {{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Color::dark_cyan()}, - {{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "uptime:", Color::dark_cyan()}}; + {{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "Uptime:", Color::dark_cyan()}}; + + Labels voltage_label{{{6 * CHARACTER_WIDTH, 15 * LINE_HEIGHT}, "Voltage:", Color::dark_cyan()}}; Text text_info_line_1{{15 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""}; Text text_info_line_2{{15 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""}; @@ -70,6 +72,7 @@ class DfuMenu : public View { Text text_info_line_8{{15 * CHARACTER_WIDTH, 12 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""}; Text text_info_line_9{{15 * CHARACTER_WIDTH, 13 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""}; Text text_info_line_10{{15 * CHARACTER_WIDTH, 14 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""}; + Text text_info_line_11{{15 * CHARACTER_WIDTH, 15 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""}; }; class DfuMenu2 : public View { diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index 6010c6044..806a1f33f 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -52,6 +52,7 @@ using asahi_kasei::ak4951::AK4951; #include "sd_card.hpp" #include "string_format.hpp" #include "bitmap.hpp" +#include "ui_widget.hpp" namespace portapack { @@ -84,6 +85,7 @@ ClockManager clock_manager{ WM8731 audio_codec_wm8731{i2c0, 0x1a}; AK4951 audio_codec_ak4951{i2c0, 0x12}; +ads1110::ADS1110 battery_ads1110{i2c0, 0x48}; ReceiverModel receiver_model; TransmitterModel transmitter_model; @@ -585,6 +587,7 @@ init_status_t init() { chThdSleepMilliseconds(10); audio::init(portapack_audio_codec()); + battery_ads1110.init(); if (lcd_fast_setup) draw_splash_screen_icon(4, ui::bitmap_icon_speaker); diff --git a/firmware/application/portapack.hpp b/firmware/application/portapack.hpp index f9f23d6e1..ba5f11471 100644 --- a/firmware/application/portapack.hpp +++ b/firmware/application/portapack.hpp @@ -33,6 +33,8 @@ #include "backlight.hpp" #include "usb_serial.hpp" +#include "ads1110.hpp" + #include "radio.hpp" #include "clock_manager.hpp" #include "temperature_logger.hpp" @@ -61,6 +63,7 @@ extern portapack::USBSerial usb_serial; extern si5351::Si5351 clock_generator; extern ClockManager clock_manager; +extern ads1110::ADS1110 battery_ads1110; extern ReceiverModel receiver_model; extern TransmitterModel transmitter_model; diff --git a/firmware/application/string_format.cpp b/firmware/application/string_format.cpp index fefbc16fe..381cb75fa 100644 --- a/firmware/application/string_format.cpp +++ b/firmware/application/string_format.cpp @@ -172,6 +172,31 @@ std::string to_string_decimal(float decimal, int8_t precision) { return result; } +std::string to_string_decimal_padding(float decimal, int8_t precision, const int32_t l) { + double integer_part; + double fractional_part; + + std::string result; + if (precision > 9) precision = 9; // we will convert to uin32_t, and that is the max it can hold. + + fractional_part = modf(decimal, &integer_part) * pow(10, precision); + + if (fractional_part < 0) { + fractional_part = -fractional_part; + } + + result = to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, precision, '0'); + + // Add padding with spaces to meet the length requirement + if (result.length() < l) { + int padding_length = l - result.length(); + std::string padding(padding_length, ' '); + result = padding + result; + } + + return result; +} + // right-justified frequency in Hz, always 10 characters std::string to_string_freq(const uint64_t f) { std::string final_str{""}; diff --git a/firmware/application/string_format.hpp b/firmware/application/string_format.hpp index 4413afc23..cfebd70f3 100644 --- a/firmware/application/string_format.hpp +++ b/firmware/application/string_format.hpp @@ -54,6 +54,7 @@ std::string to_string_bin(const uint32_t n, const uint8_t l = 0); std::string to_string_dec_uint(const uint32_t n, const int32_t l, const char fill = ' '); std::string to_string_dec_int(const int32_t n, const int32_t l, const char fill = 0); std::string to_string_decimal(float decimal, int8_t precision); +std::string to_string_decimal_padding(float decimal, int8_t precision, const int32_t l); std::string to_string_hex(uint64_t n, int32_t length); std::string to_string_hex_array(uint8_t* array, int32_t length); diff --git a/firmware/common/ads1110.cpp b/firmware/common/ads1110.cpp new file mode 100644 index 000000000..04bed5ea4 --- /dev/null +++ b/firmware/common/ads1110.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2024 jLynx. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ads1110.hpp" +#include "utility.hpp" +#include +#include + +namespace ads1110 { + +constexpr float BATTERY_MIN_VOLTAGE = 3.0; +constexpr float BATTERY_MAX_VOLTAGE = 4.0; + +void ADS1110::init() { + if (!detected_) { + detected_ = detect(); + } + if (detected_) { + // Set the configuration register + write(0x8C); + } +} + +bool ADS1110::detect() { + uint8_t data[3]; + if (bus.receive(bus_address, data, 3)) { + // Check if the received data is valid + uint8_t configRegister = data[2]; + if ((configRegister & 0x0F) == 0x0C) { + // The configuration register value matches the expected value (0x8C) + detected_ = true; + return true; + } + } + return false; +} + +bool ADS1110::write(const uint8_t value) { + return bus.transmit(bus_address, &value, 1); +} + +float ADS1110::readVoltage() { + // Read the conversion result + uint8_t data[3]; + if (!bus.receive(bus_address, data, 3)) { + return 0.0f; // Return 0 if the read fails + } + + uint16_t raw = (static_cast(data[0]) << 8) | data[1]; + + // Calculate the voltage based on the output code + float voltage = 0.0f; + float minCode = 0; + float pga = 0.0f; + + uint8_t pga_rate = data[2] & 0x03; + switch (pga_rate) { + case 0: + pga = 1.0f; + break; + case 1: + pga = 2.0f; + break; + case 2: + pga = 4.0f; + break; + case 3: + pga = 8.0f; + break; + default: + // Handle invalid data rate + break; + } + + uint8_t data_rate = (data[2] >> 2) & 0x03; + switch (data_rate) { + case 0: // 240 + minCode = -2048.0; + break; + case 1: // 60 + minCode = -8192.0; + break; + case 2: // 30 + minCode = -16384.0; + break; + case 3: // 15 + minCode = -32768.0; + break; + default: + // Handle invalid data rate + break; + } + + // 2.048 is the reference voltage & 2.0 is to make up for the voltage divider + voltage = raw / (-1.0 * minCode) * pga * 2.048 * 2.0; + + return voltage; +} + +void ADS1110::getBatteryInfo(float& batteryPercentage, float& voltage) { + voltage = readVoltage(); + + // Calculate the remaining battery percentage + batteryPercentage = (voltage - BATTERY_MIN_VOLTAGE) / + (BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE) * 100.0; + + // Limit the values to the valid range + batteryPercentage = std::clamp(batteryPercentage, 0.0f, 100.0f); + // ToDo: if its > 4, then 100%, if < 3 then 0% +} + +} /* namespace ads1110 */ diff --git a/firmware/common/ads1110.hpp b/firmware/common/ads1110.hpp new file mode 100644 index 000000000..7b5231d24 --- /dev/null +++ b/firmware/common/ads1110.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 jLynx. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __ADS1110_H__ +#define __ADS1110_H__ + +#include +#include +#include + +#include "i2c_pp.hpp" + +namespace ads1110 { + +using address_t = uint8_t; +using reg_t = uint16_t; + +class ADS1110 { + public: + constexpr ADS1110(I2C& bus, const I2C::address_t bus_address) + : bus(bus), bus_address(bus_address), detected_(false) {} + + void init(); + bool isDetected() const { return detected_; } + + float readVoltage(); + void getBatteryInfo(float& batteryPercentage, float& voltage); + + private: + I2C& bus; + const I2C::address_t bus_address; + bool detected_; + + bool write(const uint8_t value); + bool detect(); +}; + +} /* namespace ads1110 */ + +#endif /* __ADS1110_H__ */ \ No newline at end of file From d0781af7ca207a25659c371d24bfe146377a02c4 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 13:49:25 +0200 Subject: [PATCH 16/28] widget --- .../external/extsensors/ui_extsensors.cpp | 7 ++-- firmware/application/ui/ui_bmpview.cpp | 35 +++++++++++++------ firmware/common/bmpfile.cpp | 2 +- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp index 74162240a..6b7db3680 100644 --- a/firmware/application/external/extsensors/ui_extsensors.cpp +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -29,7 +29,7 @@ using namespace ui; namespace ui::external_app::extsensors { void ExtSensorsView::focus() { - text_envl1.focus(); + bmpv.focus(); } ExtSensorsView::ExtSensorsView(NavigationView& nav) @@ -40,8 +40,9 @@ ExtSensorsView::ExtSensorsView(NavigationView& nav) &text_orientation, &text_envl1, &text_envl2, &bmpv});*/ - add_children({&text_envl1, - &text_envl2, &bmpv}); + add_children({//&text_envl1, + //&text_envl2, + &bmpv}); bmpv.load_bmp("/SCREENSHOTS/splash.bmp"); } diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index bc9d3b310..279fda652 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -13,6 +13,7 @@ bool BMPViewer::load_bmp(const std::filesystem::path& file) { void BMPViewer::set_zoom(int8_t new_zoom) { if (new_zoom == 0) new_zoom = 1; + if (new_zoom == -1) new_zoom = 1; if (new_zoom > max_zoom) new_zoom = max_zoom; if (new_zoom < min_zoom) new_zoom = min_zoom; zoom = new_zoom; @@ -24,8 +25,14 @@ void BMPViewer::set_zoom(int8_t new_zoom) { // reads a lint from the bmp's bx, by coordinate to the line that's size is cnt. according to zoom void BMPViewer::get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt) { if (!bmp.is_loaded()) return; + uint32_t last_targetx = 65534; for (uint32_t x = 0; x < cnt; x++) { - uint32_t targetx = (zoom < 0) ? bx + x * -1 * zoom : bx + x / zoom; // todo fix zoom out! + uint32_t targetx = (zoom < 0) ? bx + x * -1 * zoom : bx + x / zoom; // on zoom out could probably avg the pixels, or apply some smoothing, but this is way faster. + if (last_targetx == targetx) { + line[x] = line[x - 1]; + continue; + } + last_targetx = targetx; if (!bmp.seek(targetx, by)) { line[x] = Color::white(); // can't seek there } else { @@ -35,6 +42,7 @@ void BMPViewer::get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt } void BMPViewer::paint(Painter& painter) { + UsbSerialAsyncmsg::asyncmsg("paint enter"); if (!bmp.is_loaded()) { painter.draw_string({48, 24}, ui::Styles::white, "Can't load BMP"); return; @@ -49,15 +57,16 @@ void BMPViewer::paint(Painter& painter) { // auto b_height = bmp.get_real_height(); uint32_t by = cy; // we start to read from there + uint32_t last_by = 65534; ui::Color* line = new ui::Color[d_width]; for (int32_t y = 0; y < d_height; y++) { - by = cy + ((zoom < 0) ? -1 * zoom : y / (int32_t)zoom); - get_line(line, cx, by, d_width); - - // todo optimize, not to read again and again the same.. + by = cy + ((zoom < 0) ? y * -1 * zoom : y / (int32_t)zoom); + if (by != last_by) get_line(line, cx, by, d_width); + last_by = by; portapack::display.draw_pixels({rect.left(), rect.top() + y, d_width, 1}, line, d_width); } delete line; + UsbSerialAsyncmsg::asyncmsg("paint end"); } int8_t BMPViewer::get_zoom() { @@ -66,14 +75,19 @@ int8_t BMPViewer::get_zoom() { BMPViewer::BMPViewer(Rect parent_rect) : Widget{parent_rect} { + set_focusable(true); } BMPViewer::BMPViewer(Rect parent_rect, const std::filesystem::path& file) : Widget{parent_rect} { + set_focusable(true); load_bmp(file); } -void BMPViewer::on_focus() {} +void BMPViewer::on_focus() { + UsbSerialAsyncmsg::asyncmsg("on focus"); + set_highlighted(true); +} void BMPViewer::on_blur() { set_dirty(); @@ -105,20 +119,21 @@ bool BMPViewer::on_key(const KeyEvent key) { // todo move right } if (key == KeyEvent::Select) { - reset_pos(); + reset_pos(); // todo maybe exit app?! return true; } return false; } bool BMPViewer::on_encoder(EncoderEvent delta) { + UsbSerialAsyncmsg::asyncmsg("encoder"); if (delta > 0) { set_zoom(zoom + 1); // 0 handled in set_zoom return true; } - if (delta > 0) { + if (delta < 0) { if (zoom == 1) // not 0, but -1 - set_zoom(-1); + set_zoom(-2); else set_zoom(zoom - 1); // decrease return true; @@ -133,7 +148,7 @@ bool BMPViewer::on_keyboard(const KeyboardEvent event) { } if (event == '-') { if (zoom == 1) // not 0, but -1 - set_zoom(-1); + set_zoom(-2); else set_zoom(zoom - 1); // decrease return true; diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index 3a6de2e8a..c19694248 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -227,7 +227,7 @@ bool BMPFile::seek(uint32_t x, uint32_t y) { curry = y; } else { file_pos = bmp_header.image_data; // nav to start pos. - file_pos += (get_real_height() - y) * byte_per_row; + file_pos += (get_real_height() - y - 1) * byte_per_row; file_pos += x * byte_per_px; bmpimage.seek(file_pos); currx = x; From 969717d2a9dc462088cdf678e90c2f185d1f110d Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 15:00:25 +0200 Subject: [PATCH 17/28] auto zoom --- firmware/application/ui/ui_bmpview.cpp | 45 ++++++++++++++++++++------ firmware/application/ui/ui_bmpview.hpp | 10 +++--- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index 279fda652..53dba06b7 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -4,18 +4,47 @@ bool BMPViewer::load_bmp(const std::filesystem::path& file) { if (!bmp.open(file, true)) return false; - // todo calc default zoom level to fit screen, and min / max zoom too - zoom_fit = 1; + // calc default zoom level to fit screen, and min / max zoom too + auto rect = screen_rect(); + auto d_height = rect.height(); + auto d_width = rect.width(); + auto b_width = bmp.get_width(); + auto b_height = bmp.get_real_height(); + // aspects + // if image is smaller then our vp + auto x_w = d_width / b_width; + auto x_h = d_height / b_height; + if (x_w < 1 && x_h < 1) { + // not zoom in, but zoom out + x_w = b_width / d_width; + x_h = b_height / d_height; + x_w = (127 < x_w) ? 127 : x_w; + x_h = (127 < x_h) ? 127 : x_h; + zoom_fit = (x_h > x_w) ? -1 * x_h : -1 * x_w; + } else { + UsbSerialAsyncmsg::asyncmsg("zoomin selected"); + x_w = (127 < x_w) ? 127 : x_w; + x_h = (127 < x_h) ? 127 : x_h; + zoom_fit = (x_h > x_w) ? x_h : x_w; + } + if (zoom_fit > max_zoom) zoom_fit = max_zoom; + min_zoom = zoom_fit - 3; + + UsbSerialAsyncmsg::asyncmsg("xw, xh:"); + UsbSerialAsyncmsg::asyncmsg(x_w); + UsbSerialAsyncmsg::asyncmsg(x_h); + UsbSerialAsyncmsg::asyncmsg("zf"); + UsbSerialAsyncmsg::asyncmsg(zoom_fit); + reset_pos(); - set_dirty(); return true; } void BMPViewer::set_zoom(int8_t new_zoom) { - if (new_zoom == 0) new_zoom = 1; - if (new_zoom == -1) new_zoom = 1; if (new_zoom > max_zoom) new_zoom = max_zoom; if (new_zoom < min_zoom) new_zoom = min_zoom; + if (new_zoom == 0) new_zoom = 1; + if (new_zoom == -1) new_zoom = 1; zoom = new_zoom; UsbSerialAsyncmsg::asyncmsg("New zoom: "); UsbSerialAsyncmsg::asyncmsg(zoom); @@ -52,10 +81,6 @@ void BMPViewer::paint(Painter& painter) { auto d_height = rect.height(); auto d_width = rect.width(); - // get the bmp's size - // auto b_width = bmp.get_width(); - // auto b_height = bmp.get_real_height(); - uint32_t by = cy; // we start to read from there uint32_t last_by = 65534; ui::Color* line = new ui::Color[d_width]; @@ -97,7 +122,7 @@ void BMPViewer::reset_pos() { if (!bmp.is_loaded()) return; cx = 0; cy = 0; - zoom = zoom_fit; + set_zoom(zoom_fit); set_dirty(); } diff --git a/firmware/application/ui/ui_bmpview.hpp b/firmware/application/ui/ui_bmpview.hpp index 5a80bfb8c..4fe7e5227 100644 --- a/firmware/application/ui/ui_bmpview.hpp +++ b/firmware/application/ui/ui_bmpview.hpp @@ -50,11 +50,11 @@ class BMPViewer : public Widget { private: void get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt); BMPFile bmp{}; - int8_t zoom = 1; // positive = zoom in, negative = zoom out 0-invalid 1- no zoom - int8_t zoom_fit = 1; // if this value is set, the image will fit the screen the most - int8_t max_zoom = 20; // will be calculated on load - int8_t min_zoom = -20; - uint32_t cx = 0; // current top-left coordinate + int8_t zoom = 1; // positive = zoom in, negative = zoom out 0-invalid 1- no zoom + int8_t zoom_fit = 1; // if this value is set, the image will fit the screen the most + int8_t max_zoom = 10; + int8_t min_zoom = -20; // will be calculated on load + uint32_t cx = 0; // current top-left coordinate uint32_t cy = 0; }; From 1a2ca804275beaef3b2039f80bb09b531a695c7e Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 15:02:51 +0200 Subject: [PATCH 18/28] remove debug --- firmware/application/ui/ui_bmpview.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index 53dba06b7..8465137ba 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -22,7 +22,6 @@ bool BMPViewer::load_bmp(const std::filesystem::path& file) { x_h = (127 < x_h) ? 127 : x_h; zoom_fit = (x_h > x_w) ? -1 * x_h : -1 * x_w; } else { - UsbSerialAsyncmsg::asyncmsg("zoomin selected"); x_w = (127 < x_w) ? 127 : x_w; x_h = (127 < x_h) ? 127 : x_h; zoom_fit = (x_h > x_w) ? x_h : x_w; @@ -30,12 +29,6 @@ bool BMPViewer::load_bmp(const std::filesystem::path& file) { if (zoom_fit > max_zoom) zoom_fit = max_zoom; min_zoom = zoom_fit - 3; - UsbSerialAsyncmsg::asyncmsg("xw, xh:"); - UsbSerialAsyncmsg::asyncmsg(x_w); - UsbSerialAsyncmsg::asyncmsg(x_h); - UsbSerialAsyncmsg::asyncmsg("zf"); - UsbSerialAsyncmsg::asyncmsg(zoom_fit); - reset_pos(); return true; } @@ -46,8 +39,6 @@ void BMPViewer::set_zoom(int8_t new_zoom) { if (new_zoom == 0) new_zoom = 1; if (new_zoom == -1) new_zoom = 1; zoom = new_zoom; - UsbSerialAsyncmsg::asyncmsg("New zoom: "); - UsbSerialAsyncmsg::asyncmsg(zoom); set_dirty(); } @@ -71,7 +62,6 @@ void BMPViewer::get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt } void BMPViewer::paint(Painter& painter) { - UsbSerialAsyncmsg::asyncmsg("paint enter"); if (!bmp.is_loaded()) { painter.draw_string({48, 24}, ui::Styles::white, "Can't load BMP"); return; @@ -91,7 +81,6 @@ void BMPViewer::paint(Painter& painter) { portapack::display.draw_pixels({rect.left(), rect.top() + y, d_width, 1}, line, d_width); } delete line; - UsbSerialAsyncmsg::asyncmsg("paint end"); } int8_t BMPViewer::get_zoom() { @@ -110,7 +99,6 @@ BMPViewer::BMPViewer(Rect parent_rect, const std::filesystem::path& file) } void BMPViewer::on_focus() { - UsbSerialAsyncmsg::asyncmsg("on focus"); set_highlighted(true); } @@ -151,7 +139,6 @@ bool BMPViewer::on_key(const KeyEvent key) { } bool BMPViewer::on_encoder(EncoderEvent delta) { - UsbSerialAsyncmsg::asyncmsg("encoder"); if (delta > 0) { set_zoom(zoom + 1); // 0 handled in set_zoom return true; From c163f66fa735b940b80b635264ebcee795dabe84 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 20:53:51 +0200 Subject: [PATCH 19/28] move in screen --- firmware/application/ui/ui_bmpview.cpp | 59 +++++++++++++++++--- firmware/application/ui/ui_bmpview.hpp | 3 + firmware/application/usb_serial_asyncmsg.hpp | 8 +++ 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index 8465137ba..aca9f04f1 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -33,12 +33,56 @@ bool BMPViewer::load_bmp(const std::filesystem::path& file) { return true; } +bool BMPViewer::move_pos(int32_t delta_x, int32_t delta_y) { + if (!bmp.is_loaded()) return false; + + auto rect = screen_rect(); + auto d_height = rect.height(); + auto d_width = rect.width(); + auto ocx = cx; // save old pos + auto ocy = cy; + // top left protection + if (delta_x < 0 && cx <= (uint32_t)(-1 * delta_x)) + cx = 0; + else + cx += delta_x; + + if (delta_y < 0 && cy <= (uint32_t)(-1 * delta_y)) + cy = 0; + else + cy += delta_y; + // right bottom protection + float zt = zoom < 0 ? -1.0f / (float)zoom : (float)zoom; + if (zt == 0) zt = 1; + if (cy + (uint32_t)(d_height / zt) > bmp.get_real_height()) { + cy = (bmp.get_real_height() < (uint32_t)(d_height / zt)) ? 0 : bmp.get_real_height() - (uint32_t)(d_height / zt); + } + if (cx + (uint32_t)(d_width / zt) > bmp.get_width()) { + cx = (bmp.get_width() < (uint32_t)(d_width / zt)) ? 0 : bmp.get_width() - (uint32_t)(d_width / zt); + } + bool ret = !(cx == ocx && ocy == cy); // was any change? + if (ret) set_dirty(); + return ret; +} + void BMPViewer::set_zoom(int8_t new_zoom) { + if (!bmp.is_loaded()) return; if (new_zoom > max_zoom) new_zoom = max_zoom; if (new_zoom < min_zoom) new_zoom = min_zoom; if (new_zoom == 0) new_zoom = 1; if (new_zoom == -1) new_zoom = 1; zoom = new_zoom; + auto rect = screen_rect(); + auto d_height = rect.height(); + auto d_width = rect.width(); + if (zoom < 0) { + mvx = d_width / 3 / (-1.0 * zoom); + mvy = d_height / 3 / (-1.0 * zoom); + } else { + mvx = d_width / zoom / 3; + mvy = d_height / zoom / 3; + } + move_pos(0, 0); // fix based on zoom, without real move (if not edge case) set_dirty(); } @@ -115,21 +159,18 @@ void BMPViewer::reset_pos() { } bool BMPViewer::on_key(const KeyEvent key) { + if (!bmp.is_loaded()) return false; if (key == KeyEvent::Up) { - if (cy <= 0) return false; - // todo move up + return move_pos(0, -1 * mvy); } if (key == KeyEvent::Down) { - if (cy >= 100) return false; // todo limit - // todo move down + return move_pos(0, mvy); } if (key == KeyEvent::Left) { - if (cx <= 0) return false; - // todo move left + return move_pos(-1 * mvx, 0); } if (key == KeyEvent::Right) { - if (cx >= 100) return false; // todo limit - // todo move right + return move_pos(mvx, 0); } if (key == KeyEvent::Select) { reset_pos(); // todo maybe exit app?! @@ -139,6 +180,7 @@ bool BMPViewer::on_key(const KeyEvent key) { } bool BMPViewer::on_encoder(EncoderEvent delta) { + if (!bmp.is_loaded()) return false; if (delta > 0) { set_zoom(zoom + 1); // 0 handled in set_zoom return true; @@ -154,6 +196,7 @@ bool BMPViewer::on_encoder(EncoderEvent delta) { } bool BMPViewer::on_keyboard(const KeyboardEvent event) { + if (!bmp.is_loaded()) return false; if (event == '+') { set_zoom(zoom + 1); return true; diff --git a/firmware/application/ui/ui_bmpview.hpp b/firmware/application/ui/ui_bmpview.hpp index 4fe7e5227..6ef4f5abc 100644 --- a/firmware/application/ui/ui_bmpview.hpp +++ b/firmware/application/ui/ui_bmpview.hpp @@ -49,6 +49,7 @@ class BMPViewer : public Widget { private: void get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt); + bool move_pos(int32_t delta_x, int32_t delta_y); BMPFile bmp{}; int8_t zoom = 1; // positive = zoom in, negative = zoom out 0-invalid 1- no zoom int8_t zoom_fit = 1; // if this value is set, the image will fit the screen the most @@ -56,6 +57,8 @@ class BMPViewer : public Widget { int8_t min_zoom = -20; // will be calculated on load uint32_t cx = 0; // current top-left coordinate uint32_t cy = 0; + uint32_t mvx = 1; // how much to move on key + uint32_t mvy = 1; }; #endif \ No newline at end of file diff --git a/firmware/application/usb_serial_asyncmsg.hpp b/firmware/application/usb_serial_asyncmsg.hpp index 17b22f84a..14330fe0b 100644 --- a/firmware/application/usb_serial_asyncmsg.hpp +++ b/firmware/application/usb_serial_asyncmsg.hpp @@ -120,6 +120,14 @@ void UsbSerialAsyncmsg::asyncmsg(const uint64_t& data) { chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_dec_int(data).c_str()); } +template <> +void UsbSerialAsyncmsg::asyncmsg(const float& data) { + if (!portapack::async_tx_enabled) { + return; + } + chprintf((BaseSequentialStream*)&SUSBD1, "%s\r\n", to_string_decimal(data, 7).c_str()); +} + /// fs things template <> From ad0534471b7138ecf54fc7ed8a0cc96233008aea Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 21:42:13 +0200 Subject: [PATCH 20/28] fix math --- firmware/application/ui/ui_bmpview.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index aca9f04f1..c7f5740cc 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -76,8 +76,8 @@ void BMPViewer::set_zoom(int8_t new_zoom) { auto d_height = rect.height(); auto d_width = rect.width(); if (zoom < 0) { - mvx = d_width / 3 / (-1.0 * zoom); - mvy = d_height / 3 / (-1.0 * zoom); + mvx = d_width / 3 * (-1.0 * zoom); + mvy = d_height / 3 * (-1.0 * zoom); } else { mvx = d_width / zoom / 3; mvy = d_height / zoom / 3; @@ -182,14 +182,14 @@ bool BMPViewer::on_key(const KeyEvent key) { bool BMPViewer::on_encoder(EncoderEvent delta) { if (!bmp.is_loaded()) return false; if (delta > 0) { - set_zoom(zoom + 1); // 0 handled in set_zoom + set_zoom(zoom + delta); // 0 handled in set_zoom return true; } if (delta < 0) { if (zoom == 1) // not 0, but -1 set_zoom(-2); else - set_zoom(zoom - 1); // decrease + set_zoom(zoom + delta); // decrease return true; } return false; From 844fd11f75b6050bc0556fbbea25316dbafb3157 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 21:46:33 +0200 Subject: [PATCH 21/28] remove test code --- .../application/external/extsensors/ui_extsensors.cpp | 10 +++------- .../application/external/extsensors/ui_extsensors.hpp | 3 --- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp index 6b7db3680..f430da351 100644 --- a/firmware/application/external/extsensors/ui_extsensors.cpp +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -29,21 +29,17 @@ using namespace ui; namespace ui::external_app::extsensors { void ExtSensorsView::focus() { - bmpv.focus(); + text_info.focus(); } ExtSensorsView::ExtSensorsView(NavigationView& nav) : nav_{nav} { - /*add_children({&labels, + add_children({&labels, &text_info, &text_gps, &text_orientation, &text_envl1, - &text_envl2, &bmpv});*/ - add_children({//&text_envl1, - //&text_envl2, - &bmpv}); - bmpv.load_bmp("/SCREENSHOTS/splash.bmp"); + &text_envl2, &bmpv}); } ExtSensorsView::~ExtSensorsView() { diff --git a/firmware/application/external/extsensors/ui_extsensors.hpp b/firmware/application/external/extsensors/ui_extsensors.hpp index 3c98529d4..e068ff6d2 100644 --- a/firmware/application/external/extsensors/ui_extsensors.hpp +++ b/firmware/application/external/extsensors/ui_extsensors.hpp @@ -33,7 +33,6 @@ #include "ui_record_view.hpp" #include "app_settings.hpp" #include "utility.hpp" -#include "ui_bmpview.hpp" using namespace ui; @@ -66,8 +65,6 @@ class ExtSensorsView : public View { Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"}; Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"}; - BMPViewer bmpv{{0, 100, 200, 100}}; - void on_any(); void on_gps(const GPSPosDataMessage* msg); From 505367df169806867822b4c3939502db2a54f36d Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 21:47:06 +0200 Subject: [PATCH 22/28] fix --- firmware/application/external/extsensors/ui_extsensors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp index f430da351..572effe65 100644 --- a/firmware/application/external/extsensors/ui_extsensors.cpp +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -39,7 +39,7 @@ ExtSensorsView::ExtSensorsView(NavigationView& nav) &text_gps, &text_orientation, &text_envl1, - &text_envl2, &bmpv}); + &text_envl2}); } ExtSensorsView::~ExtSensorsView() { From 7ce4a1f8f9b2ac2bdce22ee717f86db669ab7c78 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sun, 21 Apr 2024 21:53:52 +0200 Subject: [PATCH 23/28] fix compiler warning --- firmware/application/string_format.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/string_format.cpp b/firmware/application/string_format.cpp index 381cb75fa..764b7f7e9 100644 --- a/firmware/application/string_format.cpp +++ b/firmware/application/string_format.cpp @@ -188,7 +188,7 @@ std::string to_string_decimal_padding(float decimal, int8_t precision, const int result = to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, precision, '0'); // Add padding with spaces to meet the length requirement - if (result.length() < l) { + if (result.length() < (uint32_t)l) { int padding_length = l - result.length(); std::string padding(padding_length, ' '); result = padding + result; From 951e757de7e691c2c4cc4958a12db713a36cc14d Mon Sep 17 00:00:00 2001 From: HTotoo Date: Mon, 22 Apr 2024 08:56:24 +0200 Subject: [PATCH 24/28] BMP File viewer --- firmware/application/CMakeLists.txt | 1 + .../application/apps/ui_bmp_file_viewer.cpp | 57 +++++++++++++++++++ .../application/apps/ui_bmp_file_viewer.hpp | 50 ++++++++++++++++ firmware/application/apps/ui_fileman.cpp | 9 ++- firmware/application/ui/ui_bmpview.cpp | 15 ++++- firmware/application/ui/ui_bmpview.hpp | 4 ++ 6 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 firmware/application/apps/ui_bmp_file_viewer.cpp create mode 100644 firmware/application/apps/ui_bmp_file_viewer.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 44a077813..ebd5e670e 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -285,6 +285,7 @@ set(CPPSRC apps/ui_aprs_rx.cpp apps/ui_aprs_tx.cpp apps/ui_bht_tx.cpp + apps/ui_bmp_file_viewer.cpp apps/ui_btle_rx.cpp # apps/ui_coasterp.cpp apps/ui_debug.cpp diff --git a/firmware/application/apps/ui_bmp_file_viewer.cpp b/firmware/application/apps/ui_bmp_file_viewer.cpp new file mode 100644 index 000000000..00196f53d --- /dev/null +++ b/firmware/application/apps/ui_bmp_file_viewer.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 HTotoo + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui_bmp_file_viewer.hpp" + +using namespace portapack; +namespace fs = std::filesystem; + +namespace ui { + +BMPFileViewer::BMPFileViewer( + NavigationView& nav, + const std::filesystem::path& path) + : nav_{nav}, + path_{path} { + add_children( + {&bmp}); + bmp.set_enter_pass(true); // pass the enter key to me, so i can exit. this will disable zoom + pos reset + set_focusable(true); + // todo hide statusbar +} + +void BMPFileViewer::focus() { + bmp.focus(); +} + +bool BMPFileViewer::on_key(KeyEvent k) { + if (k == KeyEvent::Select) { + nav_.pop(); + return true; + } + return false; +} + +void BMPFileViewer::paint(Painter&) { + bmp.load_bmp(path_); +} + +} // namespace ui diff --git a/firmware/application/apps/ui_bmp_file_viewer.hpp b/firmware/application/apps/ui_bmp_file_viewer.hpp new file mode 100644 index 000000000..b24cb638a --- /dev/null +++ b/firmware/application/apps/ui_bmp_file_viewer.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 HTotoo + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UI_BMP_FILE_VIEWER_H__ +#define __UI_BMP_FILE_VIEWER_H__ + +#include "ui.hpp" +#include "ui_navigation.hpp" +#include "ui_painter.hpp" +#include "ui_styles.hpp" +#include "ui_widget.hpp" +#include "file.hpp" +#include "ui_bmpview.hpp" + +namespace ui { + +class BMPFileViewer : public View { + public: + BMPFileViewer(NavigationView& nav, const std::filesystem::path& path); + bool on_key(KeyEvent key) override; + void paint(Painter& painter) override; + void focus() override; + + private: + NavigationView& nav_; + std::filesystem::path path_{}; + BMPViewer bmp{{0, 0, 240, 320}}; +}; + +} // namespace ui + +#endif // __UI_BMP_FILE_VIEWER_H__ diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index 2ad716ad5..a03a614cf 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -29,11 +29,13 @@ #include "ui_playlist.hpp" #include "ui_remote.hpp" #include "ui_ss_viewer.hpp" +#include "ui_bmp_file_viewer.hpp" #include "ui_text_editor.hpp" #include "ui_iq_trim.hpp" #include "string_format.hpp" #include "portapack.hpp" #include "event_m0.hpp" +#include "file_path.hpp" using namespace portapack; namespace fs = std::filesystem; @@ -694,7 +696,12 @@ bool FileManagerView::handle_file_open() { nav_.push(path); return true; } else if (path_iequal(bmp_ext, ext)) { - nav_.push(path); + if (path_iequal(current_path, u"/" + splash_dir)) { + nav_.push(path); // splash, so load that viewer + } else { + nav_.push(path); // any other bmp + } + reload_current(false); return true; } else if (path_iequal(rem_ext, ext)) { diff --git a/firmware/application/ui/ui_bmpview.cpp b/firmware/application/ui/ui_bmpview.cpp index c7f5740cc..1d1fdd7c0 100644 --- a/firmware/application/ui/ui_bmpview.cpp +++ b/firmware/application/ui/ui_bmpview.cpp @@ -173,8 +173,10 @@ bool BMPViewer::on_key(const KeyEvent key) { return move_pos(mvx, 0); } if (key == KeyEvent::Select) { - reset_pos(); // todo maybe exit app?! - return true; + if (!enter_pass) { + reset_pos(); + return true; + } } return false; } @@ -195,6 +197,15 @@ bool BMPViewer::on_encoder(EncoderEvent delta) { return false; } +// sets if the enter key should be passed to parent or handled. true = pass it, false = handle as reset pos+zoom +void BMPViewer::set_enter_pass(bool pass) { + enter_pass = pass; +} + +bool BMPViewer::get_enter_pass() { + return enter_pass; +} + bool BMPViewer::on_keyboard(const KeyboardEvent event) { if (!bmp.is_loaded()) return false; if (event == '+') { diff --git a/firmware/application/ui/ui_bmpview.hpp b/firmware/application/ui/ui_bmpview.hpp index 6ef4f5abc..ec4a349d5 100644 --- a/firmware/application/ui/ui_bmpview.hpp +++ b/firmware/application/ui/ui_bmpview.hpp @@ -47,6 +47,9 @@ class BMPViewer : public Widget { void set_zoom(int8_t new_zoom); int8_t get_zoom(); + void set_enter_pass(bool pass); + bool get_enter_pass(); + private: void get_line(ui::Color* line, uint32_t bx, uint32_t by, uint32_t cnt); bool move_pos(int32_t delta_x, int32_t delta_y); @@ -59,6 +62,7 @@ class BMPViewer : public Widget { uint32_t cy = 0; uint32_t mvx = 1; // how much to move on key uint32_t mvy = 1; + bool enter_pass = false; }; #endif \ No newline at end of file From 50104ab59d832846b0a8bec54c8be5628d90e166 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Mon, 22 Apr 2024 09:14:25 +0200 Subject: [PATCH 25/28] Full screen --- firmware/application/apps/ui_bmp_file_viewer.cpp | 8 +++++++- firmware/application/apps/ui_bmp_file_viewer.hpp | 1 + firmware/application/ui_navigation.cpp | 9 +++++++++ firmware/application/ui_navigation.hpp | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/firmware/application/apps/ui_bmp_file_viewer.cpp b/firmware/application/apps/ui_bmp_file_viewer.cpp index 00196f53d..2f20c8198 100644 --- a/firmware/application/apps/ui_bmp_file_viewer.cpp +++ b/firmware/application/apps/ui_bmp_file_viewer.cpp @@ -21,6 +21,8 @@ #include "ui_bmp_file_viewer.hpp" +extern ui::SystemView* system_view_ptr; + using namespace portapack; namespace fs = std::filesystem; @@ -35,7 +37,11 @@ BMPFileViewer::BMPFileViewer( {&bmp}); bmp.set_enter_pass(true); // pass the enter key to me, so i can exit. this will disable zoom + pos reset set_focusable(true); - // todo hide statusbar + system_view_ptr->set_app_fullscreen(true); +} + +BMPFileViewer::~BMPFileViewer() { + system_view_ptr->set_app_fullscreen(false); } void BMPFileViewer::focus() { diff --git a/firmware/application/apps/ui_bmp_file_viewer.hpp b/firmware/application/apps/ui_bmp_file_viewer.hpp index b24cb638a..5f9914702 100644 --- a/firmware/application/apps/ui_bmp_file_viewer.hpp +++ b/firmware/application/apps/ui_bmp_file_viewer.hpp @@ -35,6 +35,7 @@ namespace ui { class BMPFileViewer : public View { public: BMPFileViewer(NavigationView& nav, const std::filesystem::path& path); + ~BMPFileViewer(); bool on_key(KeyEvent key) override; void paint(Painter& painter) override; void focus() override; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 2f36d98de..2773e5002 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -945,6 +945,15 @@ void SystemView::paint_overlay() { } } +void SystemView::set_app_fullscreen(bool fullscreen) { + auto parent_rect = screen_rect(); + Dim status_view_height = (fullscreen) ? 0 : 16; + status_view.hidden(fullscreen); + navigation_view.set_parent_rect( + {{0, status_view_height}, + {parent_rect.width(), static_cast(parent_rect.height() - status_view_height)}}); +} + /* ***********************************************************************/ void BMPView::focus() { diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 801e2a35f..0340da11a 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -377,6 +377,7 @@ class SystemView : public View { Context& context() const override; void toggle_overlay(); void paint_overlay(); + void set_app_fullscreen(bool fullscreen); NavigationView* get_navigation_view(); SystemStatusView* get_status_view(); From 01c99d447eae1b96e12faef5391e5fd0584e2aaf Mon Sep 17 00:00:00 2001 From: HTotoo Date: Mon, 22 Apr 2024 10:34:30 +0200 Subject: [PATCH 26/28] bg instead of noice --- firmware/common/bmpfile.cpp | 16 ++++++++++++++++ firmware/common/bmpfile.hpp | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index c19694248..edf31fa98 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -178,6 +178,14 @@ bool BMPFile::read_next_px(ui::Color& px, bool seek = true) { return true; } +void BMPFile::set_bg_color(ui::Color background) { + bg = background; + use_bg = true; +} +void BMPFile::delete_db_color() { + use_bg = false; +} + // writes a color data to the current position, and advances 1 px. true on success, false on error bool BMPFile::write_next_px(ui::Color& px) { if (!is_opened) return false; @@ -254,6 +262,14 @@ bool BMPFile::expand_y(uint32_t new_y) { bmpimage.seek(0); bmpimage.write(&bmp_header, sizeof(bmp_header)); // overwrite header bmpimage.seek(bmp_header.size); // seek to new end to expand + // fill with bg color if needed + if (use_bg) { + seek(0, old_height); // to the new begin + size_t newpxcount = ((new_y - old_height) * bmp_header.width); + for (size_t i = 0; i < newpxcount; ++i) + write_next_px(bg); + } + if (is_bottomup()) { seek(0, new_y - old_height); // seek to the new chunk begin } else { diff --git a/firmware/common/bmpfile.hpp b/firmware/common/bmpfile.hpp index 821af9eac..efaf13818 100644 --- a/firmware/common/bmpfile.hpp +++ b/firmware/common/bmpfile.hpp @@ -46,6 +46,8 @@ class BMPFile { uint32_t get_real_height(); uint32_t get_width(); bool is_bottomup(); + void set_bg_color(ui::Color background); + void delete_db_color(); private: bool advance_curr_px(uint32_t num); @@ -61,6 +63,8 @@ class BMPFile { uint32_t currx = 0; uint32_t curry = 0; + ui::Color bg{}; + bool use_bg = false; }; #endif \ No newline at end of file From 813c8f5bf10847523067e31bcbb2a4f07c55c476 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Mon, 22 Apr 2024 10:37:24 +0200 Subject: [PATCH 27/28] add comment --- firmware/common/bmpfile.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index edf31fa98..23cfd159c 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -178,10 +178,13 @@ bool BMPFile::read_next_px(ui::Color& px, bool seek = true) { return true; } +// if you set this, then the expanded part (or the newly created) will be filled with this color. but the expansion or the creation will be slower. void BMPFile::set_bg_color(ui::Color background) { bg = background; use_bg = true; } + +// delete bg color. default. creation or expansion will be fast, but the file will contain random garbage. no problem if you write all pixels later. void BMPFile::delete_db_color() { use_bg = false; } From e91d7137f88b5d400109486a751cfc41c888de31 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Mon, 22 Apr 2024 11:06:02 +0200 Subject: [PATCH 28/28] Handle some not supported formats. --- firmware/common/bmpfile.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/common/bmpfile.cpp b/firmware/common/bmpfile.cpp index 23cfd159c..46e74340e 100644 --- a/firmware/common/bmpfile.cpp +++ b/firmware/common/bmpfile.cpp @@ -124,10 +124,13 @@ bool BMPFile::open(const std::filesystem::path& file, bool readonly) { byte_per_px = 3; break; case 32: - default: type = 2; byte_per_px = 4; break; + default: + // not supported + return false; + break; } byte_per_row = (bmp_header.width * byte_per_px % 4 == 0) ? bmp_header.width * byte_per_px : (bmp_header.width * byte_per_px + (4 - ((bmp_header.width * byte_per_px) % 4))); file_pos = bmp_header.image_data;