mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-11-15 17:57:41 -05:00
Added Adult toy controller external app (#2840)
This commit is contained in:
parent
60a5222058
commit
81afec9ea4
8 changed files with 752 additions and 2 deletions
|
|
@ -415,6 +415,44 @@ static constexpr Bitmap bitmap_icon_adsb{
|
||||||
{16, 16},
|
{16, 16},
|
||||||
bitmap_icon_adsb_data};
|
bitmap_icon_adsb_data};
|
||||||
|
|
||||||
|
static constexpr uint8_t bitmap_icon_adulttoys_data[] = {
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x30,
|
||||||
|
0x0C,
|
||||||
|
0x78,
|
||||||
|
0x1E,
|
||||||
|
0x7C,
|
||||||
|
0x3E,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFC,
|
||||||
|
0x3F,
|
||||||
|
0xFC,
|
||||||
|
0x3F,
|
||||||
|
0xF8,
|
||||||
|
0x1F,
|
||||||
|
0xF0,
|
||||||
|
0x0F,
|
||||||
|
0xE0,
|
||||||
|
0x07,
|
||||||
|
0xC0,
|
||||||
|
0x03,
|
||||||
|
0x80,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
static constexpr Bitmap bitmap_icon_adulttoys{
|
||||||
|
{16, 16},
|
||||||
|
bitmap_icon_adulttoys_data};
|
||||||
|
|
||||||
static constexpr uint8_t bitmap_icon_ais_data[] = {
|
static constexpr uint8_t bitmap_icon_ais_data[] = {
|
||||||
0x00,
|
0x00,
|
||||||
0x01,
|
0x01,
|
||||||
|
|
|
||||||
85
firmware/application/external/adult_toys_controller/main.cpp
vendored
Normal file
85
firmware/application/external/adult_toys_controller/main.cpp
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Pezsma
|
||||||
|
*
|
||||||
|
* 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_adult_toys_controller.hpp"
|
||||||
|
#include "ui_navigation.hpp"
|
||||||
|
#include "external_app.hpp"
|
||||||
|
|
||||||
|
namespace ui::external_app::adult_toys_controller {
|
||||||
|
|
||||||
|
void initialize_app(::ui::NavigationView& nav) {
|
||||||
|
nav.push<AdultToysView>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ui::external_app::adult_toys_controller
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
__attribute__((section(".external_app.app_adult_toys_controller.application_information"), used)) application_information_t _application_information_adult_toys_controller = {
|
||||||
|
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||||
|
/*.externalAppEntry = */ ui::external_app::adult_toys_controller::initialize_app,
|
||||||
|
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||||
|
/*.app_version = */ VERSION_MD5,
|
||||||
|
|
||||||
|
/*.app_name = */ "Adult Toys",
|
||||||
|
/*.bitmap_data = */ {
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x30,
|
||||||
|
0x0C,
|
||||||
|
0x78,
|
||||||
|
0x1E,
|
||||||
|
0x7C,
|
||||||
|
0x3E,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFE,
|
||||||
|
0x7F,
|
||||||
|
0xFC,
|
||||||
|
0x3F,
|
||||||
|
0xFC,
|
||||||
|
0x3F,
|
||||||
|
0xF8,
|
||||||
|
0x1F,
|
||||||
|
0xF0,
|
||||||
|
0x0F,
|
||||||
|
0xE0,
|
||||||
|
0x07,
|
||||||
|
0xC0,
|
||||||
|
0x03,
|
||||||
|
0x80,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
},
|
||||||
|
/*.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
|
||||||
|
};
|
||||||
|
}
|
||||||
373
firmware/application/external/adult_toys_controller/ui_adult_toys_controller.cpp
vendored
Normal file
373
firmware/application/external/adult_toys_controller/ui_adult_toys_controller.cpp
vendored
Normal file
|
|
@ -0,0 +1,373 @@
|
||||||
|
|
||||||
|
#include "ui_adult_toys_controller.hpp"
|
||||||
|
|
||||||
|
#include "ui_modemsetup.hpp"
|
||||||
|
#include "modems.hpp"
|
||||||
|
#include "audio.hpp"
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
#include "ui_navigation.hpp"
|
||||||
|
|
||||||
|
using namespace portapack;
|
||||||
|
using namespace modems;
|
||||||
|
using namespace ui;
|
||||||
|
|
||||||
|
namespace ui::external_app::adult_toys_controller {
|
||||||
|
|
||||||
|
void AdultToysView::focus() {
|
||||||
|
button_on.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
AdultToysView::AdultToysView(NavigationView& nav)
|
||||||
|
: nav_{nav} {
|
||||||
|
add_children({
|
||||||
|
&button_on,
|
||||||
|
&btn_adult,
|
||||||
|
&btn_child,
|
||||||
|
&btn_mode_decrease,
|
||||||
|
&btn_mode_increase,
|
||||||
|
&btn_pcknum_inc,
|
||||||
|
&btn_pcknum_dec,
|
||||||
|
&chk_mode_rnd,
|
||||||
|
&chk_mode_play,
|
||||||
|
&chk_mode_stop,
|
||||||
|
&chk_mode_ncnt,
|
||||||
|
&chk_mode_infinite,
|
||||||
|
&field_frequency,
|
||||||
|
&txt_selected_mode,
|
||||||
|
&options_target,
|
||||||
|
&labels,
|
||||||
|
&message_num,
|
||||||
|
&tx_view,
|
||||||
|
&screen_message_1,
|
||||||
|
&screen_message_2,
|
||||||
|
&screen_message_3,
|
||||||
|
&screen_message_4,
|
||||||
|
&screen_message_5,
|
||||||
|
&screen_message_6,
|
||||||
|
&screen_message_7,
|
||||||
|
&screen_message_8,
|
||||||
|
&screen_message_9,
|
||||||
|
&screen_message_10,
|
||||||
|
});
|
||||||
|
|
||||||
|
btn_adult.on_select = [this](Button&) {
|
||||||
|
start_screen = true;
|
||||||
|
hidden_program(!start_screen);
|
||||||
|
};
|
||||||
|
|
||||||
|
btn_child.on_select = [this](Button&) {
|
||||||
|
nav_.pop();
|
||||||
|
};
|
||||||
|
|
||||||
|
button_on.on_select = [this](Button&) {
|
||||||
|
if (play_running || stop_running) {
|
||||||
|
if (button_onstate) {
|
||||||
|
button_onstate = false;
|
||||||
|
stop();
|
||||||
|
button_on.set_text(LanguageHelper::currentMessages[LANG_START]);
|
||||||
|
} else {
|
||||||
|
button_onstate = true;
|
||||||
|
printCurrentModes();
|
||||||
|
start();
|
||||||
|
button_on.set_text(LanguageHelper::currentMessages[LANG_STOP]);
|
||||||
|
}
|
||||||
|
} // if play_running || stop_running
|
||||||
|
};
|
||||||
|
|
||||||
|
btn_mode_decrease.on_select = [this](Button&) {
|
||||||
|
if (toy_packet > 0) {
|
||||||
|
toy_packet--;
|
||||||
|
printCurrentModes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
btn_mode_increase.on_select = [this](Button&) {
|
||||||
|
if (stop_running || play_running) {
|
||||||
|
if (play_running && (toy_packet < max_plays - 1)) {
|
||||||
|
toy_packet++;
|
||||||
|
} else {
|
||||||
|
if (stop_running && toy_packet < max_stops - 1) {
|
||||||
|
toy_packet++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printCurrentModes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
btn_pcknum_inc.on_select = [this](Button&) {
|
||||||
|
if (!button_onstate) {
|
||||||
|
chk_mode_ncnt.set_value(true);
|
||||||
|
if (n_message_set < n_message_max) {
|
||||||
|
n_message_set++;
|
||||||
|
} else {
|
||||||
|
n_message_set = 0;
|
||||||
|
}
|
||||||
|
message_num.set_value(n_message_set);
|
||||||
|
n_message_current = n_message_set;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
btn_pcknum_dec.on_select = [this](Button&) {
|
||||||
|
if (!button_onstate) {
|
||||||
|
chk_mode_ncnt.set_value(true);
|
||||||
|
if (n_message_set > 0) {
|
||||||
|
n_message_set--;
|
||||||
|
} else {
|
||||||
|
n_message_set = n_message_max;
|
||||||
|
}
|
||||||
|
message_num.set_value(n_message_set);
|
||||||
|
n_message_current = n_message_set;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
message_num.on_change = [this](int32_t v) {
|
||||||
|
if (!button_onstate) {
|
||||||
|
chk_mode_ncnt.set_value(true);
|
||||||
|
n_message_set = static_cast<uint16_t>(v);
|
||||||
|
n_message_current = n_message_set;
|
||||||
|
} else {
|
||||||
|
if (!button_onstate) message_num.set_value(n_message_current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
chk_mode_rnd.on_select = [this](Checkbox&, bool v) {
|
||||||
|
random_running = v;
|
||||||
|
};
|
||||||
|
|
||||||
|
chk_mode_play.on_select = [this](Checkbox&, bool v) {
|
||||||
|
play_running = v;
|
||||||
|
if (play_running && stop_running) {
|
||||||
|
toy_packet = 0;
|
||||||
|
stop_running = false;
|
||||||
|
chk_mode_stop.set_value(stop_running);
|
||||||
|
}
|
||||||
|
if (play_running) printCurrentModes();
|
||||||
|
};
|
||||||
|
|
||||||
|
chk_mode_stop.on_select = [this](Checkbox&, bool v) {
|
||||||
|
stop_running = v;
|
||||||
|
if (play_running && stop_running) {
|
||||||
|
toy_packet = 0;
|
||||||
|
play_running = false;
|
||||||
|
chk_mode_play.set_value(play_running);
|
||||||
|
}
|
||||||
|
if (stop_running) printCurrentModes();
|
||||||
|
};
|
||||||
|
|
||||||
|
chk_mode_ncnt.on_select = [this](Checkbox&, bool v) {
|
||||||
|
n_message_running = v;
|
||||||
|
if (n_message_running && inf_message_running) {
|
||||||
|
inf_message_running = false;
|
||||||
|
chk_mode_infinite.set_value(inf_message_running);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
chk_mode_infinite.on_select = [this](Checkbox&, bool v) {
|
||||||
|
inf_message_running = v;
|
||||||
|
if (n_message_running && inf_message_running) {
|
||||||
|
n_message_running = false;
|
||||||
|
chk_mode_ncnt.set_value(n_message_running);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
options_target.on_change = [this](size_t, int32_t i) {
|
||||||
|
target = (uint8_t)i;
|
||||||
|
};
|
||||||
|
|
||||||
|
chk_mode_infinite.set_value(true);
|
||||||
|
chk_mode_play.set_value(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::hidden_program(bool hide) {
|
||||||
|
options_target.hidden(hide);
|
||||||
|
labels.hidden(hide);
|
||||||
|
button_on.hidden(hide);
|
||||||
|
btn_mode_decrease.hidden(hide);
|
||||||
|
btn_mode_increase.hidden(hide);
|
||||||
|
btn_pcknum_inc.hidden(hide);
|
||||||
|
btn_pcknum_dec.hidden(hide);
|
||||||
|
chk_mode_rnd.hidden(hide);
|
||||||
|
chk_mode_play.hidden(hide);
|
||||||
|
chk_mode_stop.hidden(hide);
|
||||||
|
chk_mode_ncnt.hidden(hide);
|
||||||
|
chk_mode_infinite.hidden(hide);
|
||||||
|
field_frequency.hidden(hide);
|
||||||
|
txt_selected_mode.hidden(hide);
|
||||||
|
message_num.hidden(hide);
|
||||||
|
tx_view.hidden(hide);
|
||||||
|
btn_adult.hidden(!hide);
|
||||||
|
btn_child.hidden(!hide);
|
||||||
|
screen_message_1.hidden(!hide);
|
||||||
|
screen_message_2.hidden(!hide);
|
||||||
|
screen_message_3.hidden(!hide);
|
||||||
|
screen_message_4.hidden(!hide);
|
||||||
|
screen_message_5.hidden(!hide);
|
||||||
|
screen_message_6.hidden(!hide);
|
||||||
|
screen_message_7.hidden(!hide);
|
||||||
|
screen_message_8.hidden(!hide);
|
||||||
|
screen_message_9.hidden(!hide);
|
||||||
|
screen_message_10.hidden(!hide);
|
||||||
|
set_dirty();
|
||||||
|
if (hide)
|
||||||
|
btn_child.focus();
|
||||||
|
else
|
||||||
|
button_on.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::on_show() {
|
||||||
|
hidden_program(!start_screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::createPacket(bool regenerate) {
|
||||||
|
if (regenerate) randomizeMac();
|
||||||
|
randomChn();
|
||||||
|
if (target == 1 || 1) { // now only lovespouse supported, in the future, need to separee them
|
||||||
|
uint32_t mode = play_running ? plays[toy_packet].value : stops[toy_packet].value;
|
||||||
|
|
||||||
|
const uint8_t size = 22;
|
||||||
|
uint8_t packet[size];
|
||||||
|
uint8_t i = 0;
|
||||||
|
|
||||||
|
// 1. AD Flags
|
||||||
|
packet[i++] = 2;
|
||||||
|
packet[i++] = 0x01;
|
||||||
|
packet[i++] = 0x1A;
|
||||||
|
|
||||||
|
// 2. Manufacturer Specific
|
||||||
|
packet[i++] = 14;
|
||||||
|
packet[i++] = 0xFF;
|
||||||
|
packet[i++] = 0xFF;
|
||||||
|
packet[i++] = 0x00;
|
||||||
|
packet[i++] = 0x6D;
|
||||||
|
packet[i++] = 0xB6;
|
||||||
|
packet[i++] = 0x43;
|
||||||
|
packet[i++] = 0xCE;
|
||||||
|
packet[i++] = 0x97;
|
||||||
|
packet[i++] = 0xFE;
|
||||||
|
packet[i++] = 0x42;
|
||||||
|
packet[i++] = 0x7C;
|
||||||
|
packet[i++] = (mode >> 0x10) & 0xFF;
|
||||||
|
packet[i++] = (mode >> 0x8) & 0xFF;
|
||||||
|
packet[i++] = (mode >> 0x0) & 0xFF;
|
||||||
|
|
||||||
|
// 3. Service UUID List
|
||||||
|
packet[i++] = 3;
|
||||||
|
packet[i++] = 0x03;
|
||||||
|
packet[i++] = 0x8F;
|
||||||
|
packet[i++] = 0xAE;
|
||||||
|
|
||||||
|
std::string res = to_string_hex_array(packet, i);
|
||||||
|
|
||||||
|
memset(advertisementData, 0, sizeof(advertisementData));
|
||||||
|
std::copy(res.begin(), res.end(), advertisementData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AdultToysView::~AdultToysView() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::stop() {
|
||||||
|
transmitter_model.disable();
|
||||||
|
baseband::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::start() {
|
||||||
|
baseband::run_image(portapack::spi_flash::image_tag_btle_tx);
|
||||||
|
transmitter_model.enable();
|
||||||
|
on_tx_progress(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::reset() {
|
||||||
|
stop();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t AdultToysView::randomize(uint8_t max) {
|
||||||
|
return static_cast<uint8_t>(rand() % max);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::printCurrentModes() {
|
||||||
|
uint8_t max_val = play_running ? max_plays : max_stops;
|
||||||
|
auto name = play_running ? plays[toy_packet].name : stops[toy_packet].name;
|
||||||
|
std::string current = to_string_dec_uint(toy_packet + 1);
|
||||||
|
std::string max_val_str = to_string_dec_uint(max_val);
|
||||||
|
|
||||||
|
std::string result_str = current;
|
||||||
|
result_str += "/";
|
||||||
|
result_str += max_val_str;
|
||||||
|
result_str += " ";
|
||||||
|
result_str += name;
|
||||||
|
txt_selected_mode.set(result_str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t AdultToysView::get_freq_by_channel_number(uint8_t channel_number) {
|
||||||
|
uint64_t freq_hz;
|
||||||
|
|
||||||
|
switch (channel_number) {
|
||||||
|
case 37:
|
||||||
|
freq_hz = 2'402'000'000ull;
|
||||||
|
break;
|
||||||
|
case 38:
|
||||||
|
freq_hz = 2'426'000'000ull;
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
freq_hz = 2'480'000'000ull;
|
||||||
|
break;
|
||||||
|
case 0 ... 10:
|
||||||
|
freq_hz = 2'404'000'000ull + channel_number * 2'000'000ull;
|
||||||
|
break;
|
||||||
|
case 11 ... 36:
|
||||||
|
freq_hz = 2'428'000'000ull + (channel_number - 11) * 2'000'000ull;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
freq_hz = UINT64_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq_hz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::randomizeMac() {
|
||||||
|
const char hexDigits[] = "0123456789ABCDEF";
|
||||||
|
// Generate 12 random hexadecimal characters
|
||||||
|
for (int i = 0; i < 12; ++i) {
|
||||||
|
int randomIndex = rand() % 16;
|
||||||
|
mac[i] = hexDigits[randomIndex];
|
||||||
|
}
|
||||||
|
mac[12] = '\0'; // Null-terminate the string
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::randomChn() {
|
||||||
|
channel_number = 37 + std::rand() % (39 - 37 + 1);
|
||||||
|
field_frequency.set_value(get_freq_by_channel_number(channel_number));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdultToysView::on_tx_progress(const bool done) {
|
||||||
|
if (!done) return;
|
||||||
|
if (!button_onstate) return;
|
||||||
|
bool regenerate = (counter++ % 600) == 0;
|
||||||
|
if (random_running && regenerate) {
|
||||||
|
toy_packet = randomize(play_running ? max_plays : max_stops);
|
||||||
|
}
|
||||||
|
createPacket(regenerate);
|
||||||
|
printCurrentModes();
|
||||||
|
|
||||||
|
if (n_message_running) {
|
||||||
|
if (n_message_current > 0) {
|
||||||
|
n_message_current--;
|
||||||
|
message_num.set_value(n_message_current);
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
message_num.set_value(n_message_set);
|
||||||
|
button_on.set_text(LanguageHelper::currentMessages[LANG_START]);
|
||||||
|
button_onstate = false;
|
||||||
|
n_message_current = n_message_set;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} // if n_message
|
||||||
|
|
||||||
|
baseband::set_btletx(channel_number, mac, advertisementData, pduType);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ui::external_app::adult_toys_controller
|
||||||
245
firmware/application/external/adult_toys_controller/ui_adult_toys_controller.hpp
vendored
Normal file
245
firmware/application/external/adult_toys_controller/ui_adult_toys_controller.hpp
vendored
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Pezsma
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code from https://github.com/Next-Flip/Momentum-Apps/blob/89d493daa1ea0cb86906fa0042c41dd4edc22a6a/ble_spam/protocols/lovespouse.c#L93
|
||||||
|
// Thanks for the work of the original creators!
|
||||||
|
|
||||||
|
#ifndef __UI_ADULT_TOYS_H__
|
||||||
|
#define __UI_ADULT_TOYS_H__
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
|
#include "ui_language.hpp"
|
||||||
|
#include "ui_navigation.hpp"
|
||||||
|
#include "ui_transmitter.hpp"
|
||||||
|
#include "ui_freq_field.hpp"
|
||||||
|
#include "ui_record_view.hpp"
|
||||||
|
#include "app_settings.hpp"
|
||||||
|
#include "radio_state.hpp"
|
||||||
|
#include "log_file.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
|
using namespace ui;
|
||||||
|
|
||||||
|
namespace ui::external_app::adult_toys_controller {
|
||||||
|
|
||||||
|
enum PKT_TYPE {
|
||||||
|
PKT_TYPE_INVALID_TYPE,
|
||||||
|
PKT_TYPE_RAW,
|
||||||
|
PKT_TYPE_DISCOVERY,
|
||||||
|
PKT_TYPE_IBEACON,
|
||||||
|
PKT_TYPE_ADV_IND,
|
||||||
|
PKT_TYPE_ADV_DIRECT_IND,
|
||||||
|
PKT_TYPE_ADV_NONCONN_IND,
|
||||||
|
PKT_TYPE_ADV_SCAN_IND,
|
||||||
|
PKT_TYPE_SCAN_REQ,
|
||||||
|
PKT_TYPE_SCAN_RSP,
|
||||||
|
PKT_TYPE_CONNECT_REQ,
|
||||||
|
PKT_TYPE_LL_DATA,
|
||||||
|
PKT_TYPE_LL_CONNECTION_UPDATE_REQ,
|
||||||
|
PKT_TYPE_LL_CHANNEL_MAP_REQ,
|
||||||
|
PKT_TYPE_LL_TERMINATE_IND,
|
||||||
|
PKT_TYPE_LL_ENC_REQ,
|
||||||
|
PKT_TYPE_LL_ENC_RSP,
|
||||||
|
PKT_TYPE_LL_START_ENC_REQ,
|
||||||
|
PKT_TYPE_LL_START_ENC_RSP,
|
||||||
|
PKT_TYPE_LL_UNKNOWN_RSP,
|
||||||
|
PKT_TYPE_LL_FEATURE_REQ,
|
||||||
|
PKT_TYPE_LL_FEATURE_RSP,
|
||||||
|
PKT_TYPE_LL_PAUSE_ENC_REQ,
|
||||||
|
PKT_TYPE_LL_PAUSE_ENC_RSP,
|
||||||
|
PKT_TYPE_LL_VERSION_IND,
|
||||||
|
PKT_TYPE_LL_REJECT_IND,
|
||||||
|
PKT_TYPE_NUM_PKT_TYPE
|
||||||
|
};
|
||||||
|
|
||||||
|
class AdultToysView : public ui::View {
|
||||||
|
public:
|
||||||
|
AdultToysView(NavigationView& nav);
|
||||||
|
~AdultToysView();
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
void on_show() override;
|
||||||
|
|
||||||
|
std::string title() const override {
|
||||||
|
return "Adult Toys";
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LovespouseMode {
|
||||||
|
uint32_t value;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
NavigationView& nav_;
|
||||||
|
TxRadioState radio_state_{
|
||||||
|
2'402'000'000 /* frequency */,
|
||||||
|
4'000'000 /* bandwidth */,
|
||||||
|
4'000'000 /* sampling rate */
|
||||||
|
};
|
||||||
|
|
||||||
|
TxFrequencyField field_frequency{
|
||||||
|
{UI_POS_X(0), UI_POS_Y(0)},
|
||||||
|
nav_};
|
||||||
|
|
||||||
|
TransmitterView2 tx_view{
|
||||||
|
{UI_POS_X(11), UI_POS_Y(0)},
|
||||||
|
/*short_ui*/ true};
|
||||||
|
|
||||||
|
app_settings::SettingsManager settings_{
|
||||||
|
"Adult Toys", app_settings::Mode::TX};
|
||||||
|
|
||||||
|
OptionsField options_target{
|
||||||
|
{UI_POS_X(6), UI_POS_Y(1)},
|
||||||
|
11,
|
||||||
|
{{"LoveSpouse", 1}}};
|
||||||
|
|
||||||
|
Button btn_adult{{UI_POS_X(0), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(10), UI_POS_HEIGHT(3)}, "adult"};
|
||||||
|
|
||||||
|
Button btn_child{{UI_POS_X_RIGHT(10), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(10), UI_POS_HEIGHT(3)}, "child"};
|
||||||
|
|
||||||
|
Button button_on{
|
||||||
|
{UI_POS_X(0), UI_POS_Y(3), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||||
|
LanguageHelper::currentMessages[LANG_START]};
|
||||||
|
|
||||||
|
Button btn_mode_decrease{
|
||||||
|
{UI_POS_X(0), UI_POS_Y(13), UI_POS_WIDTH(3), UI_POS_HEIGHT(2)},
|
||||||
|
"<-"};
|
||||||
|
|
||||||
|
Button btn_mode_increase{
|
||||||
|
{UI_POS_X_RIGHT(3), UI_POS_Y(13), UI_POS_WIDTH(3), UI_POS_HEIGHT(2)},
|
||||||
|
"->"};
|
||||||
|
|
||||||
|
Text txt_selected_mode{{UI_POS_X_CENTER(22), UI_POS_Y(13.5), UI_POS_WIDTH(22), UI_POS_HEIGHT(1)}, ""};
|
||||||
|
|
||||||
|
Button btn_pcknum_inc{
|
||||||
|
{UI_POS_X(7), UI_POS_Y(9), UI_POS_WIDTH(2), UI_POS_HEIGHT(1.5)},
|
||||||
|
"+"};
|
||||||
|
|
||||||
|
Button btn_pcknum_dec{
|
||||||
|
{UI_POS_X(0), UI_POS_Y(9), UI_POS_WIDTH(2), UI_POS_HEIGHT(1.5)},
|
||||||
|
"-"};
|
||||||
|
|
||||||
|
NumberField message_num{{UI_POS_X(3), UI_POS_Y(9.2)}, 3, {0, 999}, 1, ' ', true};
|
||||||
|
|
||||||
|
Checkbox chk_mode_rnd{{UI_POS_X_RIGHT(15), UI_POS_Y(3)}, 12, "Random Msg.", false};
|
||||||
|
Checkbox chk_mode_play{{UI_POS_X_RIGHT(15), UI_POS_Y(5)}, 10, "Play Mode", false};
|
||||||
|
Checkbox chk_mode_stop{{UI_POS_X_RIGHT(15), UI_POS_Y(7)}, 10, "Stop Mode", false};
|
||||||
|
Checkbox chk_mode_ncnt{{UI_POS_X_RIGHT(15), UI_POS_Y(9)}, 7, "N Msg.", false};
|
||||||
|
Checkbox chk_mode_infinite{{UI_POS_X_RIGHT(15), UI_POS_Y(11)}, 10, "Inf. Msg.", false};
|
||||||
|
|
||||||
|
Text screen_message_1{{0, 0, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "The application is intended"};
|
||||||
|
Text screen_message_2{{0, 25, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "for controlling Love Spouse"};
|
||||||
|
Text screen_message_3{{0, 50, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "auxiliary tools/devices."};
|
||||||
|
Text screen_message_4{{0, 75, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "It is only for use by adults."};
|
||||||
|
Text screen_message_5{{0, 100, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "Are you an adult?"};
|
||||||
|
|
||||||
|
Text screen_message_6{{0, 140, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "To use the application, "};
|
||||||
|
Text screen_message_7{{0, 165, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "I assume full responsibility"};
|
||||||
|
Text screen_message_8{{0, 190, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "for the \"I do not assume"};
|
||||||
|
Text screen_message_9{{0, 215, UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)}, "responsibility\"."};
|
||||||
|
Text screen_message_10{{UI_POS_X_RIGHT(16), 230, UI_POS_WIDTH(16), UI_POS_HEIGHT(1)}, "(The developer)"};
|
||||||
|
|
||||||
|
Labels labels{
|
||||||
|
{{UI_POS_X(0), UI_POS_Y(1)}, "Type:", Theme::getInstance()->fg_light->foreground}};
|
||||||
|
|
||||||
|
bool button_onstate{false};
|
||||||
|
bool play_running{false};
|
||||||
|
bool stop_running{false};
|
||||||
|
bool random_running{false};
|
||||||
|
bool n_message_running{false};
|
||||||
|
bool inf_message_running{false};
|
||||||
|
bool start_screen{false};
|
||||||
|
|
||||||
|
uint8_t target = 1; // lovespouse
|
||||||
|
|
||||||
|
char mac[13] = "010203040506";
|
||||||
|
uint8_t channel_number = 37;
|
||||||
|
char advertisementData[63] = {"03032CFE06162CFED5A59E020AB4\0"};
|
||||||
|
|
||||||
|
PKT_TYPE pduType = {PKT_TYPE_DISCOVERY};
|
||||||
|
|
||||||
|
uint8_t toy_packet = 0;
|
||||||
|
uint16_t n_message_max = 999;
|
||||||
|
uint16_t n_message_set = 0;
|
||||||
|
uint16_t n_message_current = 0;
|
||||||
|
static const size_t max_plays = 27;
|
||||||
|
static const size_t max_stops = 3;
|
||||||
|
|
||||||
|
uint16_t counter = 599;
|
||||||
|
|
||||||
|
void createPacket(bool regenerate);
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
void reset();
|
||||||
|
void printCurrentModes();
|
||||||
|
void on_tx_progress(const bool done);
|
||||||
|
void hidden_program(bool hide);
|
||||||
|
void randomizeMac();
|
||||||
|
void randomChn();
|
||||||
|
uint8_t randomize(uint8_t max);
|
||||||
|
uint64_t get_freq_by_channel_number(uint8_t channel_number);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}};
|
||||||
|
|
||||||
|
LovespouseMode plays[max_plays] = {
|
||||||
|
{0xE49C6C, "Classic 1"},
|
||||||
|
{0xE7075E, "Classic 2"},
|
||||||
|
{0xE68E4F, "Classic 3"},
|
||||||
|
{0xE1313B, "Classic 4"},
|
||||||
|
{0xE0B82A, "Classic 5"},
|
||||||
|
{0xE32318, "Classic 6"},
|
||||||
|
{0xE2AA09, "Classic 7"},
|
||||||
|
{0xED5DF1, "Classic 8"},
|
||||||
|
{0xECD4E0, "Classic 9"},
|
||||||
|
{0xD41F5D, "Independent 1-1"},
|
||||||
|
{0xD7846F, "Independent 1-2"},
|
||||||
|
{0xD60D7E, "Independent 1-3"},
|
||||||
|
{0xD1B20A, "Independent 1-4"},
|
||||||
|
{0xD0B31B, "Independent 1-5"},
|
||||||
|
{0xD3A029, "Independent 1-6"},
|
||||||
|
{0xD22938, "Independent 1-7"},
|
||||||
|
{0xDDDEC0, "Independent 1-8"},
|
||||||
|
{0xDC57D1, "Independent 1-9"},
|
||||||
|
{0xA4982E, "Independent 2-1"},
|
||||||
|
{0xA7031C, "Independent 2-2"},
|
||||||
|
{0xA68A0D, "Independent 2-3"},
|
||||||
|
{0xA13579, "Independent 2-4"},
|
||||||
|
{0xA0BC68, "Independent 2-5"},
|
||||||
|
{0xA3275A, "Independent 2-6"},
|
||||||
|
{0xA2AE4B, "Independent 2-7"},
|
||||||
|
{0xAD59B3, "Independent 2-8"},
|
||||||
|
{0xACD0A2, "Independent 2-9"},
|
||||||
|
};
|
||||||
|
|
||||||
|
LovespouseMode stops[max_stops] = {
|
||||||
|
{0xE5157D, "Classic Stop"},
|
||||||
|
{0xD5964C, "Independent 1 Stop"},
|
||||||
|
{0xA5113F, "Independent 2 Stop"},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}; // namespace ui::external_app::adult_toys_controller
|
||||||
|
|
||||||
|
#endif // ui_adult_toys_controller_hpp
|
||||||
5
firmware/application/external/external.cmake
vendored
5
firmware/application/external/external.cmake
vendored
|
|
@ -258,6 +258,10 @@ set(EXTCPPSRC
|
||||||
#morse_practice
|
#morse_practice
|
||||||
external/morse_practice/main.cpp
|
external/morse_practice/main.cpp
|
||||||
external/morse_practice/ui_morse_practice.cpp
|
external/morse_practice/ui_morse_practice.cpp
|
||||||
|
|
||||||
|
#adult_toys_controller
|
||||||
|
external/adult_toys_controller/main.cpp
|
||||||
|
external/adult_toys_controller/ui_adult_toys_controller.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(EXTAPPLIST
|
set(EXTAPPLIST
|
||||||
|
|
@ -323,4 +327,5 @@ set(EXTAPPLIST
|
||||||
game2048
|
game2048
|
||||||
bht_tx
|
bht_tx
|
||||||
morse_practice
|
morse_practice
|
||||||
|
adult_toys_controller
|
||||||
)
|
)
|
||||||
|
|
|
||||||
7
firmware/application/external/external.ld
vendored
7
firmware/application/external/external.ld
vendored
|
|
@ -85,7 +85,7 @@ MEMORY
|
||||||
ram_external_app_game2048 (rwx) : org = 0xADEC0000, len = 32k
|
ram_external_app_game2048 (rwx) : org = 0xADEC0000, len = 32k
|
||||||
ram_external_app_bht_tx (rwx) : org = 0xADED0000, len = 32k
|
ram_external_app_bht_tx (rwx) : org = 0xADED0000, len = 32k
|
||||||
ram_external_app_morse_practice (rwx) : org = 0xADEE0000, len = 32k
|
ram_external_app_morse_practice (rwx) : org = 0xADEE0000, len = 32k
|
||||||
|
ram_external_app_adult_toys_controller (rwx) : org = 0xADEF0000, len = 32k
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,6 +465,11 @@ SECTIONS
|
||||||
*(*ui*external_app*morse_practice*);
|
*(*ui*external_app*morse_practice*);
|
||||||
} > ram_external_app_morse_practice
|
} > ram_external_app_morse_practice
|
||||||
|
|
||||||
|
.external_app_adult_toys_controller : ALIGN(4) SUBALIGN(4)
|
||||||
|
{
|
||||||
|
KEEP(*(.external_app.app_adult_toys_controller.application_information));
|
||||||
|
*(*ui*external_app*adult_toys_controller*);
|
||||||
|
} > ram_external_app_adult_toys_controller
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ void initialize_app(NavigationView& nav) {
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
// Az alkalmazás információ C-linkage-ként, hogy a firmware hívhassa
|
|
||||||
__attribute__((section(".external_app.app_morse_practice.application_information"), used))
|
__attribute__((section(".external_app.app_morse_practice.application_information"), used))
|
||||||
application_information_t _application_information_morse_practice = {
|
application_information_t _application_information_morse_practice = {
|
||||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||||
|
|
|
||||||
BIN
firmware/graphics/icon_adulttoys.png
Normal file
BIN
firmware/graphics/icon_adulttoys.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 215 B |
Loading…
Add table
Add a link
Reference in a new issue