Merge branch 'dev' into release
1
.github/FUNDING.yml
vendored
@@ -1,4 +1,3 @@
|
|||||||
ko_fi: masterx
|
|
||||||
custom:
|
custom:
|
||||||
[
|
[
|
||||||
"https://boosty.to/mmxdev",
|
"https://boosty.to/mmxdev",
|
||||||
|
|||||||
32
CHANGELOG.md
@@ -1,27 +1,14 @@
|
|||||||
### New changes
|
### New changes
|
||||||
* Power + BLE: DeepSleep + required ble stack upgrade added back, all known issues was fixed in OFW, no issues was found during our tests
|
* NFC: Temp fix for Detect reader not collecting nonces
|
||||||
* Desktop: Allow locking without pin using Up menu on desktop (Short click on `Lock` = Without PIN / Long = With PIN)
|
* Desktop: Temp fix for old backlight bug when locking by holding up arrow
|
||||||
* RFID: Add confirmation message before running `Clear T5577 Password`
|
* IR: Add Sharp and Vizio to Universal TV remote
|
||||||
* RFID: Add more user friendly RAW emulation via UI [(by Dan Caprita)](https://forum.flipperzero.one/t/electra-intercom/6368/43)
|
* BLE Info: Show version instead of branch
|
||||||
* SubGHz: Fixed `Frequency Analyzer` issues, fixed `Read` mode issues
|
* Plugins: Add new game - Bomberduck (by @leo-need-more-coffee | PR #450)
|
||||||
* SubGHz: Fix NFC crash when using external CC1101 radio module
|
* Plugins: Fix `SWD Probe` plugin GPIO pins state reset on exit
|
||||||
* SubGHz: Fix multiple external CC1101 radio module issues, (int callbacks, SPI handlers init/reinit)
|
* Plugins: Bluetooth Remote - new UI (by @krolchonok | PR #447)
|
||||||
* SubGHz: Using scene manager function in add manually (by @gid9798 | PR #437)
|
|
||||||
* Plugins: ESP32: WiFi Marauder - add icon for log files in logs browser
|
|
||||||
* Plugins: Update **ESP32: WiFi Marauder companion** plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) merged [PR by @tcpassos](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion/pull/11)
|
|
||||||
* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||||
* Plugins: Fix RFID Fuzzer and iButton Fuzzer crashes
|
* Docs: Update HowToInstall (by @krolchonok | PR #443)
|
||||||
* Plugins: iButton Fuzzer default keys update (by @team-orangeBlue)
|
* OFW PR 2627: Add HID mouse auto-clicker (by @rwl4)
|
||||||
* Infrared: Updated infrared assets (by @amec0e | PR #441)
|
|
||||||
* Docs: Update **How To Install** images (by @krolchonok | PR #436)
|
|
||||||
* OFW PR 2620: NFC: Fix reading Mifare Classic cards with unusual access conditions and fix emulation of unknown keys (by Astrrra)
|
|
||||||
* OFW PR 2616: Picopass: remove spaces in CSN (by bettse)
|
|
||||||
* OFW PR 2604: WS: add protocol "Wendox W6726" (by Skorpionm)
|
|
||||||
* OFW PR 2607: BadUSB: command parser fix (by nminaylov)
|
|
||||||
* OFW: Keep HSI16 working in stop mode.
|
|
||||||
* OFW: FuriHal: use proper divider for core2 when transition to sleep, remove extra stop mode transition checks, cleanup code. Furi: proper assert and check messages.
|
|
||||||
* OFW: Don't reboot on crash in debug builds
|
|
||||||
* OFW: cubewb: downgraded to v1.15.0
|
|
||||||
|
|
||||||
#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)
|
#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)
|
||||||
|
|
||||||
@@ -31,7 +18,6 @@
|
|||||||
|
|
||||||
## Please support development of the project
|
## Please support development of the project
|
||||||
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
|
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
|
||||||
* Ko-Fi: https://ko-fi.com/masterx
|
|
||||||
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
|
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
|
||||||
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
|
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
|
||||||
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
|
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ The amount of work done on this project is huge and we need your support, no mat
|
|||||||
Also, regarding our releases, every build has and always will be free and open-source. There will be no paywall releases or closed-source apps within the firmware. As long as I am working on this project it will never happen.
|
Also, regarding our releases, every build has and always will be free and open-source. There will be no paywall releases or closed-source apps within the firmware. As long as I am working on this project it will never happen.
|
||||||
You can support us by using links or addresses below:
|
You can support us by using links or addresses below:
|
||||||
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
|
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
|
||||||
* Ko-Fi: https://ko-fi.com/masterx
|
|
||||||
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
|
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
|
||||||
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
|
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
|
||||||
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
|
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
|
||||||
@@ -162,6 +161,7 @@ You can support us by using links or addresses below:
|
|||||||
- **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main)
|
- **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main)
|
||||||
- **ProtoView** [(by antirez)](https://github.com/antirez/protoview)
|
- **ProtoView** [(by antirez)](https://github.com/antirez/protoview)
|
||||||
- **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe)
|
- **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe)
|
||||||
|
- IR Scope [(by kallanreed)](https://github.com/DarkFlippers/unleashed-firmware/pull/407)
|
||||||
|
|
||||||
Games:
|
Games:
|
||||||
- DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)
|
- DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)
|
||||||
@@ -176,6 +176,7 @@ Games:
|
|||||||
- Solitaire [(by teeebor)](https://github.com/teeebor/flipper_games)
|
- Solitaire [(by teeebor)](https://github.com/teeebor/flipper_games)
|
||||||
- BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games)
|
- BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games)
|
||||||
- 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game)
|
- 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game)
|
||||||
|
- Bomberduck [(by leo-need-more-coffee)](https://github.com/leo-need-more-coffee/flipperzero-bomberduck)
|
||||||
|
|
||||||
|
|
||||||
# Instructions
|
# Instructions
|
||||||
|
|||||||
22
applications/external/bomberduck/LICENSE
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 лень
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
2
applications/external/bomberduck/README.md
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# flipperzero-bomberduck
|
||||||
|
Bomberman clone on flipper zero!
|
||||||
14
applications/external/bomberduck/application.fam
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
App(
|
||||||
|
appid="bomberduck",
|
||||||
|
name="Bomberduck",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
entry_point="bomberduck_app",
|
||||||
|
requires=[
|
||||||
|
"gui",
|
||||||
|
],
|
||||||
|
stack_size=1 * 1024,
|
||||||
|
order=90,
|
||||||
|
fap_icon="bomb.png",
|
||||||
|
fap_category="Games",
|
||||||
|
fap_icon_assets="assets",
|
||||||
|
)
|
||||||
BIN
applications/external/bomberduck/assets/bomb0.png
vendored
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
applications/external/bomberduck/assets/bomb1.png
vendored
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
applications/external/bomberduck/assets/bomb2.png
vendored
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
applications/external/bomberduck/assets/box.png
vendored
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
applications/external/bomberduck/assets/end.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
applications/external/bomberduck/assets/enemy1.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
applications/external/bomberduck/assets/enemyleft.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
applications/external/bomberduck/assets/enemyright.png
vendored
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
applications/external/bomberduck/assets/explore.png
vendored
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
applications/external/bomberduck/assets/playerleft.png
vendored
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
applications/external/bomberduck/assets/playerright.png
vendored
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
applications/external/bomberduck/assets/unbreakbox.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
applications/external/bomberduck/bomb.png
vendored
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
648
applications/external/bomberduck/bomberduck.c
vendored
Normal file
@@ -0,0 +1,648 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
#include <notification/notification.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
#include <gui/canvas_i.h>
|
||||||
|
#include "bomberduck_icons.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
int max(int a, int b) {
|
||||||
|
return (a > b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int min(int a, int b) {
|
||||||
|
return (a < b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WorldSizeX 12
|
||||||
|
#define WorldSizeY 6
|
||||||
|
#define BombRange 1
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FuriMutex* mutex;
|
||||||
|
} BomberState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int row;
|
||||||
|
int col;
|
||||||
|
} Cell;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Cell cells[WorldSizeY * WorldSizeX];
|
||||||
|
int front;
|
||||||
|
int rear;
|
||||||
|
} Queue;
|
||||||
|
|
||||||
|
void enqueue(Queue* q, Cell c) {
|
||||||
|
q->cells[q->rear] = c;
|
||||||
|
q->rear++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell dequeue(Queue* q) {
|
||||||
|
Cell c = q->cells[q->front];
|
||||||
|
q->front++;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty(Queue* q) {
|
||||||
|
return q->front == q->rear;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int planted;
|
||||||
|
} Bomb;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
bool side;
|
||||||
|
} Player;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int last;
|
||||||
|
bool side;
|
||||||
|
int level;
|
||||||
|
} Enemy;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int matrix[WorldSizeY][WorldSizeX];
|
||||||
|
Player* player;
|
||||||
|
bool running;
|
||||||
|
int level;
|
||||||
|
|
||||||
|
Enemy enemies[10];
|
||||||
|
int enemies_count;
|
||||||
|
|
||||||
|
Bomb bombs[100];
|
||||||
|
int bombs_count;
|
||||||
|
|
||||||
|
int endx;
|
||||||
|
int endy;
|
||||||
|
} World;
|
||||||
|
|
||||||
|
Player player = {0, 0, 1};
|
||||||
|
World world = {{{0}}, &player, 1, 0, {}, 0, {}, 0, 0, 0};
|
||||||
|
bool vibration = false;
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
player.x = 1;
|
||||||
|
player.y = 1;
|
||||||
|
|
||||||
|
world.endx = 4 + rand() % 8;
|
||||||
|
world.endy = rand() % 6;
|
||||||
|
for(int i = 0; i < WorldSizeY; i++) {
|
||||||
|
for(int j = 0; j < WorldSizeX; j++) {
|
||||||
|
world.matrix[i][j] = rand() % 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
world.running = 1;
|
||||||
|
world.bombs_count = 0;
|
||||||
|
vibration = false;
|
||||||
|
for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) {
|
||||||
|
world.matrix[j][player.x] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int j = max(0, player.x - BombRange); j < min(WorldSizeX, player.x + BombRange + 1); j++) {
|
||||||
|
world.matrix[player.y][j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
world.enemies_count = 0;
|
||||||
|
for(int j = 0; j < rand() % 4 + world.level / 5; j++) {
|
||||||
|
Enemy enemy;
|
||||||
|
enemy.x = 4 + rand() % 7;
|
||||||
|
enemy.y = rand() % 6;
|
||||||
|
enemy.last = 0;
|
||||||
|
enemy.side = 1;
|
||||||
|
enemy.level = 0;
|
||||||
|
|
||||||
|
world.enemies[j] = enemy;
|
||||||
|
world.enemies_count++;
|
||||||
|
|
||||||
|
for(int m = max(0, world.enemies[j].y - BombRange);
|
||||||
|
m < min(WorldSizeY, world.enemies[j].y + BombRange + 1);
|
||||||
|
m++) {
|
||||||
|
world.matrix[m][world.enemies[j].x] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int m = max(0, world.enemies[j].x - BombRange);
|
||||||
|
m < min(WorldSizeX, world.enemies[j].x + BombRange + 1);
|
||||||
|
m++) {
|
||||||
|
world.matrix[world.enemies[j].y][m] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
world.matrix[world.endy][world.endx] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NotificationSequence end = {
|
||||||
|
&message_vibro_on,
|
||||||
|
|
||||||
|
&message_note_ds4,
|
||||||
|
&message_delay_10,
|
||||||
|
&message_sound_off,
|
||||||
|
&message_delay_10,
|
||||||
|
|
||||||
|
&message_note_ds4,
|
||||||
|
&message_delay_10,
|
||||||
|
&message_sound_off,
|
||||||
|
&message_delay_10,
|
||||||
|
|
||||||
|
&message_note_ds4,
|
||||||
|
&message_delay_10,
|
||||||
|
&message_sound_off,
|
||||||
|
&message_delay_10,
|
||||||
|
|
||||||
|
&message_vibro_off,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NotificationSequence bomb2 = {
|
||||||
|
&message_vibro_on,
|
||||||
|
&message_delay_25,
|
||||||
|
&message_vibro_off,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NotificationSequence bomb_explore = {
|
||||||
|
&message_vibro_on,
|
||||||
|
&message_delay_50,
|
||||||
|
&message_vibro_off,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NotificationSequence vibr1 = {
|
||||||
|
&message_vibro_on,
|
||||||
|
&message_delay_10,
|
||||||
|
&message_vibro_off,
|
||||||
|
&message_delay_10,
|
||||||
|
&message_vibro_on,
|
||||||
|
&message_delay_10,
|
||||||
|
&message_vibro_off,
|
||||||
|
&message_delay_10,
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void intToStr(int num, char* str) {
|
||||||
|
int i = 0, sign = 0;
|
||||||
|
|
||||||
|
if(num < 0) {
|
||||||
|
num = -num;
|
||||||
|
sign = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
str[i++] = num % 10 + '0';
|
||||||
|
num /= 10;
|
||||||
|
} while(num > 0);
|
||||||
|
|
||||||
|
if(sign) {
|
||||||
|
str[i++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i] = '\0';
|
||||||
|
|
||||||
|
// Reverse the string
|
||||||
|
int j, len = i;
|
||||||
|
char temp;
|
||||||
|
for(j = 0; j < len / 2; j++) {
|
||||||
|
temp = str[j];
|
||||||
|
str[j] = str[len - j - 1];
|
||||||
|
str[len - j - 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BFS() {
|
||||||
|
// Initialize visited array and queue
|
||||||
|
int visited[WorldSizeY][WorldSizeX] = {0};
|
||||||
|
Queue q = {.front = 0, .rear = 0};
|
||||||
|
// Mark the starting cell as visited and enqueue it
|
||||||
|
visited[world.player->y][world.player->x] = 1;
|
||||||
|
Cell startCell = {.row = world.player->y, .col = world.player->x};
|
||||||
|
enqueue(&q, startCell);
|
||||||
|
// Traverse the field
|
||||||
|
while(!is_empty(&q)) {
|
||||||
|
// Dequeue a cell from the queue
|
||||||
|
Cell currentCell = dequeue(&q);
|
||||||
|
// Check if the current cell is the destination cell
|
||||||
|
if(currentCell.row == world.endy && currentCell.col == world.endx) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Check the neighboring cells
|
||||||
|
for(int rowOffset = -1; rowOffset <= 1; rowOffset++) {
|
||||||
|
for(int colOffset = -1; colOffset <= 1; colOffset++) {
|
||||||
|
// Skip diagonals and the current cell
|
||||||
|
if(rowOffset == 0 && colOffset == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(rowOffset != 0 && colOffset != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Calculate the row and column of the neighboring cell
|
||||||
|
int neighborRow = currentCell.row + rowOffset;
|
||||||
|
int neighborCol = currentCell.col + colOffset;
|
||||||
|
// Skip out-of-bounds cells and already visited cells
|
||||||
|
if(neighborRow < 0 || neighborRow >= WorldSizeY || neighborCol < 0 ||
|
||||||
|
neighborCol >= WorldSizeX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(visited[neighborRow][neighborCol]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Mark the neighboring cell as visited and enqueue it
|
||||||
|
if(world.matrix[neighborRow][neighborCol] != 2) {
|
||||||
|
visited[neighborRow][neighborCol] = 1;
|
||||||
|
Cell neighborCell = {.row = neighborRow, .col = neighborCol};
|
||||||
|
enqueue(&q, neighborCell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_callback(Canvas* canvas, void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
const BomberState* bomber_state = ctx;
|
||||||
|
|
||||||
|
furi_mutex_acquire(bomber_state->mutex, FuriWaitForever);
|
||||||
|
if(!BFS()) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
canvas_clear(canvas);
|
||||||
|
|
||||||
|
canvas_draw_icon(canvas, world.endx * 10 + 4, world.endy * 10 + 2, &I_end);
|
||||||
|
|
||||||
|
if(world.running) {
|
||||||
|
for(size_t i = 0; i < WorldSizeY; i++) {
|
||||||
|
for(size_t j = 0; j < WorldSizeX; j++) {
|
||||||
|
switch(world.matrix[i][j]) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_box);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_unbreakbox);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb0);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb1);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb2);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_explore);
|
||||||
|
world.matrix[i][j] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(world.player->side) {
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerright);
|
||||||
|
} else {
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerleft);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < world.enemies_count; i++) {
|
||||||
|
if(world.enemies[i].level > 0) {
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas, world.enemies[i].x * 10 + 4, world.enemies[i].y * 10 + 2, &I_enemy1);
|
||||||
|
} else {
|
||||||
|
if(world.enemies[i].side) {
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas,
|
||||||
|
world.enemies[i].x * 10 + 4,
|
||||||
|
world.enemies[i].y * 10 + 2,
|
||||||
|
&I_enemyright);
|
||||||
|
} else {
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas,
|
||||||
|
world.enemies[i].x * 10 + 4,
|
||||||
|
world.enemies[i].y * 10 + 2,
|
||||||
|
&I_enemyleft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
if(world.player->x == world.endx && world.player->y == world.endy) {
|
||||||
|
if(world.level == 20) {
|
||||||
|
canvas_draw_str(canvas, 30, 35, "You win!");
|
||||||
|
} else {
|
||||||
|
canvas_draw_str(canvas, 30, 35, "Next level!");
|
||||||
|
char str[20];
|
||||||
|
intToStr(world.level, str);
|
||||||
|
canvas_draw_str(canvas, 90, 35, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
canvas_draw_str(canvas, 30, 35, "You died :(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_mutex_release(bomber_state->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||||
|
// Проверяем, что контекст не нулевой
|
||||||
|
furi_assert(ctx);
|
||||||
|
FuriMessageQueue* event_queue = ctx;
|
||||||
|
|
||||||
|
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t bomberduck_app(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
|
||||||
|
// Текущее событие типа InputEvent
|
||||||
|
InputEvent event;
|
||||||
|
// Очередь событий на 8 элементов размера InputEvent
|
||||||
|
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
|
||||||
|
|
||||||
|
BomberState* bomber_state = malloc(sizeof(BomberState));
|
||||||
|
|
||||||
|
bomber_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex
|
||||||
|
if(!bomber_state->mutex) {
|
||||||
|
FURI_LOG_E("BomberDuck", "cannot create mutex\r\n");
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
free(bomber_state);
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||||
|
// Создаем новый view port
|
||||||
|
ViewPort* view_port = view_port_alloc();
|
||||||
|
// Создаем callback отрисовки, без контекста
|
||||||
|
view_port_draw_callback_set(view_port, draw_callback, bomber_state);
|
||||||
|
// Создаем callback нажатий на клавиши, в качестве контекста передаем
|
||||||
|
// нашу очередь сообщений, чтоб запихивать в неё эти события
|
||||||
|
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||||
|
|
||||||
|
// Создаем GUI приложения
|
||||||
|
Gui* gui = furi_record_open(RECORD_GUI);
|
||||||
|
// Подключаем view port к GUI в полноэкранном режиме
|
||||||
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||||
|
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||||
|
notification_message_block(notification, &sequence_display_backlight_enforce_on);
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
// Бесконечный цикл обработки очереди событий
|
||||||
|
while(1) {
|
||||||
|
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
|
||||||
|
furi_mutex_acquire(bomber_state->mutex, FuriWaitForever);
|
||||||
|
// Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения
|
||||||
|
|
||||||
|
if(event.type == InputTypePress) {
|
||||||
|
if(event.key == InputKeyOk) {
|
||||||
|
if(world.running) {
|
||||||
|
if(world.matrix[world.player->y][world.player->x] == 0 &&
|
||||||
|
world.bombs_count < 2) {
|
||||||
|
notification_message(notification, &bomb2);
|
||||||
|
world.matrix[world.player->y][world.player->x] = 3;
|
||||||
|
Bomb bomb = {world.player->x, world.player->y, furi_get_tick()};
|
||||||
|
world.bombs[world.bombs_count] = bomb;
|
||||||
|
world.bombs_count++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(world.running) {
|
||||||
|
if(event.key == InputKeyUp) {
|
||||||
|
if(world.player->y > 0 &&
|
||||||
|
world.matrix[world.player->y - 1][world.player->x] == 0)
|
||||||
|
world.player->y--;
|
||||||
|
}
|
||||||
|
if(event.key == InputKeyDown) {
|
||||||
|
if(world.player->y < WorldSizeY - 1 &&
|
||||||
|
world.matrix[world.player->y + 1][world.player->x] == 0)
|
||||||
|
world.player->y++;
|
||||||
|
}
|
||||||
|
if(event.key == InputKeyLeft) {
|
||||||
|
world.player->side = 0;
|
||||||
|
if(world.player->x > 0 &&
|
||||||
|
world.matrix[world.player->y][world.player->x - 1] == 0)
|
||||||
|
world.player->x--;
|
||||||
|
}
|
||||||
|
if(event.key == InputKeyRight) {
|
||||||
|
world.player->side = 1;
|
||||||
|
if(world.player->x < WorldSizeX - 1 &&
|
||||||
|
world.matrix[world.player->y][world.player->x + 1] == 0)
|
||||||
|
world.player->x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(event.type == InputTypeLong) {
|
||||||
|
if(event.key == InputKeyBack) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(world.running) {
|
||||||
|
if(world.player->x == world.endx && world.player->y == world.endy) {
|
||||||
|
notification_message(notification, &end);
|
||||||
|
world.running = 0;
|
||||||
|
world.level += 1;
|
||||||
|
if(world.level % 5 == 0) {
|
||||||
|
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 0; i < world.bombs_count; i++) {
|
||||||
|
if(furi_get_tick() - world.bombs[i].planted >
|
||||||
|
(unsigned long)max((3000 - world.level * 150), 1000)) {
|
||||||
|
vibration = false;
|
||||||
|
world.matrix[world.bombs[i].y][world.bombs[i].x] = 6;
|
||||||
|
notification_message(notification, &bomb_explore);
|
||||||
|
|
||||||
|
for(int j = max(0, world.bombs[i].y - BombRange);
|
||||||
|
j < min(WorldSizeY, world.bombs[i].y + BombRange + 1);
|
||||||
|
j++) {
|
||||||
|
if(world.matrix[j][world.bombs[i].x] != 2) {
|
||||||
|
world.matrix[j][world.bombs[i].x] = 6;
|
||||||
|
if(j == world.player->y && world.bombs[i].x == world.player->x) {
|
||||||
|
notification_message(notification, &end);
|
||||||
|
world.running = 0;
|
||||||
|
}
|
||||||
|
for(int e = 0; e < world.enemies_count; e++) {
|
||||||
|
if(j == world.enemies[e].y &&
|
||||||
|
world.bombs[i].x == world.enemies[e].x) {
|
||||||
|
if(world.enemies[e].level > 0) {
|
||||||
|
world.enemies[e].level--;
|
||||||
|
} else {
|
||||||
|
for(int l = e; l < world.enemies_count - 1; l++) {
|
||||||
|
world.enemies[l] = world.enemies[l + 1];
|
||||||
|
}
|
||||||
|
world.enemies_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int j = max(0, world.bombs[i].x - BombRange);
|
||||||
|
j < min(WorldSizeX, world.bombs[i].x + BombRange + 1);
|
||||||
|
j++) {
|
||||||
|
if(world.matrix[world.bombs[i].y][j] != 2) {
|
||||||
|
world.matrix[world.bombs[i].y][j] = 6;
|
||||||
|
if(world.bombs[i].y == world.player->y && j == world.player->x) {
|
||||||
|
notification_message(notification, &end);
|
||||||
|
world.running = 0;
|
||||||
|
}
|
||||||
|
for(int e = 0; e < world.enemies_count; e++) {
|
||||||
|
if(world.bombs[i].y == world.enemies[e].y &&
|
||||||
|
j == world.enemies[e].x) {
|
||||||
|
if(world.enemies[e].level > 0) {
|
||||||
|
world.enemies[e].level--;
|
||||||
|
} else {
|
||||||
|
for(int l = e; l < world.enemies_count - 1; l++) {
|
||||||
|
world.enemies[l] = world.enemies[l + 1];
|
||||||
|
}
|
||||||
|
world.enemies_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int j = i; j < world.bombs_count - 1; j++) {
|
||||||
|
world.bombs[j] = world.bombs[j + 1];
|
||||||
|
}
|
||||||
|
world.bombs_count--;
|
||||||
|
} else if(
|
||||||
|
furi_get_tick() - world.bombs[i].planted >
|
||||||
|
(unsigned long)max((3000 - world.level * 150) * 2 / 3, 666) &&
|
||||||
|
world.matrix[world.bombs[i].y][world.bombs[i].x] != 5) {
|
||||||
|
world.matrix[world.bombs[i].y][world.bombs[i].x] = 5;
|
||||||
|
vibration = true;
|
||||||
|
|
||||||
|
} else if(
|
||||||
|
furi_get_tick() - world.bombs[i].planted >
|
||||||
|
(unsigned long)max((3000 - world.level * 150) / 3, 333) &&
|
||||||
|
world.matrix[world.bombs[i].y][world.bombs[i].x] != 4) {
|
||||||
|
world.matrix[world.bombs[i].y][world.bombs[i].x] = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int e = 0; e < world.enemies_count; e++) {
|
||||||
|
if(world.player->y == world.enemies[e].y &&
|
||||||
|
world.player->x == world.enemies[e].x) {
|
||||||
|
notification_message(notification, &end);
|
||||||
|
world.running = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int e = 0; e < world.enemies_count; e++) {
|
||||||
|
if(world.enemies[e].level > 0) {
|
||||||
|
if(furi_get_tick() - world.enemies[e].last >
|
||||||
|
(unsigned long)max((2000 - world.level * 100), 1000)) {
|
||||||
|
world.enemies[e].last = furi_get_tick();
|
||||||
|
int move = rand() % 4;
|
||||||
|
switch(move) {
|
||||||
|
case 0:
|
||||||
|
if(world.enemies[e].y > 0 &&
|
||||||
|
world.matrix[world.enemies[e].y - 1][world.enemies[e].x] != 2)
|
||||||
|
world.enemies[e].y--;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(world.enemies[e].y < WorldSizeY - 1 &&
|
||||||
|
world.matrix[world.enemies[e].y + 1][world.enemies[e].x] != 2)
|
||||||
|
world.enemies[e].y++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
world.enemies[e].side = 0;
|
||||||
|
if(world.enemies[e].x > 0 &&
|
||||||
|
world.matrix[world.enemies[e].y][world.enemies[e].x - 1] != 2)
|
||||||
|
world.enemies[e].x--;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
world.enemies[e].side = 1;
|
||||||
|
if(world.enemies[e].x < WorldSizeX - 1 &&
|
||||||
|
world.matrix[world.enemies[e].y][world.enemies[e].x + 1] != 2)
|
||||||
|
world.enemies[e].x++;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(furi_get_tick() - world.enemies[e].last >
|
||||||
|
(unsigned long)max((1000 - world.level * 50), 500)) {
|
||||||
|
world.enemies[e].last = furi_get_tick();
|
||||||
|
int move = rand() % 4;
|
||||||
|
switch(move) {
|
||||||
|
case 0:
|
||||||
|
if(world.enemies[e].y > 0 &&
|
||||||
|
world.matrix[world.enemies[e].y - 1][world.enemies[e].x] == 0)
|
||||||
|
world.enemies[e].y--;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(world.enemies[e].y < WorldSizeY - 1 &&
|
||||||
|
world.matrix[world.enemies[e].y + 1][world.enemies[e].x] == 0)
|
||||||
|
world.enemies[e].y++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
world.enemies[e].side = 0;
|
||||||
|
if(world.enemies[e].x > 0 &&
|
||||||
|
world.matrix[world.enemies[e].y][world.enemies[e].x - 1] == 0)
|
||||||
|
world.enemies[e].x--;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
world.enemies[e].side = 1;
|
||||||
|
if(world.enemies[e].x < WorldSizeX - 1 &&
|
||||||
|
world.matrix[world.enemies[e].y][world.enemies[e].x + 1] == 0)
|
||||||
|
world.enemies[e].x++;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int e = 0; e < world.enemies_count; e++) {
|
||||||
|
for(int h = e + 1; h < world.enemies_count; h++) {
|
||||||
|
if(world.enemies[e].y == world.enemies[h].y &&
|
||||||
|
world.enemies[e].x == world.enemies[h].x) {
|
||||||
|
world.enemies[h].level++;
|
||||||
|
for(int l = e; l < world.enemies_count - 1; l++) {
|
||||||
|
world.enemies[l] = world.enemies[l + 1];
|
||||||
|
}
|
||||||
|
world.enemies_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(vibration) {
|
||||||
|
notification_message(notification, &vibr1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view_port_update(view_port);
|
||||||
|
furi_mutex_release(bomber_state->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to normal backlight settings
|
||||||
|
notification_message_block(notification, &sequence_display_backlight_enforce_auto);
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
// Специальная очистка памяти, занимаемой очередью
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
|
||||||
|
// Чистим созданные объекты, связанные с интерфейсом
|
||||||
|
gui_remove_view_port(gui, view_port);
|
||||||
|
view_port_free(view_port);
|
||||||
|
|
||||||
|
furi_mutex_free(bomber_state->mutex);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
free(bomber_state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
applications/external/hid_app/assets/OutCircles.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
applications/external/hid_app/assets/Pin_back_arrow_10x10.png
vendored
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
applications/external/hid_app/assets/Pressed_Button_19x19.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
applications/external/hid_app/assets/S_DOWN.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/hid_app/assets/S_LEFT.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/external/hid_app/assets/S_RIGHT.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/external/hid_app/assets/S_UP.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/hid_app/assets/Voldwn_6x6.png
vendored
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
applications/external/hid_app/assets/Volup_8x6.png
vendored
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 4.5 KiB |
21
applications/external/hid_app/hid.c
vendored
@@ -13,6 +13,7 @@ enum HidDebugSubmenuIndex {
|
|||||||
HidSubmenuIndexTikTok,
|
HidSubmenuIndexTikTok,
|
||||||
HidSubmenuIndexYTShorts,
|
HidSubmenuIndexYTShorts,
|
||||||
HidSubmenuIndexMouse,
|
HidSubmenuIndexMouse,
|
||||||
|
HidSubmenuIndexMouseClicker,
|
||||||
HidSubmenuIndexMouseJiggler,
|
HidSubmenuIndexMouseJiggler,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,6 +41,9 @@ static void hid_submenu_callback(void* context, uint32_t index) {
|
|||||||
} else if(index == HidSubmenuIndexYTShorts) {
|
} else if(index == HidSubmenuIndexYTShorts) {
|
||||||
app->view_id = BtHidViewYTShorts;
|
app->view_id = BtHidViewYTShorts;
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts);
|
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts);
|
||||||
|
} else if(index == HidSubmenuIndexMouseClicker) {
|
||||||
|
app->view_id = HidViewMouseClicker;
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker);
|
||||||
} else if(index == HidSubmenuIndexMouseJiggler) {
|
} else if(index == HidSubmenuIndexMouseJiggler) {
|
||||||
app->view_id = HidViewMouseJiggler;
|
app->view_id = HidViewMouseJiggler;
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
|
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
|
||||||
@@ -62,6 +66,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con
|
|||||||
hid_keyboard_set_connected_status(hid->hid_keyboard, connected);
|
hid_keyboard_set_connected_status(hid->hid_keyboard, connected);
|
||||||
hid_media_set_connected_status(hid->hid_media, connected);
|
hid_media_set_connected_status(hid->hid_media, connected);
|
||||||
hid_mouse_set_connected_status(hid->hid_mouse, connected);
|
hid_mouse_set_connected_status(hid->hid_mouse, connected);
|
||||||
|
hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected);
|
||||||
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
|
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
|
||||||
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
|
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
|
||||||
hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected);
|
hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected);
|
||||||
@@ -136,6 +141,12 @@ Hid* hid_alloc(HidTransport transport) {
|
|||||||
hid_submenu_callback,
|
hid_submenu_callback,
|
||||||
app);
|
app);
|
||||||
}
|
}
|
||||||
|
submenu_add_item(
|
||||||
|
app->device_type_submenu,
|
||||||
|
"Mouse Clicker",
|
||||||
|
HidSubmenuIndexMouseClicker,
|
||||||
|
hid_submenu_callback,
|
||||||
|
app);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
app->device_type_submenu,
|
app->device_type_submenu,
|
||||||
"Mouse Jiggler",
|
"Mouse Jiggler",
|
||||||
@@ -209,6 +220,14 @@ Hid* hid_app_alloc_view(void* context) {
|
|||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse));
|
app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse));
|
||||||
|
|
||||||
|
// Mouse clicker view
|
||||||
|
app->hid_mouse_clicker = hid_mouse_clicker_alloc(app);
|
||||||
|
view_set_previous_callback(
|
||||||
|
hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_exit_confirm_view);
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher,
|
||||||
|
HidViewMouseClicker,
|
||||||
|
hid_mouse_clicker_get_view(app->hid_mouse_clicker));
|
||||||
// Mouse jiggler view
|
// Mouse jiggler view
|
||||||
app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app);
|
app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app);
|
||||||
view_set_previous_callback(
|
view_set_previous_callback(
|
||||||
@@ -244,6 +263,8 @@ void hid_free(Hid* app) {
|
|||||||
hid_media_free(app->hid_media);
|
hid_media_free(app->hid_media);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse);
|
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse);
|
||||||
hid_mouse_free(app->hid_mouse);
|
hid_mouse_free(app->hid_mouse);
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseClicker);
|
||||||
|
hid_mouse_clicker_free(app->hid_mouse_clicker);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler);
|
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler);
|
||||||
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
|
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
|
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
|
||||||
|
|||||||
2
applications/external/hid_app/hid.h
vendored
@@ -24,6 +24,7 @@
|
|||||||
#include "views/hid_mouse_jiggler.h"
|
#include "views/hid_mouse_jiggler.h"
|
||||||
#include "views/hid_tiktok.h"
|
#include "views/hid_tiktok.h"
|
||||||
#include "views/hid_ytshorts.h"
|
#include "views/hid_ytshorts.h"
|
||||||
|
#include "views/hid_mouse_clicker.h"
|
||||||
|
|
||||||
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
|
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ struct Hid {
|
|||||||
HidKeyboard* hid_keyboard;
|
HidKeyboard* hid_keyboard;
|
||||||
HidMedia* hid_media;
|
HidMedia* hid_media;
|
||||||
HidMouse* hid_mouse;
|
HidMouse* hid_mouse;
|
||||||
|
HidMouseClicker* hid_mouse_clicker;
|
||||||
HidMouseJiggler* hid_mouse_jiggler;
|
HidMouseJiggler* hid_mouse_jiggler;
|
||||||
HidTikTok* hid_tiktok;
|
HidTikTok* hid_tiktok;
|
||||||
HidYTShorts* hid_ytshorts;
|
HidYTShorts* hid_ytshorts;
|
||||||
|
|||||||
1
applications/external/hid_app/views.h
vendored
@@ -5,6 +5,7 @@ typedef enum {
|
|||||||
HidViewKeyboard,
|
HidViewKeyboard,
|
||||||
HidViewMedia,
|
HidViewMedia,
|
||||||
HidViewMouse,
|
HidViewMouse,
|
||||||
|
HidViewMouseClicker,
|
||||||
HidViewMouseJiggler,
|
HidViewMouseJiggler,
|
||||||
BtHidViewTikTok,
|
BtHidViewTikTok,
|
||||||
BtHidViewYTShorts,
|
BtHidViewYTShorts,
|
||||||
|
|||||||
51
applications/external/hid_app/views/hid_media.c
vendored
@@ -21,6 +21,7 @@ typedef struct {
|
|||||||
bool down_pressed;
|
bool down_pressed;
|
||||||
bool ok_pressed;
|
bool ok_pressed;
|
||||||
bool connected;
|
bool connected;
|
||||||
|
bool back_pressed;
|
||||||
HidTransport transport;
|
HidTransport transport;
|
||||||
} HidMediaModel;
|
} HidMediaModel;
|
||||||
|
|
||||||
@@ -55,61 +56,72 @@ static void hid_media_draw_callback(Canvas* canvas, void* context) {
|
|||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
// Keypad circles
|
// Keypad circles
|
||||||
canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47);
|
canvas_draw_icon(canvas, 58, 3, &I_OutCircles);
|
||||||
|
|
||||||
// Up
|
// Up
|
||||||
if(model->up_pressed) {
|
if(model->up_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 6, &I_S_UP);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6);
|
canvas_draw_icon(canvas, 79, 9, &I_Volup_8x6);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Down
|
// Down
|
||||||
if(model->down_pressed) {
|
if(model->down_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 36, &I_S_DOWN);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6);
|
canvas_draw_icon(canvas, 80, 41, &I_Voldwn_6x6);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Left
|
// Left
|
||||||
if(model->left_pressed) {
|
if(model->left_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 61, 13, &I_S_LEFT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft);
|
hid_media_draw_arrow(canvas, 65, 28, CanvasDirectionRightToLeft);
|
||||||
hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft);
|
hid_media_draw_arrow(canvas, 70, 28, CanvasDirectionRightToLeft);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Right
|
// Right
|
||||||
if(model->right_pressed) {
|
if(model->right_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight);
|
hid_media_draw_arrow(canvas, 96, 28, CanvasDirectionLeftToRight);
|
||||||
hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight);
|
hid_media_draw_arrow(canvas, 101, 28, CanvasDirectionLeftToRight);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Ok
|
// Ok
|
||||||
if(model->ok_pressed) {
|
if(model->ok_pressed) {
|
||||||
canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
|
canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight);
|
hid_media_draw_arrow(canvas, 80, 28, CanvasDirectionLeftToRight);
|
||||||
canvas_draw_line(canvas, 100, 29, 100, 33);
|
canvas_draw_line(canvas, 84, 26, 84, 30);
|
||||||
canvas_draw_line(canvas, 102, 29, 102, 33);
|
canvas_draw_line(canvas, 86, 26, 86, 30);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Exit
|
// Exit
|
||||||
|
if(model->back_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
|
canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
|
}
|
||||||
|
canvas_draw_icon(canvas, 111, 38, &I_Pin_back_arrow_10x10);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
|
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
|
||||||
@@ -135,6 +147,8 @@ static void hid_media_process_press(HidMedia* hid_media, InputEvent* event) {
|
|||||||
} else if(event->key == InputKeyOk) {
|
} else if(event->key == InputKeyOk) {
|
||||||
model->ok_pressed = true;
|
model->ok_pressed = true;
|
||||||
hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_PLAY_PAUSE);
|
hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_PLAY_PAUSE);
|
||||||
|
} else if(event->key == InputKeyBack) {
|
||||||
|
model->back_pressed = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
@@ -160,6 +174,8 @@ static void hid_media_process_release(HidMedia* hid_media, InputEvent* event) {
|
|||||||
} else if(event->key == InputKeyOk) {
|
} else if(event->key == InputKeyOk) {
|
||||||
model->ok_pressed = false;
|
model->ok_pressed = false;
|
||||||
hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_PLAY_PAUSE);
|
hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_PLAY_PAUSE);
|
||||||
|
} else if(event->key == InputKeyBack) {
|
||||||
|
model->back_pressed = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
@@ -176,12 +192,7 @@ static bool hid_media_input_callback(InputEvent* event, void* context) {
|
|||||||
} else if(event->type == InputTypeRelease) {
|
} else if(event->type == InputTypeRelease) {
|
||||||
hid_media_process_release(hid_media, event);
|
hid_media_process_release(hid_media, event);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event->type == InputTypeShort) {
|
|
||||||
if(event->key == InputKeyBack) {
|
|
||||||
hid_hal_consumer_key_release_all(hid_media->hid);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
applications/external/hid_app/views/hid_mouse.c
vendored
@@ -49,66 +49,66 @@ static void hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keypad circles
|
// Keypad circles
|
||||||
canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47);
|
canvas_draw_icon(canvas, 58, 3, &I_OutCircles);
|
||||||
|
|
||||||
// Up
|
// Up
|
||||||
if(model->up_pressed) {
|
if(model->up_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 6, &I_S_UP);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9);
|
canvas_draw_icon(canvas, 80, 8, &I_Pin_arrow_up_7x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Down
|
// Down
|
||||||
if(model->down_pressed) {
|
if(model->down_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 36, &I_S_DOWN);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9);
|
canvas_draw_icon(canvas, 80, 40, &I_Pin_arrow_down_7x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Left
|
// Left
|
||||||
if(model->left_pressed) {
|
if(model->left_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 61, 13, &I_S_LEFT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7);
|
canvas_draw_icon(canvas, 63, 25, &I_Pin_arrow_left_9x7);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Right
|
// Right
|
||||||
if(model->right_pressed) {
|
if(model->right_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7);
|
canvas_draw_icon(canvas, 95, 25, &I_Pin_arrow_right_9x7);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Ok
|
// Ok
|
||||||
if(model->left_mouse_pressed) {
|
if(model->left_mouse_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9);
|
canvas_draw_icon(canvas, 79, 24, &I_Left_mouse_icon_9x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Back
|
// Back
|
||||||
if(model->right_mouse_pressed) {
|
if(model->right_mouse_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9);
|
canvas_draw_icon(canvas, 112, 38, &I_Right_mouse_icon_9x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
214
applications/external/hid_app/views/hid_mouse_clicker.c
vendored
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
#include "hid_mouse_clicker.h"
|
||||||
|
#include <gui/elements.h>
|
||||||
|
#include "../hid.h"
|
||||||
|
|
||||||
|
#include "hid_icons.h"
|
||||||
|
|
||||||
|
#define TAG "HidMouseClicker"
|
||||||
|
#define DEFAULT_CLICK_RATE 1
|
||||||
|
#define MAXIMUM_CLICK_RATE 60
|
||||||
|
|
||||||
|
struct HidMouseClicker {
|
||||||
|
View* view;
|
||||||
|
Hid* hid;
|
||||||
|
FuriTimer* timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool connected;
|
||||||
|
bool running;
|
||||||
|
int rate;
|
||||||
|
HidTransport transport;
|
||||||
|
} HidMouseClickerModel;
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_start_or_restart_timer(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
|
||||||
|
if(furi_timer_is_running(hid_mouse_clicker->timer)) {
|
||||||
|
furi_timer_stop(hid_mouse_clicker->timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
furi_timer_start(
|
||||||
|
hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClickerModel* model = context;
|
||||||
|
|
||||||
|
// Header
|
||||||
|
if(model->transport == HidTransportBle) {
|
||||||
|
if(model->connected) {
|
||||||
|
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
|
||||||
|
} else {
|
||||||
|
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Clicker");
|
||||||
|
|
||||||
|
// Ok
|
||||||
|
canvas_draw_icon(canvas, 63, 25, &I_Space_65x18);
|
||||||
|
if(model->running) {
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
|
||||||
|
FuriString* rate_label = furi_string_alloc();
|
||||||
|
furi_string_printf(rate_label, "%d clicks/s\n\nUp / Down", model->rate);
|
||||||
|
elements_multiline_text(canvas, AlignLeft, 35, furi_string_get_cstr(rate_label));
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
furi_string_free(rate_label);
|
||||||
|
|
||||||
|
elements_slightly_rounded_box(canvas, 66, 27, 60, 13);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
|
} else {
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto start\nclicking");
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
}
|
||||||
|
canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9);
|
||||||
|
if(model->running) {
|
||||||
|
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop");
|
||||||
|
} else {
|
||||||
|
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start");
|
||||||
|
}
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
|
// Back
|
||||||
|
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
|
||||||
|
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_timer_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
if(model->running) {
|
||||||
|
hid_hal_mouse_press(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT);
|
||||||
|
hid_hal_mouse_release(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_enter_callback(void* context) {
|
||||||
|
hid_mouse_clicker_start_or_restart_timer(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_exit_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
furi_timer_stop(hid_mouse_clicker->timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
bool rate_changed = false;
|
||||||
|
|
||||||
|
if(event->type != InputTypeRelease) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
switch(event->key) {
|
||||||
|
case InputKeyOk:
|
||||||
|
model->running = !model->running;
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
case InputKeyUp:
|
||||||
|
if(model->rate < MAXIMUM_CLICK_RATE) {
|
||||||
|
model->rate++;
|
||||||
|
}
|
||||||
|
rate_changed = true;
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
case InputKeyDown:
|
||||||
|
if(model->rate > 1) {
|
||||||
|
model->rate--;
|
||||||
|
}
|
||||||
|
rate_changed = true;
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
if(rate_changed) {
|
||||||
|
hid_mouse_clicker_start_or_restart_timer(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
HidMouseClicker* hid_mouse_clicker_alloc(Hid* hid) {
|
||||||
|
HidMouseClicker* hid_mouse_clicker = malloc(sizeof(HidMouseClicker));
|
||||||
|
|
||||||
|
hid_mouse_clicker->view = view_alloc();
|
||||||
|
view_set_context(hid_mouse_clicker->view, hid_mouse_clicker);
|
||||||
|
view_allocate_model(
|
||||||
|
hid_mouse_clicker->view, ViewModelTypeLocking, sizeof(HidMouseClickerModel));
|
||||||
|
view_set_draw_callback(hid_mouse_clicker->view, hid_mouse_clicker_draw_callback);
|
||||||
|
view_set_input_callback(hid_mouse_clicker->view, hid_mouse_clicker_input_callback);
|
||||||
|
view_set_enter_callback(hid_mouse_clicker->view, hid_mouse_clicker_enter_callback);
|
||||||
|
view_set_exit_callback(hid_mouse_clicker->view, hid_mouse_clicker_exit_callback);
|
||||||
|
|
||||||
|
hid_mouse_clicker->hid = hid;
|
||||||
|
|
||||||
|
hid_mouse_clicker->timer = furi_timer_alloc(
|
||||||
|
hid_mouse_clicker_timer_callback, FuriTimerTypePeriodic, hid_mouse_clicker);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
model->transport = hid->transport;
|
||||||
|
model->rate = DEFAULT_CLICK_RATE;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
return hid_mouse_clicker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker) {
|
||||||
|
furi_assert(hid_mouse_clicker);
|
||||||
|
|
||||||
|
furi_timer_stop(hid_mouse_clicker->timer);
|
||||||
|
furi_timer_free(hid_mouse_clicker->timer);
|
||||||
|
|
||||||
|
view_free(hid_mouse_clicker->view);
|
||||||
|
|
||||||
|
free(hid_mouse_clicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker) {
|
||||||
|
furi_assert(hid_mouse_clicker);
|
||||||
|
return hid_mouse_clicker->view;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected) {
|
||||||
|
furi_assert(hid_mouse_clicker);
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{ model->connected = connected; },
|
||||||
|
true);
|
||||||
|
}
|
||||||
14
applications/external/hid_app/views/hid_mouse_clicker.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gui/view.h>
|
||||||
|
|
||||||
|
typedef struct Hid Hid;
|
||||||
|
typedef struct HidMouseClicker HidMouseClicker;
|
||||||
|
|
||||||
|
HidMouseClicker* hid_mouse_clicker_alloc(Hid* bt_hid);
|
||||||
|
|
||||||
|
void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker);
|
||||||
|
|
||||||
|
View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker);
|
||||||
|
|
||||||
|
void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected);
|
||||||
42
applications/external/hid_app/views/hid_tiktok.c
vendored
@@ -41,64 +41,68 @@ static void hid_tiktok_draw_callback(Canvas* canvas, void* context) {
|
|||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
// Keypad circles
|
// Keypad circles
|
||||||
canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47);
|
canvas_draw_icon(canvas, 58, 3, &I_OutCircles);
|
||||||
|
|
||||||
// Pause
|
// Pause
|
||||||
if(model->back_mouse_pressed) {
|
if(model->back_mouse_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9);
|
canvas_draw_icon(canvas, 113, 37, &I_Pause_icon_9x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Up
|
// Up
|
||||||
if(model->up_pressed) {
|
if(model->up_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 6, &I_S_UP);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9);
|
canvas_draw_icon(canvas, 80, 8, &I_Arr_up_7x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Down
|
// Down
|
||||||
if(model->down_pressed) {
|
if(model->down_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 36, &I_S_DOWN);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9);
|
canvas_draw_icon(canvas, 80, 40, &I_Arr_dwn_7x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Left
|
// Left
|
||||||
if(model->left_pressed) {
|
if(model->left_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 61, 13, &I_S_LEFT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6);
|
canvas_draw_icon(canvas, 64, 25, &I_Voldwn_6x6);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Right
|
// Right
|
||||||
if(model->right_pressed) {
|
if(model->right_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6);
|
canvas_draw_icon(canvas, 95, 25, &I_Volup_8x6);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Ok
|
// Ok
|
||||||
if(model->ok_pressed) {
|
if(model->ok_pressed) {
|
||||||
canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
} else {
|
canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19);
|
||||||
canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
|
canvas_draw_icon(canvas, 78, 25, &I_Like_def_11x9);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Exit
|
// Exit
|
||||||
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
@@ -186,18 +190,18 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) {
|
|||||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event->key == InputKeyDown) {
|
} else if(event->key == InputKeyDown) {
|
||||||
// Swipe to new video
|
// Swipe to previous video
|
||||||
hid_hal_mouse_scroll(hid_tiktok->hid, 19);
|
hid_hal_mouse_scroll(hid_tiktok->hid, 19);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event->key == InputKeyUp) {
|
} else if(event->key == InputKeyUp) {
|
||||||
// Swipe to previous video
|
// Swipe to new video
|
||||||
hid_hal_mouse_scroll(hid_tiktok->hid, -19);
|
hid_hal_mouse_scroll(hid_tiktok->hid, -19);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event->key == InputKeyBack) {
|
} else if(event->key == InputKeyBack) {
|
||||||
// Pause
|
// Pause
|
||||||
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT);
|
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||||
furi_delay_ms(25);
|
furi_delay_ms(50);
|
||||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT);
|
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event->type == InputTypeLong) {
|
} else if(event->type == InputTypeLong) {
|
||||||
|
|||||||
@@ -41,64 +41,68 @@ static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) {
|
|||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
// Keypad circles
|
// Keypad circles
|
||||||
canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47);
|
canvas_draw_icon(canvas, 58, 3, &I_OutCircles);
|
||||||
|
|
||||||
// Pause
|
// Pause
|
||||||
if(model->back_mouse_pressed) {
|
if(model->back_mouse_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9);
|
canvas_draw_icon(canvas, 113, 37, &I_Pause_icon_9x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Up
|
// Up
|
||||||
if(model->up_pressed) {
|
if(model->up_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 6, &I_S_UP);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9);
|
canvas_draw_icon(canvas, 80, 8, &I_Arr_up_7x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Down
|
// Down
|
||||||
if(model->down_pressed) {
|
if(model->down_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 68, 36, &I_S_DOWN);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9);
|
canvas_draw_icon(canvas, 80, 40, &I_Arr_dwn_7x9);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Left
|
// Left
|
||||||
if(model->left_pressed) {
|
if(model->left_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 61, 13, &I_S_LEFT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6);
|
canvas_draw_icon(canvas, 64, 25, &I_Voldwn_6x6);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Right
|
// Right
|
||||||
if(model->right_pressed) {
|
if(model->right_pressed) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT);
|
||||||
canvas_set_bitmap_mode(canvas, 0);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6);
|
canvas_draw_icon(canvas, 95, 25, &I_Volup_8x6);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Ok
|
// Ok
|
||||||
if(model->ok_pressed) {
|
if(model->ok_pressed) {
|
||||||
canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
} else {
|
canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19);
|
||||||
canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9);
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
|
canvas_draw_icon(canvas, 78, 25, &I_Like_def_11x9);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
// Exit
|
// Exit
|
||||||
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|||||||
@@ -3166,6 +3166,11 @@ int32_t swd_probe_app_main(void* p) {
|
|||||||
furi_message_queue_free(app->event_queue);
|
furi_message_queue_free(app->event_queue);
|
||||||
furi_mutex_free(app->gui_mutex);
|
furi_mutex_free(app->gui_mutex);
|
||||||
furi_mutex_free(app->swd_mutex);
|
furi_mutex_free(app->swd_mutex);
|
||||||
|
|
||||||
|
// Reset GPIO pins to default state
|
||||||
|
for(int io = 0; io < 8; io++) {
|
||||||
|
furi_hal_gpio_init(gpios[io], GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||||
|
}
|
||||||
free(app);
|
free(app);
|
||||||
|
|
||||||
furi_record_close(RECORD_GUI);
|
furi_record_close(RECORD_GUI);
|
||||||
|
|||||||
@@ -68,7 +68,9 @@ static bool seek_to_token(size_t token_index, TokenInfoIteratorContext* context)
|
|||||||
direction = StreamDirectionBackward;
|
direction = StreamDirectionBackward;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart);
|
if(!stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(token_index_diff != 0) {
|
if(token_index_diff != 0) {
|
||||||
long i = 0;
|
long i = 0;
|
||||||
@@ -89,10 +91,6 @@ static bool seek_to_token(size_t token_index, TokenInfoIteratorContext* context)
|
|||||||
|
|
||||||
context->last_seek_offset = stream_tell(stream);
|
context->last_seek_offset = stream_tell(stream);
|
||||||
context->last_seek_index = token_index;
|
context->last_seek_index = token_index;
|
||||||
} else {
|
|
||||||
if(!stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -495,11 +493,9 @@ bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t to
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t temp_data32;
|
uint32_t temp_data32;
|
||||||
if(flipper_format_read_uint32(
|
if(!flipper_format_read_uint32(
|
||||||
context->config_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &temp_data32, 1) &&
|
context->config_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &temp_data32, 1) ||
|
||||||
temp_data32 <= STEAM) {
|
!token_info_set_algo_from_int(tokenInfo, temp_data32)) {
|
||||||
tokenInfo->algo = (TokenHashAlgo)temp_data32;
|
|
||||||
} else {
|
|
||||||
tokenInfo->algo = SHA1;
|
tokenInfo->algo = SHA1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sha256.h"
|
|
||||||
#include "memxor.h"
|
#include "memxor.h"
|
||||||
|
|
||||||
#define IPAD 0x36
|
#define IPAD 0x36
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include "hmac_sha256.h"
|
#include "hmac_sha256.h"
|
||||||
|
#include "sha256.h"
|
||||||
|
|
||||||
#define GL_HMAC_NAME 256
|
#define GL_HMAC_NAME 256
|
||||||
#define GL_HMAC_BLOCKSIZE 64
|
#define GL_HMAC_BLOCKSIZE 64
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define SWAP(n) (n)
|
#define SWAP(n) (n)
|
||||||
#else
|
#else
|
||||||
@@ -34,10 +36,6 @@
|
|||||||
#define SWAP(n) swap_uint32(n)
|
#define SWAP(n) swap_uint32(n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This array contains the bytes used to pad the buffer to the next
|
|
||||||
64-byte boundary. (RFC 1321, 3.1: Step 1) */
|
|
||||||
static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
|
|
||||||
|
|
||||||
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
|
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
|
||||||
initialize it to the start constants of the SHA1 algorithm. This
|
initialize it to the start constants of the SHA1 algorithm. This
|
||||||
must be called before using hash in the call to sha1_hash. */
|
must be called before using hash in the call to sha1_hash. */
|
||||||
@@ -87,7 +85,7 @@ void* sha1_finish_ctx(struct sha1_ctx* ctx, void* resbuf) {
|
|||||||
ctx->buffer[size - 2] = SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29));
|
ctx->buffer[size - 2] = SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29));
|
||||||
ctx->buffer[size - 1] = SWAP(ctx->total[0] << 3);
|
ctx->buffer[size - 1] = SWAP(ctx->total[0] << 3);
|
||||||
|
|
||||||
memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
|
sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 4 - bytes);
|
||||||
|
|
||||||
/* Process last bytes. */
|
/* Process last bytes. */
|
||||||
sha1_process_block(ctx->buffer, size * 4, ctx);
|
sha1_process_block(ctx->buffer, size * 4, ctx);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define SWAP(n) (n)
|
#define SWAP(n) (n)
|
||||||
@@ -33,10 +34,6 @@
|
|||||||
#define SWAP(n) swap_uint32(n)
|
#define SWAP(n) swap_uint32(n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This array contains the bytes used to pad the buffer to the next
|
|
||||||
64-byte boundary. */
|
|
||||||
static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
|
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
|
||||||
initializes it to the start constants of the SHA256 algorithm. This
|
initializes it to the start constants of the SHA256 algorithm. This
|
||||||
@@ -91,7 +88,7 @@ static void sha256_conclude_ctx(struct sha256_ctx* ctx) {
|
|||||||
set_uint32((char*)&ctx->buffer[size - 2], SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
|
set_uint32((char*)&ctx->buffer[size - 2], SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
|
||||||
set_uint32((char*)&ctx->buffer[size - 1], SWAP(ctx->total[0] << 3));
|
set_uint32((char*)&ctx->buffer[size - 1], SWAP(ctx->total[0] << 3));
|
||||||
|
|
||||||
memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
|
sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 4 - bytes);
|
||||||
|
|
||||||
/* Process last bytes. */
|
/* Process last bytes. */
|
||||||
sha256_process_block(ctx->buffer, size * 4, ctx);
|
sha256_process_block(ctx->buffer, size * 4, ctx);
|
||||||
|
|||||||
@@ -27,13 +27,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "byteswap.h"
|
#include "byteswap.h"
|
||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
|
||||||
#define SWAP(n) swap_uint64(n)
|
#define SWAP(n) swap_uint64(n)
|
||||||
|
|
||||||
/* This array contains the bytes used to pad the buffer to the next
|
|
||||||
128-byte boundary. */
|
|
||||||
static const unsigned char fillbuf[128] = {0x80, 0 /* , 0, 0, ... */};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Takes a pointer to a 512 bit block of data (eight 64 bit ints) and
|
Takes a pointer to a 512 bit block of data (eight 64 bit ints) and
|
||||||
initializes it to the start constants of the SHA512 algorithm. This
|
initializes it to the start constants of the SHA512 algorithm. This
|
||||||
@@ -90,7 +87,7 @@ static void sha512_conclude_ctx(struct sha512_ctx* ctx) {
|
|||||||
SWAP(u64or(u64shl(ctx->total[1], 3), u64shr(ctx->total[0], 61))));
|
SWAP(u64or(u64shl(ctx->total[1], 3), u64shr(ctx->total[0], 61))));
|
||||||
set_uint64((char*)&ctx->buffer[size - 1], SWAP(u64shl(ctx->total[0], 3)));
|
set_uint64((char*)&ctx->buffer[size - 1], SWAP(u64shl(ctx->total[0], 3)));
|
||||||
|
|
||||||
memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes);
|
sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 8 - bytes);
|
||||||
|
|
||||||
/* Process last bytes. */
|
/* Process last bytes. */
|
||||||
sha512_process_block(ctx->buffer, size * 8, ctx);
|
sha512_process_block(ctx->buffer, size * 8, ctx);
|
||||||
|
|||||||
11
applications/external/totp/services/hmac/sha_pad_buffer.c
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include "sha_pad_buffer.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void sha_pad_buffer(uint8_t* buffer, size_t size) {
|
||||||
|
if(size > 0) {
|
||||||
|
buffer[0] = 0x80;
|
||||||
|
if(size > 1) {
|
||||||
|
memset(&buffer[1], 0, size - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
applications/external/totp/services/hmac/sha_pad_buffer.h
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void sha_pad_buffer(uint8_t* buffer, size_t size);
|
||||||
21
applications/external/totp/types/token_info.c
vendored
@@ -117,6 +117,27 @@ bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool token_info_set_algo_from_int(TokenInfo* token_info, uint8_t algo_code) {
|
||||||
|
switch(algo_code) {
|
||||||
|
case SHA1:
|
||||||
|
token_info->algo = SHA1;
|
||||||
|
break;
|
||||||
|
case SHA256:
|
||||||
|
token_info->algo = SHA256;
|
||||||
|
break;
|
||||||
|
case SHA512:
|
||||||
|
token_info->algo = SHA512;
|
||||||
|
break;
|
||||||
|
case STEAM:
|
||||||
|
token_info->algo = STEAM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
|
char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
|
||||||
switch(token_info->algo) {
|
switch(token_info->algo) {
|
||||||
case SHA1:
|
case SHA1:
|
||||||
|
|||||||
12
applications/external/totp/types/token_info.h
vendored
@@ -168,7 +168,7 @@ void token_info_free(TokenInfo* token_info);
|
|||||||
/**
|
/**
|
||||||
* @brief Encrypts & sets plain token secret to the given instance of \c TokenInfo
|
* @brief Encrypts & sets plain token secret to the given instance of \c TokenInfo
|
||||||
* @param token_info instance where secret should be updated
|
* @param token_info instance where secret should be updated
|
||||||
* @param base32_token_secret plain token secret in Base32 format
|
* @param plain_token_secret plain token secret
|
||||||
* @param token_secret_length plain token secret length
|
* @param token_secret_length plain token secret length
|
||||||
* @param plain_token_secret_encoding plain token secret encoding
|
* @param plain_token_secret_encoding plain token secret encoding
|
||||||
* @param iv initialization vecor (IV) to be used for encryption
|
* @param iv initialization vecor (IV) to be used for encryption
|
||||||
@@ -201,10 +201,18 @@ bool token_info_set_duration_from_int(TokenInfo* token_info, uint8_t duration);
|
|||||||
* @brief Sets token hashing algorithm from \c str value
|
* @brief Sets token hashing algorithm from \c str value
|
||||||
* @param token_info instance whichs token hashing algorithm should be updated
|
* @param token_info instance whichs token hashing algorithm should be updated
|
||||||
* @param str desired token algorithm
|
* @param str desired token algorithm
|
||||||
* @return \c true if token hahsing algorithm has been updated; \c false otherwise
|
* @return \c true if token hashing algorithm has been updated; \c false otherwise
|
||||||
*/
|
*/
|
||||||
bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str);
|
bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets token hashing algorithm from \c algo_code code
|
||||||
|
* @param token_info instance whichs token hashing algorithm should be updated
|
||||||
|
* @param algo_code desired token algorithm code
|
||||||
|
* @return \c true if token hashing algorithm has been updated; \c false otherwise
|
||||||
|
*/
|
||||||
|
bool token_info_set_algo_from_int(TokenInfo* token_info, uint8_t algo_code);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets token hahsing algorithm name as C-string
|
* @brief Gets token hahsing algorithm name as C-string
|
||||||
* @param token_info instance which token hahsing algorithm name should be returned
|
* @param token_info instance which token hahsing algorithm name should be returned
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ static uint32_t get_keypress_delay(TokenAutomationFeature features) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void totp_type_code_worker_press_key(
|
static void totp_type_code_worker_press_key(
|
||||||
uint8_t key,
|
uint16_t key,
|
||||||
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
||||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||||
TokenAutomationFeature features) {
|
TokenAutomationFeature features) {
|
||||||
@@ -47,8 +47,6 @@ void totp_type_code_worker_execute_automation(
|
|||||||
TokenAutomationFeature features) {
|
TokenAutomationFeature features) {
|
||||||
furi_delay_ms(500);
|
furi_delay_ms(500);
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
totp_type_code_worker_press_key(
|
|
||||||
HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features);
|
|
||||||
|
|
||||||
while(i < code_buffer_size && code_buffer[i] != 0) {
|
while(i < code_buffer_size && code_buffer[i] != 0) {
|
||||||
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]);
|
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]);
|
||||||
@@ -58,7 +56,11 @@ void totp_type_code_worker_execute_automation(
|
|||||||
|
|
||||||
if(char_index > 35) break;
|
if(char_index > 35) break;
|
||||||
|
|
||||||
uint8_t hid_kb_key = hid_number_keys[char_index];
|
uint16_t hid_kb_key = hid_number_keys[char_index];
|
||||||
|
if(char_index > 9) {
|
||||||
|
hid_kb_key |= KEY_MOD_LEFT_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
totp_type_code_worker_press_key(hid_kb_key, key_press_fn, key_release_fn, features);
|
totp_type_code_worker_press_key(hid_kb_key, key_press_fn, key_release_fn, features);
|
||||||
furi_delay_ms(get_keystroke_delay(features));
|
furi_delay_ms(get_keystroke_delay(features));
|
||||||
i++;
|
i++;
|
||||||
@@ -74,7 +76,4 @@ void totp_type_code_worker_execute_automation(
|
|||||||
furi_delay_ms(get_keystroke_delay(features));
|
furi_delay_ms(get_keystroke_delay(features));
|
||||||
totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, features);
|
totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, features);
|
||||||
}
|
}
|
||||||
|
|
||||||
totp_type_code_worker_press_key(
|
|
||||||
HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features);
|
|
||||||
}
|
}
|
||||||
@@ -242,5 +242,6 @@ bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view)
|
|||||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||||
const DesktopViewLockedState view_state = model->view_state;
|
const DesktopViewLockedState view_state = model->view_state;
|
||||||
view_commit_model(locked_view->view, false);
|
view_commit_model(locked_view->view, false);
|
||||||
return view_state == DesktopViewLockedStateLockedHintShown;
|
return view_state == DesktopViewLockedStateLockedHintShown ||
|
||||||
|
view_state == DesktopViewLockedStateLocked;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Filetype: IR library file
|
Filetype: IR library file
|
||||||
Version: 1
|
Version: 1
|
||||||
# Last Updated 07th Mar, 2023
|
# Last Updated 2, May, 2023
|
||||||
# Last Checked 25th Apr, 2023
|
# Last Checked 2, May, 2023
|
||||||
#
|
#
|
||||||
name: POWER
|
name: POWER
|
||||||
type: parsed
|
type: parsed
|
||||||
@@ -1899,3 +1899,39 @@ type: parsed
|
|||||||
protocol: SIRC20
|
protocol: SIRC20
|
||||||
address: 10 01 00 00
|
address: 10 01 00 00
|
||||||
command: 33 00 00 00
|
command: 33 00 00 00
|
||||||
|
#
|
||||||
|
name: POWER
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 195 1833 300 766 280 760 275 790 276 737 309 731 304 1801 301 1804 309 731 304 1801 270 795 282 758 277 762 273 1832 270 769 246 45851 326 1780 302 739 307 785 282 732 303 736 310 1795 307 732 303 763 303 1775 307 733 334 1798 273 1832 270 1810 251 814 273 1780 281 43762 302 1804 309 758 277 737 330 762 284 730 305 734 301 1803 310 1796 306 733 302 1829 273 767 279 734 301 791 275 1804 278 762 253 45870 307 1798 304 763 272 767 279 787 279 760 275 1829 284 730 305 734 301 1804 309 757 278 1827 275 1804 278 1828 274 765 270 1835 278 43740 303 1776 306 787 279 760 275 765 281 759 307 758 277 1775 307 1799 303 736 299 1832 281 759 276 763 304 736 299 1832 281 733 302 45820 306 1800 302 764 282 758 277 788 278 762 284 1821 281 732 303 736 310 1796 307 733 302 1829 273 1806 276 1830 272 767 268 1837 245 43772 302 1778 304 789 277 762 284 756 279 786 249 765 301 1777 336 1770 301 764 282 1824 278 761 274 765 301 738 308 1824 278 761 274
|
||||||
|
#
|
||||||
|
name: MUTE
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 254 1721 360 681 354 738 308 706 329 711 355 1774 307 1772 361 1744 327 687 359 1772 299 742 335 705 330 736 279 1825 298 742 283 44773 384 1721 360 707 308 707 359 733 302 711 335 705 361 704 331 708 338 1766 336 704 331 1773 329 1776 306 1773 360 681 323 1782 331 44726 411 1722 328 686 360 733 302 711 335 705 361 1742 329 1803 330 1749 332 708 327 1777 335 705 330 710 325 741 274 1830 303 737 278 44778 359 1747 355 712 303 711 355 711 335 705 330 709 337 703 363 703 332 1770 332 709 337 1767 335 1771 300 1752 360 733 302 1776 326 44731 355 1751 330 711 355 737 309 705 330 710 336 1793 309 1771 331 1774 307 706 360 1771 300 740 326 714 332 735 280 1798 325 741 274
|
||||||
|
#
|
||||||
|
name: POWER
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 9219 4484 662 469 661 469 661 1627 660 471 658 474 656 499 631 499 631 499 631 1657 630 1657 631 500 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 500 630 1657 630 500 631 500 630 500 631 500 630 1657 630 1658 630 1657 631 500 630 1657 631 1658 630 1658 630 1658 630 40107 9106 2202 631
|
||||||
|
#
|
||||||
|
name: VOL+
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 9218 4484 636 495 660 469 661 1627 660 471 658 472 658 474 656 475 655 474 656 1632 655 1632 656 474 657 1632 656 1631 657 1632 656 1631 656 1632 656 474 656 1632 655 475 656 474 657 474 656 474 656 474 656 474 656 1632 655 474 656 1632 656 1632 656 1632 656 1632 656 1632 656 1632 656 40103 9107 2177 655
|
||||||
|
#
|
||||||
|
name: VOL-
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 9245 4429 689 467 662 468 661 1626 660 471 658 473 657 474 656 474 656 474 656 1631 657 1631 657 474 656 1631 656 1632 656 1631 657 1631 657 1631 656 1632 656 1631 657 474 656 474 656 474 657 474 656 474 656 474 657 474 656 474 656 1631 656 1632 656 1632 656 1632 656 1632 656 1631 656 40082 9109 2175 656
|
||||||
|
#
|
||||||
|
name: MUTE
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 9219 4485 636 495 660 469 661 1626 661 471 658 473 657 474 656 499 631 500 630 1657 630 1657 631 500 630 1657 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 1657 631 500 630 500 630 500 630 500 631 500 630 1657 631 1657 631 500 630 1657 631 1658 630 1657 631 1658 630 39868 9106 2178 655
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ after that on web updater page - press `Connect` button
|
|||||||
- And wait, if all flashed
|
- And wait, if all flashed
|
||||||
successfully - you will have all needed assets pre installed
|
successfully - you will have all needed assets pre installed
|
||||||
- Done
|
- Done
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@@ -40,7 +40,7 @@ after that on web updater page - press `Connect` button
|
|||||||
- Error in ios app will show up, but flipper will be updated successfully
|
- Error in ios app will show up, but flipper will be updated successfully
|
||||||
- And if all flashed successfully - you will have all needed assets pre installed
|
- And if all flashed successfully - you will have all needed assets pre installed
|
||||||
- Done
|
- Done
|
||||||

|

|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@@ -56,7 +56,8 @@ after that on web updater page - press `Connect` button
|
|||||||
- Wait until update is finished
|
- Wait until update is finished
|
||||||
- And if all flashed successfully - you will have all needed assets pre installed
|
- And if all flashed successfully - you will have all needed assets pre installed
|
||||||
- Done
|
- Done
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@@ -71,7 +72,7 @@ after that on web updater page - press `Connect` button
|
|||||||
- Wait until update is finished
|
- Wait until update is finished
|
||||||
- And if all flashed successfully - you will have all needed assets pre installed
|
- And if all flashed successfully - you will have all needed assets pre installed
|
||||||
- Done
|
- Done
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@@ -89,8 +90,7 @@ after that on web updater page - press `Connect` button
|
|||||||
- Update will start
|
- Update will start
|
||||||
- And wait, if all flashed successfully - you will have all needed assets pre installed
|
- And wait, if all flashed successfully - you will have all needed assets pre installed
|
||||||
- Done
|
- Done
|
||||||
|

|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -110,8 +110,9 @@ after that on web updater page - press `Connect` button
|
|||||||
`update/f7-update-(CURRENT VERSION)/update.fuf`
|
`update/f7-update-(CURRENT VERSION)/update.fuf`
|
||||||
- Update will start, wait for all stages
|
- Update will start, wait for all stages
|
||||||
- Done
|
- Done
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ void dev_info_svc_start() {
|
|||||||
dev_info_svc->version_string = furi_string_alloc_printf(
|
dev_info_svc->version_string = furi_string_alloc_printf(
|
||||||
"%s %s %s %s",
|
"%s %s %s %s",
|
||||||
version_get_githash(NULL),
|
version_get_githash(NULL),
|
||||||
version_get_gitbranch(NULL),
|
version_get_version(NULL),
|
||||||
version_get_gitbranchnum(NULL),
|
version_get_gitbranchnum(NULL),
|
||||||
version_get_builddate(NULL));
|
version_get_builddate(NULL));
|
||||||
snprintf(
|
snprintf(
|
||||||
|
|||||||
@@ -892,25 +892,11 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
|
|||||||
MfClassicSectorTrailer* sector_trailer =
|
MfClassicSectorTrailer* sector_trailer =
|
||||||
(MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value;
|
(MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value;
|
||||||
if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) {
|
if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) {
|
||||||
if(mf_classic_is_key_found(
|
|
||||||
&emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyA)) {
|
|
||||||
key = nfc_util_bytes2num(sector_trailer->key_a, 6);
|
key = nfc_util_bytes2num(sector_trailer->key_a, 6);
|
||||||
access_key = MfClassicKeyA;
|
access_key = MfClassicKeyA;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(TAG, "Key not known");
|
|
||||||
command_processed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(mf_classic_is_key_found(
|
|
||||||
&emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyB)) {
|
|
||||||
key = nfc_util_bytes2num(sector_trailer->key_b, 6);
|
key = nfc_util_bytes2num(sector_trailer->key_b, 6);
|
||||||
access_key = MfClassicKeyB;
|
access_key = MfClassicKeyB;
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Key not known");
|
|
||||||
command_processed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA;
|
uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA;
|
||||||
|
|||||||