Compare commits

..

23 Commits

Author SHA1 Message Date
Erwin Ried 9a14d04c91 Update README.md
Mistake
2024-11-27 10:08:38 +01:00
Erwin Ried e17aef3724 New techminds video :) 2024-11-27 10:08:14 +01:00
gullradriel 4155216a7f added ppfw to sdcard/FIRMWARE (#2395)
Co-authored-by: gullradriel <gullradriel@no-mail.com>
2024-11-27 06:57:05 +13:00
E.T. d9bc542b06 Upgrade build container (#2394)
* Upgrade build container os version

* Also updare the arm build container
2024-11-25 21:19:43 +13:00
gullradriel 3dcfa4f8c1 use full_reset_and_init return value in init and reset_learned (#2393)
* use full_reset_and_init return value in init and reset_learned

* do not uncomment status clear

---------

Co-authored-by: gullradriel <gullradriel@no-mail.com>
2024-11-25 21:01:16 +13:00
gullradriel d36ae88284 Changed portapack-h1_h2-mayhem to portapack-mayhem-firmware (#2390)
Co-authored-by: gullradriel <gullradriel@no-mail.com>
2024-11-24 23:24:14 +08:00
E.T. 69271632ae Restore home menu order (#2384)
* Fix ext notice position ( No need to alter the position of the ext app notice, as there is no back button on the home screen )
* add desired position to external apps
* read and store desired location
* apply ext apps desired order
* fix memory alignment in application_information_t
2024-11-23 21:37:03 +01:00
gullradriel e6a099913a Update about file from generated one (#2382)
* added launch permission
* updated about file with script
2024-11-23 00:41:20 +08:00
Benjamin Møller 280b8afc0a Add changes from "fixed memory usage #2380" to about_simple file generator. (#2381)
* Generator for updating the about-page in PP from github.
* Rename generate_ui-about-simple.ccp.py to generate_ui-about-simple.cpp.py
* Adapt changes from "fixed memory usage #2380" to the file generator.
2024-11-22 17:12:17 +01:00
Bernd Herzog b108d975c0 fixed memory usage (#2380)
* fixed memory usage in ui_about_simple
* fixed memory usage in freqman_db
* fixed memory usage in tone_key
2024-11-22 09:54:34 +01:00
gullradriel fc08d4ead9 renaming Ook to OOK (#2379) 2024-11-21 21:24:40 +01:00
Totoo 07cae4a298 Remove warn text too from batt (#2377) 2024-11-20 15:02:02 +01:00
sommermorgentraum e88e0b5f8f splash fix and draw bmp fuc logic wrong (#2376)
* revert

* rename drawBMP to draw_bmp_from_bmp_hex_arr

* rename drawBMP2

* add comments

* rename BMPView class in child of nav into SplashView

* rename SplashView class in child of nav into SplashScreeView

* fix draw from wrong line

* comment

* comment

* comment
2024-11-20 17:35:40 +08:00
Totoo 131523d726 Csv from subghzd (#2375) 2024-11-20 09:22:55 +01:00
gullradriel 24d15c1643 Externalize Remote (#2370)
* externalize Remote app, disabling fileman integration (need workaround)

* regenerate bitmap.hpp

* added external HOME apps to HOME
2024-11-19 21:02:29 +01:00
Totoo 4a83118557 Weather csv log (#2369) 2024-11-19 17:39:30 +01:00
gullradriel ff54f59d38 Ook Editor adjustements (#2366)
* adding ook_file.cpp

* aligned GUI, change low_bit to pause, start to use ook_file API

* bit duration, pause, fields step, indent

* working OOK file loading

* revamped GUI with the decided names and units

* read, start tx, stop tx in ook_file API

* cleanings, using ook_file_data and API to load, save, send, stop tx

* renamed text widget

* moved set target frequency to start_ook_file_tx function

* comments, took out a function to put it in API

* removed non working Tesla OOK files

* changed space to tab

* set author information

* Renamed to OOKEditor
2024-11-19 17:16:37 +01:00
Erwin Ried 6b8274d792 Update README.md
Direct link to opensourcesdrlabs device
2024-11-19 15:49:38 +01:00
Totoo 1fc84e7eac Hide cycles until 0 error resolved (#2367) 2024-11-19 11:23:33 +01:00
gullradriel d31857c21e Ook remote adjustements (#2365)
* moved to ook_remote dir

* moved to new filenames / dir

* adjusted build files to new dir/filenames

* changed name of var / dirname

* deleted wrongly included swap files

* Added 'Set' 'Open File'

* Use language API, make it so TX can be started and also stopped

* added send, recv

* fixed the name which was too long

* renamed some fields, moved the ui, added some text informations, renames some variables

* changed to FrequencyField, allow on change, on edit, commented out button_save for a next pass

* added OOK files examples

* added button_save feature
2024-11-18 14:51:49 +01:00
Erwin Ried 52b2cb241a Grabifyed link to opensdrlabs h4m 2024-11-18 09:55:48 +01:00
Samir Sánchez Garnica 64f8158134 External App ROOK(Remote On-Off Keying) (#2363) 2024-11-17 21:23:56 +01:00
Totoo 59f72cbff1 Flipper sub (raw+binraw AND ONLY OOK) TX (#2361) 2024-11-16 18:03:53 +01:00
92 changed files with 2869 additions and 857 deletions
+3 -3
View File
@@ -54,7 +54,7 @@ jobs:
run: docker run -e VERSION_STRING=${{ steps.version_date.outputs.date }} -i -v ${{ github.workspace }}:/havoc portapack-dev
- name: Create Small SD Card ZIP - No World Map
run: |
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-mayhem-firmware.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && cp build/firmware/portapack-mayhem_OCI.ppfw.tar sdcard/FIRMWARE/mayhem_nightly_${{ steps.version_date.outputs.date }}_OCI.ppfw.tar && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
- name: Download world map
run: |
wget https://github.com/portapack-mayhem/mayhem-firmware/releases/download/world_map/world_map.zip
@@ -63,10 +63,10 @@ jobs:
unzip world_map.zip -d sdcard/ADSB
- name: Create Firmware ZIP
run: |
zip -j firmware.zip build/firmware/portapack-h1_h2-mayhem.bin && cd flashing && zip -r ../firmware.zip *
zip -j firmware.zip build/firmware/portapack-mayhem-firmware.bin && cd flashing && zip -r ../firmware.zip *
- name: Create SD Card ZIP
run: |
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-mayhem-firmware.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && cp build/firmware/portapack-mayhem_OCI.ppfw.tar sdcard/FIRMWARE/mayhem_nightly_${{ steps.version_date.outputs.date }}_OCI.ppfw.tar && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
- name: Create changelog
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+3 -3
View File
@@ -38,7 +38,7 @@ jobs:
run: docker run -e VERSION_STRING=${{ steps.version.outputs.version }} -i -v ${{ github.workspace }}:/havoc portapack-dev
- name: Create Small SD Card ZIP - No World Map
run: |
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-mayhem-firmware.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && cp build/firmware/portapack-mayhem_OCI.ppfw.tar sdcard/FIRMWARE/mayhem_${{ steps.version.outputs.version }}_OCI.ppfw.tar && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
- name: Download world map
run: |
wget https://github.com/portapack-mayhem/mayhem-firmware/releases/download/world_map/world_map.zip
@@ -47,10 +47,10 @@ jobs:
unzip world_map.zip -d sdcard/ADSB
- name: Create Firmware ZIP
run: |
zip -j firmware.zip build/firmware/portapack-h1_h2-mayhem.bin && cd flashing && zip -r ../firmware.zip *
zip -j firmware.zip build/firmware/portapack-mayhem-firmware.bin && cd flashing && zip -r ../firmware.zip *
- name: Create SD Card ZIP
run: |
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-mayhem-firmware.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && cp build/firmware/portapack-mayhem_OCI.ppfw.tar sdcard/FIRMWARE/mayhem_${{ steps.version.outputs.version }}_OCI.ppfw.tar && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
- name: Create changelog
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+4 -3
View File
@@ -17,9 +17,9 @@ This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmw
If you are new to *HackRF+PortaPack+Mayhem*, check these:
[<img alt="HackRF Portapack H4M - Getting Started Guide" src="https://img.youtube.com/vi/wzP0zWi85SI/maxresdefault.jpg" width="701">](https://grabify.link/F9MPOO)
[<img alt="The Latest HackRF & Portapak Combo - H4M The Flipper Zero Killer?" src="https://img.youtube.com/vi/Ew2qDgm2hf0/maxresdefault.jpg" width="701">](https://grabify.link/6HKX9A)
[<img alt="Its TOO Easy to Accidentally Do Illegal Stuff with This" src="https://img.youtube.com/vi/OPckpjBSAOw/maxresdefault.jpg" width="172">](https://grabify.link/X4D5TF) [<img alt="What is the HackRF One Portapack H2+?" src="https://img.youtube.com/vi/alrFbY5vxt4/maxresdefault.jpg" width="172">](https://grabify.link/9UZGEW) [<img alt="The new HackRF Portapack H4M" src="https://img.youtube.com/vi/onQRdCITmuk/maxresdefault.jpg" width="172">](https://grabify.link/0JUHZ6) [<img alt="HackRF 101 : Everything You Need to Know to Get Started!" src="https://img.youtube.com/vi/xGR_PMD9LeU/maxresdefault.jpg" width="172">](https://grabify.link/C0J6ZR)
[<img alt="Its TOO Easy to Accidentally Do Illegal Stuff with This" src="https://img.youtube.com/vi/OPckpjBSAOw/maxresdefault.jpg" width="172">](https://grabify.link/X4D5TF) [<img alt="HackRF Portapack H4M - Getting Started Guide" src="https://img.youtube.com/vi/wzP0zWi85SI/maxresdefault.jpg" width="172">](https://grabify.link/F9MPOO) [<img alt="The new HackRF Portapack H4M" src="https://img.youtube.com/vi/onQRdCITmuk/maxresdefault.jpg" width="172">](https://grabify.link/0JUHZ6) [<img alt="HackRF 101 : Everything You Need to Know to Get Started!" src="https://img.youtube.com/vi/xGR_PMD9LeU/maxresdefault.jpg" width="172">](https://grabify.link/C0J6ZR)
# Frequently Asked Questions
@@ -27,7 +27,8 @@ This repository expands upon the previous work by many people and aims to consta
## What to buy?
:heavy_check_mark: ![Static Badge](https://img.shields.io/badge/NEW-yellow) The fabulous [PortaPack H4M Mayhem](https://opensourcesdrlab.com/products/h4m-receiver-and-spectrum-analyzer), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://grabify.link/99SAMT). Join their giveaways on discord (check the badge on top).
<!---not direct to h4m but to opensourcesdrlab https://grabify.link/TUOLYI--->
:heavy_check_mark: ![Static Badge](https://img.shields.io/badge/NEW-yellow) The fabulous [PortaPack H4M Mayhem](https://grabify.link/0STXCA), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://grabify.link/99SAMT). Join their giveaways on discord (check the badge on top).
:heavy_check_mark: A recommended one is this [PortaPack H2](https://grabify.link/P9CO0J), that includes everything you need with the plastic case "inspired" on [this](https://github.com/portapack-mayhem/mayhem-firmware/wiki/3d-printed-enclosure).
+2 -11
View File
@@ -1,4 +1,4 @@
FROM ubuntu:xenial
FROM ubuntu:noble
# Set location to download ARM toolkit from.
# This will need to be changed over time or replaced with a static link to the latest release.
@@ -11,19 +11,10 @@ WORKDIR /havoc/firmware
# Fetch dependencies from APT
RUN apt-get update \
&& apt-get install -y git tar wget dfu-util cmake python3 ccache bzip2 liblz4-tool curl ninja-build \
&& apt-get install -y git tar wget dfu-util cmake python3 python3-pip python3-yaml ccache bzip2 liblz4-tool curl ninja-build \
&& apt-get -qy autoremove \
&& rm -rf /var/lib/apt/lists/*
#Install current pip from PyPa
RUN curl https://bootstrap.pypa.io/pip/3.4/get-pip.py -o get-pip.py && \
python3 get-pip.py
#Fetch additional dependencies from Python 3.x pip
RUN pip install pyyaml \
&& ln -s /usr/bin/python3 /usr/bin/python \
&& ln -s /usr/bin/pip3 /usr/bin/pip
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
+2 -11
View File
@@ -1,4 +1,4 @@
FROM ubuntu:xenial
FROM ubuntu:noble
# Set location to download ARM toolkit from.
# This will need to be changed over time or replaced with a static link to the latest release.
@@ -11,19 +11,10 @@ WORKDIR /havoc/firmware
# Fetch dependencies from APT
RUN apt-get update \
&& apt-get install -y git tar wget dfu-util cmake python3 ccache bzip2 liblz4-tool curl ninja-build \
&& apt-get install -y git tar wget dfu-util cmake python3 python3-pip python3-yaml ccache bzip2 liblz4-tool curl ninja-build \
&& apt-get -qy autoremove \
&& rm -rf /var/lib/apt/lists/*
#Install current pip from PyPa
RUN curl https://bootstrap.pypa.io/pip/3.4/get-pip.py -o get-pip.py && \
python3 get-pip.py
#Fetch additional dependencies from Python 3.x pip
RUN pip install pyyaml \
&& ln -s /usr/bin/python3 /usr/bin/python \
&& ln -s /usr/bin/pip3 /usr/bin/pip
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
+1 -1
View File
@@ -33,7 +33,7 @@ set(MAKE_SPI_IMAGE ${PROJECT_SOURCE_DIR}/tools/make_spi_image.py)
set(MAKE_IMAGE_CHUNK ${PROJECT_SOURCE_DIR}/tools/make_image_chunk.py)
set(LZ4 lz4)
set(FIRMWARE_NAME portapack-h1_h2-mayhem)
set(FIRMWARE_NAME portapack-mayhem-firmware)
set(FIRMWARE_FILENAME ${FIRMWARE_NAME}.bin)
set(PPFW_FILENAME "portapack-mayhem_OCI.ppfw.tar")
+1 -1
View File
@@ -244,6 +244,7 @@ set(CPPSRC
hw/si5351.cpp
hw/spi_pp.cpp
hw/touch_adc.cpp
ook_file.cpp
ui_baseband_stats_view.cpp
ui_navigation.cpp
ui_record_view.cpp
@@ -302,7 +303,6 @@ set(CPPSRC
apps/ui_rds.cpp
apps/ui_recon_settings.cpp
apps/ui_recon.cpp
apps/ui_remote.cpp
apps/ui_scanner.cpp
apps/ui_sd_over_usb.cpp
apps/ui_sd_wipe.cpp
+44 -42
View File
@@ -1,58 +1,60 @@
#include "ui_about_simple.hpp"
#include <string_view>
#define ROLL_SPEED_FRAME_PER_LINE 60
// cuz frame rate of pp screen is probably 60, scroll per sec
namespace ui {
// TODO: Generate this automatically from github
// Information: a line starting with a '#' will be yellow coloured
const std::string authors_list[] = {
constexpr std::string_view authors_list[] = {
"# * List of contributors * ",
" ",
"#Mayhem:",
"eried,euquiq,gregoryfenton",
"johnelder,jwetzell,nnemanjan00",
"N0vaPixel,klockee,gullradriel",
"jamesshao8,ITAxReal,rascafr",
"mcules,dqs105,strijar,fossum",
"zhang00963,RedFox-Fr,aldude999",
"East2West,ArjanOnwezen,jLynx",
"vXxOinvizioNxX,teixeluis,n0xa",
"Brumi-2021,texasyojimbo,zigad",
"heurist1,intoxsick,ckuethe",
"notpike,MichalLeonBorsuk",
"kallanreed,bernd-herzog,zxkmm",
"NotherNgineer,jimilinuxguy",
"iNetro,HTotoo,BehleZebub,dc2dc",
"arneluehrs,u-foka,Maescool",
"nnesetto,formtapez,F33RNI",
"rusty-labs,andrej-mk,taskinen",
"MatiasFernandez,TQMatvey,KimIV",
"RobertoD91,RndmNmbr,OpCode1300",
"alex10791,GitClo,GermanAizek",
"JimiHFord,jstockdale,aSmig",
"KillerTurtleSoftware,Lpd738",
"MattLodge,z3r0l1nk,joyel24",
"#Mayhem-Firmware:",
"jboone,eried,furrtek,",
"NotherNgineer,gullradriel,",
"jLynx,kallanreed,Brumi-2021,",
"htotoo,bernd-herzog,zxkmm,",
"ArjanOnwezen,euquiq,u-foka,",
"iNetro,heurist1,dqs105,",
"teixeluis,jwetzell,",
"jimilinuxguy,gregoryfenton,",
"notpike,strijar,BehleZebub,",
"arneluehrs,rascafr,joyel24,",
"ImDroided,zigad,johnelder,",
"klockee,nnesetto,LupusE,",
"argilo,dc2dc,formtapez,",
"RocketGod-git,mrmookie,",
"ITAxReal,F33RNI,F4GEV,",
"rusty-labs,mjwaxios,andrej-mk,",
"RedFox-Fr,nemanjan00,",
"MichalLeonBorsuk,",
"MatiasFernandez,Giorgiofox,",
"ckuethe",
" ",
"#Havoc:",
"furrtek,mrmookie,NotPike",
"mjwaxios,ImDroided,Giorgiofox",
"F4GEV,z4ziggy,xmycroftx",
"troussos,silascutler",
"nickbouwhuis,msoose,leres",
"joakar,dhoetger,clem-42",
"brianlechthaler,ZeroChaos-...",
"jboone,furrtek,eried,argilo,",
"mrmookie,Giorgiofox,ImDroided,",
"mjwaxios,F4GEV,OpCode1300,",
"ZeroChaos-,RndmNmbr,",
"silascutler,troussos,z4ziggy,",
"clem-42,dhoetger,NickBouwhuis,",
"xmycroftx,Maescool,KimIV,",
"joakar,leres,brianlechthaler,",
"N0vaPixel",
" ",
"#PortaPack:",
"jboone,argilo",
"jboone,mossmann,martinling,",
"argilo,eried,ZeroChaos-,",
"RndmNmbr",
" ",
"#HackRF:",
"mossmann,dominicgs,bvernoux",
"bgamari,schneider42,miek",
"willcode,hessu,Sec42",
"yhetti,ckuethe,smunaut",
"wishi,mrbubble62,scateu..."};
"mossmann,jboone,dominicgs,",
"martinling,bvernoux,miek,",
"bgamari,schneider42,straithe,",
"grvvy,willcode,hessu,yhetti,",
"Sec42,ckuethe",
" "};
AboutView::AboutView(NavigationView& nav) {
add_children({&menu_view,
@@ -70,18 +72,18 @@ AboutView::AboutView(NavigationView& nav) {
button_ok.focus();
};
for (const std::string& authors_line : authors_list) {
for (auto& authors_line : authors_list) {
// if it's starting with #, it's a title and we have to substract the '#' and paint yellow
if (authors_line.size() > 0) {
if (authors_line[0] == '#') {
menu_view.add_item(
{authors_line.substr(1, authors_line.size() - 1),
{(std::string)authors_line.substr(1, authors_line.size() - 1),
ui::Theme::getInstance()->fg_yellow->foreground,
nullptr,
nullptr});
} else {
menu_view.add_item(
{authors_line,
{(std::string)authors_line,
Theme::getInstance()->bg_darkest->foreground,
nullptr,
nullptr});
+13 -13
View File
@@ -50,10 +50,10 @@ void BattinfoView::update_result() {
text_voltage.set("UNKNOWN");
text_current.set("-");
text_charge.set("-");
text_cycles.set("-");
// text_cycles.set("-");
text_ttef.set("-");
text_method.set("-");
text_warn.set("");
// text_warn.set("");
return;
}
bool uichg = false;
@@ -96,22 +96,22 @@ void BattinfoView::update_result() {
labels_opt.hidden(true);
text_current.hidden(true);
text_charge.hidden(true);
text_cycles.hidden(true);
// text_cycles.hidden(true);
text_ttef.hidden(true);
text_warn.set("");
// text_warn.set("");
}
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
text_cycles.hidden(false);
uint16_t cycles = battery::BatteryManagement::get_cycles();
/* if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
// text_cycles.hidden(false);
uint16_t cycles = 0; // battery::BatteryManagement::get_cycles();
if (cycles < 2)
text_warn.set("SoC improves after 2 cycles");
text_warn.set("SoC improves after each cycles");
else
text_warn.set("");
text_cycles.set(to_string_dec_uint(cycles));
// text_cycles.set(to_string_dec_uint(cycles));
} else {
text_cycles.hidden(true);
// text_cycles.hidden(true);
text_warn.set("");
}
} */
if ((valid_mask & battery::BatteryManagement::BATT_VALID_TTEF) == battery::BatteryManagement::BATT_VALID_TTEF) {
text_ttef.hidden(false);
float ttef = 0;
@@ -160,8 +160,8 @@ BattinfoView::BattinfoView(NavigationView& nav)
&text_method,
&button_mode,
&button_exit,
&text_cycles,
&text_warn,
// &text_cycles,
// &text_warn,
&text_ttef});
button_exit.on_select = [this, &nav](Button&) {
+4 -4
View File
@@ -63,7 +63,7 @@ class BattinfoView : public View {
{{2 * 8, 4 * 16}, "Current:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 5 * 16}, "Charge:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 6 * 16}, "TTF/E:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 7 * 16}, "Cycles:", Theme::getInstance()->fg_light->foreground},
// {{2 * 8, 7 * 16}, "Cycles:", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 10 * 16}, "Change method:", Theme::getInstance()->fg_light->foreground},
};
@@ -85,13 +85,13 @@ class BattinfoView : public View {
Text text_ttef{
{13 * 8, 6 * 16, 10 * 16, 16},
"-"};
Text text_cycles{
/* Text text_cycles{
{13 * 8, 7 * 16, 10 * 16, 16},
"-"};
Text text_warn{
{2 * 8, 8 * 16, 30 * 8, 2 * 16},
""};
{1 * 8, 8 * 16, 30 * 8, 2 * 16},
""}; */
Button button_mode{
{2 * 8, 11 * 16 + 5, 5 * 16, 32},
+3 -3
View File
@@ -27,7 +27,6 @@
#include <algorithm>
#include "ui_fileman.hpp"
#include "ui_playlist.hpp"
#include "ui_remote.hpp"
#include "ui_ss_viewer.hpp"
#include "ui_bmp_file_viewer.hpp"
#include "ui_text_editor.hpp"
@@ -704,10 +703,11 @@ bool FileManagerView::handle_file_open() {
reload_current(false);
return true;
} else if (path_iequal(rem_ext, ext)) {
}
/*else if (path_iequal(rem_ext, ext)) {
nav_.push<RemoteView>(path);
return true;
}
}*/
return false;
}
+22 -10
View File
@@ -40,27 +40,39 @@ namespace fs = std::filesystem;
// TODO: Clean up after moving to better lookup tables.
using options_t = OptionsField::options_t;
extern options_t freqman_modulations;
extern options_t freqman_bandwidths[4];
extern options_t freqman_steps;
extern options_t freqman_steps_short;
using option_db_t = std::pair<std::string_view, int32_t>;
using options_db_t = std::vector<option_db_t>;
extern options_db_t freqman_modulations;
extern options_db_t freqman_bandwidths[4];
extern options_db_t freqman_steps;
extern options_db_t freqman_steps_short;
options_t dboptions_to_options(const options_db_t& dboptions) {
options_t options;
for (const auto& dboption : dboptions) {
options.emplace_back(dboption.first, dboption.second);
}
return options;
}
/* Set options. */
void freqman_set_modulation_option(OptionsField& option) {
option.set_options(freqman_modulations);
option.set_options(dboptions_to_options(freqman_modulations));
}
void freqman_set_bandwidth_option(freqman_index_t modulation, OptionsField& option) {
if (is_valid(modulation))
option.set_options(freqman_bandwidths[modulation]);
option.set_options(dboptions_to_options(freqman_bandwidths[modulation]));
}
void freqman_set_step_option(OptionsField& option) {
option.set_options(freqman_steps);
option.set_options(dboptions_to_options(freqman_steps));
}
void freqman_set_step_option_short(OptionsField& option) {
option.set_options(freqman_steps_short);
option.set_options(dboptions_to_options(freqman_steps_short));
}
namespace ui {
@@ -438,7 +450,7 @@ void FrequencyEditView::populate_bandwidth_options() {
auto& bandwidths = freqman_bandwidths[entry_.modulation];
for (auto i = 0u; i < bandwidths.size(); ++i) {
auto& item = bandwidths[i];
options.push_back({item.first, (OptionsField::value_t)i});
options.push_back({(std::string)item.first, (OptionsField::value_t)i});
}
}
@@ -451,7 +463,7 @@ void FrequencyEditView::populate_step_options() {
for (auto i = 0u; i < freqman_steps.size(); ++i) {
auto& item = freqman_steps[i];
options.push_back({item.first, (OptionsField::value_t)i});
options.push_back({(std::string)item.first, (OptionsField::value_t)i});
}
field_step.set_options(std::move(options));
+1 -1
View File
@@ -56,7 +56,7 @@ SIGFRXView::~SIGFRXView() {
void SIGFRXView::paint(Painter& painter) {
uint8_t i, xp;
// portapack::display.drawBMP({0, 302-160}, fox_bmp);
// portapack::display.draw_bmp_from_bmp_hex_arr({0, 302-160}, fox_bmp);
portapack::display.fill_rectangle({0, 16, 240, 160 - 16}, Theme::getInstance()->bg_darkest->foreground);
for (i = 0; i < 6; i++) {
xp = sigfrx_marks[i * 3];
+1 -1
View File
@@ -119,7 +119,7 @@ bool SplashViewer::on_key(const KeyEvent key) {
void SplashViewer::paint(Painter& painter) {
painter.fill_rectangle({0, 0, screen_width, screen_height}, Color::black());
if (!portapack::display.drawBMP2({0, 0}, path_)) {
if (!portapack::display.draw_bmp_from_sdcard_file({0, 0}, path_)) {
painter.draw_string({10, 160}, *Theme::getInstance()->bg_darkest, "Not a valid splash image.");
return;
}
+26 -1
View File
@@ -24,6 +24,7 @@
#include "audio.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
@@ -31,6 +32,18 @@ using namespace ui;
namespace ui {
std::string SubGhzDRecentEntry::to_csv() {
std::string csv = ";";
csv += SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)sensorType);
csv += ";" + to_string_dec_uint(bits) + ";";
csv += to_string_hex(data, 64 / 4);
return csv;
}
void SubGhzDLogger::log_data(SubGhzDRecentEntry& data) {
log_file.write_entry(data.to_csv());
}
void SubGhzDRecentEntryDetailView::update_data() {
// process protocol data
parseProtocol();
@@ -76,16 +89,25 @@ SubGhzDView::SubGhzDView(NavigationView& nav)
&field_vga,
&field_frequency,
&button_clear_list,
&check_log,
&recent_entries_view});
baseband::run_image(portapack::spi_flash::image_tag_subghzd);
logger = std::make_unique<SubGhzDLogger>();
button_clear_list.on_select = [this](Button&) {
recent.clear();
recent_entries_view.set_dirty();
};
field_frequency.set_step(10000);
check_log.on_select = [this](Checkbox&, bool v) {
logging = v;
if (logger && logging) {
logger->append(logs_dir.string() + "/SUBGHZDLOG_" + to_string_timestamp(rtc_time::now()) + ".CSV");
logger->write_header();
}
};
check_log.set_value(logging);
const Rect content_rect{0, header_height, screen_width, screen_height - header_height};
recent_entries_view.set_parent_rect(content_rect);
recent_entries_view.on_select = [this](const SubGhzDRecentEntry& entry) {
@@ -107,6 +129,9 @@ void SubGhzDView::on_tick_second() {
void SubGhzDView::on_data(const SubGhzDDataMessage* data) {
SubGhzDRecentEntry key{data->sensorType, data->data, data->bits};
if (logger && logging) {
logger->log_data(key);
}
auto matching_recent = find(recent, key.key());
if (matching_recent != std::end(recent)) {
// Found within. Move to front of list, increment counter.
+30 -1
View File
@@ -34,6 +34,7 @@
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "utility.hpp"
#include "log_file.hpp"
#include "recent_entries.hpp"
#include "../baseband/fprotos/subghztypes.hpp"
@@ -68,6 +69,23 @@ struct SubGhzDRecentEntry {
void reset_age() {
age = 0;
}
std::string to_csv();
};
class SubGhzDLogger {
public:
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
void log_data(SubGhzDRecentEntry& data);
void write_header() {
log_file.write_entry(";Type; Bits; Data;");
}
private:
LogFile log_file{};
};
using SubGhzDRecentEntries = RecentEntries<SubGhzDRecentEntry>;
using SubGhzDRecentEntriesView = RecentEntriesView<SubGhzDRecentEntries>;
@@ -93,10 +111,13 @@ class SubGhzDView : public View {
1'750'000 /* bandwidth */,
4'000'000 /* sampling rate */,
ReceiverModel::Mode::AMAudio};
bool logging = false;
app_settings::SettingsManager settings_{
"rx_subghzd",
app_settings::Mode::RX,
{}};
{
{"log"sv, &logging},
}};
SubGhzDRecentEntries recent{};
@@ -118,8 +139,16 @@ class SubGhzDView : public View {
{0, 16, 7 * 8, 32},
"Clear"};
Checkbox check_log{
{10 * 8, 18},
3,
"Log",
true};
static constexpr auto header_height = 3 * 16;
std::unique_ptr<SubGhzDLogger> logger{};
const RecentEntriesColumns columns{{
{"Type", 19},
{"Bits", 4},
@@ -25,6 +25,7 @@
#include "audio.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
#include "portapack_persistent_memory.hpp"
#include "../baseband/fprotos/fprotogeneral.hpp"
@@ -35,6 +36,21 @@ namespace pmem = portapack::persistent_memory;
namespace ui {
std::string WeatherRecentEntry::to_csv() {
std::string csv = ";";
csv += WeatherView::getWeatherSensorTypeName((FPROTO_WEATHER_SENSOR)sensorType);
csv += ";" + to_string_dec_uint(id) + ";";
csv += to_string_decimal(temp, 2) + ";";
csv += to_string_dec_uint(humidity) + ";";
csv += to_string_dec_uint(channel) + ";";
csv += to_string_dec_uint(battery_low);
return csv;
}
void WeatherLogger::log_data(WeatherRecentEntry& data) {
log_file.write_entry(data.to_csv());
}
void WeatherRecentEntryDetailView::update_data() {
// set text elements
text_type.set(WeatherView::getWeatherSensorTypeName((FPROTO_WEATHER_SENSOR)entry_.sensorType));
@@ -98,8 +114,11 @@ WeatherView::WeatherView(NavigationView& nav)
&field_frequency,
&options_temperature,
&button_clear_list,
&check_log,
&recent_entries_view});
logger = std::make_unique<WeatherLogger>();
baseband::run_image(portapack::spi_flash::image_tag_weather);
button_clear_list.on_select = [this](Button&) {
@@ -114,6 +133,15 @@ WeatherView::WeatherView(NavigationView& nav)
};
options_temperature.set_selected_index(weather_units_fahr, false);
check_log.on_select = [this](Checkbox&, bool v) {
logging = v;
if (logger && logging) {
logger->append(logs_dir.string() + "/WEATHERLOG_" + to_string_timestamp(rtc_time::now()) + ".CSV");
logger->write_header();
}
};
check_log.set_value(logging);
const Rect content_rect{0, header_height, screen_width, screen_height - header_height};
recent_entries_view.set_parent_rect(content_rect);
recent_entries_view.on_select = [this](const WeatherRecentEntry& entry) {
@@ -140,6 +168,9 @@ void WeatherView::on_tick_second() {
void WeatherView::on_data(const WeatherDataMessage* data) {
WeatherRecentEntry key = process_data(data);
if (logger && logging) {
logger->log_data(key);
}
// WeatherRecentEntry key{data->sensorType, data->id, data->temp, data->humidity, data->channel, data->battery_low};
auto matching_recent = find(recent, key.key());
if (matching_recent != std::end(recent)) {
@@ -30,6 +30,7 @@
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "utility.hpp"
#include "log_file.hpp"
#include "recent_entries.hpp"
#include "../baseband/fprotos/weathertypes.hpp"
@@ -78,7 +79,25 @@ struct WeatherRecentEntry {
void reset_age() {
age = 0;
}
std::string to_csv();
};
class WeatherLogger {
public:
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
void log_data(WeatherRecentEntry& data);
void write_header() {
log_file.write_entry(";Type; id; Temp; Hum; CH; Batt");
}
private:
LogFile log_file{};
};
using WeatherRecentEntries = RecentEntries<WeatherRecentEntry>;
using WeatherRecentEntriesView = RecentEntriesView<WeatherRecentEntries>;
@@ -103,11 +122,13 @@ class WeatherView : public View {
1'750'000 /* bandwidth */,
2'000'000 /* sampling rate */,
ReceiverModel::Mode::AMAudio};
bool logging = false;
app_settings::SettingsManager settings_{
"rx_weather",
app_settings::Mode::RX,
{
{"units_fahr"sv, &weather_units_fahr},
{"log"sv, &logging},
}};
WeatherRecentEntries recent{};
@@ -140,8 +161,16 @@ class WeatherView : public View {
{0, 16, 7 * 8, 32},
"Clear"};
Checkbox check_log{
{10 * 8, 18},
3,
"Log",
true};
static constexpr auto header_height = 3 * 16;
std::unique_ptr<WeatherLogger> logger{};
const RecentEntriesColumns columns{{
{"Type", 10},
{"Temp", 5},
File diff suppressed because it is too large Load Diff
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_acars_rx.application_information"), us
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_acars */ {'P', 'A', 'C', 'A'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_adsbtx.application_information"), used
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_adsbtx */ {'P', 'A', 'D', 'T'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_afsk_rx.application_information"), use
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'A', 'F', 'R'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_analogtv.application_information"), us
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_am_tv */ {'P', 'A', 'M', 'T'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_audio_test.application_information"),
},
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {'P', 'A', 'B', 'P'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_blespam.application_information"), use
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_btle_tx */ {'P', 'B', 'T', 'T'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_calculator.application_information"),
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -76,6 +76,7 @@ __attribute__((section(".external_app.app_coasterp.application_information"), us
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_fsktx */ {'P', 'F', 'S', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+14 -13
View File
@@ -17,17 +17,18 @@ void initialize_app(NavigationView& nav) {
extern "C" {
__attribute__((section(".external_app.app_cvs_spam.application_information"), used)) application_information_t _application_information_cvs_spam = {
(uint8_t*)0x00000000,
ui::external_app::cvs_spam::initialize_app,
CURRENT_HEADER_VERSION,
VERSION_MD5,
"CVS Spam",
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81},
ui::Color::red().v,
app_location_t::TX,
{'P', 'R', 'E', 'P'},
0x00000000};
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::cvs_spam::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "CVS Spam",
/*.bitmap_data = */ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81},
/*.icon_color = */ ui::Color::red().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'R', 'E', 'P'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+16 -1
View File
@@ -115,9 +115,21 @@ set(EXTCPPSRC
external/ookbrute/main.cpp
external/ookbrute/ui_ookbrute.cpp
#ook_editor
external/ook_editor/main.cpp
external/ook_editor/ui_ook_editor.cpp
#cvs_spam
external/cvs_spam/main.cpp
external/cvs_spam/cvs_spam.cpp
external/cvs_spam/cvs_spam.cpp
#flippertx
external/flippertx/main.cpp
external/flippertx/ui_flippertx.cpp
#remote
external/remote/main.cpp
external/remote/ui_remote.cpp
)
set(EXTAPPLIST
@@ -148,5 +160,8 @@ set(EXTAPPLIST
random_password
#acars_rx
ookbrute
ook_editor
shoppingcart_lock
flippertx
remote
)
+20
View File
@@ -51,6 +51,9 @@ MEMORY
ram_external_app_shoppingcart_lock(rwx) : org = 0xADCA0000, len = 32k
ram_external_app_cvs_spam(rwx) : org = 0xADCB0000, len = 32k
ram_external_app_ookbrute(rwx) : org = 0xADCC0000, len = 32k
ram_external_app_flippertx(rwx) : org = 0xADCD0000, len = 32k
ram_external_app_ook_editor(rwx) : org = 0xADCE0000, len = 32k
ram_external_app_remote(rwx) : org = 0xADCF0000, len = 32k
}
SECTIONS
@@ -224,4 +227,21 @@ SECTIONS
*(*ui*external_app*ookbrute*);
} > ram_external_app_ookbrute
.external_app_ook_editor : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_ook_editor.application_information));
*(*ui*external_app*ook_editor*);
} > ram_external_app_ook_editor
.external_app_flippertx : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_flippertx.application_information));
*(*ui*external_app*flippertx*);
} > ram_external_app_flippertx
.external_app_remote : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_remote.application_information));
*(*ui*external_app*remote*);
} > ram_external_app_remote
}
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_extsensors.application_information"),
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_flippertx.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::flippertx {
void initialize_app(ui::NavigationView& nav) {
nav.push<FlipperTxView>();
}
} // namespace ui::external_app::flippertx
extern "C" {
__attribute__((section(".external_app.app_flippertx.application_information"), used)) application_information_t _application_information_flippertx = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::flippertx::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "FlipperTx",
/*.bitmap_data = */ {
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0xE0,
0x07,
0xF0,
0x0F,
0x30,
0x0C,
0x30,
0x0C,
0xF0,
0x0F,
0xF0,
0x0F,
0x70,
0x0D,
0xB0,
0x0E,
0x70,
0x0D,
0xB0,
0x0E,
0xF0,
0x0F,
0xE0,
0x07,
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_ookstreaming */ {'P', 'O', 'S', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+285
View File
@@ -0,0 +1,285 @@
/*
* 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_flippertx.hpp"
#include "audio.hpp"
#include "rtc_time.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "buffer_exchange.hpp"
using namespace portapack;
using namespace ui;
namespace ui::external_app::flippertx {
void FlipperTxView::focus() {
button_browse.focus();
}
void FlipperTxView::set_ready() {
ready_signal = true;
}
FlipperTxView::FlipperTxView(NavigationView& nav)
: nav_{nav} {
add_children({&button_startstop,
&field_frequency,
&tx_view,
&field_filename,
&button_browse});
button_startstop.on_select = [this](Button&) {
if (is_running) {
stop();
} else {
start();
}
};
button_browse.on_select = [this](Button&) {
auto open_view = nav_.push<FileLoadView>(".sub");
open_view->push_dir(subghz_dir);
open_view->on_changed = [this](std::filesystem::path new_file_path) {
if (on_file_changed(new_file_path)) {
; // tif (button_startstop.parent()) button_startstop.focus(); parent_ is null error.....
}
};
};
}
bool FlipperTxView::on_file_changed(std::filesystem::path new_file_path) {
submeta = read_flippersub_file(new_file_path);
filename = "";
if (!submeta.is_valid()) {
field_filename.set_text("File: err, bad file");
return false;
}
proto = submeta.value().protocol;
if (proto != FLIPPER_PROTO_RAW && proto != FLIPPER_PROTO_BINRAW) { // temp disabled
field_filename.set_text("File: err, not supp. proto");
return false;
}
preset = submeta.value().preset;
if (preset != FLIPPER_PRESET_OOK) {
field_filename.set_text("File: err, not supp. preset");
return false;
}
te = submeta.value().te;
binraw_bit_count = submeta.value().binraw_bit_count;
/*if (binraw_bit_count >= 512 * 800) {
field_filename.set_text("File: err, too long"); // should stream, but not in this scope YET
return false;
}*/
field_filename.set_text("File: " + new_file_path.string());
filename = new_file_path;
return true;
}
void FlipperTxView::stop() {
if (is_running && replay_thread) replay_thread.reset();
is_running = false;
ready_signal = false;
transmitter_model.disable();
baseband::shutdown();
button_startstop.set_text(LanguageHelper::currentMessages[LANG_START]);
}
bool FlipperTxView::start() {
if (filename.empty()) return false;
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
transmitter_model.enable();
button_startstop.set_text(LanguageHelper::currentMessages[LANG_STOP]);
// start thread
replay_thread = std::make_unique<FlipperPlayThread>(
filename,
1024, 4,
&ready_signal,
submeta.value().protocol,
submeta.value().te,
[](uint32_t return_code) {
ReplayThreadDoneMessage message{return_code};
EventDispatcher::send_message(message);
});
is_running = true;
return true;
}
void FlipperTxView::on_tx_progress(const bool done) {
if (done) {
if (is_running) {
stop();
}
}
}
FlipperTxView::~FlipperTxView() {
stop();
}
FlipperPlayThread::FlipperPlayThread(
std::filesystem::path filename,
size_t read_size,
size_t buffer_count,
bool* ready_signal,
FlipperProto proto,
uint16_t te,
std::function<void(uint32_t return_code)> terminate_callback)
: config{read_size, buffer_count},
filename{filename},
ready_sig{ready_signal},
proto{proto},
te{te},
terminate_callback{std::move(terminate_callback)} {
thread = chThdCreateFromHeap(NULL, 6 * 1024, NORMALPRIO + 10, FlipperPlayThread::static_fn, this);
}
FlipperPlayThread::~FlipperPlayThread() {
if (thread) {
chThdTerminate(thread);
if (thread->p_refs) chThdWait(thread);
thread = nullptr;
}
}
msg_t FlipperPlayThread::static_fn(void* arg) {
auto obj = static_cast<FlipperPlayThread*>(arg);
const auto return_code = obj->run();
if (obj->terminate_callback) {
obj->terminate_callback(return_code);
}
chThdExit(0);
return 0;
}
uint32_t FlipperPlayThread::run() {
BasebandReplay replay{&config};
BufferExchange buffers{&config};
StreamBuffer* prefill_buffer{nullptr};
int32_t read_result = 0;
// assume it is ok, since prev we checked it.
// open the sub file
File f; // don't worry, destructor will close it.
auto error = f.open(filename);
if (error) return READ_ERROR;
// seek to the first data
if (proto == FLIPPER_PROTO_RAW)
seek_flipper_raw_first_data(f);
else {
seek_flipper_binraw_first_data(f);
}
// Wait for FIFOs to be allocated in baseband
// Wait for _view to tell us that the buffers are ready
while (!(*ready_sig) && !chThdShouldTerminate()) {
chThdSleep(100);
};
uint8_t readall = 0;
int32_t endsignals[3] = {0, 42069, 613379}; // unlikely a valid data
// While empty buffers fifo is not empty...
while (!buffers.empty() && !chThdShouldTerminate()) {
prefill_buffer = buffers.get_prefill();
if (prefill_buffer == nullptr) {
buffers.put_app(prefill_buffer);
} else {
size_t c = 0;
for (c = 0; c < config.read_size / 4;) {
read_result = 0;
if (0 == readall) {
if (proto == FLIPPER_PROTO_RAW) {
auto data = read_flipper_raw_next_data(f);
if (!data.is_valid()) {
((int32_t*)prefill_buffer->data())[c] = endsignals[++readall];
} else {
read_result = data.value();
((int32_t*)prefill_buffer->data())[c] = read_result;
}
c++;
} else { // BINRAW
auto data = read_flipper_binraw_next_data(f);
if (!data.is_valid())
readall = 1;
else {
read_result = data.value();
// add 8 data
for (uint8_t bit = 0; bit < 8; bit++) {
((int32_t*)prefill_buffer->data())[c + bit] = ((get_flipper_binraw_bitvalue(read_result, (7 - bit)) ? 1 : -1) * te);
c++;
}
}
}
} else {
((int32_t*)prefill_buffer->data())[c] = endsignals[readall];
if (readall == 1) readall++;
c++;
}
}
prefill_buffer->set_size(config.read_size);
buffers.put(prefill_buffer);
}
};
baseband::set_fifo_data(nullptr);
if (readall) return END_OF_FILE;
while (!chThdShouldTerminate()) {
auto buffer = buffers.get();
int32_t read_result = 0;
for (size_t d = 0; d < buffer->capacity() / 4; d++) {
read_result = -133469;
if (!readall) {
if (proto == FLIPPER_PROTO_RAW) {
auto data = read_flipper_raw_next_data(f);
if (!data.is_valid()) {
readall = 1;
} else {
read_result = data.value();
}
} else {
auto data = read_flipper_binraw_next_data(f);
if (!data.is_valid())
readall = 1;
else {
read_result = data.value();
// add 8 data
for (uint8_t bit = 0; bit < 8; bit++) {
((int32_t*)prefill_buffer->data())[d + bit] = ((get_flipper_binraw_bitvalue(read_result, (7 - bit)) ? 1 : -1) * te);
}
d += 7;
continue;
}
}
}
if (readall >= 1 && readall <= 2) {
read_result = endsignals[readall++];
}
((int32_t*)buffer->data())[d] = read_result;
}
buffer->set_size(buffer->capacity());
buffers.put(buffer);
if (readall == 3) return END_OF_FILE;
}
return TERMINATED;
}
} // namespace ui::external_app::flippertx
+171
View File
@@ -0,0 +1,171 @@
/*
* Copyright (C) 2024 HTotoo
*
* This file is part of PortaPack.
*
*/
#ifndef __UI_flippertx_H__
#define __UI_flippertx_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_transmitter.hpp"
#include "ui_freq_field.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "utility.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
#include "metadata_file.hpp"
#include "flipper_subfile.hpp"
#include "ui_fileman.hpp"
#include "baseband_api.hpp"
using namespace ui;
namespace ui::external_app::flippertx {
#define OOK_SAMPLERATE 2280000U
class FlipperPlayThread;
class FlipperTxView : public View {
public:
FlipperTxView(NavigationView& nav);
~FlipperTxView();
void focus() override;
std::string title() const override {
return "FlipperTx";
};
private:
NavigationView& nav_;
TxRadioState radio_state_{
433920000 /* frequency */,
1750000 /* bandwidth */,
OOK_SAMPLERATE /* sampling rate */
};
TxFrequencyField field_frequency{
{0 * 8, 0 * 16},
nav_};
TransmitterView2 tx_view{
{11 * 8, 0 * 16},
/*short_ui*/ true};
app_settings::SettingsManager settings_{
"tx_flippertx", app_settings::Mode::TX};
TextField field_filename{
{0, 2 * 16, 300, 1 * 8},
"File: -"};
Button button_startstop{
{1, 6 * 16, 96, 24},
LanguageHelper::currentMessages[LANG_START]};
Button button_browse{
{1, 3 * 16 + 3, 96, 24},
LanguageHelper::currentMessages[LANG_BROWSE]};
bool is_running{false};
bool start();
void stop();
void set_ready();
void on_tx_progress(const bool done);
bool on_file_changed(std::filesystem::path new_file_path);
std::filesystem::path filename = {};
FlipperProto proto = FLIPPER_PROTO_UNSUPPORTED;
FlipperPreset preset = FLIPPER_PRESET_UNK;
uint16_t te = 0; // for binraw
uint32_t binraw_bit_count = 0;
bool ready_signal = false;
std::unique_ptr<FlipperPlayThread> replay_thread{};
Optional<flippersub_metadata> submeta{};
const std::filesystem::path subghz_dir = u"subghz";
MessageHandlerRegistration message_handler_tx_progress{
Message::ID::TXProgress,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
this->on_tx_progress(message.done);
}};
MessageHandlerRegistration message_handler_fifo_signal{
Message::ID::RequestSignal,
[this](const Message* const p) {
const auto message = static_cast<const RequestSignalMessage*>(p);
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
this->set_ready();
}
}};
MessageHandlerRegistration message_handler_replay_thread_done{
Message::ID::ReplayThreadDone,
[this](const Message* const p) {
// const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
(void)p;
// stop(); //don't stop for now, stop when i get the tx finished msg
}};
};
struct BasebandReplay {
BasebandReplay(ReplayConfig* const config) {
baseband::replay_start(config);
}
~BasebandReplay() {
// baseband::replay_stop(); // wont, since we need to send out that is in the buffer
}
};
class FlipperPlayThread {
public:
FlipperPlayThread(
std::filesystem::path,
size_t read_size,
size_t buffer_count,
bool* ready_signal,
FlipperProto proto,
uint16_t te,
std::function<void(uint32_t return_code)> terminate_callback);
~FlipperPlayThread();
FlipperPlayThread(const FlipperPlayThread&) = delete;
FlipperPlayThread(FlipperPlayThread&&) = delete;
FlipperPlayThread& operator=(const FlipperPlayThread&) = delete;
FlipperPlayThread& operator=(FlipperPlayThread&&) = delete;
const ReplayConfig& state() const {
return config;
};
enum FlipperPlayThread_return {
READ_ERROR = 0,
END_OF_FILE,
TERMINATED
};
private:
ReplayConfig config;
std::filesystem::path filename;
bool* ready_sig;
FlipperProto proto;
uint16_t te;
std::function<void(uint32_t return_code)> terminate_callback;
Thread* thread{nullptr};
static msg_t static_fn(void* arg);
uint32_t run();
};
}; // namespace ui::external_app::flippertx
#endif /*__UI_flippertx_H__*/
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_font_viewer.application_information"),
},
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_foxhunt_rx.application_information"),
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_am_audio */ {'P', 'A', 'M', 'A'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_gpssim.application_information"), used
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_gpssim */ {'P', 'G', 'P', 'S'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_jammer.application_information"), used
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_jammer */ {'P', 'J', 'A', 'M'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_keyfob.application_information"), used
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_keyfob */ {'P', 'O', 'O', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_lcr.application_information"), used))
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk */ {'P', 'A', 'F', 'T'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_lge.application_information"), used))
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_fsktx */ {'P', 'F', 'S', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_morse_tx.application_information"), us
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_tones */ {'P', 'T', 'O', 'N'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -76,6 +76,7 @@ __attribute__((section(".external_app.app_nrf_rx.application_information"), used
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_nrf_rx */ {'P', 'N', 'R', 'R'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2024 Samir Sánchez Garnica @sasaga92
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_ook_editor.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::ook_editor {
void initialize_app(ui::NavigationView& nav) {
nav.push<OOKEditorAppView>();
}
} // namespace ui::external_app::ook_editor
extern "C" {
__attribute__((section(".external_app.app_ook_editor.application_information"), used)) application_information_t _application_information_ook_editor = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::ook_editor::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "OOKEditor",
/*.bitmap_data = */ {
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0xE0,
0x07,
0xF0,
0x0F,
0x30,
0x0C,
0x30,
0x0C,
0xF0,
0x0F,
0xF0,
0x0F,
0x70,
0x0D,
0xB0,
0x0E,
0x70,
0x0D,
0xB0,
0x0E,
0xF0,
0x0F,
0xE0,
0x07,
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_ook */ {'P', 'O', 'O', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -0,0 +1,282 @@
/*
* Copyright (C) 2024 Samir Sánchez Garnica @sasaga92
*
* 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_ook_editor.hpp"
using namespace portapack;
using namespace ui;
namespace fs = std::filesystem;
namespace ui::external_app::ook_editor {
// give focus to set button
void OOKEditorAppView::focus() {
button_set.focus();
}
// update internal ook_data with GUI values
void OOKEditorAppView::update_ook_data_from_app() {
ook_data.frequency = field_frequency.value();
ook_data.sample_rate = field_sample_rate.selected_index_value();
ook_data.symbol_rate = field_symbol_rate.value();
ook_data.repeat = field_repeat.value();
ook_data.pause_symbol_duration = field_pause_symbol_duration.value();
}
// `start_tx` method: Configures and begins OOK data transmission with a specific message.
void OOKEditorAppView::start_tx() {
// check if there is a payload
if (ook_data.payload.length() < 1) {
text_app_status.set("Error: no payload to tx !!");
return;
}
progressbar.set_max(field_repeat.value()); // Size the progress bar accordingly to the number of repeat
is_transmitting = true; // set transmitting flag
button_send_stop.set_text(LanguageHelper::currentMessages[LANG_STOP]); // set button back to initial "start" state
start_ook_file_tx(ook_data); // start the transmission
}
// `stop_tx` method: Stops the transmission and resets the progress bar.
void OOKEditorAppView::stop_tx() {
is_transmitting = false; // set transmitting flag
stop_ook_file_tx(); // stop transmission
progressbar.set_value(0); // Reset progress bar to 0
button_send_stop.set_text(LanguageHelper::currentMessages[LANG_START]); // set button back to initial "start" state
}
// `on_file_changed` method: Called when a new file is loaded; parses file data into variables
void OOKEditorAppView::on_file_changed(const fs::path& new_file_path) {
ook_data.payload.clear(); // Clear previous payload content
if (!read_ook_file(new_file_path, ook_data)) {
text_app_status.set("Error loading " + new_file_path.filename().string());
return;
}
field_frequency.set_value(ook_data.frequency);
field_symbol_rate.set_value(ook_data.symbol_rate);
field_repeat.set_value(ook_data.repeat);
field_pause_symbol_duration.set_value(ook_data.pause_symbol_duration);
field_sample_rate.set_by_value(ook_data.sample_rate);
text_payload.set(ook_data.payload);
button_send_stop.focus();
text_app_status.set("Loaded: " + new_file_path.filename().string());
}
// `on_tx_progress` method: Updates the progress bar based on transmission progress.
void OOKEditorAppView::on_tx_progress(const uint32_t progress, const bool done) {
progressbar.set_value(progress); // Update progress bar value
if (done) {
stop_tx(); // Stop transmission when progress reaches maximum
}
}
// `draw_waveform` method: Draws the waveform on the UI based on the payload data
void OOKEditorAppView::draw_waveform() {
// Padding reason:
// In real-world scenarios, the signal would always start low and return low after turning off the radio.
// `waveform_buffer` only controls drawing; the actual send logic is handled by frame_fragments.
size_t length = ook_data.payload.length();
// Ensure waveform length does not exceed buffer size
if (length + (PADDING_LEFT + PADDING_RIGHT) >= WAVEFORM_BUFFER_SIZE) {
length = WAVEFORM_BUFFER_SIZE - (PADDING_LEFT + PADDING_RIGHT);
}
// Left padding
for (size_t i = 0; i < PADDING_LEFT; i++) {
waveform_buffer[i] = 0;
}
// Draw the actual waveform
for (size_t n = 0; n < length; n++) {
waveform_buffer[n + PADDING_LEFT] = (ook_data.payload[n] == '0') ? 0 : 1;
}
// Right padding
for (size_t i = length + PADDING_LEFT; i < WAVEFORM_BUFFER_SIZE; i++) {
waveform_buffer[i] = 0;
}
waveform.set_length(length + PADDING_LEFT + PADDING_RIGHT);
waveform.set_dirty();
}
// build a new path+file, make some tests, call save_ook_to_file
void OOKEditorAppView::on_save_file(const std::string value) {
// check if there is a payload, else Error
if (ook_data.payload.length() < 1) {
text_app_status.set("Err: can't save, no payload !");
return;
}
ensure_directory(ook_editor_dir);
auto new_path = ook_editor_dir / value + ".OOK";
if (save_ook_to_file(new_path)) {
text_app_status.set("Saved to " + new_path.string());
} else {
text_app_status.set("Error saving " + new_path.string());
}
}
// update ook_data from GUI and save
bool OOKEditorAppView::save_ook_to_file(const std::filesystem::path& path) {
update_ook_data_from_app();
return save_ook_file(ook_data, path);
}
// Destructor for `OOKEditorAppView`: Disables the transmitter and shuts down the baseband
OOKEditorAppView::~OOKEditorAppView() {
stop_ook_file_tx();
baseband::shutdown();
}
// Constructor for `OOKEditorAppView`: Sets up the app view and initializes UI elements
OOKEditorAppView::OOKEditorAppView(NavigationView& nav)
: nav_{nav} {
// load OOK baseband
baseband::run_image(portapack::spi_flash::image_tag_ook);
// add all the widgets
add_children({&field_frequency,
&tx_view,
&button_send_stop,
&label_step,
&field_step,
&label_sample_rate,
&field_sample_rate,
&label_symbol_rate,
&field_symbol_rate,
&label_symbol_rate_unit,
&text_payload,
&button_set,
&progressbar,
&label_repeat,
&field_repeat,
&label_pause_symbol_duration,
&field_pause_symbol_duration,
&label_pause_symbol_duration_unit,
&label_payload,
&text_app_status,
&label_waveform,
&waveform,
&button_open,
&button_save});
// Initialize default values for controls
field_symbol_rate.set_value(100);
field_pause_symbol_duration.set_value(100);
field_repeat.set_value(4);
// Configure open ook file button
button_open.on_select = [this](Button&) {
auto open_view = nav_.push<FileLoadView>(".OOK");
ensure_directory(ook_editor_dir);
open_view->push_dir(ook_editor_dir);
open_view->on_changed = [this](std::filesystem::path new_file_path) {
// Postpone `on_file_changed` call until `FileLoadView` is closed
nav_.set_on_pop([this, new_file_path]() {
on_file_changed(new_file_path);
button_send_stop.focus();
draw_waveform();
});
};
};
// Configure save to ook file button
button_save.on_select = [this, &nav](const ui::Button&) {
outputFileBuffer = "";
text_prompt(
nav,
outputFileBuffer,
64,
[this](std::string& buffer) {
on_save_file(buffer);
});
};
// clean out loaded file name if field is changed
field_symbol_rate.on_change = [this](int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// clean out loaded file name if field is changed
field_repeat.on_change = [this](int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// clean out loaded file name if field is changed
field_pause_symbol_duration.on_change = [this](int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// clean out loaded file name if field is changed
field_sample_rate.on_change = [this](size_t, int32_t) {
text_app_status.set(""); // Clear loaded file text field
};
// setting up FrequencyField
field_frequency.set_value(ook_editor_tx_freq);
// clean out loaded file name if field is changed, save ook_editor_tx_freq
field_frequency.on_change = [this](rf::Frequency f) {
ook_editor_tx_freq = f;
text_app_status.set(""); // Clear loaded file text field
};
// allow typing frequency number
field_frequency.on_edit = [this]() {
auto freq_view = nav_.push<FrequencyKeypadView>(field_frequency.value());
freq_view->on_changed = [this](rf::Frequency f) {
field_frequency.set_value(f);
text_app_status.set(""); // Clear loaded file text field
};
};
// allow different steps on symbol_rate and pause_symbol_duration
field_step.on_change = [this](size_t, int32_t value) {
text_app_status.set(""); // Clear loaded file text field
field_symbol_rate.set_step(value);
field_pause_symbol_duration.set_step(value);
};
// Configure button to manually set payload through text input
button_set.on_select = [this, &nav](Button&) {
text_prompt(
nav,
ook_data.payload,
100,
[this](std::string& s) {
text_payload.set(s);
draw_waveform();
text_app_status.set(""); // Clear loaded file text field
});
};
// Configure button to start or stop the transmission
button_send_stop.on_select = [this](Button&) {
if (!is_transmitting) {
update_ook_data_from_app();
start_tx(); // Begin transmission
} else {
stop_tx();
}
};
// initial waveform drawing (should be a single line)
draw_waveform();
}
} // namespace ui::external_app::ook_editor
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2024 Samir Sánchez Garnica @sasaga92
*
* This file is part of PortaPack.
*
*/
#ifndef __UI_OOK_EDITOR_H__
#define __UI_OOK_EDITOR_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_freq_field.hpp"
#include "ui_textentry.hpp"
#include "ui_fileman.hpp"
#include "ui_transmitter.hpp"
#include "radio_state.hpp"
#include "app_settings.hpp"
#include "file_path.hpp"
#include "ook_file.hpp"
using namespace ui;
namespace ui::external_app::ook_editor {
#define PADDING_LEFT 1 // waveform padding
#define PADDING_RIGHT 1 // waveform padding
#define OOK_SAMPLERATE_DEFAULT 2280000U // Set the default Sample Rate
#define TRANSMISSION_FREQUENCY_DEFAULT 433920000U // Sets the default transmission frequency (27 MHz).
#define WAVEFORM_BUFFER_SIZE 550
class OOKEditorAppView : public View {
public:
void focus() override;
OOKEditorAppView(NavigationView& nav);
~OOKEditorAppView();
std::string title() const override {
return "OOKEditor";
};
private:
NavigationView& nav_; // Reference to the navigation system.
uint32_t progress = 0; // Stores the current transmission progress.
int16_t waveform_buffer[WAVEFORM_BUFFER_SIZE]; // Buffer for waveform data.
bool is_transmitting = false; // State of transmission.
rf::Frequency ook_editor_tx_freq{24000000}; // last used transmit frequency
std::string outputFileBuffer{}; // buffer for output file
ook_file_data ook_data = {0, 0, 0, 0, 0, ""}; // ook files handle
// draw current payload waveform
void draw_waveform();
// update ook_data from GUI selection
void update_ook_data_from_app();
// start transmission
void start_tx();
// stop transmission
void stop_tx();
// Updates the transmission progress on the progress bar.
void on_tx_progress(const uint32_t progress, const bool done);
// Updates data when a new file is loaded.
void on_file_changed(const std::filesystem::path& new_file_path);
// Prepare a new std::filesystem::path from string value and call saveFile
void on_save_file(const std::string value);
// Called by on_save_file to save the current OOK parameters to the file
bool save_ook_to_file(const std::filesystem::path& path);
// Registers a message handler for transmission progress updates.
MessageHandlerRegistration message_handler_tx_progress{
Message::ID::TXProgress, // Transmission progress message ID.
[this](const Message* const p) { // Callback to handle the message.
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
this->on_tx_progress(message.progress, message.done);
}};
// Sets transmission frequency, bandwidth, and default sample rate for OOK.
TxRadioState radio_state_{TRANSMISSION_FREQUENCY_DEFAULT, 1750000, OOK_SAMPLERATE_DEFAULT};
// Settings manager for app configuration.
app_settings::SettingsManager settings_{
"ook_editor",
app_settings::Mode::TX,
{{"ook_editor_tx_freq"sv, &ook_editor_tx_freq}}};
// UI components for frequency and transmitter view.
FrequencyField field_frequency{{0 * 8, 0 * 16}};
TransmitterView2 tx_view{{20 * 7, 0 * 16}, true};
// Labels for various fields such as sample rate and repeat count.
Labels label_step{{{170, 20}, "Step:", Theme::getInstance()->fg_light->foreground}};
Labels label_sample_rate{{{0, 20}, "SampleRate:", Theme::getInstance()->fg_light->foreground}};
Labels label_symbol_rate{{{0, 40}, "SymbolRate:", Theme::getInstance()->fg_light->foreground}};
Labels label_symbol_rate_unit{{{132, 40}, "/s", Theme::getInstance()->fg_light->foreground}};
Labels label_repeat{{{154, 40}, "Repeat:", Theme::getInstance()->fg_light->foreground}};
Labels label_pause_symbol_duration{{{0, 60}, "PauseSymbol:", Theme::getInstance()->fg_light->foreground}};
Labels label_pause_symbol_duration_unit{{{132, 60}, "us", Theme::getInstance()->fg_light->foreground}};
Labels label_payload{{{0, 80}, "Payload:", Theme::getInstance()->fg_light->foreground}};
Labels label_waveform{{{0, 188}, "Waveform:", Theme::getInstance()->fg_light->foreground}};
// Text field to display the various status message of the app
Text text_app_status{{0, 160, 30 * 8, 16}, ""};
// OptionsField for selectable sample rates.
OptionsField field_sample_rate{{96, 20}, 7, {{"250k", 250000U}, {"1M", 1000000U}, {"2M", 2000000U}, {"5M", 5000000U}, {"10M", 10000000U}, {"20M", 20000000U}}};
// OptionsField for step symbol rates.
OptionsField field_step{{210, 20}, 7, {{"1", 1}, {"10", 10}, {"100", 100}}};
// Number fields for symbols, pause_symbol between repeat, and repeat count.
NumberField field_symbol_rate{{96, 40}, 4, {0, 9999}, 1, '0', false};
NumberField field_pause_symbol_duration{{96, 60}, 4, {0, 9999}, 1, '0', false};
NumberField field_repeat{{210, 40}, 3, {1, 999}, 1, '0', false};
// Text field to display the payload data.
Text text_payload{{0 * 8, 100, 30 * 8, 16}, ""};
// Buttons for setting configurations, opening files, and starting transmission.
Button button_set{{0, 125, 60, 28}, LanguageHelper::currentMessages[LANG_SET]};
Button button_open{{68, 125, 80, 28}, LanguageHelper::currentMessages[LANG_OPEN_FILE]};
Button button_save{{154, 125, 80, 28}, LanguageHelper::currentMessages[LANG_SAVE_FILE]};
Button button_send_stop{{80, 273, 80, 32}, LanguageHelper::currentMessages[LANG_SEND]};
// Progress bar to display transmission progress.
ProgressBar progressbar{{2 * 8, 250, 208, 16}};
// Waveform display using waveform buffer and yellow theme color.
Waveform waveform{{0, 208, 240, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
};
}; // namespace ui::external_app::ook_editor
#endif /*__UI_OOK_EDITOR_H__*/
+3 -2
View File
@@ -26,7 +26,7 @@
namespace ui::external_app::ookbrute {
void initialize_app(ui::NavigationView& nav) {
nav.push<OokBruteView>();
nav.push<OOKBruteView>();
}
} // namespace ui::external_app::ookbrute
@@ -38,7 +38,7 @@ __attribute__((section(".external_app.app_ookbrute.application_information"), us
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "OokBrute",
/*.app_name = */ "OOKBrute",
/*.bitmap_data = */ {
0x20,
0x00,
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_ookbrute.application_information"), us
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_ook */ {'P', 'O', 'O', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+10 -10
View File
@@ -31,11 +31,11 @@ using namespace ui;
namespace ui::external_app::ookbrute {
void OokBruteView::focus() {
void OOKBruteView::focus() {
button_startstop.focus();
}
OokBruteView::OokBruteView(NavigationView& nav)
OOKBruteView::OOKBruteView(NavigationView& nav)
: nav_{nav} {
add_children({
&button_startstop,
@@ -69,7 +69,7 @@ OokBruteView::OokBruteView(NavigationView& nav)
update_start_stop(0);
}
void OokBruteView::update_start_stop(uint32_t proto) {
void OOKBruteView::update_start_stop(uint32_t proto) {
uint8_t bits = 12;
switch (proto) {
default:
@@ -91,7 +91,7 @@ void OokBruteView::update_start_stop(uint32_t proto) {
field_stop.set_value(max);
}
void OokBruteView::validate_start_stop() {
void OOKBruteView::validate_start_stop() {
if (field_start.value() > field_stop.value()) {
field_start.set_value(field_stop.value());
}
@@ -100,7 +100,7 @@ void OokBruteView::validate_start_stop() {
}
}
void OokBruteView::generate_packet() {
void OOKBruteView::generate_packet() {
uint32_t protocol = options_atkmode.selected_index_value();
uint8_t byte = 0;
size_t bitstream_length = 0;
@@ -210,13 +210,13 @@ void OokBruteView::generate_packet() {
0);
}
void OokBruteView::stop() {
void OOKBruteView::stop() {
transmitter_model.disable();
baseband::shutdown();
button_startstop.set_text(LanguageHelper::currentMessages[LANG_START]);
}
void OokBruteView::start() {
void OOKBruteView::start() {
counter = field_start.value();
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
transmitter_model.enable();
@@ -224,7 +224,7 @@ void OokBruteView::start() {
generate_packet();
}
void OokBruteView::on_tx_progress(const bool done) {
void OOKBruteView::on_tx_progress(const bool done) {
if (done) {
if (is_running) {
counter++;
@@ -238,7 +238,7 @@ void OokBruteView::on_tx_progress(const bool done) {
}
}
OokBruteView::~OokBruteView() {
OOKBruteView::~OOKBruteView() {
is_running = false;
stop();
}
@@ -250,4 +250,4 @@ OokBruteView::~OokBruteView() {
https://web.archive.org/web/20230331125843/https://phreakerclub.com/447
*/
*/
+4 -4
View File
@@ -24,15 +24,15 @@ namespace ui::external_app::ookbrute {
#define OOK_SAMPLERATE 2280000U
class OokBruteView : public View {
class OOKBruteView : public View {
public:
OokBruteView(NavigationView& nav);
~OokBruteView();
OOKBruteView(NavigationView& nav);
~OOKBruteView();
void focus() override;
std::string title() const override {
return "OokBrute";
return "OOKBrute";
};
private:
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_protoview.application_information"), u
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_protoview */ {'P', 'P', 'V', 'W'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_random_password.application_informatio
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'A', 'F', 'R'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2024 gullradriel
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_remote.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::remote {
void initialize_app(ui::NavigationView& nav) {
nav.push<RemoteAppView>();
}
} // namespace ui::external_app::remote
extern "C" {
__attribute__((section(".external_app.app_remote.application_information"), used)) application_information_t _application_information_remote = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::remote::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Remote",
/*.bitmap_data = */ {
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0xE0,
0x07,
0xF0,
0x0F,
0x30,
0x0C,
0x30,
0x0C,
0xF0,
0x0F,
0xF0,
0x0F,
0x70,
0x0D,
0xB0,
0x0E,
0x70,
0x0D,
0xB0,
0x0E,
0xF0,
0x0F,
0xE0,
0x07,
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::HOME,
/*.desired_menu_position = */ 4,
/*.m4_app_tag = portapack::spi_flash::image_tag_replay */ {'P', 'R', 'E', 'P'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -20,7 +20,6 @@
*/
#include "ui_remote.hpp"
#include "binder.hpp"
#include "convert.hpp"
#include "file_reader.hpp"
@@ -34,11 +33,11 @@
#include "utility.hpp"
#include "file_path.hpp"
namespace ui::external_app::remote {
using namespace portapack;
namespace fs = std::filesystem;
namespace ui {
static constexpr uint8_t text_edit_max = 30;
/* RemoteEntryModel **************************************/
@@ -309,9 +308,9 @@ void RemoteEntryEditView::load_path(std::filesystem::path&& path) {
entry_.metadata = {transmitter_model.target_frequency(), 500'000};
}
/* RemoteView ********************************************/
/* RemoteAppView ********************************************/
RemoteView::RemoteView(
RemoteAppView::RemoteAppView(
NavigationView& nav)
: nav_{nav} {
baseband::run_image(portapack::spi_flash::image_tag_replay);
@@ -365,27 +364,27 @@ RemoteView::RemoteView(
refresh_ui();
}
RemoteView::RemoteView(NavigationView& nav, fs::path path)
: RemoteView(nav) {
RemoteAppView::RemoteAppView(NavigationView& nav, fs::path path)
: RemoteAppView(nav) {
load_remote(std::move(path));
refresh_ui();
}
RemoteView::~RemoteView() {
RemoteAppView::~RemoteAppView() {
stop();
baseband::shutdown();
save_remote(/*show_error*/ false);
}
void RemoteView::focus() {
void RemoteAppView::focus() {
if (model_.entries.empty())
button_add.focus();
else
buttons_[0]->focus();
}
void RemoteView::create_buttons() {
void RemoteAppView::create_buttons() {
// Handler callbacks.
auto handle_send = [this](RemoteButton& btn) {
if (btn.entry()->path.empty())
@@ -420,7 +419,7 @@ void RemoteView::create_buttons() {
}
}
void RemoteView::reset_buttons() {
void RemoteAppView::reset_buttons() {
// Whever the model's entries instance is invalidated,
// all the pointers in the buttons will end up dangling.
// TODO: This is pretty lame. Could maybe static alloc?
@@ -428,7 +427,7 @@ void RemoteView::reset_buttons() {
btn->set_entry(nullptr);
}
void RemoteView::refresh_ui() {
void RemoteAppView::refresh_ui() {
field_title.set_text(model_.name);
field_filename.set_text(remote_path_.stem().string());
@@ -441,7 +440,7 @@ void RemoteView::refresh_ui() {
}
}
void RemoteView::add_button() {
void RemoteAppView::add_button() {
if (model_.entries.size() >= max_buttons)
return;
@@ -454,7 +453,7 @@ void RemoteView::add_button() {
set_needs_save();
}
void RemoteView::edit_button(RemoteButton& btn) {
void RemoteAppView::edit_button(RemoteButton& btn) {
// Don't let replay thread read the model while editing.
stop();
@@ -471,7 +470,7 @@ void RemoteView::edit_button(RemoteButton& btn) {
};
}
void RemoteView::send_button(RemoteButton& btn) {
void RemoteAppView::send_button(RemoteButton& btn) {
// TODO: If this is called while is_sending() == true,
// it just stops and doesn't start the new button?
@@ -510,14 +509,14 @@ void RemoteView::send_button(RemoteButton& btn) {
});
}
void RemoteView::stop() {
void RemoteAppView::stop() {
// This terminates the underlying chThread.
replay_thread_.reset();
transmitter_model.disable();
ready_signal_ = false;
}
void RemoteView::new_remote() {
void RemoteAppView::new_remote() {
save_remote();
init_remote();
refresh_ui();
@@ -526,7 +525,7 @@ void RemoteView::new_remote() {
set_dirty();
}
void RemoteView::open_remote() {
void RemoteAppView::open_remote() {
auto open_view = nav_.push<FileLoadView>(".REM");
open_view->push_dir(remotes_dir);
open_view->on_changed = [this](fs::path path) {
@@ -536,7 +535,7 @@ void RemoteView::open_remote() {
};
}
void RemoteView::init_remote() {
void RemoteAppView::init_remote() {
model_ = {"<Unnamed Remote>", {}};
reset_buttons();
set_remote_path(next_filename_matching_pattern(remotes_dir / u"REMOTE_????.REM"));
@@ -546,14 +545,14 @@ void RemoteView::init_remote() {
show_error("Couldn't make new remote file.");
}
bool RemoteView::load_remote(fs::path&& path) {
bool RemoteAppView::load_remote(fs::path&& path) {
set_remote_path(std::move(path));
set_needs_save(false);
reset_buttons();
return model_.load(remote_path_);
}
void RemoteView::save_remote(bool show_errors) {
void RemoteAppView::save_remote(bool show_errors) {
if (!needs_save_)
return;
@@ -564,7 +563,7 @@ void RemoteView::save_remote(bool show_errors) {
set_needs_save(false);
}
void RemoteView::rename_remote(const std::string& new_name) {
void RemoteAppView::rename_remote(const std::string& new_name) {
auto folder = remote_path_.parent_path();
auto ext = remote_path_.extension();
auto new_path = folder / new_name + ext;
@@ -581,7 +580,7 @@ void RemoteView::rename_remote(const std::string& new_name) {
set_remote_path(std::move(new_path));
}
void RemoteView::handle_replay_thread_done(uint32_t return_code) {
void RemoteAppView::handle_replay_thread_done(uint32_t return_code) {
if (return_code == ReplayThread::END_OF_FILE) {
if (check_loop.value() && current_btn_) {
send_button(*current_btn_);
@@ -598,15 +597,15 @@ void RemoteView::handle_replay_thread_done(uint32_t return_code) {
stop();
}
void RemoteView::set_remote_path(fs::path&& path) {
void RemoteAppView::set_remote_path(fs::path&& path) {
// Unfortunately, have to keep these two in sync because
// settings doesn't know about fs::path.
remote_path_ = std::move(path);
settings_.remote_path = remote_path_.string();
}
void RemoteView::show_error(const std::string& msg) const {
void RemoteAppView::show_error(const std::string& msg) const {
nav_.display_modal("Error", msg);
}
} /* namespace ui */
} // namespace ui::external_app::remote
@@ -41,7 +41,7 @@
#include <string_view>
#include <vector>
namespace ui {
namespace ui::external_app::remote {
/* Maps icon index to bitmap. */
class RemoteIcons {
@@ -257,14 +257,14 @@ class RemoteEntryEditView : public View {
};
/* App that allows for buttons to be bound to captures for playback. */
class RemoteView : public View {
class RemoteAppView : public View {
public:
RemoteView(NavigationView& nav);
RemoteView(NavigationView& nav, std::filesystem::path path);
~RemoteView();
RemoteAppView(NavigationView& nav);
RemoteAppView(NavigationView& nav, std::filesystem::path path);
~RemoteAppView();
RemoteView(const RemoteView&) = delete;
RemoteView& operator=(const RemoteView&) = delete;
RemoteAppView(const RemoteAppView&) = delete;
RemoteAppView& operator=(const RemoteAppView&) = delete;
std::string title() const override { return "Remote"; };
void focus() override;
@@ -385,4 +385,4 @@ class RemoteView : public View {
}};
};
} /* namespace ui */
} // namespace ui::external_app::remote
+13 -10
View File
@@ -16,12 +16,13 @@ void initialize_app(NavigationView& nav) {
extern "C" {
__attribute__((section(".external_app.app_shoppingcart_lock.application_information"), used)) application_information_t _application_information_shoppingcart_lock = {
(uint8_t*)0x00000000,
ui::external_app::shoppingcart_lock::initialize_app,
CURRENT_HEADER_VERSION,
VERSION_MD5,
"Cart Lock",
{
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::shoppingcart_lock::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Cart Lock",
/*.bitmap_data = */ {
0x00,
0x00,
0x00,
@@ -55,9 +56,11 @@ __attribute__((section(".external_app.app_shoppingcart_lock.application_informat
0x7E,
0x00,
},
ui::Color::red().v,
app_location_t::UTILITIES,
{'P', 'A', 'T', 'X'},
0x00000000,
/*.icon_color = */ ui::Color::red().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'A', 'T', 'X'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_spainter.application_information"), us
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_spainter */ {'P', 'S', 'P', 'T'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_sstvtx.application_information"), used
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::TX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_sstvtx */ {'P', 'S', 'T', 'X'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_tetris.application_information"), used
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_tpmsrx.application_information"), used
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_tpms */ {'P', 'T', 'P', 'M'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -75,6 +75,7 @@ __attribute__((section(".external_app.app_wardrivemap.application_information"),
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
+1
View File
@@ -48,3 +48,4 @@ const std::filesystem::path splash_dir = u"SPLASH";
const std::filesystem::path sstv_dir = u"SSTV";
const std::filesystem::path wav_dir = u"WAV";
const std::filesystem::path whipcalc_dir = u"WHIPCALC";
const std::filesystem::path ook_editor_dir = u"OOKFILES";
+1
View File
@@ -50,5 +50,6 @@ extern const std::filesystem::path splash_dir;
extern const std::filesystem::path sstv_dir;
extern const std::filesystem::path wav_dir;
extern const std::filesystem::path whipcalc_dir;
extern const std::filesystem::path ook_editor_dir;
#endif /* __FILE_PATH_H__ */
+127 -31
View File
@@ -29,15 +29,16 @@
namespace fs = std::filesystem;
using namespace std::literals;
const std::string_view filetype_name = "Filetype"sv;
const std::string_view frequency_name = "Frequency"sv;
const std::string_view latitude_name_old = "Latitute"sv;
const std::string_view longitude_name_old = "Longitude"sv;
const std::string_view latitude_name = "Lat"sv;
const std::string_view longitude_name = "Lon"sv;
const std::string_view protocol_name = "Protocol"sv;
const std::string_view preset_name = "Preset"sv;
const std::string_view te_name = "TE"sv; // only in BinRAW
const std::string filetype_name = "Filetype";
const std::string frequency_name = "Frequency";
const std::string latitude_name_old = "Latitute";
const std::string longitude_name_old = "Longitude";
const std::string latitude_name = "Lat";
const std::string longitude_name = "Lon";
const std::string protocol_name = "Protocol";
const std::string preset_name = "Preset";
const std::string te_name = "TE"; // only in BinRAW
const std::string bit_count_name = "Bit"; // for us, only in BinRAW
/*
Filetype: Flipper SubGhz Key File
@@ -72,39 +73,54 @@ raw_data- positive: carrier for n time, negative: no carrier for n time. (us)
Optional<flippersub_metadata> read_flippersub_file(const fs::path& path) {
File f;
auto error = f.open(path);
if (error)
return {};
flippersub_metadata metadata{};
auto reader = FileLineReader(f);
for (const auto& line : reader) {
auto cols = split_string(line, ':');
if (cols.size() != 2)
char ch = 0;
std::string line = "";
auto fr = f.read(&ch, 1);
while (!fr.is_error() && fr.value() > 0) {
if (line.length() < 130 && ch != '\n') line += ch;
if (ch != '\n') {
fr = f.read(&ch, 1);
continue;
}
auto it = line.find(':', 0);
if (it == std::string::npos) {
fr = f.read(&ch, 1);
continue; // Bad line.
if (cols[1].length() <= 1) continue;
std::string fixed = cols[1].data() + 1;
}
std::string fixed = line.data() + it + 1;
fixed = trim(fixed);
if (cols[0] == filetype_name) {
std::string head = line.substr(0, it);
line = "";
if (fixed.length() <= 1) {
fr = f.read(&ch, 1);
continue;
}
if (head == filetype_name) {
if (fixed != "Flipper SubGhz Key File" && fixed != "Flipper SubGhz RAW File") return {}; // not supported
} else if (cols[0] == frequency_name)
} else if (head == frequency_name)
parse_int(fixed, metadata.center_frequency);
else if (cols[0] == latitude_name)
else if (head == latitude_name)
parse_float_meta(fixed, metadata.latitude);
else if (cols[0] == longitude_name)
else if (head == longitude_name)
parse_float_meta(fixed, metadata.longitude);
else if (cols[0] == latitude_name_old)
else if (head == latitude_name_old)
parse_float_meta(fixed, metadata.latitude);
else if (cols[0] == longitude_name_old)
else if (head == longitude_name_old)
parse_float_meta(fixed, metadata.longitude);
else if (cols[0] == protocol_name) {
else if (head == protocol_name) {
if (fixed == "RAW") metadata.protocol = FLIPPER_PROTO_RAW;
if (fixed == "BinRAW") metadata.protocol = FLIPPER_PROTO_BINRAW;
} else if (cols[0] == te_name) {
} else if (head == te_name) {
metadata.te = atoi(fixed.c_str());
} else if (cols[0] == preset_name) {
} else if (head == bit_count_name) {
metadata.binraw_bit_count = atol(fixed.c_str());
} else if (head == preset_name) {
if (fixed.find("FSK") != std::string::npos) {
metadata.preset = FLIPPER_PRESET_2FSK;
} else if (fixed.find("Ook") != std::string::npos) {
@@ -112,12 +128,92 @@ Optional<flippersub_metadata> read_flippersub_file(const fs::path& path) {
} else if (fixed.find("Custom") != std::string::npos) {
metadata.preset = FLIPPER_PRESET_CUSTOM;
}
} else
continue;
}
fr = f.read(&ch, 1);
}
f.close();
if (metadata.center_frequency == 0) return {}; // Parse failed.
return metadata;
}
bool seek_flipper_raw_first_data(File& f) {
f.seek(0);
std::string chs = "";
char ch;
while (f.read(&ch, 1)) {
if (ch == '\r') continue;
if (ch == '\n') {
chs = "";
continue;
};
chs += ch;
if (ch == 0) break;
if (chs == "RAW_Data: ") {
return true;
}
}
return false;
}
bool seek_flipper_binraw_first_data(File& f, bool seekzero) {
if (seekzero) f.seek(0);
std::string chs = "";
char ch;
while (f.read(&ch, 1)) {
if (ch == '\r') continue;
if (ch == '\n') {
chs = "";
continue;
};
if (ch == 0) break;
chs += ch;
if (chs == "Data_RAW: ") {
return true;
}
}
return false;
}
Optional<int32_t> read_flipper_raw_next_data(File& f) {
// RAW_Data: 5832 -12188 130 -162
std::string chs = "";
char ch = 0;
while (f.read(&ch, 1).is_ok()) {
if (ch == '\r') continue; // should not present
if ((ch == ' ') || ch == '\n') {
if (chs == "RAW_Data:") {
chs = "";
continue;
}
break;
};
if (ch == 0) break;
chs += ch;
}
if (chs == "") return {};
return atol(chs.c_str());
}
Optional<uint8_t> read_flipper_binraw_next_data(File& f) {
// Data_RAW: 02 10 84 BUT THERE ARE Bit_RAW lines to skip!
std::string chs = "";
char ch = 0;
while (f.read(&ch, 1)) {
if (ch == '\r') continue; // should not present
if ((ch == ' ') || ch == '\n') {
if (chs == "RAW_Data:") {
chs = "";
continue;
}
break;
};
if (ch == 0) break;
chs += ch;
}
if (chs == "") return {};
return static_cast<uint8_t>(std::stoul(chs, nullptr, 16));
}
bool get_flipper_binraw_bitvalue(uint8_t byte, uint8_t nthBit) {
return (byte & (1 << nthBit)) != 0;
}
+6
View File
@@ -44,9 +44,15 @@ struct flippersub_metadata {
FlipperProto protocol = FLIPPER_PROTO_UNSUPPORTED;
FlipperPreset preset = FLIPPER_PRESET_UNK;
uint16_t te = 0;
uint32_t binraw_bit_count = 0;
};
Optional<flippersub_metadata> read_flippersub_file(const std::filesystem::path& path);
bool seek_flipper_raw_first_data(File& f);
bool seek_flipper_binraw_first_data(File& f, bool seekzero = true);
Optional<int32_t> read_flipper_raw_next_data(File& f);
Optional<uint8_t> read_flipper_binraw_next_data(File& f);
bool get_flipper_binraw_bitvalue(uint8_t byte, uint8_t nthBit);
// Maybe sometime there will be a data part reader / converter
+5 -2
View File
@@ -28,8 +28,11 @@
using option_t = ui::OptionsField::option_t;
using options_t = ui::OptionsField::options_t;
extern options_t freqman_steps;
extern const option_t* find_by_index(const options_t& options, freqman_index_t index);
using option_db_t = std::pair<std::string_view, int32_t>;
using options_db_t = std::vector<option_db_t>;
extern options_db_t freqman_steps;
extern const option_db_t* find_by_index(const options_db_t& options, freqman_index_t index);
/* Option value lookup. */
int32_t freqman_entry_get_step_value(freqman_index_t step) {
+5 -5
View File
@@ -41,7 +41,7 @@ namespace fs = std::filesystem;
const std::filesystem::path freqman_extension{u".TXT"};
// NB: Don't include UI headers to keep this code unit testable.
using option_t = std::pair<std::string, int32_t>;
using option_t = std::pair<std::string_view, int32_t>;
using options_t = std::vector<option_t>;
options_t freqman_modulations = {
@@ -194,27 +194,27 @@ bool operator==(const freqman_entry& lhs, const freqman_entry& rhs) {
std::string freqman_entry_get_modulation_string(freqman_index_t modulation) {
if (auto opt = find_by_index(freqman_modulations, modulation))
return opt->first;
return (std::string)opt->first;
return {};
}
std::string freqman_entry_get_bandwidth_string(freqman_index_t modulation, freqman_index_t bandwidth) {
if (modulation < freqman_modulations.size()) {
if (auto opt = find_by_index(freqman_bandwidths[modulation], bandwidth))
return opt->first;
return (std::string)opt->first;
}
return {};
}
std::string freqman_entry_get_step_string(freqman_index_t step) {
if (auto opt = find_by_index(freqman_steps, step))
return opt->first;
return (std::string)opt->first;
return {};
}
std::string freqman_entry_get_step_string_short(freqman_index_t step) {
if (auto opt = find_by_index(freqman_steps_short, step))
return opt->first;
return (std::string)opt->first;
return {};
}
+158
View File
@@ -0,0 +1,158 @@
/*
* Copyright (C) 2024 gullradriel
*
* 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 "ook_file.hpp"
using namespace portapack;
namespace fs = std::filesystem;
/*
struct of an OOK file:
Frequency SampleRate SymbolRate Repeat PauseSymbolDuration Payload
-Frequency is in hertz
-SampleRate is one of 250k, 1M, 2M, 5M , 10M ,20M
-SymbolRate is the number of symbols /s
-Repeat is the number of times we will repeat the payload
-PauseSymbolDuration is the duration of the pause between repeat, in usec
-Payload is the payload in form of a string of 0 and 1
*/
bool read_ook_file(const std::filesystem::path& path, ook_file_data& ook_data) {
File data_file;
auto open_result = data_file.open(path);
if (open_result) {
return false;
}
FileLineReader reader(data_file);
for (const auto& line : reader) {
// Split the line into segments to extract each value
size_t first_space = line.find(' ');
size_t second_space = line.find(' ', first_space + 1);
size_t third_space = line.find(' ', second_space + 1);
size_t fourth_space = line.find(' ', third_space + 1);
size_t fifth_space = line.find(' ', fourth_space + 1);
// Extract each component of the line
std::string frequency_str = line.substr(0, first_space);
std::string sample_rate_str = line.substr(first_space + 1, second_space - first_space - 1);
std::string symbol_rate_str = line.substr(second_space + 1, third_space - second_space - 1);
std::string repeat_str = line.substr(third_space + 1, fourth_space - third_space - 1);
std::string pause_symbol_duration_str = line.substr(fourth_space + 1, fifth_space - fourth_space - 1);
std::string payload_data = line.substr(fifth_space + 1); // Extract binary payload as final value
// Convert and assign frequency
ook_data.frequency = std::stoull(frequency_str);
// Convert and assign symbol_rate
ook_data.symbol_rate = static_cast<unsigned int>(atoi(symbol_rate_str.c_str()));
// Convert and assign repeat count
ook_data.repeat = static_cast<unsigned int>(atoi(repeat_str.c_str()));
// Convert and assign pause_symbol_duration
ook_data.pause_symbol_duration = static_cast<unsigned int>(atoi(pause_symbol_duration_str.c_str()));
// Select sample rate based on value read from file
if (sample_rate_str == "250k") {
ook_data.sample_rate = 250000U;
} else if (sample_rate_str == "1M") {
ook_data.sample_rate = 1000000U;
} else if (sample_rate_str == "2M") {
ook_data.sample_rate = 2000000U;
} else if (sample_rate_str == "5M") {
ook_data.sample_rate = 5000000U;
} else if (sample_rate_str == "10M") {
ook_data.sample_rate = 10000000U;
} else if (sample_rate_str == "20M") {
ook_data.sample_rate = 20000000U;
} else {
return false;
}
// Update payload with binary data
ook_data.payload = std::move(payload_data);
// Process only the first line
break;
}
return true;
}
bool save_ook_file(ook_file_data& ook_data, const std::filesystem::path& path) {
// delete file if it exists
delete_file(path);
// Attempt to open, if it can't be opened. Create new.
auto src = std::make_unique<File>();
auto error = src->open(path, false, true);
if (error) {
return false;
}
std::string sample_rate_str;
if (ook_data.sample_rate == 250000U) {
sample_rate_str = "250k";
} else if (ook_data.sample_rate == 1000000U) {
sample_rate_str = "1M";
} else if (ook_data.sample_rate == 2000000U) {
sample_rate_str = "2M";
} else if (ook_data.sample_rate == 5000000U) {
sample_rate_str = "5M";
} else if (ook_data.sample_rate == 10000000U) {
sample_rate_str = "10M";
} else if (ook_data.sample_rate == 20000000U) {
sample_rate_str = "20M";
} else {
return false;
}
// write informations
src->write_line(to_string_dec_uint(ook_data.frequency) + " " +
sample_rate_str + " " +
to_string_dec_uint(ook_data.symbol_rate) + " " +
to_string_dec_uint(ook_data.repeat) + " " +
to_string_dec_uint(ook_data.pause_symbol_duration) + " " +
ook_data.payload);
// Close files
src.reset();
return true;
}
void start_ook_file_tx(ook_file_data& ook_data) {
size_t bitstream_length = encoders::make_bitstream(const_cast<std::string&>(ook_data.payload)); // Convert the message into a bitstream
transmitter_model.set_target_frequency(ook_data.frequency); // Set target frequency
transmitter_model.set_sampling_rate(ook_data.sample_rate); // Set the OOK sampling rate
transmitter_model.set_baseband_bandwidth(1750000); // Set the baseband bandwidth
transmitter_model.enable(); // Enable the transmitter
// Configure OOK data and transmission characteristics
baseband::set_ook_data(
bitstream_length, // Length of the bitstream to transmit
ook_data.sample_rate / ook_data.symbol_rate, // Calculate symbol period based on repetition rate
ook_data.repeat, // Set the number of times the whole bitstream is repeated
ook_data.pause_symbol_duration // Set the pause_symbol between reps
);
}
void stop_ook_file_tx() {
transmitter_model.disable(); // Disable the transmitter
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 gullradriel
*
* 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 __OOK_FILE_HPP__
#define __OOK_FILE_HPP__
#include "portapack.hpp"
#include "metadata_file.hpp"
#include "encoders.hpp" // Includes data encoding functions for transmission
#include "convert.hpp"
#include "file_reader.hpp"
#include "string_format.hpp"
#include <string_view>
#include "transmitter_model.hpp"
#include "baseband_api.hpp" // Includes baseband API for handling transmission settings
struct ook_file_data {
rf::Frequency frequency = rf::Frequency(0); // Default frequency
uint32_t sample_rate = 0; // Default sample rate
uint16_t symbol_rate = 0; // Default bit duration
uint16_t pause_symbol_duration = 0; // Default pause between repeat
uint16_t repeat = 0; // Default repeat
std::string payload = ""; // Default payload
};
bool read_ook_file(const std::filesystem::path& path, ook_file_data& ook_data);
bool save_ook_file(ook_file_data& data, const std::filesystem::path& path);
void start_ook_file_tx(ook_file_data& ook_data);
void stop_ook_file_tx();
#endif // __FLIPPER_SUBFILE_HPP__
+1 -1
View File
@@ -96,7 +96,7 @@ float tone_key_frequency(tone_index index) {
std::string tone_key_string(tone_index index) {
if (index < 0 || (unsigned)index >= tone_keys.size())
return std::string("");
return tone_keys[index].first;
return (std::string)tone_keys[index].first;
}
// Return string showing frequency only from specific table index
+2 -1
View File
@@ -26,6 +26,7 @@
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace tonekey {
@@ -35,7 +36,7 @@ namespace tonekey {
#define F2Ix100(x) (int32_t)(x * 100.0 + 0.5) // add 0.5f to round vs truncate during FP->int conversion
using tone_index = int32_t;
using tone_key_t = std::vector<std::pair<std::string, uint32_t>>;
using tone_key_t = std::vector<std::pair<std::string_view, uint32_t>>;
extern const tone_key_t tone_keys;
+15 -9
View File
@@ -118,30 +118,36 @@ void BtnGridView::clear() {
menu_item_views.clear();
}
void BtnGridView::add_items(std::initializer_list<GridItem> new_items) {
void BtnGridView::add_items(std::initializer_list<GridItem> new_items, bool inhibit_update) {
for (auto item : new_items) {
if (!blacklisted_app(item))
menu_items.push_back(item);
}
update_items();
}
void BtnGridView::add_item(GridItem new_item) {
if (!blacklisted_app(new_item)) {
menu_items.push_back(new_item);
if (!inhibit_update) {
update_items();
}
}
void BtnGridView::insert_item(GridItem new_item, uint8_t position) {
void BtnGridView::add_item(const GridItem& new_item, bool inhibit_update) {
if (!blacklisted_app(new_item)) {
menu_items.push_back(new_item);
if (!inhibit_update) {
update_items();
}
}
}
void BtnGridView::insert_item(const GridItem& new_item, size_t position, bool inhibit_update) {
if (!blacklisted_app(new_item)) {
if (position < menu_items.size()) {
auto pos_iter = menu_items.begin() + position;
menu_items.insert(pos_iter, new_item);
update_items();
} else {
menu_items.push_back(new_item);
}
if (!inhibit_update) {
update_items();
}
}
+5 -4
View File
@@ -59,9 +59,9 @@ class BtnGridView : public View {
~BtnGridView();
void add_items(std::initializer_list<GridItem> new_items);
void add_item(GridItem new_item);
void insert_item(GridItem new_item, uint8_t position);
void add_items(std::initializer_list<GridItem> new_items, bool inhibit_update = false);
void add_item(const GridItem& new_item, bool inhibit_update = false);
void insert_item(const GridItem& new_item, size_t position, bool inhibit_update = false);
void set_max_rows(int rows);
int rows();
void clear();
@@ -81,12 +81,13 @@ class BtnGridView : public View {
bool on_encoder(const EncoderEvent event) override;
bool blacklisted_app(GridItem new_item);
void update_items();
protected:
virtual void on_populate() = 0;
private:
int rows_{3};
void update_items();
void on_tick_second();
bool keep_highlight{false};
+1 -1
View File
@@ -34,7 +34,7 @@ void tone_keys_populate(OptionsField& field) {
for (size_t c = 0; c < tone_keys.size(); c++) {
auto f = tone_keys[c].second;
if ((c != 0) && (f < 1000 * 100))
tone_name = "CTCSS " + fx100_string(f) + " #" + tone_keys[c].first;
tone_name = "CTCSS " + fx100_string(f) + " #" + (std::string)tone_keys[c].first;
else
tone_name = tone_keys[c].first;
@@ -97,10 +97,10 @@ namespace ui {
}
}
/* static */ std::vector<GridItem> ExternalItemsMenuLoader::load_external_items(app_location_t app_location, NavigationView& nav) {
/* static */ std::vector<ExternalItemsMenuLoader::GridItemEx> ExternalItemsMenuLoader::load_external_items(app_location_t app_location, NavigationView& nav) {
bitmaps.clear();
std::vector<GridItem> external_apps;
std::vector<GridItemEx> external_apps;
auto dev = (i2cdev::I2cDev_PPmod*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDECMDL_PPMOD);
@@ -121,7 +121,7 @@ namespace ui {
if (appInfo->header_version > CURRENT_STANDALONE_APPLICATION_API_VERSION)
continue;
GridItem gridItem = {};
GridItemEx gridItem = {};
gridItem.text = reinterpret_cast<char*>(&appInfo->app_name[0]);
gridItem.color = Color((uint16_t)appInfo->icon_color);
@@ -150,6 +150,8 @@ namespace ui {
nav.display_modal("Error", "Unable to download app.");
};
gridItem.desired_position = -1; // TODO: Where should we put the module's app icon? First? Last? Also configurable?
external_apps.push_back(gridItem);
}
}
@@ -180,7 +182,7 @@ namespace ui {
bool versionMatches = VERSION_MD5 == application_information.app_version;
GridItem gridItem = {};
GridItemEx gridItem = {};
gridItem.text = reinterpret_cast<char*>(&application_information.app_name[0]);
if (versionMatches) {
@@ -195,6 +197,8 @@ namespace ui {
nav.display_modal("Error", "The .ppma file in your " + apps_dir.string() + "\nfolder can't be read. Please\nupdate your SD Card content.");
}
};
gridItem.desired_position = application_information.desired_menu_position;
} else {
gridItem.color = Theme::getInstance()->fg_light->foreground;
@@ -203,6 +207,8 @@ namespace ui {
gridItem.on_select = [&nav]() {
nav.display_modal("Error", "The .ppma file in your " + apps_dir.string() + "\nfolder is outdated. Please\nupdate your SD Card content.");
};
gridItem.desired_position = application_information.desired_menu_position;
}
external_apps.push_back(gridItem);
@@ -228,7 +234,7 @@ namespace ui {
if (application_information.header_version > CURRENT_STANDALONE_APPLICATION_API_VERSION)
continue;
GridItem gridItem = {};
GridItemEx gridItem = {};
gridItem.text = reinterpret_cast<char*>(&application_information.app_name[0]);
gridItem.color = Color((uint16_t)application_information.icon_color);
@@ -243,6 +249,8 @@ namespace ui {
}
};
gridItem.desired_position = -1; // No desired position support for standalone apps yet
external_apps.push_back(gridItem);
}
@@ -55,7 +55,11 @@ class DynamicBitmap {
class ExternalItemsMenuLoader {
public:
static std::vector<GridItem> load_external_items(app_location_t, NavigationView&);
struct GridItemEx : GridItem {
int32_t desired_position;
};
static std::vector<GridItemEx> load_external_items(app_location_t, NavigationView&);
ExternalItemsMenuLoader() = delete;
static bool run_external_app(ui::NavigationView&, std::filesystem::path);
static bool run_standalone_app(ui::NavigationView&, std::filesystem::path);
+40 -21
View File
@@ -52,7 +52,6 @@
#include "ui_pocsag_tx.hpp"
#include "ui_rds.hpp"
#include "ui_recon.hpp"
#include "ui_remote.hpp"
#include "ui_scanner.hpp"
#include "ui_sd_over_usb.hpp"
#include "ui_sd_wipe.hpp"
@@ -126,7 +125,6 @@ const NavigationView::AppList NavigationView::appList = {
{nullptr, "Transmit", HOME, Color::cyan(), &bitmap_icon_transmit, new ViewFactory<TransmittersMenuView>()},
{"capture", "Capture", HOME, Color::red(), &bitmap_icon_capture, new ViewFactory<CaptureAppView>()},
{"replay", "Replay", HOME, Color::green(), &bitmap_icon_replay, new ViewFactory<PlaylistView>()},
{"remote", "Remote", HOME, ui::Color::green(), &bitmap_icon_remote, new ViewFactory<RemoteView>()},
{"scanner", "Scanner", HOME, Color::green(), &bitmap_icon_scanner, new ViewFactory<ScannerView>()},
{"microphone", "Microphone", HOME, Color::green(), &bitmap_icon_microphone, new ViewFactory<MicTXView>()},
{"lookingglass", "Looking Glass", HOME, Color::green(), &bitmap_icon_looking, new ViewFactory<GlassView>()},
@@ -754,13 +752,16 @@ static void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc)
grid.add_item({app.displayName, app.iconColor, app.icon,
[&nav, &app]() {
i2cdev::I2CDevManager::set_autoscan_interval(0); //if i navigate away from any menu, turn off autoscan
nav.push_view(std::unique_ptr<View>(app.viewFactory->produce(nav))); }});
nav.push_view(std::unique_ptr<View>(app.viewFactory->produce(nav))); }},
true);
}
};
grid.update_items();
}
// clang-format off
void addExternalItems(NavigationView& nav, app_location_t location, BtnGridView& grid) {
void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t notice_pos) {
auto externalItems = ExternalItemsMenuLoader::load_external_items(location, nav);
if (externalItems.empty()) {
grid.insert_item({"Notice!",
@@ -773,11 +774,23 @@ void addExternalItems(NavigationView& nav, app_location_t location, BtnGridView&
"see Mayhem wiki and copy apps\n"
"to " + apps_dir.string() + " folder of SD card.");
}},
pmem::show_gui_return_icon() ? 1 : 0);
notice_pos);
} else {
std::sort(externalItems.begin(), externalItems.end(), [](const auto &a, const auto &b)
{
return a.desired_position < b.desired_position;
});
for (auto const& gridItem : externalItems) {
grid.add_item(gridItem);
if (gridItem.desired_position < 0) {
grid.add_item(gridItem, true);
} else {
grid.insert_item(gridItem, gridItem.desired_position, true);
}
}
grid.update_items();
}
}
// clang-format on
@@ -788,13 +801,14 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav)
: nav_(nav) {}
void ReceiversMenuView::on_populate() {
if (pmem::show_gui_return_icon()) {
bool return_icon = pmem::show_gui_return_icon();
if (return_icon) {
add_item({"..", Theme::getInstance()->fg_light->foreground, &bitmap_icon_previous, [this]() { nav_.pop(); }});
}
add_apps(nav_, *this, RX);
addExternalItems(nav_, app_location_t::RX, *this);
add_external_items(nav_, app_location_t::RX, *this, return_icon ? 1 : 0);
}
/* TransmittersMenuView **************************************************/
@@ -803,13 +817,14 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav)
: nav_(nav) {}
void TransmittersMenuView::on_populate() {
if (pmem::show_gui_return_icon()) {
bool return_icon = pmem::show_gui_return_icon();
if (return_icon) {
add_items({{"..", Theme::getInstance()->fg_light->foreground, &bitmap_icon_previous, [this]() { nav_.pop(); }}});
}
add_apps(nav_, *this, TX);
addExternalItems(nav_, app_location_t::TX, *this);
add_external_items(nav_, app_location_t::TX, *this, return_icon ? 1 : 0);
}
/* UtilitiesMenuView *****************************************************/
@@ -820,13 +835,14 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav)
}
void UtilitiesMenuView::on_populate() {
if (pmem::show_gui_return_icon()) {
bool return_icon = pmem::show_gui_return_icon();
if (return_icon) {
add_items({{"..", Theme::getInstance()->fg_light->foreground, &bitmap_icon_previous, [this]() { nav_.pop(); }}});
}
add_apps(nav_, *this, UTILITIES);
addExternalItems(nav_, app_location_t::UTILITIES, *this);
add_external_items(nav_, app_location_t::UTILITIES, *this, return_icon ? 1 : 0);
}
/* SystemMenuView ********************************************************/
@@ -851,6 +867,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav)
void SystemMenuView::on_populate() {
add_apps(nav_, *this, HOME);
add_external_items(nav_, app_location_t::HOME, *this, 2);
add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }});
}
@@ -902,7 +919,7 @@ SystemView::SystemView(
navigation_view.push<SystemMenuView>();
if (pmem::config_splash()) {
navigation_view.push<BMPView>();
navigation_view.push<SplashScreenView>();
}
status_view.set_back_enabled(false);
status_view.set_title_image_enabled(true);
@@ -971,11 +988,11 @@ void SystemView::set_app_fullscreen(bool fullscreen) {
/* ***********************************************************************/
void BMPView::focus() {
void SplashScreenView::focus() {
button_done.focus();
}
BMPView::BMPView(NavigationView& nav)
SplashScreenView::SplashScreenView(NavigationView& nav)
: nav_(nav) {
add_children({&button_done});
@@ -984,12 +1001,14 @@ BMPView::BMPView(NavigationView& nav)
};
}
void BMPView::paint(Painter&) {
if (!portapack::display.drawBMP2({0, 0}, splash_dot_bmp))
portapack::display.drawBMP({0, 16}, splash_bmp, (const uint8_t[]){0x29, 0x18, 0x16});
void SplashScreenView::paint(Painter&) {
if (!portapack::display.draw_bmp_from_sdcard_file({0, 0}, splash_dot_bmp))
// ^ try draw bmp file from sdcard at (0,0), and the (0,0) already bypassed the status bar, so actual pos is (0, STATUS_BAR_HEIGHT)
portapack::display.draw_bmp_from_bmp_hex_arr({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, (const uint8_t[]){0x29, 0x18, 0x16});
// ^ draw BMP HEX arr in firmware, note that the BMP HEX arr only cover the image part (instead of fill the screen with background, this position is located it in the center)
}
bool BMPView::on_touch(const TouchEvent event) {
bool SplashScreenView::on_touch(const TouchEvent event) {
/* the event thing were resolved by HTotoo, talked here https://discord.com/channels/719669764804444213/956561375155589192/1287756910950486027
* the touch screen policy can be better, talked here https://discord.com/channels/719669764804444213/956561375155589192/1198926225897443328
* this workaround discussed here: https://discord.com/channels/719669764804444213/1170738202924044338/1295630640158478418
@@ -1011,7 +1030,7 @@ bool BMPView::on_touch(const TouchEvent event) {
return false;
}
void BMPView::handle_pop() {
void SplashScreenView::handle_pop() {
if (nav_.is_valid()) {
nav_.pop();
}
@@ -1080,7 +1099,7 @@ ModalMessageView::ModalMessageView(
}
void ModalMessageView::paint(Painter& painter) {
if (!compact) portapack::display.drawBMP({100, 48}, modal_warning_bmp, (const uint8_t[]){0, 0, 0});
if (!compact) portapack::display.draw_bmp_from_bmp_hex_arr({100, 48}, modal_warning_bmp, (const uint8_t[]){0, 0, 0});
// Break lines.
auto lines = split_string(message_, '\n');
+2 -2
View File
@@ -332,9 +332,9 @@ class InformationView : public View {
{86, 0, 19 * 8, 16}};
};
class BMPView : public View {
class SplashScreenView : public View {
public:
BMPView(NavigationView& nav);
SplashScreenView(NavigationView& nav);
void paint(Painter&) override;
void focus() override;
+1 -1
View File
@@ -138,7 +138,7 @@ bool strEndsWith(const std::u16string& str, const std::u16string& suffix) {
static void cmd_flash(BaseSequentialStream* chp, int argc, char* argv[]) {
if (argc != 1) {
chprintf(chp, "Usage: flash /FIRMWARE/portapack-h1_h2-mayhem.bin\r\n");
chprintf(chp, "Usage: flash /FIRMWARE/portapack-mayhem-firmware.bin\r\n");
return;
}
+8
View File
@@ -656,6 +656,14 @@ set(MODE_CPPSRC
)
DeclareTargets(PADT adsbtx)
### OOKStream
set(MODE_CPPSRC
proc_ook_stream_tx.cpp
)
DeclareTargets(POSK ookstream)
### HackRF "factory" firmware
+127
View File
@@ -0,0 +1,127 @@
/*
* 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 "proc_ook_stream_tx.hpp"
#include "sine_table_int8.hpp"
#include "portapack_shared_memory.hpp"
#include "event_m4.hpp"
#include "utility.hpp"
OOKProcessorStreamed::OOKProcessorStreamed() {
configured = false;
baseband_thread.start();
}
inline void OOKProcessorStreamed::write_sample(const buffer_c8_t& buffer, bool bit_value, size_t i) {
int8_t re, im;
if (bit_value) {
phase = (phase + 200); // What ?
sphase = phase + (64 << 18);
re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]);
im = (sine_table_i8[(phase & 0x03FC0000) >> 18]);
} else {
re = 0;
im = 0;
}
buffer.p[i] = {re, im};
}
void OOKProcessorStreamed::execute(const buffer_c8_t& buffer) {
if (!configured || !stream) return;
for (size_t i = 0; i < buffer.count; i++) {
if (rem_samples <= curr_samples) {
// get a new sample from stream
int32_t sample = -13346;
rem_samples = 0; // reset my pointer
curr_samples = 0;
size_t readed = 0;
if (configured) readed = stream->read(&sample, 4); // read from stream // todo htotoo error handling?!
if (readed == 0) {
txprogress_message.progress = -10;
shared_memory.application_queue.push(txprogress_message); // debug
} else {
if (sample == endsignals[readerrs + 1]) { // if no more samples, stop
readerrs++;
if (readerrs == 2) {
configured = false;
txprogress_message.done = true;
txprogress_message.progress = 100;
curr_hilow = false;
shared_memory.application_queue.push(txprogress_message);
}
} else {
if (sample < 0) {
rem_samples = OOK_SAMPLERATE * ((-1 * sample) / 1000000.0);
curr_hilow = false;
} else {
rem_samples = OOK_SAMPLERATE * (sample / 1000000.0);
curr_hilow = true;
}
}
}
}
++curr_samples;
write_sample(buffer, curr_hilow, i);
}
}
void OOKProcessorStreamed::on_message(const Message* const message) {
switch (message->id) {
case Message::ID::ReplayConfig:
configured = false;
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
break;
case Message::ID::FIFOData:
configured = true;
txprogress_message.progress = -4;
shared_memory.application_queue.push(txprogress_message);
break;
default:
break;
}
}
void OOKProcessorStreamed::replay_config(const ReplayConfigMessage& message) {
if (message.config) {
txprogress_message.progress = -2;
shared_memory.application_queue.push(txprogress_message);
stream = std::make_unique<StreamOutput>(message.config);
// Tell application that the buffers and FIFO pointers are ready, prefill
RequestSignalMessage sig_message{RequestSignalMessage::Signal::FillRequest};
shared_memory.application_queue.push(sig_message);
} else {
txprogress_message.progress = -3;
shared_memory.application_queue.push(txprogress_message);
stream.reset();
}
}
int main() {
EventDispatcher event_dispatcher{std::make_unique<OOKProcessorStreamed>()};
event_dispatcher.run();
return 0;
}
+65
View File
@@ -0,0 +1,65 @@
/*
* 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.
*/
/*
For usage check the FlipperTX app. Don't forget to "close" the tx by sending 42069, 613379 values at the end of the stream.
Only close baseband when you get the TX done msg, not on replay thread done, because, there can still data in the buffer.
*/
#ifndef __PROC_OOKSTREAMTX_HPP__
#define __PROC_OOKSTREAMTX_HPP__
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#include "stream_output.hpp"
#include <array>
#include <memory>
#define OOK_SAMPLERATE 2280000U
class OOKProcessorStreamed : public BasebandProcessor {
public:
OOKProcessorStreamed();
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const message) override;
private:
uint32_t rem_samples = 0;
uint32_t curr_samples = 0;
bool curr_hilow = false;
uint32_t phase{0}, sphase{0};
void write_sample(const buffer_c8_t& buffer, bool bit_value, size_t i);
std::unique_ptr<StreamOutput> stream{};
bool configured{false};
void replay_config(const ReplayConfigMessage& message);
int32_t endsignals[3] = {0, 42069, 613379}; // 0 is skipped, count from 1, don't ask...
uint8_t readerrs = 0; // to count in the array
TXProgressMessage txprogress_message{};
/* NB: Threads should be the last members in the class definition. */
BasebandThread baseband_thread{OOK_SAMPLERATE, this, baseband::Direction::Transmit};
};
#endif /*__PROC_OOKSTREAMTX_HPP__*/
+2 -1
View File
@@ -27,7 +27,7 @@
#include "spi_image.hpp"
#include "standalone_app.hpp"
#define CURRENT_HEADER_VERSION 0x00000002
#define CURRENT_HEADER_VERSION 0x00000003
#define MIN_HEADER_VERSION_FOR_CHECKSUM 0x00000002
typedef void (*externalAppEntry_t)(ui::NavigationView& nav);
@@ -42,6 +42,7 @@ struct application_information_t {
uint8_t bitmap_data[32];
uint32_t icon_color;
app_location_t menu_location;
int32_t desired_menu_position;
portapack::spi_flash::image_tag_t m4_app_tag;
uint32_t m4_app_offset;
+6 -13
View File
@@ -202,16 +202,14 @@ bool I2cDev_MAX17055::init(uint8_t addr_) {
model = I2CDEVMDL_MAX17055;
query_interval = BATTERY_WIDGET_REFRESH_INTERVAL;
if (detect()) {
bool return_status = true;
if (needsInitialization()) {
// First-time or POR initialization
full_reset_and_init();
} else {
// Subsequent boot
partialInit();
return_status = full_reset_and_init();
}
partialInit();
// statusClear(); I am not sure if this should be here or not
return true;
partialInit(); // If you always want hibernation disabled
// statusClear(); // I am not sure if this should be here or not (Clear all bits in the Status register (0x00))
return return_status;
}
return false;
}
@@ -220,19 +218,15 @@ bool I2cDev_MAX17055::full_reset_and_init() {
if (!soft_reset()) {
return false;
}
if (!initialize_custom_parameters()) {
return false;
}
if (!load_custom_parameters()) {
return false;
}
if (!clear_por()) {
return false;
}
return true;
}
@@ -298,8 +292,7 @@ void I2cDev_MAX17055::partialInit() {
bool I2cDev_MAX17055::reset_learned() {
// this if for reset all the learned parameters by ic
// the full inis should do this
full_reset_and_init();
return true;
return full_reset_and_init();
}
bool I2cDev_MAX17055::detect() {
+9 -7
View File
@@ -345,19 +345,19 @@ void ILI9341::render_box(const ui::Point p, const ui::Size s, const ui::Color* l
// RLE_4 BMP loader (delta not implemented)
/* draw transparent, pass transparent color as arg, usage inline anonymous obj
* portapack::display.drawBMP({100, 100}, foo_bmp, (const uint8_t[]){41, 24, 22}); // dec, out of {255, 255, 255}
* portapack::display.drawBMP({100, 100}, foo_bmp, (const uint8_t[]){0x29, 0x18, 0x16}); //hex out of {0xFF, 0xFF, 0xFF}
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, (const uint8_t[]){41, 24, 22}); // dec, out of {255, 255, 255}
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, (const uint8_t[]){0x29, 0x18, 0x16}); //hex out of {0xFF, 0xFF, 0xFF}
*
* draw transparent, pass transparent color as arg, usage pass uint8_t[] obj
* const uint8_t c[] = {41, 24, 22}; or const uint8_t c[3] = {0x29, 0x18, 0x16};
* portapack::display.drawBMP({100, 100}, foo_bmp, c);
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, c);
*
* don't draw transparent, pass nullptr as arg, usage
* portapack::display.drawBMP({100, 100}, foo_bmp, nullptr);
* portapack::display.draw_bmp_from_bmp_hex_arr({100, 100}, foo_bmp, nullptr);
*
* if your image use RLE compress as transparency methods, pass any valid color as arg, it doesn't matter (like the modal bmp. TODO: write RLE transparency generator)
* */
void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color) {
void ILI9341::draw_bmp_from_bmp_hex_arr(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color) {
const bmp_header_t* bmp_header = (const bmp_header_t*)bitmap;
uint32_t data_idx;
uint8_t by, c, count, transp_idx = 0;
@@ -463,7 +463,7 @@ void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* t
* 24bpp RGB
* 32bpp ARGB
*/
bool ILI9341::drawBMP2(const ui::Point p, const std::filesystem::path& file) {
bool ILI9341::draw_bmp_from_sdcard_file(const ui::Point p, const std::filesystem::path& file) {
File bmpimage;
size_t file_pos = 0;
uint16_t pointer = 0;
@@ -512,7 +512,9 @@ bool ILI9341::drawBMP2(const ui::Point p, const std::filesystem::path& file) {
file_pos = bmp_header.image_data;
py = height + 16;
py = height + 16 - 1;
/* ^ this is for to "start" AKA "image end" draw at the 17th line,
* because the render_line logic below is start with p.y() + py until "end" AKA "image start"*/
while (1) {
while (px < width) {
+2 -2
View File
@@ -62,8 +62,8 @@ class ILI9341 {
const ui::Color background);
void draw_pixel(const ui::Point p, const ui::Color color);
void drawBMP(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color);
bool drawBMP2(const ui::Point p, const std::filesystem::path& file);
void draw_bmp_from_bmp_hex_arr(const ui::Point p, const uint8_t* bitmap, const uint8_t* transparency_color);
bool draw_bmp_from_sdcard_file(const ui::Point p, const std::filesystem::path& file);
void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
void render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer);
+1
View File
@@ -104,6 +104,7 @@ constexpr image_tag_t image_tag_fskrx{'P', 'F', 'S', 'R'};
constexpr image_tag_t image_tag_jammer{'P', 'J', 'A', 'M'};
constexpr image_tag_t image_tag_mic_tx{'P', 'M', 'T', 'X'};
constexpr image_tag_t image_tag_ook{'P', 'O', 'O', 'K'};
constexpr image_tag_t image_tag_ookstream{'P', 'O', 'S', 'K'};
constexpr image_tag_t image_tag_rds{'P', 'R', 'D', 'S'};
constexpr image_tag_t image_tag_replay{'P', 'R', 'E', 'P'};
constexpr image_tag_t image_tag_gps{'P', 'G', 'P', 'S'};
+1 -1
View File
@@ -1,7 +1,7 @@
#include "ui_language.hpp"
// use the exact position in this array! the enum's value is the identifier. Best to add to the end
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset", "Pause", "Resume", "Flood", "Show QR", "Save", "Lock", "Unlock"};
const char* LanguageHelper::englishMessages[] = {"OK", "Cancel", "Error", "Modem setup", "Debug", "Log", "Done", "Start", "Stop", "Scan", "Clear", "Ready", "Data:", "Loop", "Reset", "Pause", "Resume", "Flood", "Show QR", "Save", "Lock", "Unlock", "Browse", "Set", "Open File", "Save File", "Send", "Receive"};
// multi language support will changes (not in use for now)
const char** LanguageHelper::currentMessages = englishMessages;
+8 -2
View File
@@ -60,7 +60,13 @@ enum LangConsts {
LANG_SHOWQR,
LANG_SAVE,
LANG_LOCK,
LANG_UNLOCK
LANG_UNLOCK,
LANG_BROWSE,
LANG_SET,
LANG_OPEN_FILE,
LANG_SAVE_FILE,
LANG_SEND,
LANG_RECV
};
class LanguageHelper {
@@ -73,4 +79,4 @@ class LanguageHelper {
static const char* englishMessages[];
};
#endif
#endif
+5 -2
View File
@@ -91,8 +91,8 @@ cmake_objcopy = sys.argv[3]
memory_location_header_position = 0
externalAppEntry_header_position = 4
m4_app_tag_header_position = 72
m4_app_offset_header_position = 76
m4_app_tag_header_position = 76
m4_app_offset_header_position = 80
for external_image_prefix in sys.argv[4:]:
@@ -123,7 +123,10 @@ for external_image_prefix in sys.argv[4:]:
write_image(external_application_image, "{}/{}.ppma".format(binary_dir, external_image_prefix))
continue
print(chunk_data)
chunk_tag = chunk_data.decode("utf-8")
print(chunk_tag)
print("{}/../baseband/{}.bin".format(binary_dir, chunk_tag))
m4_image = read_image("{}/../baseband/{}.bin".format(binary_dir, chunk_tag))
app_image_len = len(external_application_image)
external_application_image += m4_image
+7 -6
View File
@@ -26,6 +26,7 @@ import requests
import sys
cppheader = """#include "ui_about_simple.hpp"
#include <string_view>
#define ROLL_SPEED_FRAME_PER_LINE 60
// cuz frame rate of pp screen is probably 60, scroll per sec
@@ -33,7 +34,7 @@ cppheader = """#include "ui_about_simple.hpp"
namespace ui {
// Information: a line starting with a '#' will be yellow coloured
const std::"""
constexpr std::"""
cppfooter = """
AboutView::AboutView(NavigationView& nav) {
@@ -52,18 +53,18 @@ AboutView::AboutView(NavigationView& nav) {
button_ok.focus();
};
for (const std::string& authors_line : authors_list) {
for (auto& authors_line : authors_list) {
// if it's starting with #, it's a title and we have to substract the '#' and paint yellow
if (authors_line.size() > 0) {
if (authors_line[0] == '#') {
menu_view.add_item(
{authors_line.substr(1, authors_line.size() - 1),
{(std::string)authors_line.substr(1, authors_line.size() - 1),
ui::Theme::getInstance()->fg_yellow->foreground,
nullptr,
nullptr});
} else {
menu_view.add_item(
{authors_line,
{(std::string)authors_line,
Theme::getInstance()->bg_darkest->foreground,
nullptr,
nullptr});
@@ -140,7 +141,7 @@ def get_contributors(url):
def generate_content(projects):
project_contrib = []
project_contrib.append("string authors_list[] = {\n")
project_contrib.append("string_view authors_list[] = {\n")
project_contrib.append(" \"# * List of contributors * \",\n")
for project in projects:
project_contrib.append(" \" \",\n")
@@ -169,7 +170,7 @@ def pp_create_ui_about_simple_cpp(cpp_file, cppheader, cppcontent, cppfooter):
def pp_change_ui_about_simple_cpp(cpp_file, cppcontent):
content = []
content_pattern = re.compile(r"string authors_list\[\] = {\n(?:\s+(?:.*,\n)+\s+.*};\n)", re.MULTILINE)
content_pattern = re.compile(r"string_view authors_list\[\] = {\n(?:\s+(?:.*,\n)+\s+.*};\n)", re.MULTILINE)
# Read original file
with open(cpp_file, 'r') as file:
+3 -3
View File
@@ -12,8 +12,8 @@ pause
echo.
REM Check if the firmware file exists
if not exist portapack-h1_h2-mayhem.bin (
echo The firmware file "portapack-h1_h2-mayhem.bin" does not exist.
if not exist portapack-mayhem-firmware.bin (
echo The firmware file "portapack-mayhem-firmware.bin" does not exist.
echo Please ensure that you have downloaded the latest release from:
echo https://github.com/portapack-mayhem/mayhem-firmware/releases/
echo.
@@ -21,7 +21,7 @@ if not exist portapack-h1_h2-mayhem.bin (
exit /b
)
"utils/hackrf_update.exe" portapack-h1_h2-mayhem.bin
"utils/hackrf_update.exe" portapack-mayhem-firmware.bin
echo.
echo If your device never boot after flashing, please refer to https://github.com/portapack-mayhem/mayhem-firmware/wiki/Won't-boot
echo.
+1
View File
@@ -0,0 +1 @@
27000000 1M 1076 4 100 01110111011101110101010101010101010101110111011101110101