merge
63
.github/workflows/build.yml
vendored
@@ -10,7 +10,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
TARGETS: f7
|
TARGETS: f7 f18
|
||||||
DEFAULT_TARGET: f7
|
DEFAULT_TARGET: f7
|
||||||
FBT_TOOLCHAIN_PATH: /home/runner/work
|
FBT_TOOLCHAIN_PATH: /home/runner/work
|
||||||
|
|
||||||
@@ -57,8 +57,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
for TARGET in ${TARGETS}; do
|
for TARGET in ${TARGETS}; do
|
||||||
./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
|
TARGET="$(echo "${TARGET}" | sed 's/f//')"; \
|
||||||
copro_dist updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
./fbt TARGET_HW=$TARGET copro_dist updater_package \
|
||||||
|
${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: 'Move upload files'
|
- name: 'Move upload files'
|
||||||
@@ -79,14 +80,14 @@ jobs:
|
|||||||
- name: 'Bundle core2 firmware'
|
- name: 'Bundle core2 firmware'
|
||||||
run: |
|
run: |
|
||||||
cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz"
|
cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz"
|
||||||
|
|
||||||
- name: 'Updater artifact'
|
- name: 'Updater artifact'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: updater
|
name: updater
|
||||||
path: |
|
path: |
|
||||||
artifacts/f7-*
|
artifacts/f7-*
|
||||||
|
|
||||||
- name: 'Firmware artifact'
|
- name: 'Firmware artifact'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
@@ -94,31 +95,31 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
artifacts
|
artifacts
|
||||||
|
|
||||||
- name: 'Find Previous Comment'
|
# - name: 'Find Previous Comment'
|
||||||
if: ${{ github.event.pull_request }}
|
# if: ${{ github.event.pull_request }}
|
||||||
uses: peter-evans/find-comment@v1
|
# uses: peter-evans/find-comment@v1
|
||||||
id: fc
|
# id: fc
|
||||||
with:
|
# with:
|
||||||
issue-number: ${{ github.event.pull_request.number }}
|
# issue-number: ${{ github.event.pull_request.number }}
|
||||||
comment-author: 'github-actions[bot]'
|
# comment-author: 'github-actions[bot]'
|
||||||
body-includes: 'Compiled firmware for commit'
|
# body-includes: 'Compiled firmware for commit'
|
||||||
|
|
||||||
- name: Artifact info
|
|
||||||
id: artifact-info
|
|
||||||
uses: dawidd6/action-download-artifact@v2
|
|
||||||
with:
|
|
||||||
dry_run: true
|
|
||||||
|
|
||||||
- name: 'Create or update comment'
|
# - name: Artifact info
|
||||||
if: ${{ github.event.pull_request}}
|
# id: artifact-info
|
||||||
uses: peter-evans/create-or-update-comment@v1
|
# uses: dawidd6/action-download-artifact@v2
|
||||||
with:
|
# with:
|
||||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
# dry_run: true
|
||||||
issue-number: ${{ github.event.pull_request.number }}
|
|
||||||
body: |
|
# - name: 'Create or update comment'
|
||||||
**Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:**
|
# if: ${{ github.event.pull_request}}
|
||||||
- [📦 Update package](${{steps.artifact-info.outputs.artifacts[0].archive_download_url}})
|
# uses: peter-evans/create-or-update-comment@v1
|
||||||
edit-mode: replace
|
# with:
|
||||||
|
# comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||||
|
# issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
# body: |
|
||||||
|
# **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:**
|
||||||
|
# - [📦 Update package](${{steps.artifact-info.outputs.artifacts[0].archive_download_url}})
|
||||||
|
# edit-mode: replace
|
||||||
|
|
||||||
compact:
|
compact:
|
||||||
if: ${{ !startsWith(github.ref, 'refs/tags') }}
|
if: ${{ !startsWith(github.ref, 'refs/tags') }}
|
||||||
@@ -154,6 +155,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
for TARGET in ${TARGETS}; do
|
for TARGET in ${TARGETS}; do
|
||||||
./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
|
TARGET="$(echo "${TARGET}" | sed 's/f//')"; \
|
||||||
updater_package DEBUG=0 COMPACT=1
|
./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 updater_package
|
||||||
done
|
done
|
||||||
|
|||||||
93
.github/workflows/pvs_studio.yml
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
name: 'Static C/C++ analysis with PVS-Studio'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- "release*"
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
TARGETS: f7
|
||||||
|
DEFAULT_TARGET: f7
|
||||||
|
FBT_TOOLCHAIN_PATH: /runner/_work
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyse_c_cpp:
|
||||||
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
|
runs-on: [self-hosted, FlipperZeroShell]
|
||||||
|
steps:
|
||||||
|
- name: 'Decontaminate previous build leftovers'
|
||||||
|
run: |
|
||||||
|
if [ -d .git ]; then
|
||||||
|
git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 'Checkout code'
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
|
- name: 'Get commit details'
|
||||||
|
id: names
|
||||||
|
run: |
|
||||||
|
if [[ ${{ github.event_name }} == 'pull_request' ]]; then
|
||||||
|
TYPE="pull"
|
||||||
|
elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||||
|
TYPE="tag"
|
||||||
|
else
|
||||||
|
TYPE="other"
|
||||||
|
fi
|
||||||
|
python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE"
|
||||||
|
|
||||||
|
- name: 'Supply PVS credentials'
|
||||||
|
run: |
|
||||||
|
pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }}
|
||||||
|
|
||||||
|
- name: 'Convert PVS-Studio output to html and detect warnings'
|
||||||
|
id: pvs-warn
|
||||||
|
run: |
|
||||||
|
WARNINGS=0
|
||||||
|
./fbt COMPACT=1 PVSNOBROWSER=1 firmware_pvs || WARNINGS=1
|
||||||
|
echo "warnings=${WARNINGS}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: 'Upload report'
|
||||||
|
if: ${{ !github.event.pull_request.head.repo.fork && (steps.pvs-warn.outputs.warnings != 0) }}
|
||||||
|
uses: prewk/s3-cp-action@v2
|
||||||
|
with:
|
||||||
|
aws_s3_endpoint: "${{ secrets.PVS_AWS_ENDPOINT }}"
|
||||||
|
aws_access_key_id: "${{ secrets.PVS_AWS_ACCESS_KEY }}"
|
||||||
|
aws_secret_access_key: "${{ secrets.PVS_AWS_SECRET_KEY }}"
|
||||||
|
source: "./build/f7-firmware-DC/pvsreport"
|
||||||
|
dest: "s3://${{ secrets.PVS_AWS_BUCKET }}/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/"
|
||||||
|
flags: "--recursive --acl public-read"
|
||||||
|
|
||||||
|
- name: 'Find Previous Comment'
|
||||||
|
if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request && (steps.pvs-warn.outputs.warnings != 0) }}
|
||||||
|
uses: peter-evans/find-comment@v2
|
||||||
|
id: fc
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
comment-author: 'github-actions[bot]'
|
||||||
|
body-includes: 'PVS-Studio report for commit'
|
||||||
|
|
||||||
|
- name: 'Create or update comment'
|
||||||
|
if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request && (steps.pvs-warn.outputs.warnings != 0) }}
|
||||||
|
uses: peter-evans/create-or-update-comment@v1
|
||||||
|
with:
|
||||||
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
body: |
|
||||||
|
**PVS-Studio report for commit `${{steps.names.outputs.commit_sha}}`:**
|
||||||
|
- [Report](https://pvs.flipp.dev/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/index.html)
|
||||||
|
edit-mode: replace
|
||||||
|
|
||||||
|
- name: 'Raise exception'
|
||||||
|
if: ${{ steps.pvs-warn.outputs.warnings != 0 }}
|
||||||
|
run: |
|
||||||
|
echo "Please fix all PVS warnings before merge"
|
||||||
|
exit 1
|
||||||
|
|
||||||
12
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
*.swp
|
*.swp
|
||||||
|
*.swo
|
||||||
*.gdb_history
|
*.gdb_history
|
||||||
|
|
||||||
|
|
||||||
@@ -67,8 +68,15 @@ PVS-Studio.log
|
|||||||
# Automate files, etc
|
# Automate files, etc
|
||||||
automate.py
|
automate.py
|
||||||
deployments/
|
deployments/
|
||||||
assets/dolphin/custom/
|
|
||||||
assets/resources/dolphin_custom/
|
|
||||||
fbt_options.py
|
fbt_options.py
|
||||||
commitnotes.md
|
commitnotes.md
|
||||||
lib/STM32CubeWB
|
lib/STM32CubeWB
|
||||||
|
|
||||||
|
# Asset packs
|
||||||
|
assets/dolphin/custom/*
|
||||||
|
!assets/dolphin/custom/NSFW/
|
||||||
|
!assets/dolphin/custom/WatchDogs/
|
||||||
|
!assets/dolphin/custom/ReadMe.md
|
||||||
|
assets/resources/dolphin_custom/*
|
||||||
|
!assets/resources/dolphin_custom/NSFW/
|
||||||
|
!assets/resources/dolphin_custom/WatchDogs/
|
||||||
|
|||||||
7
.vscode/extensions.json
vendored
@@ -11,5 +11,8 @@
|
|||||||
"augustocdias.tasks-shell-input"
|
"augustocdias.tasks-shell-input"
|
||||||
],
|
],
|
||||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||||
"unwantedRecommendations": []
|
"unwantedRecommendations": [
|
||||||
}
|
"twxs.cmake",
|
||||||
|
"ms-vscode.cmake-tools"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ App(
|
|||||||
appid="accessor",
|
appid="accessor",
|
||||||
name="Accessor",
|
name="Accessor",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
|
targets=["f7"],
|
||||||
entry_point="accessor_app",
|
entry_point="accessor_app",
|
||||||
cdefines=["APP_ACCESSOR"],
|
cdefines=["APP_ACCESSOR"],
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "bt_carrier_test.h"
|
#include "bt_carrier_test.h"
|
||||||
#include "bt_test.h"
|
#include "bt_test.h"
|
||||||
#include "bt_test_types.h"
|
#include "bt_test_types.h"
|
||||||
#include "furi_hal_bt.h"
|
#include <furi_hal_bt.h>
|
||||||
|
|
||||||
struct BtCarrierTest {
|
struct BtCarrierTest {
|
||||||
BtTest* bt_test;
|
BtTest* bt_test;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "bt_packet_test.h"
|
#include "bt_packet_test.h"
|
||||||
#include "bt_test.h"
|
#include "bt_test.h"
|
||||||
#include "bt_test_types.h"
|
#include "bt_test_types.h"
|
||||||
#include "furi_hal_bt.h"
|
#include <furi_hal_bt.h>
|
||||||
|
|
||||||
struct BtPacketTest {
|
struct BtPacketTest {
|
||||||
BtTest* bt_test;
|
BtTest* bt_test;
|
||||||
|
|||||||
9
applications/debug/example_custom_font/application.fam
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
App(
|
||||||
|
appid="example_custom_font",
|
||||||
|
name="Example: custom font",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
entry_point="example_custom_font_main",
|
||||||
|
requires=["gui"],
|
||||||
|
stack_size=1 * 1024,
|
||||||
|
fap_category="Debug",
|
||||||
|
)
|
||||||
98
applications/debug/example_custom_font/example_custom_font.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
|
//This arrays contains the font itself. You can use any u8g2 font you want
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fontname: -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1
|
||||||
|
Copyright:
|
||||||
|
Glyphs: 95/203
|
||||||
|
BBX Build Mode: 0
|
||||||
|
*/
|
||||||
|
const uint8_t u8g2_font_tom_thumb_4x6_tr[725] =
|
||||||
|
"_\0\2\2\2\3\3\4\4\3\6\0\377\5\377\5\0\0\352\1\330\2\270 \5\340\315\0!\6\265\310"
|
||||||
|
"\254\0\42\6\213\313$\25#\10\227\310\244\241\206\12$\10\227\310\215\70b\2%\10\227\310d\324F\1"
|
||||||
|
"&\10\227\310(\65R\22'\5\251\313\10(\6\266\310\251\62)\10\226\310\304\224\24\0*\6\217\312\244"
|
||||||
|
"\16+\7\217\311\245\225\0,\6\212\310)\0-\5\207\312\14.\5\245\310\4/\7\227\310Ve\4\60"
|
||||||
|
"\7\227\310-k\1\61\6\226\310\255\6\62\10\227\310h\220\312\1\63\11\227\310h\220\62X\0\64\10\227"
|
||||||
|
"\310$\65b\1\65\10\227\310\214\250\301\2\66\10\227\310\315\221F\0\67\10\227\310\314TF\0\70\10\227"
|
||||||
|
"\310\214\64\324\10\71\10\227\310\214\64\342\2:\6\255\311\244\0;\7\222\310e\240\0<\10\227\310\246\32"
|
||||||
|
"d\20=\6\217\311l\60>\11\227\310d\220A*\1\77\10\227\310\314\224a\2@\10\227\310UC\3"
|
||||||
|
"\1A\10\227\310UC\251\0B\10\227\310\250\264\322\2C\7\227\310\315\32\10D\10\227\310\250d-\0"
|
||||||
|
"E\10\227\310\214\70\342\0F\10\227\310\214\70b\4G\10\227\310\315\221\222\0H\10\227\310$\65\224\12"
|
||||||
|
"I\7\227\310\254X\15J\7\227\310\226\252\2K\10\227\310$\265\222\12L\7\227\310\304\346\0M\10\227"
|
||||||
|
"\310\244\61\224\12N\10\227\310\244q\250\0O\7\227\310UV\5P\10\227\310\250\264b\4Q\10\227\310"
|
||||||
|
"Uj$\1R\10\227\310\250\64V\1S\10\227\310m\220\301\2T\7\227\310\254\330\2U\7\227\310$"
|
||||||
|
"W\22V\10\227\310$\253L\0W\10\227\310$\65\206\12X\10\227\310$\325R\1Y\10\227\310$U"
|
||||||
|
"V\0Z\7\227\310\314T\16[\7\227\310\214X\16\134\10\217\311d\220A\0]\7\227\310\314r\4^"
|
||||||
|
"\5\213\313\65_\5\207\310\14`\6\212\313\304\0a\7\223\310\310\65\2b\10\227\310D\225\324\2c\7"
|
||||||
|
"\223\310\315\14\4d\10\227\310\246\245\222\0e\6\223\310\235\2f\10\227\310\246\264b\2g\10\227\307\35"
|
||||||
|
"\61%\0h\10\227\310D\225\254\0i\6\265\310\244\1j\10\233\307f\30U\5k\10\227\310\304\264T"
|
||||||
|
"\1l\7\227\310\310\326\0m\7\223\310<R\0n\7\223\310\250d\5o\7\223\310U\252\2p\10\227"
|
||||||
|
"\307\250\244V\4q\10\227\307-\225d\0r\6\223\310\315\22s\10\223\310\215\70\22\0t\10\227\310\245"
|
||||||
|
"\25\243\0u\7\223\310$+\11v\10\223\310$\65R\2w\7\223\310\244q\4x\7\223\310\244\62\25"
|
||||||
|
"y\11\227\307$\225dJ\0z\7\223\310\254\221\6{\10\227\310\251\32D\1|\6\265\310(\1}\11"
|
||||||
|
"\227\310\310\14RR\0~\6\213\313\215\4\0\0\0\4\377\377\0";
|
||||||
|
|
||||||
|
// Screen is 128x64 px
|
||||||
|
static void app_draw_callback(Canvas* canvas, void* ctx) {
|
||||||
|
UNUSED(ctx);
|
||||||
|
|
||||||
|
canvas_clear(canvas);
|
||||||
|
|
||||||
|
canvas_set_custom_u8g2_font(canvas, u8g2_font_tom_thumb_4x6_tr);
|
||||||
|
|
||||||
|
canvas_draw_str(canvas, 0, 6, "This is a tiny custom font");
|
||||||
|
canvas_draw_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_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 example_custom_font_main(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
|
||||||
|
|
||||||
|
// Configure view port
|
||||||
|
ViewPort* view_port = view_port_alloc();
|
||||||
|
view_port_draw_callback_set(view_port, app_draw_callback, view_port);
|
||||||
|
view_port_input_callback_set(view_port, app_input_callback, event_queue);
|
||||||
|
|
||||||
|
// Register view port in GUI
|
||||||
|
Gui* gui = furi_record_open(RECORD_GUI);
|
||||||
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
|
InputEvent event;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
|
||||||
|
while(running) {
|
||||||
|
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
|
||||||
|
if((event.type == InputTypePress) || (event.type == InputTypeRepeat)) {
|
||||||
|
switch(event.key) {
|
||||||
|
case InputKeyBack:
|
||||||
|
running = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view_port_enabled_set(view_port, false);
|
||||||
|
gui_remove_view_port(gui, view_port);
|
||||||
|
view_port_free(view_port);
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
#include <file_browser_test_icons.h>
|
|
||||||
#include "file_browser_app_i.h"
|
#include "file_browser_app_i.h"
|
||||||
#include "gui/modules/file_browser.h"
|
#include <file_browser_test_icons.h>
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
#include <gui/modules/file_browser.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <lib/toolbox/path.h>
|
#include <lib/toolbox/path.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
|
||||||
static bool file_browser_app_custom_event_callback(void* context, uint32_t event) {
|
static bool file_browser_app_custom_event_callback(void* context, uint32_t event) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ App(
|
|||||||
appid="lfrfid_debug",
|
appid="lfrfid_debug",
|
||||||
name="LF-RFID Debug",
|
name="LF-RFID Debug",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
|
targets=["f7"],
|
||||||
entry_point="lfrfid_debug_app",
|
entry_point="lfrfid_debug_app",
|
||||||
requires=[
|
requires=[
|
||||||
"gui",
|
"gui",
|
||||||
|
|||||||
44
applications/examples/example_thermo/README.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# 1-Wire Thermometer
|
||||||
|
This example application demonstrates the use of the 1-Wire library with a DS18B20 thermometer.
|
||||||
|
It also covers basic GUI, input handling, threads and localisation.
|
||||||
|
|
||||||
|
## Electrical connections
|
||||||
|
Before launching the application, connect the sensor to Flipper's external GPIO according to the table below:
|
||||||
|
| DS18B20 | Flipper |
|
||||||
|
| :-----: | :-----: |
|
||||||
|
| VDD | 9 |
|
||||||
|
| GND | 18 |
|
||||||
|
| DQ | 17 |
|
||||||
|
|
||||||
|
*NOTE 1*: GND is also available on pins 8 and 11.
|
||||||
|
|
||||||
|
*NOTE 2*: For any other pin than 17, connect an external 4.7k pull-up resistor to pin 9.
|
||||||
|
|
||||||
|
## Launching the application
|
||||||
|
In order to launch this demo, follow the steps below:
|
||||||
|
1. Make sure your Flipper has an SD card installed.
|
||||||
|
2. Connect your Flipper to the computer via a USB cable.
|
||||||
|
3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice.
|
||||||
|
|
||||||
|
## Changing the data pin
|
||||||
|
It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* Possible GPIO pin choices:
|
||||||
|
- gpio_ext_pc0
|
||||||
|
- gpio_ext_pc1
|
||||||
|
- gpio_ext_pc3
|
||||||
|
- gpio_ext_pb2
|
||||||
|
- gpio_ext_pb3
|
||||||
|
- gpio_ext_pa4
|
||||||
|
- gpio_ext_pa6
|
||||||
|
- gpio_ext_pa7
|
||||||
|
- ibutton_gpio
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define THERMO_GPIO_PIN (ibutton_gpio)
|
||||||
|
```
|
||||||
|
Do not forget about the external pull-up resistor as these pins do not have one built-in.
|
||||||
|
|
||||||
|
With the changes been made, recompile and launch the application again.
|
||||||
|
The on-screen text should reflect it by asking to connect the thermometer to another pin.
|
||||||
10
applications/examples/example_thermo/application.fam
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
App(
|
||||||
|
appid="example_thermo",
|
||||||
|
name="Example: Thermometer",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
entry_point="example_thermo_main",
|
||||||
|
requires=["gui"],
|
||||||
|
stack_size=1 * 1024,
|
||||||
|
fap_icon="example_thermo_10px.png",
|
||||||
|
fap_category="Examples",
|
||||||
|
)
|
||||||
356
applications/examples/example_thermo/example_thermo.c
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
/*
|
||||||
|
* This file contains an example application that reads and displays
|
||||||
|
* the temperature from a DS18B20 1-wire thermometer.
|
||||||
|
*
|
||||||
|
* It also covers basic GUI, input handling, threads and localisation.
|
||||||
|
*
|
||||||
|
* References:
|
||||||
|
* [1] DS18B20 Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS18B20.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/view_port.h>
|
||||||
|
|
||||||
|
#include <core/thread.h>
|
||||||
|
#include <core/kernel.h>
|
||||||
|
|
||||||
|
#include <locale/locale.h>
|
||||||
|
|
||||||
|
#include <one_wire/maxim_crc.h>
|
||||||
|
#include <one_wire/one_wire_host.h>
|
||||||
|
|
||||||
|
#define UPDATE_PERIOD_MS 1000UL
|
||||||
|
#define TEXT_STORE_SIZE 64U
|
||||||
|
|
||||||
|
#define DS18B20_CMD_CONVERT 0x44U
|
||||||
|
#define DS18B20_CMD_READ_SCRATCHPAD 0xbeU
|
||||||
|
|
||||||
|
#define DS18B20_CFG_RESOLUTION_POS 5U
|
||||||
|
#define DS18B20_CFG_RESOLUTION_MASK 0x03U
|
||||||
|
#define DS18B20_DECIMAL_PART_MASK 0x0fU
|
||||||
|
|
||||||
|
#define DS18B20_SIGN_MASK 0xf0U
|
||||||
|
|
||||||
|
/* Possible GPIO pin choices:
|
||||||
|
- gpio_ext_pc0
|
||||||
|
- gpio_ext_pc1
|
||||||
|
- gpio_ext_pc3
|
||||||
|
- gpio_ext_pb2
|
||||||
|
- gpio_ext_pb3
|
||||||
|
- gpio_ext_pa4
|
||||||
|
- gpio_ext_pa6
|
||||||
|
- gpio_ext_pa7
|
||||||
|
- ibutton_gpio
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define THERMO_GPIO_PIN (ibutton_gpio)
|
||||||
|
|
||||||
|
/* Flags which the reader thread responds to */
|
||||||
|
typedef enum {
|
||||||
|
ReaderThreadFlagExit = 1,
|
||||||
|
} ReaderThreadFlag;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
uint8_t temp_lsb; /* Least significant byte of the temperature */
|
||||||
|
uint8_t temp_msb; /* Most significant byte of the temperature */
|
||||||
|
uint8_t user_alarm_high; /* User register 1 (Temp high alarm) */
|
||||||
|
uint8_t user_alarm_low; /* User register 2 (Temp low alarm) */
|
||||||
|
uint8_t config; /* Configuration register */
|
||||||
|
uint8_t reserved[3]; /* Not used */
|
||||||
|
uint8_t crc; /* CRC checksum for error detection */
|
||||||
|
} fields;
|
||||||
|
uint8_t bytes[9];
|
||||||
|
} DS18B20Scratchpad;
|
||||||
|
|
||||||
|
/* Application context structure */
|
||||||
|
typedef struct {
|
||||||
|
Gui* gui;
|
||||||
|
ViewPort* view_port;
|
||||||
|
FuriThread* reader_thread;
|
||||||
|
FuriMessageQueue* event_queue;
|
||||||
|
OneWireHost* onewire;
|
||||||
|
float temp_celsius;
|
||||||
|
bool has_device;
|
||||||
|
} ExampleThermoContext;
|
||||||
|
|
||||||
|
/*************** 1-Wire Communication and Processing *****************/
|
||||||
|
|
||||||
|
/* Commands the thermometer to begin measuring the temperature. */
|
||||||
|
static void example_thermo_request_temperature(ExampleThermoContext* context) {
|
||||||
|
OneWireHost* onewire = context->onewire;
|
||||||
|
|
||||||
|
/* All 1-wire transactions must happen in a critical section, i.e
|
||||||
|
not interrupted by other threads. */
|
||||||
|
FURI_CRITICAL_ENTER();
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
do {
|
||||||
|
/* Each communication with a 1-wire device starts by a reset.
|
||||||
|
The functon will return true if a device responded with a presence pulse. */
|
||||||
|
if(!onewire_host_reset(onewire)) break;
|
||||||
|
/* After the reset, a ROM operation must follow.
|
||||||
|
If there is only one device connected, the "Skip ROM" command is most appropriate
|
||||||
|
(it can also be used to address all of the connected devices in some cases).*/
|
||||||
|
onewire_host_skip(onewire);
|
||||||
|
/* After the ROM operation, a device-specific command is issued.
|
||||||
|
In this case, it's a request to start measuring the temperature. */
|
||||||
|
onewire_host_write(onewire, DS18B20_CMD_CONVERT);
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
context->has_device = success;
|
||||||
|
|
||||||
|
FURI_CRITICAL_EXIT();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reads the measured temperature from the thermometer. */
|
||||||
|
static void example_thermo_read_temperature(ExampleThermoContext* context) {
|
||||||
|
/* If there was no device detected, don't try to read the temperature */
|
||||||
|
if(!context->has_device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OneWireHost* onewire = context->onewire;
|
||||||
|
|
||||||
|
/* All 1-wire transactions must happen in a critical section, i.e
|
||||||
|
not interrupted by other threads. */
|
||||||
|
FURI_CRITICAL_ENTER();
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
DS18B20Scratchpad buf;
|
||||||
|
|
||||||
|
/* Attempt reading the temperature 10 times before giving up */
|
||||||
|
size_t attempts_left = 10;
|
||||||
|
do {
|
||||||
|
/* Each communication with a 1-wire device starts by a reset.
|
||||||
|
The functon will return true if a device responded with a presence pulse. */
|
||||||
|
if(!onewire_host_reset(onewire)) continue;
|
||||||
|
|
||||||
|
/* After the reset, a ROM operation must follow.
|
||||||
|
If there is only one device connected, the "Skip ROM" command is most appropriate
|
||||||
|
(it can also be used to address all of the connected devices in some cases).*/
|
||||||
|
onewire_host_skip(onewire);
|
||||||
|
|
||||||
|
/* After the ROM operation, a device-specific command is issued.
|
||||||
|
This time, it will be the "Read Scratchpad" command which will
|
||||||
|
prepare the device's internal buffer memory for reading. */
|
||||||
|
onewire_host_write(onewire, DS18B20_CMD_READ_SCRATCHPAD);
|
||||||
|
|
||||||
|
/* The actual reading happens here. A total of 9 bytes is read. */
|
||||||
|
onewire_host_read_bytes(onewire, buf.bytes, sizeof(buf.bytes));
|
||||||
|
|
||||||
|
/* Calculate the checksum and compare it with one provided by the device. */
|
||||||
|
const uint8_t crc = maxim_crc8(buf.bytes, sizeof(buf.bytes) - 1, MAXIM_CRC8_INIT);
|
||||||
|
|
||||||
|
/* Checksums match, exit the loop */
|
||||||
|
if(crc == buf.fields.crc) break;
|
||||||
|
|
||||||
|
} while(--attempts_left);
|
||||||
|
|
||||||
|
if(attempts_left == 0) break;
|
||||||
|
|
||||||
|
/* Get the measurement resolution from the configuration register. (See [1] page 9) */
|
||||||
|
const uint8_t resolution_mode = (buf.fields.config >> DS18B20_CFG_RESOLUTION_POS) &
|
||||||
|
DS18B20_CFG_RESOLUTION_MASK;
|
||||||
|
|
||||||
|
/* Generate a mask for undefined bits in the decimal part. (See [1] page 6) */
|
||||||
|
const uint8_t decimal_mask =
|
||||||
|
(DS18B20_DECIMAL_PART_MASK << (DS18B20_CFG_RESOLUTION_MASK - resolution_mode)) &
|
||||||
|
DS18B20_DECIMAL_PART_MASK;
|
||||||
|
|
||||||
|
/* Get the integer and decimal part of the temperature (See [1] page 6) */
|
||||||
|
const uint8_t integer_part = (buf.fields.temp_msb << 4U) | (buf.fields.temp_lsb >> 4U);
|
||||||
|
const uint8_t decimal_part = buf.fields.temp_lsb & decimal_mask;
|
||||||
|
|
||||||
|
/* Calculate the sign of the temperature (See [1] page 6) */
|
||||||
|
const bool is_negative = (buf.fields.temp_msb & DS18B20_SIGN_MASK) != 0;
|
||||||
|
|
||||||
|
/* Combine the integer and decimal part together */
|
||||||
|
const float temp_celsius_abs = integer_part + decimal_part / 16.f;
|
||||||
|
|
||||||
|
/* Set the appropriate sign */
|
||||||
|
context->temp_celsius = is_negative ? -temp_celsius_abs : temp_celsius_abs;
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
context->has_device = success;
|
||||||
|
|
||||||
|
FURI_CRITICAL_EXIT();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Periodically requests measurements and reads temperature. This function runs in a separare thread. */
|
||||||
|
static int32_t example_thermo_reader_thread_callback(void* ctx) {
|
||||||
|
ExampleThermoContext* context = ctx;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
/* Tell the termometer to start measuring the temperature. The process may take up to 750ms. */
|
||||||
|
example_thermo_request_temperature(context);
|
||||||
|
|
||||||
|
/* Wait for the measurement to finish. At the same time wait for an exit signal. */
|
||||||
|
const uint32_t flags =
|
||||||
|
furi_thread_flags_wait(ReaderThreadFlagExit, FuriFlagWaitAny, UPDATE_PERIOD_MS);
|
||||||
|
|
||||||
|
/* If an exit signal was received, return from this thread. */
|
||||||
|
if(flags != (unsigned)FuriFlagErrorTimeout) break;
|
||||||
|
|
||||||
|
/* The measurement is now ready, read it from the termometer. */
|
||||||
|
example_thermo_read_temperature(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************** GUI, Input and Main Loop *****************/
|
||||||
|
|
||||||
|
/* Draw the GUI of the application. The screen is completely redrawn during each call. */
|
||||||
|
static void example_thermo_draw_callback(Canvas* canvas, void* ctx) {
|
||||||
|
ExampleThermoContext* context = ctx;
|
||||||
|
char text_store[TEXT_STORE_SIZE];
|
||||||
|
const size_t middle_x = canvas_width(canvas) / 2U;
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(canvas, middle_x, 12, AlignCenter, AlignBottom, "Thermometer Demo");
|
||||||
|
canvas_draw_line(canvas, 0, 16, 128, 16);
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, middle_x, 30, AlignCenter, AlignBottom, "Connnect thermometer");
|
||||||
|
|
||||||
|
snprintf(
|
||||||
|
text_store,
|
||||||
|
TEXT_STORE_SIZE,
|
||||||
|
"to GPIO pin %ld",
|
||||||
|
furi_hal_resources_get_ext_pin_number(&THERMO_GPIO_PIN));
|
||||||
|
canvas_draw_str_aligned(canvas, middle_x, 42, AlignCenter, AlignBottom, text_store);
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontKeyboard);
|
||||||
|
|
||||||
|
if(context->has_device) {
|
||||||
|
float temp;
|
||||||
|
char temp_units;
|
||||||
|
|
||||||
|
/* The applicaton is locale-aware.
|
||||||
|
Change Settings->System->Units to check it out. */
|
||||||
|
switch(locale_get_measurement_unit()) {
|
||||||
|
case LocaleMeasurementUnitsMetric:
|
||||||
|
temp = context->temp_celsius;
|
||||||
|
temp_units = 'C';
|
||||||
|
break;
|
||||||
|
case LocaleMeasurementUnitsImperial:
|
||||||
|
temp = locale_celsius_to_fahrenheit(context->temp_celsius);
|
||||||
|
temp_units = 'F';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_crash("Illegal measurement units");
|
||||||
|
}
|
||||||
|
/* If a reading is available, display it */
|
||||||
|
snprintf(text_store, TEXT_STORE_SIZE, "Temperature: %+.1f%c", (double)temp, temp_units);
|
||||||
|
} else {
|
||||||
|
/* Or show a message that no data is available */
|
||||||
|
strncpy(text_store, "-- No data --", TEXT_STORE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_draw_str_aligned(canvas, middle_x, 58, AlignCenter, AlignBottom, text_store);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is called from the GUI thread. All it does is put the event
|
||||||
|
into the application's queue so it can be processed later. */
|
||||||
|
static void example_thermo_input_callback(InputEvent* event, void* ctx) {
|
||||||
|
ExampleThermoContext* context = ctx;
|
||||||
|
furi_message_queue_put(context->event_queue, event, FuriWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Starts the reader thread and handles the input */
|
||||||
|
static void example_thermo_run(ExampleThermoContext* context) {
|
||||||
|
/* Configure the hardware in host mode */
|
||||||
|
onewire_host_start(context->onewire);
|
||||||
|
|
||||||
|
/* Start the reader thread. It will talk to the thermometer in the background. */
|
||||||
|
furi_thread_start(context->reader_thread);
|
||||||
|
|
||||||
|
/* An endless loop which handles the input*/
|
||||||
|
for(bool is_running = true; is_running;) {
|
||||||
|
InputEvent event;
|
||||||
|
/* Wait for an input event. Input events come from the GUI thread via a callback. */
|
||||||
|
const FuriStatus status =
|
||||||
|
furi_message_queue_get(context->event_queue, &event, FuriWaitForever);
|
||||||
|
|
||||||
|
/* This application is only interested in short button presses. */
|
||||||
|
if((status != FuriStatusOk) || (event.type != InputTypeShort)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When the user presses the "Back" button, break the loop and exit the application. */
|
||||||
|
if(event.key == InputKeyBack) {
|
||||||
|
is_running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signal the reader thread to cease operation and exit */
|
||||||
|
furi_thread_flags_set(furi_thread_get_id(context->reader_thread), ReaderThreadFlagExit);
|
||||||
|
|
||||||
|
/* Wait for the reader thread to finish */
|
||||||
|
furi_thread_join(context->reader_thread);
|
||||||
|
|
||||||
|
/* Reset the hardware */
|
||||||
|
onewire_host_stop(context->onewire);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************** Initialisation & startup *****************************/
|
||||||
|
|
||||||
|
/* Allocate the memory and initialise the variables */
|
||||||
|
static ExampleThermoContext* example_thermo_context_alloc() {
|
||||||
|
ExampleThermoContext* context = malloc(sizeof(ExampleThermoContext));
|
||||||
|
|
||||||
|
context->view_port = view_port_alloc();
|
||||||
|
view_port_draw_callback_set(context->view_port, example_thermo_draw_callback, context);
|
||||||
|
view_port_input_callback_set(context->view_port, example_thermo_input_callback, context);
|
||||||
|
|
||||||
|
context->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
|
||||||
|
|
||||||
|
context->reader_thread = furi_thread_alloc();
|
||||||
|
furi_thread_set_stack_size(context->reader_thread, 1024U);
|
||||||
|
furi_thread_set_context(context->reader_thread, context);
|
||||||
|
furi_thread_set_callback(context->reader_thread, example_thermo_reader_thread_callback);
|
||||||
|
|
||||||
|
context->gui = furi_record_open(RECORD_GUI);
|
||||||
|
gui_add_view_port(context->gui, context->view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
|
context->onewire = onewire_host_alloc(&THERMO_GPIO_PIN);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the unused resources and deallocate memory */
|
||||||
|
static void example_thermo_context_free(ExampleThermoContext* context) {
|
||||||
|
view_port_enabled_set(context->view_port, false);
|
||||||
|
gui_remove_view_port(context->gui, context->view_port);
|
||||||
|
|
||||||
|
onewire_host_free(context->onewire);
|
||||||
|
furi_thread_free(context->reader_thread);
|
||||||
|
furi_message_queue_free(context->event_queue);
|
||||||
|
view_port_free(context->view_port);
|
||||||
|
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The application's entry point. Execution starts from here. */
|
||||||
|
int32_t example_thermo_main(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
|
||||||
|
/* Allocate all of the necessary structures */
|
||||||
|
ExampleThermoContext* context = example_thermo_context_alloc();
|
||||||
|
|
||||||
|
/* Start the applicaton's main loop. It won't return until the application was requested to exit. */
|
||||||
|
example_thermo_run(context);
|
||||||
|
|
||||||
|
/* Release all unneeded resources */
|
||||||
|
example_thermo_context_free(context);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
applications/examples/example_thermo/example_thermo_10px.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
@@ -1,10 +1,11 @@
|
|||||||
#include <archive/views/archive_browser_view.h>
|
|
||||||
#include "archive_files.h"
|
#include "archive_files.h"
|
||||||
#include "archive_apps.h"
|
#include "archive_apps.h"
|
||||||
#include "archive_browser.h"
|
#include "archive_browser.h"
|
||||||
|
#include "../views/archive_browser_view.h"
|
||||||
|
|
||||||
#include <core/common_defines.h>
|
#include <core/common_defines.h>
|
||||||
#include <core/log.h>
|
#include <core/log.h>
|
||||||
#include "gui/modules/file_browser_worker.h"
|
#include <gui/modules/file_browser_worker.h>
|
||||||
#include <fap_loader/fap_loader_app.h>
|
#include <fap_loader/fap_loader_app.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@@ -456,10 +457,14 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
|||||||
|
|
||||||
browser->last_tab_switch_dir = key;
|
browser->last_tab_switch_dir = key;
|
||||||
|
|
||||||
if(key == InputKeyLeft) {
|
for(int i = 0; i < 2; i++) {
|
||||||
tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal;
|
if(key == InputKeyLeft) {
|
||||||
} else {
|
tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal;
|
||||||
tab = (tab + 1) % ArchiveTabTotal;
|
} else {
|
||||||
|
tab = (tab + 1) % ArchiveTabTotal;
|
||||||
|
}
|
||||||
|
if(tab == ArchiveTabInternal && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) continue;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
browser->is_root = true;
|
browser->is_root = true;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ static const char* tab_default_paths[] = {
|
|||||||
[ArchiveTabBadKb] = ANY_PATH("badkb"),
|
[ArchiveTabBadKb] = ANY_PATH("badkb"),
|
||||||
[ArchiveTabU2f] = "/app:u2f",
|
[ArchiveTabU2f] = "/app:u2f",
|
||||||
[ArchiveTabApplications] = ANY_PATH("apps"),
|
[ArchiveTabApplications] = ANY_PATH("apps"),
|
||||||
|
[ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX,
|
||||||
[ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
|
[ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ static const ArchiveFileTypeEnum known_type[] = {
|
|||||||
[ArchiveTabBadKb] = ArchiveFileTypeBadKb,
|
[ArchiveTabBadKb] = ArchiveFileTypeBadKb,
|
||||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||||
[ArchiveTabApplications] = ArchiveFileTypeApplication,
|
[ArchiveTabApplications] = ArchiveFileTypeApplication,
|
||||||
|
[ArchiveTabInternal] = ArchiveFileTypeUnknown,
|
||||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <m-string.h>
|
#include <m-string.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include "toolbox/path.h"
|
#include "toolbox/path.h"
|
||||||
|
#include "../../../settings/xtreme_settings/xtreme_settings.h"
|
||||||
|
|
||||||
#define FAP_MANIFEST_MAX_ICON_SIZE 32
|
#define FAP_MANIFEST_MAX_ICON_SIZE 32
|
||||||
|
|
||||||
@@ -84,11 +85,16 @@ static void ArchiveFile_t_clear(ArchiveFile_t* obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ArchiveFile_t_cmp(const ArchiveFile_t* a, const ArchiveFile_t* b) {
|
static int ArchiveFile_t_cmp(const ArchiveFile_t* a, const ArchiveFile_t* b) {
|
||||||
if(a->type == ArchiveFileTypeFolder && b->type != ArchiveFileTypeFolder) {
|
if(!XTREME_SETTINGS()->sort_ignore_dirs) {
|
||||||
return -1;
|
if(a->type == ArchiveFileTypeFolder && b->type != ArchiveFileTypeFolder) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(a->type != ArchiveFileTypeFolder && b->type == ArchiveFileTypeFolder) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return furi_string_cmp(a->path, b->path);
|
return furi_string_cmpi(a->path, b->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define M_OPL_ArchiveFile_t() \
|
#define M_OPL_ArchiveFile_t() \
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ static const char* ArchiveTabNames[] = {
|
|||||||
[ArchiveTabBadKb] = "Bad KB",
|
[ArchiveTabBadKb] = "Bad KB",
|
||||||
[ArchiveTabU2f] = "U2F",
|
[ArchiveTabU2f] = "U2F",
|
||||||
[ArchiveTabApplications] = "Apps",
|
[ArchiveTabApplications] = "Apps",
|
||||||
|
[ArchiveTabInternal] = "Internal",
|
||||||
[ArchiveTabBrowser] = "Browser",
|
[ArchiveTabBrowser] = "Browser",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../helpers/archive_files.h"
|
||||||
|
#include "../helpers/archive_favorites.h"
|
||||||
|
|
||||||
#include <gui/gui_i.h>
|
#include <gui/gui_i.h>
|
||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
#include <gui/canvas.h>
|
#include <gui/canvas.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include <furi.h>
|
#include <gui/modules/file_browser_worker.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include "../helpers/archive_files.h"
|
#include "../helpers/archive_files.h"
|
||||||
#include "../helpers/archive_menu.h"
|
#include "../helpers/archive_menu.h"
|
||||||
@@ -28,6 +31,7 @@ typedef enum {
|
|||||||
ArchiveTabBadKb,
|
ArchiveTabBadKb,
|
||||||
ArchiveTabU2f,
|
ArchiveTabU2f,
|
||||||
ArchiveTabApplications,
|
ArchiveTabApplications,
|
||||||
|
ArchiveTabInternal,
|
||||||
ArchiveTabBrowser,
|
ArchiveTabBrowser,
|
||||||
ArchiveTabTotal,
|
ArchiveTabTotal,
|
||||||
} ArchiveTabEnum;
|
} ArchiveTabEnum;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "../bad_kb_app_i.h"
|
#include "../bad_kb_app_i.h"
|
||||||
#include "../../../settings/xtreme_settings/xtreme_settings.h"
|
#include "../../../settings/xtreme_settings/xtreme_assets.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bad_kb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
|
bad_kb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
@@ -28,7 +28,7 @@ void bad_kb_scene_error_on_enter(void* context) {
|
|||||||
app->widget, GuiButtonTypeLeft, "Back", bad_kb_scene_error_event_callback, app);
|
app->widget, GuiButtonTypeLeft, "Back", bad_kb_scene_error_event_callback, app);
|
||||||
} else if(app->error == BadKbAppErrorCloseRpc) {
|
} else if(app->error == BadKbAppErrorCloseRpc) {
|
||||||
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
|
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
|
||||||
if(XTREME_SETTINGS()->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
widget_add_string_multiline_element(
|
widget_add_string_multiline_element(
|
||||||
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "I am not\na whore!");
|
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "I am not\na whore!");
|
||||||
widget_add_string_multiline_element(
|
widget_add_string_multiline_element(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "../bad_kb_app_i.h"
|
#include "../bad_kb_app_i.h"
|
||||||
#include "furi_hal_power.h"
|
#include <furi_hal_power.h>
|
||||||
#include "furi_hal_usb.h"
|
#include <furi_hal_usb.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
|
|
||||||
static bool bad_kb_file_select(BadKbApp* bad_kb) {
|
static bool bad_kb_file_select(BadKbApp* bad_kb) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "../bad_kb_script.h"
|
#include "../bad_kb_script.h"
|
||||||
#include "../bad_kb_app_i.h"
|
#include "../bad_kb_app_i.h"
|
||||||
#include "../views/bad_kb_view.h"
|
#include "../views/bad_kb_view.h"
|
||||||
#include "furi_hal.h"
|
#include <furi_hal.h>
|
||||||
#include "toolbox/path.h"
|
#include "toolbox/path.h"
|
||||||
|
|
||||||
void bad_kb_scene_work_button_callback(InputKey key, void* context) {
|
void bad_kb_scene_work_button_callback(InputKey key, void* context) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <toolbox/path.h>
|
#include <toolbox/path.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
#include "../../../settings/xtreme_settings/xtreme_settings.h"
|
#include "../../../settings/xtreme_settings/xtreme_assets.h"
|
||||||
|
|
||||||
#define MAX_NAME_LEN 64
|
#define MAX_NAME_LEN 64
|
||||||
|
|
||||||
@@ -28,7 +28,6 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
|
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
|
||||||
XtremeSettings* xtreme_settings = XTREME_SETTINGS();
|
|
||||||
|
|
||||||
if(strlen(model->layout) == 0) {
|
if(strlen(model->layout) == 0) {
|
||||||
furi_string_set(disp_str, "(default)");
|
furi_string_set(disp_str, "(default)");
|
||||||
@@ -49,7 +48,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
|
|
||||||
if((model->state.state == BadKbStateIdle) || (model->state.state == BadKbStateDone) ||
|
if((model->state.state == BadKbStateIdle) || (model->state.state == BadKbStateDone) ||
|
||||||
(model->state.state == BadKbStateNotConnected)) {
|
(model->state.state == BadKbStateNotConnected)) {
|
||||||
if(xtreme_settings->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
elements_button_center(canvas, "Cum");
|
elements_button_center(canvas, "Cum");
|
||||||
} else {
|
} else {
|
||||||
elements_button_center(canvas, "Start");
|
elements_button_center(canvas, "Start");
|
||||||
@@ -68,7 +67,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
if(model->state.state == BadKbStateNotConnected) {
|
if(model->state.state == BadKbStateNotConnected) {
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
if(xtreme_settings->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Plug me");
|
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Plug me");
|
||||||
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "in, Daddy");
|
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "in, Daddy");
|
||||||
} else {
|
} else {
|
||||||
@@ -78,7 +77,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
} else if(model->state.state == BadKbStateWillRun) {
|
} else if(model->state.state == BadKbStateWillRun) {
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
if(xtreme_settings->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will cum");
|
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will cum");
|
||||||
} else {
|
} else {
|
||||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run");
|
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run");
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ GpioApp* gpio_app_alloc() {
|
|||||||
GpioApp* app = malloc(sizeof(GpioApp));
|
GpioApp* app = malloc(sizeof(GpioApp));
|
||||||
|
|
||||||
app->gui = furi_record_open(RECORD_GUI);
|
app->gui = furi_record_open(RECORD_GUI);
|
||||||
|
app->gpio_items = gpio_items_alloc();
|
||||||
|
|
||||||
app->view_dispatcher = view_dispatcher_alloc();
|
app->view_dispatcher = view_dispatcher_alloc();
|
||||||
app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app);
|
app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app);
|
||||||
@@ -47,7 +48,7 @@ GpioApp* gpio_app_alloc() {
|
|||||||
app->view_dispatcher,
|
app->view_dispatcher,
|
||||||
GpioAppViewVarItemList,
|
GpioAppViewVarItemList,
|
||||||
variable_item_list_get_view(app->var_item_list));
|
variable_item_list_get_view(app->var_item_list));
|
||||||
app->gpio_test = gpio_test_alloc();
|
app->gpio_test = gpio_test_alloc(app->gpio_items);
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test));
|
app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test));
|
||||||
|
|
||||||
@@ -105,6 +106,7 @@ void gpio_app_free(GpioApp* app) {
|
|||||||
furi_record_close(RECORD_GUI);
|
furi_record_close(RECORD_GUI);
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
gpio_items_free(app->gpio_items);
|
||||||
free(app);
|
free(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gpio_app.h"
|
#include "gpio_app.h"
|
||||||
#include "gpio_item.h"
|
#include "gpio_items.h"
|
||||||
#include "scenes/gpio_scene.h"
|
#include "scenes/gpio_scene.h"
|
||||||
#include "gpio_custom_event.h"
|
#include "gpio_custom_event.h"
|
||||||
#include "usb_uart_bridge.h"
|
#include "usb_uart_bridge.h"
|
||||||
@@ -30,6 +30,7 @@ struct GpioApp {
|
|||||||
VariableItem* var_item_flow;
|
VariableItem* var_item_flow;
|
||||||
GpioTest* gpio_test;
|
GpioTest* gpio_test;
|
||||||
GpioUsbUart* gpio_usb_uart;
|
GpioUsbUart* gpio_usb_uart;
|
||||||
|
GPIOItems* gpio_items;
|
||||||
UsbUartBridge* usb_uart_bridge;
|
UsbUartBridge* usb_uart_bridge;
|
||||||
GpioI2CScanner* gpio_i2c_scanner;
|
GpioI2CScanner* gpio_i2c_scanner;
|
||||||
GpioI2CSfp* gpio_i2c_sfp;
|
GpioI2CSfp* gpio_i2c_sfp;
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
#include "gpio_item.h"
|
|
||||||
|
|
||||||
#include <furi_hal_resources.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char* name;
|
|
||||||
const GpioPin* pin;
|
|
||||||
} GpioItem;
|
|
||||||
|
|
||||||
static const GpioItem gpio_item[GPIO_ITEM_COUNT] = {
|
|
||||||
{"1.2: PA7", &gpio_ext_pa7},
|
|
||||||
{"1.3: PA6", &gpio_ext_pa6},
|
|
||||||
{"1.4: PA4", &gpio_ext_pa4},
|
|
||||||
{"1.5: PB3", &gpio_ext_pb3},
|
|
||||||
{"1.6: PB2", &gpio_ext_pb2},
|
|
||||||
{"1.7: PC3", &gpio_ext_pc3},
|
|
||||||
{"2.7: PC1", &gpio_ext_pc1},
|
|
||||||
{"2.8: PC0", &gpio_ext_pc0},
|
|
||||||
};
|
|
||||||
|
|
||||||
void gpio_item_configure_pin(uint8_t index, GpioMode mode) {
|
|
||||||
furi_assert(index < GPIO_ITEM_COUNT);
|
|
||||||
furi_hal_gpio_write(gpio_item[index].pin, false);
|
|
||||||
furi_hal_gpio_init(gpio_item[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_item_configure_all_pins(GpioMode mode) {
|
|
||||||
for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) {
|
|
||||||
gpio_item_configure_pin(i, mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_item_set_pin(uint8_t index, bool level) {
|
|
||||||
furi_assert(index < GPIO_ITEM_COUNT);
|
|
||||||
furi_hal_gpio_write(gpio_item[index].pin, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_item_set_all_pins(bool level) {
|
|
||||||
for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) {
|
|
||||||
gpio_item_set_pin(i, level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* gpio_item_get_pin_name(uint8_t index) {
|
|
||||||
furi_assert(index < GPIO_ITEM_COUNT + 1);
|
|
||||||
if(index == GPIO_ITEM_COUNT) {
|
|
||||||
return "ALL";
|
|
||||||
} else {
|
|
||||||
return gpio_item[index].name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal_gpio.h>
|
|
||||||
|
|
||||||
#define GPIO_ITEM_COUNT 8
|
|
||||||
|
|
||||||
void gpio_item_configure_pin(uint8_t index, GpioMode mode);
|
|
||||||
|
|
||||||
void gpio_item_configure_all_pins(GpioMode mode);
|
|
||||||
|
|
||||||
void gpio_item_set_pin(uint8_t index, bool level);
|
|
||||||
|
|
||||||
void gpio_item_set_all_pins(bool level);
|
|
||||||
|
|
||||||
const char* gpio_item_get_pin_name(uint8_t index);
|
|
||||||
69
applications/main/gpio/gpio_items.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "gpio_items.h"
|
||||||
|
|
||||||
|
#include <furi_hal_resources.h>
|
||||||
|
|
||||||
|
struct GPIOItems {
|
||||||
|
GpioPinRecord* pins;
|
||||||
|
size_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
GPIOItems* gpio_items_alloc() {
|
||||||
|
GPIOItems* items = malloc(sizeof(GPIOItems));
|
||||||
|
|
||||||
|
items->count = 0;
|
||||||
|
for(size_t i = 0; i < gpio_pins_count; i++) {
|
||||||
|
if(!gpio_pins[i].debug) {
|
||||||
|
items->count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items->pins = malloc(sizeof(GpioPinRecord) * items->count);
|
||||||
|
for(size_t i = 0; i < items->count; i++) {
|
||||||
|
if(!gpio_pins[i].debug) {
|
||||||
|
items->pins[i].pin = gpio_pins[i].pin;
|
||||||
|
items->pins[i].name = gpio_pins[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_items_free(GPIOItems* items) {
|
||||||
|
free(items->pins);
|
||||||
|
free(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t gpio_items_get_count(GPIOItems* items) {
|
||||||
|
return items->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_items_configure_pin(GPIOItems* items, uint8_t index, GpioMode mode) {
|
||||||
|
furi_assert(index < items->count);
|
||||||
|
furi_hal_gpio_write(items->pins[index].pin, false);
|
||||||
|
furi_hal_gpio_init(items->pins[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_items_configure_all_pins(GPIOItems* items, GpioMode mode) {
|
||||||
|
for(uint8_t i = 0; i < items->count; i++) {
|
||||||
|
gpio_items_configure_pin(items, i, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_items_set_pin(GPIOItems* items, uint8_t index, bool level) {
|
||||||
|
furi_assert(index < items->count);
|
||||||
|
furi_hal_gpio_write(items->pins[index].pin, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_items_set_all_pins(GPIOItems* items, bool level) {
|
||||||
|
for(uint8_t i = 0; i < items->count; i++) {
|
||||||
|
gpio_items_set_pin(items, i, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* gpio_items_get_pin_name(GPIOItems* items, uint8_t index) {
|
||||||
|
furi_assert(index < items->count + 1);
|
||||||
|
if(index == items->count) {
|
||||||
|
return "ALL";
|
||||||
|
} else {
|
||||||
|
return items->pins[index].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
applications/main/gpio/gpio_items.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi_hal_gpio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct GPIOItems GPIOItems;
|
||||||
|
|
||||||
|
GPIOItems* gpio_items_alloc();
|
||||||
|
|
||||||
|
void gpio_items_free(GPIOItems* items);
|
||||||
|
|
||||||
|
uint8_t gpio_items_get_count(GPIOItems* items);
|
||||||
|
|
||||||
|
void gpio_items_configure_pin(GPIOItems* items, uint8_t index, GpioMode mode);
|
||||||
|
|
||||||
|
void gpio_items_configure_all_pins(GPIOItems* items, GpioMode mode);
|
||||||
|
|
||||||
|
void gpio_items_set_pin(GPIOItems* items, uint8_t index, bool level);
|
||||||
|
|
||||||
|
void gpio_items_set_all_pins(GPIOItems* items, bool level);
|
||||||
|
|
||||||
|
const char* gpio_items_get_pin_name(GPIOItems* items, uint8_t index);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -2,8 +2,9 @@
|
|||||||
#define __GPIO_SCENE_START_H__
|
#define __GPIO_SCENE_START_H__
|
||||||
|
|
||||||
#include "../gpio_app_i.h"
|
#include "../gpio_app_i.h"
|
||||||
#include "furi_hal_power.h"
|
#include <furi_hal_power.h>
|
||||||
#include "furi_hal_usb.h"
|
#include <furi_hal_usb.h>
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
enum GpioItem {
|
enum GpioItem {
|
||||||
GpioItemUsbUart,
|
GpioItemUsbUart,
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ void gpio_scene_test_ok_callback(InputType type, void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void gpio_scene_test_on_enter(void* context) {
|
void gpio_scene_test_on_enter(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
GpioApp* app = context;
|
GpioApp* app = context;
|
||||||
gpio_item_configure_all_pins(GpioModeOutputPushPull);
|
gpio_items_configure_all_pins(app->gpio_items, GpioModeOutputPushPull);
|
||||||
gpio_test_set_ok_callback(app->gpio_test, gpio_scene_test_ok_callback, app);
|
gpio_test_set_ok_callback(app->gpio_test, gpio_scene_test_ok_callback, app);
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewGpioTest);
|
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewGpioTest);
|
||||||
}
|
}
|
||||||
@@ -25,6 +26,7 @@ bool gpio_scene_test_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void gpio_scene_test_on_exit(void* context) {
|
void gpio_scene_test_on_exit(void* context) {
|
||||||
UNUSED(context);
|
furi_assert(context);
|
||||||
gpio_item_configure_all_pins(GpioModeAnalog);
|
GpioApp* app = context;
|
||||||
|
gpio_items_configure_all_pins(app->gpio_items, GpioModeAnalog);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "../usb_uart_bridge.h"
|
#include "../usb_uart_bridge.h"
|
||||||
#include "../gpio_app_i.h"
|
#include "../gpio_app_i.h"
|
||||||
#include "furi_hal.h"
|
#include <furi_hal.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UsbUartLineIndexVcp,
|
UsbUartLineIndexVcp,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "usb_uart_bridge.h"
|
#include "usb_uart_bridge.h"
|
||||||
#include "furi_hal.h"
|
|
||||||
#include <furi_hal_usb_cdc.h>
|
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
#include "cli/cli_vcp.h"
|
#include <cli/cli_vcp.h>
|
||||||
|
#include <cli/cli.h>
|
||||||
#include <toolbox/api_lock.h>
|
#include <toolbox/api_lock.h>
|
||||||
#include "cli/cli.h"
|
#include <furi_hal.h>
|
||||||
|
#include <furi_hal_usb_cdc.h>
|
||||||
|
|
||||||
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
||||||
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
|
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include "gpio_i2c_scanner.h"
|
#include "gpio_i2c_scanner.h"
|
||||||
#include "../gpio_item.h"
|
#include "../gpio_items.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include "gpio_i2c_sfp.h"
|
#include "gpio_i2c_sfp.h"
|
||||||
#include "../gpio_item.h"
|
#include "../gpio_items.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "gpio_test.h"
|
#include "gpio_test.h"
|
||||||
#include "../gpio_item.h"
|
#include "../gpio_items.h"
|
||||||
|
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ struct GpioTest {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t pin_idx;
|
uint8_t pin_idx;
|
||||||
|
GPIOItems* gpio_items;
|
||||||
} GpioTestModel;
|
} GpioTestModel;
|
||||||
|
|
||||||
static bool gpio_test_process_left(GpioTest* gpio_test);
|
static bool gpio_test_process_left(GpioTest* gpio_test);
|
||||||
@@ -25,7 +26,12 @@ static void gpio_test_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
elements_multiline_text_aligned(
|
elements_multiline_text_aligned(
|
||||||
canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin");
|
canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin");
|
||||||
elements_multiline_text_aligned(
|
elements_multiline_text_aligned(
|
||||||
canvas, 64, 32, AlignCenter, AlignTop, gpio_item_get_pin_name(model->pin_idx));
|
canvas,
|
||||||
|
64,
|
||||||
|
32,
|
||||||
|
AlignCenter,
|
||||||
|
AlignTop,
|
||||||
|
gpio_items_get_pin_name(model->gpio_items, model->pin_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gpio_test_input_callback(InputEvent* event, void* context) {
|
static bool gpio_test_input_callback(InputEvent* event, void* context) {
|
||||||
@@ -64,7 +70,7 @@ static bool gpio_test_process_right(GpioTest* gpio_test) {
|
|||||||
gpio_test->view,
|
gpio_test->view,
|
||||||
GpioTestModel * model,
|
GpioTestModel * model,
|
||||||
{
|
{
|
||||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
|
||||||
model->pin_idx++;
|
model->pin_idx++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -80,17 +86,17 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
|
|||||||
GpioTestModel * model,
|
GpioTestModel * model,
|
||||||
{
|
{
|
||||||
if(event->type == InputTypePress) {
|
if(event->type == InputTypePress) {
|
||||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
|
||||||
gpio_item_set_pin(model->pin_idx, true);
|
gpio_items_set_pin(model->gpio_items, model->pin_idx, true);
|
||||||
} else {
|
} else {
|
||||||
gpio_item_set_all_pins(true);
|
gpio_items_set_all_pins(model->gpio_items, true);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event->type == InputTypeRelease) {
|
} else if(event->type == InputTypeRelease) {
|
||||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
|
||||||
gpio_item_set_pin(model->pin_idx, false);
|
gpio_items_set_pin(model->gpio_items, model->pin_idx, false);
|
||||||
} else {
|
} else {
|
||||||
gpio_item_set_all_pins(false);
|
gpio_items_set_all_pins(model->gpio_items, false);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
@@ -101,11 +107,15 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpioTest* gpio_test_alloc() {
|
GpioTest* gpio_test_alloc(GPIOItems* gpio_items) {
|
||||||
GpioTest* gpio_test = malloc(sizeof(GpioTest));
|
GpioTest* gpio_test = malloc(sizeof(GpioTest));
|
||||||
|
|
||||||
gpio_test->view = view_alloc();
|
gpio_test->view = view_alloc();
|
||||||
view_allocate_model(gpio_test->view, ViewModelTypeLocking, sizeof(GpioTestModel));
|
view_allocate_model(gpio_test->view, ViewModelTypeLocking, sizeof(GpioTestModel));
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
gpio_test->view, GpioTestModel * model, { model->gpio_items = gpio_items; }, false);
|
||||||
|
|
||||||
view_set_context(gpio_test->view, gpio_test);
|
view_set_context(gpio_test->view, gpio_test);
|
||||||
view_set_draw_callback(gpio_test->view, gpio_test_draw_callback);
|
view_set_draw_callback(gpio_test->view, gpio_test_draw_callback);
|
||||||
view_set_input_callback(gpio_test->view, gpio_test_input_callback);
|
view_set_input_callback(gpio_test->view, gpio_test_input_callback);
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../gpio_items.h"
|
||||||
|
|
||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
|
|
||||||
typedef struct GpioTest GpioTest;
|
typedef struct GpioTest GpioTest;
|
||||||
typedef void (*GpioTestOkCallback)(InputType type, void* context);
|
typedef void (*GpioTestOkCallback)(InputType type, void* context);
|
||||||
|
|
||||||
GpioTest* gpio_test_alloc();
|
GpioTest* gpio_test_alloc(GPIOItems* gpio_items);
|
||||||
|
|
||||||
void gpio_test_free(GpioTest* gpio_test);
|
void gpio_test_free(GpioTest* gpio_test);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "../usb_uart_bridge.h"
|
#include "../usb_uart_bridge.h"
|
||||||
#include "../gpio_app_i.h"
|
#include "../gpio_app_i.h"
|
||||||
#include "furi_hal.h"
|
#include <furi_hal.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
struct GpioUsbUart {
|
struct GpioUsbUart {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ App(
|
|||||||
appid="ibutton",
|
appid="ibutton",
|
||||||
name="iButton",
|
name="iButton",
|
||||||
apptype=FlipperAppType.APP,
|
apptype=FlipperAppType.APP,
|
||||||
|
targets=["f7"],
|
||||||
entry_point="ibutton_app",
|
entry_point="ibutton_app",
|
||||||
cdefines=["APP_IBUTTON"],
|
cdefines=["APP_IBUTTON"],
|
||||||
requires=[
|
requires=[
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ App(
|
|||||||
name="Infrared",
|
name="Infrared",
|
||||||
apptype=FlipperAppType.APP,
|
apptype=FlipperAppType.APP,
|
||||||
entry_point="infrared_app",
|
entry_point="infrared_app",
|
||||||
|
targets=["f7"],
|
||||||
cdefines=["APP_INFRARED"],
|
cdefines=["APP_INFRARED"],
|
||||||
requires=[
|
requires=[
|
||||||
"gui",
|
"gui",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "../infrared_i.h"
|
#include "../infrared_i.h"
|
||||||
#include "gui/canvas.h"
|
#include <gui/canvas.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
InfraredRpcStateIdle,
|
InfraredRpcStateIdle,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "infrared_debug_view.h"
|
#include "infrared_debug_view.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <gui/canvas.h>
|
#include <gui/canvas.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define INFRARED_DEBUG_TEXT_LENGTH 64
|
#define INFRARED_DEBUG_TEXT_LENGTH 64
|
||||||
|
|
||||||
struct InfraredDebugView {
|
struct InfraredDebugView {
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#include <core/check.h>
|
|
||||||
#include "furi_hal_resources.h"
|
|
||||||
#include "assets_icons.h"
|
|
||||||
#include "gui/canvas.h"
|
|
||||||
#include "gui/view.h"
|
|
||||||
#include "input/input.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
#include <furi.h>
|
|
||||||
#include "infrared_progress_view.h"
|
#include "infrared_progress_view.h"
|
||||||
#include "gui/modules/button_panel.h"
|
|
||||||
|
#include <assets_icons.h>
|
||||||
|
#include <gui/canvas.h>
|
||||||
|
#include <gui/view.h>
|
||||||
|
#include <gui/elements.h>
|
||||||
|
#include <gui/modules/button_panel.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal_resources.h>
|
||||||
|
#include <core/check.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct InfraredProgressView {
|
struct InfraredProgressView {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ App(
|
|||||||
appid="lfrfid",
|
appid="lfrfid",
|
||||||
name="125 kHz RFID",
|
name="125 kHz RFID",
|
||||||
apptype=FlipperAppType.APP,
|
apptype=FlipperAppType.APP,
|
||||||
|
targets=["f7"],
|
||||||
entry_point="lfrfid_app",
|
entry_point="lfrfid_app",
|
||||||
cdefines=["APP_LF_RFID"],
|
cdefines=["APP_LF_RFID"],
|
||||||
requires=[
|
requires=[
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ App(
|
|||||||
appid="nfc",
|
appid="nfc",
|
||||||
name="NFC",
|
name="NFC",
|
||||||
apptype=FlipperAppType.APP,
|
apptype=FlipperAppType.APP,
|
||||||
|
targets=["f7"],
|
||||||
entry_point="nfc_app",
|
entry_point="nfc_app",
|
||||||
cdefines=["APP_NFC"],
|
cdefines=["APP_NFC"],
|
||||||
requires=[
|
requires=[
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "nfc_i.h"
|
#include "nfc_i.h"
|
||||||
#include "furi_hal_nfc.h"
|
#include <furi_hal_nfc.h>
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
bool nfc_custom_event_callback(void* context, uint32_t event) {
|
bool nfc_custom_event_callback(void* context, uint32_t event) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ App(
|
|||||||
appid="subghz",
|
appid="subghz",
|
||||||
name="Sub-GHz",
|
name="Sub-GHz",
|
||||||
apptype=FlipperAppType.APP,
|
apptype=FlipperAppType.APP,
|
||||||
|
targets=["f7"],
|
||||||
entry_point="subghz_app",
|
entry_point="subghz_app",
|
||||||
cdefines=["APP_SUBGHZ"],
|
cdefines=["APP_SUBGHZ"],
|
||||||
requires=[
|
requires=[
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
|
|||||||
//init setting
|
//init setting
|
||||||
subghz->setting = subghz_setting_alloc();
|
subghz->setting = subghz_setting_alloc();
|
||||||
|
|
||||||
subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user"));
|
subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user.txt"));
|
||||||
|
|
||||||
// Custom Presets load without using config file
|
// Custom Presets load without using config file
|
||||||
|
|
||||||
@@ -208,26 +208,37 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
|
|||||||
|
|
||||||
flipper_format_free(temp_fm_preset2);
|
flipper_format_free(temp_fm_preset2);
|
||||||
|
|
||||||
// # HND - FM presets
|
// Pagers
|
||||||
FlipperFormat* temp_fm_preset3 = flipper_format_string_alloc();
|
FlipperFormat* temp_fm_preset3 = flipper_format_string_alloc();
|
||||||
flipper_format_write_string_cstr(
|
flipper_format_write_string_cstr(
|
||||||
temp_fm_preset3,
|
temp_fm_preset2,
|
||||||
(const char*)"Custom_preset_data",
|
(const char*)"Custom_preset_data",
|
||||||
(const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00");
|
(const char*)"02 0D 07 04 08 32 0B 06 10 64 11 93 12 0C 13 02 14 00 15 15 18 18 19 16 1B 07 1C 00 1D 91 20 FB 21 56 22 10 00 00 C0 00 00 00 00 00 00 00");
|
||||||
flipper_format_rewind(temp_fm_preset3);
|
flipper_format_rewind(temp_fm_preset3);
|
||||||
subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_1", temp_fm_preset3);
|
subghz_setting_load_custom_preset(subghz->setting, (const char*)"Pagers", temp_fm_preset3);
|
||||||
|
|
||||||
flipper_format_free(temp_fm_preset3);
|
flipper_format_free(temp_fm_preset3);
|
||||||
|
|
||||||
|
// # HND - FM presets
|
||||||
FlipperFormat* temp_fm_preset4 = flipper_format_string_alloc();
|
FlipperFormat* temp_fm_preset4 = flipper_format_string_alloc();
|
||||||
flipper_format_write_string_cstr(
|
flipper_format_write_string_cstr(
|
||||||
temp_fm_preset4,
|
temp_fm_preset4,
|
||||||
(const char*)"Custom_preset_data",
|
(const char*)"Custom_preset_data",
|
||||||
(const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00");
|
(const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00");
|
||||||
flipper_format_rewind(temp_fm_preset4);
|
flipper_format_rewind(temp_fm_preset4);
|
||||||
subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_2", temp_fm_preset4);
|
subghz_setting_load_custom_preset(subghz->setting, (const char*)"Honda_1", temp_fm_preset4);
|
||||||
|
|
||||||
flipper_format_free(temp_fm_preset4);
|
flipper_format_free(temp_fm_preset3);
|
||||||
|
|
||||||
|
FlipperFormat* temp_fm_preset5 = flipper_format_string_alloc();
|
||||||
|
flipper_format_write_string_cstr(
|
||||||
|
temp_fm_preset5,
|
||||||
|
(const char*)"Custom_preset_data",
|
||||||
|
(const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00");
|
||||||
|
flipper_format_rewind(temp_fm_preset5);
|
||||||
|
subghz_setting_load_custom_preset(subghz->setting, (const char*)"Honda_2", temp_fm_preset5);
|
||||||
|
|
||||||
|
flipper_format_free(temp_fm_preset5);
|
||||||
|
|
||||||
// custom presets loading - end
|
// custom presets loading - end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "../u2f_app_i.h"
|
#include "../u2f_app_i.h"
|
||||||
#include "../../../settings/xtreme_settings/xtreme_settings.h"
|
#include "../../../settings/xtreme_settings/xtreme_assets.h"
|
||||||
|
|
||||||
static void u2f_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
|
static void u2f_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
@@ -27,7 +27,7 @@ void u2f_scene_error_on_enter(void* context) {
|
|||||||
app->widget, GuiButtonTypeLeft, "Back", u2f_scene_error_event_callback, app);
|
app->widget, GuiButtonTypeLeft, "Back", u2f_scene_error_event_callback, app);
|
||||||
} else if(app->error == U2fAppErrorCloseRpc) {
|
} else if(app->error == U2fAppErrorCloseRpc) {
|
||||||
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
|
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
|
||||||
if(XTREME_SETTINGS()->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
widget_add_string_multiline_element(
|
widget_add_string_multiline_element(
|
||||||
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "I am not\na whore!");
|
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "I am not\na whore!");
|
||||||
widget_add_string_multiline_element(
|
widget_add_string_multiline_element(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "../u2f_app_i.h"
|
#include "../u2f_app_i.h"
|
||||||
#include "../views/u2f_view.h"
|
#include "../views/u2f_view.h"
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
#include "furi_hal.h"
|
#include <furi_hal.h>
|
||||||
#include "../u2f.h"
|
#include "../u2f.h"
|
||||||
|
|
||||||
#define U2F_REQUEST_TIMEOUT 500
|
#define U2F_REQUEST_TIMEOUT 500
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
|
|
||||||
if(model->display_msg == U2fMsgNotConnected) {
|
if(model->display_msg == U2fMsgNotConnected) {
|
||||||
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connect_me_62x31);
|
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connect_me_62x31);
|
||||||
if(XTREME_SETTINGS()->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas, 128 / 2, 3, AlignCenter, AlignTop, "Plug me in d-daddy");
|
canvas, 128 / 2, 3, AlignCenter, AlignTop, "Plug me in d-daddy");
|
||||||
} else {
|
} else {
|
||||||
@@ -32,7 +32,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connected_62x31);
|
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connected_62x31);
|
||||||
canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connected!");
|
canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connected!");
|
||||||
} else if(model->display_msg == U2fMsgRegister) {
|
} else if(model->display_msg == U2fMsgRegister) {
|
||||||
if(XTREME_SETTINGS()->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
elements_button_center(canvas, "CUM");
|
elements_button_center(canvas, "CUM");
|
||||||
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Auth_62x31);
|
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Auth_62x31);
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
@@ -44,7 +44,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
canvas, 128 / 2, 3, AlignCenter, AlignTop, "Press OK to register");
|
canvas, 128 / 2, 3, AlignCenter, AlignTop, "Press OK to register");
|
||||||
}
|
}
|
||||||
} else if(model->display_msg == U2fMsgAuth) {
|
} else if(model->display_msg == U2fMsgAuth) {
|
||||||
if(XTREME_SETTINGS()->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
elements_button_center(canvas, "CUM");
|
elements_button_center(canvas, "CUM");
|
||||||
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Auth_62x31);
|
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Auth_62x31);
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
@@ -57,7 +57,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
}
|
}
|
||||||
} else if(model->display_msg == U2fMsgSuccess) {
|
} else if(model->display_msg == U2fMsgSuccess) {
|
||||||
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connected_62x31);
|
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connected_62x31);
|
||||||
if(XTREME_SETTINGS()->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Cum released~");
|
canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Cum released~");
|
||||||
} else {
|
} else {
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
@@ -65,7 +65,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
}
|
}
|
||||||
} else if(model->display_msg == U2fMsgError) {
|
} else if(model->display_msg == U2fMsgError) {
|
||||||
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Error_62x31);
|
canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Error_62x31);
|
||||||
if(XTREME_SETTINGS()->nsfw_mode) {
|
if(XTREME_ASSETS()->is_nsfw) {
|
||||||
canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Unable to cum");
|
canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Unable to cum");
|
||||||
} else {
|
} else {
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
|
|||||||
@@ -706,7 +706,7 @@ static void input_callback(InputEvent* input_event, void* ctx) {
|
|||||||
void unirfremix_subghz_alloc(UniRFRemix* app) {
|
void unirfremix_subghz_alloc(UniRFRemix* app) {
|
||||||
// load subghz presets
|
// load subghz presets
|
||||||
app->setting = subghz_setting_alloc();
|
app->setting = subghz_setting_alloc();
|
||||||
subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user"));
|
subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user.txt"));
|
||||||
|
|
||||||
// load mfcodes
|
// load mfcodes
|
||||||
app->environment = subghz_environment_alloc();
|
app->environment = subghz_environment_alloc();
|
||||||
|
|||||||
15
applications/plugins/brainfuck/application.fam
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
App(
|
||||||
|
appid="Brainfuck",
|
||||||
|
name="Brainfuck",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
entry_point="brainfuck_app",
|
||||||
|
requires=[
|
||||||
|
"storage",
|
||||||
|
"gui",
|
||||||
|
],
|
||||||
|
stack_size=8 * 1024,
|
||||||
|
fap_icon="bfico.png",
|
||||||
|
fap_category="Misc",
|
||||||
|
fap_icon_assets="icons",
|
||||||
|
fap_icon_assets_symbol="brainfuck",
|
||||||
|
)
|
||||||
BIN
applications/plugins/brainfuck/bfico.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
149
applications/plugins/brainfuck/brainfuck.c
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#include "brainfuck_i.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Due to the lack of documentation on the flipper i copied the picopass app,
|
||||||
|
ripped its insides out and used its hollow corpse to build this app inside of.
|
||||||
|
|
||||||
|
i dont know how this stuff works and after 6 hours of trying to learn it, i dont care
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool brainfuck_custom_event_callback(void* context, uint32_t event) {
|
||||||
|
furi_assert(context);
|
||||||
|
BFApp* brainfuck = context;
|
||||||
|
return scene_manager_handle_custom_event(brainfuck->scene_manager, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brainfuck_back_event_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
BFApp* brainfuck = context;
|
||||||
|
return scene_manager_handle_back_event(brainfuck->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
BFApp* brainfuck_alloc() {
|
||||||
|
BFApp* brainfuck = malloc(sizeof(BFApp));
|
||||||
|
|
||||||
|
brainfuck->dataSize = 0;
|
||||||
|
brainfuck->view_dispatcher = view_dispatcher_alloc();
|
||||||
|
brainfuck->scene_manager = scene_manager_alloc(&brainfuck_scene_handlers, brainfuck);
|
||||||
|
view_dispatcher_enable_queue(brainfuck->view_dispatcher);
|
||||||
|
view_dispatcher_set_event_callback_context(brainfuck->view_dispatcher, brainfuck);
|
||||||
|
view_dispatcher_set_custom_event_callback(
|
||||||
|
brainfuck->view_dispatcher, brainfuck_custom_event_callback);
|
||||||
|
view_dispatcher_set_navigation_event_callback(
|
||||||
|
brainfuck->view_dispatcher, brainfuck_back_event_callback);
|
||||||
|
|
||||||
|
// Open GUI record
|
||||||
|
brainfuck->gui = furi_record_open(RECORD_GUI);
|
||||||
|
view_dispatcher_attach_to_gui(
|
||||||
|
brainfuck->view_dispatcher, brainfuck->gui, ViewDispatcherTypeFullscreen);
|
||||||
|
|
||||||
|
// Open Notification record
|
||||||
|
brainfuck->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
// Submenu
|
||||||
|
brainfuck->submenu = submenu_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
brainfuck->view_dispatcher, brainfuckViewMenu, submenu_get_view(brainfuck->submenu));
|
||||||
|
|
||||||
|
// Popup
|
||||||
|
brainfuck->popup = popup_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
brainfuck->view_dispatcher, brainfuckViewPopup, popup_get_view(brainfuck->popup));
|
||||||
|
|
||||||
|
// Text Input
|
||||||
|
brainfuck->text_input = text_input_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
brainfuck->view_dispatcher,
|
||||||
|
brainfuckViewTextInput,
|
||||||
|
text_input_get_view(brainfuck->text_input));
|
||||||
|
|
||||||
|
// Textbox
|
||||||
|
brainfuck->text_box = text_box_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
brainfuck->view_dispatcher, brainfuckViewTextBox, text_box_get_view(brainfuck->text_box));
|
||||||
|
brainfuck->text_box_store = furi_string_alloc();
|
||||||
|
|
||||||
|
// Dev environment
|
||||||
|
brainfuck->BF_dev_env = bf_dev_env_alloc(brainfuck);
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
brainfuck->view_dispatcher, brainfuckViewDev, bf_dev_env_get_view(brainfuck->BF_dev_env));
|
||||||
|
|
||||||
|
// File path
|
||||||
|
brainfuck->BF_file_path = furi_string_alloc();
|
||||||
|
|
||||||
|
return brainfuck;
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_free(BFApp* brainfuck) {
|
||||||
|
furi_assert(brainfuck);
|
||||||
|
|
||||||
|
// Submenu
|
||||||
|
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewMenu);
|
||||||
|
submenu_free(brainfuck->submenu);
|
||||||
|
|
||||||
|
// Popup
|
||||||
|
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewPopup);
|
||||||
|
popup_free(brainfuck->popup);
|
||||||
|
|
||||||
|
// TextInput
|
||||||
|
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewTextInput);
|
||||||
|
text_input_free(brainfuck->text_input);
|
||||||
|
|
||||||
|
// TextBox
|
||||||
|
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewTextBox);
|
||||||
|
text_box_free(brainfuck->text_box);
|
||||||
|
furi_string_free(brainfuck->text_box_store);
|
||||||
|
|
||||||
|
//dev env
|
||||||
|
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewDev);
|
||||||
|
bf_dev_env_free(brainfuck->BF_dev_env);
|
||||||
|
|
||||||
|
// View Dispatcher
|
||||||
|
view_dispatcher_free(brainfuck->view_dispatcher);
|
||||||
|
|
||||||
|
// Scene Manager
|
||||||
|
scene_manager_free(brainfuck->scene_manager);
|
||||||
|
|
||||||
|
// GUI
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
brainfuck->gui = NULL;
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
brainfuck->notifications = NULL;
|
||||||
|
|
||||||
|
free(brainfuck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_show_loading_popup(void* context, bool show) {
|
||||||
|
BFApp* brainfuck = context;
|
||||||
|
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
|
||||||
|
|
||||||
|
if(show) {
|
||||||
|
// Raise timer priority so that animations can play
|
||||||
|
vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
|
||||||
|
view_dispatcher_switch_to_view(brainfuck->view_dispatcher, brainfuckViewLoading);
|
||||||
|
} else {
|
||||||
|
// Restore default timer priority
|
||||||
|
vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t brainfuck_app(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
BFApp* brainfuck = brainfuck_alloc();
|
||||||
|
if(!brainfuck) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
storage_simply_mkdir(storage, "/ext/brainfuck");
|
||||||
|
|
||||||
|
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneStart);
|
||||||
|
|
||||||
|
view_dispatcher_run(brainfuck->view_dispatcher);
|
||||||
|
|
||||||
|
brainfuck_free(brainfuck);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
3
applications/plugins/brainfuck/brainfuck.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct BFApp BFApp;
|
||||||
89
applications/plugins/brainfuck/brainfuck_i.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct BFDevEnv BFDevEnv;
|
||||||
|
typedef struct BFExecEnv BFExecEnv;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
|
||||||
|
#include "brainfuck.h"
|
||||||
|
#include "worker.h"
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <gui/scene_manager.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
|
||||||
|
#include <gui/modules/submenu.h>
|
||||||
|
#include <gui/modules/popup.h>
|
||||||
|
#include <gui/modules/loading.h>
|
||||||
|
#include <gui/modules/text_input.h>
|
||||||
|
#include <gui/modules/widget.h>
|
||||||
|
#include <gui/modules/text_box.h>
|
||||||
|
|
||||||
|
#include <dialogs/dialogs.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
|
#include "scenes/brainfuck_scene.h"
|
||||||
|
|
||||||
|
#include "views/bf_dev_env.h"
|
||||||
|
|
||||||
|
#include <storage/storage.h>
|
||||||
|
#include <lib/toolbox/path.h>
|
||||||
|
#include <brainfuck_icons.h>
|
||||||
|
|
||||||
|
#include <storage/storage.h>
|
||||||
|
#include <stream/stream.h>
|
||||||
|
#include <stream/buffered_file_stream.h>
|
||||||
|
#include <toolbox/stream/file_stream.h>
|
||||||
|
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
#include <notification/notification_app.h>
|
||||||
|
|
||||||
|
#define BF_INST_BUFFER_SIZE 2048
|
||||||
|
#define BF_OUTPUT_SIZE 512
|
||||||
|
#define BF_STACK_INITIAL_SIZE 128
|
||||||
|
#define BF_INPUT_BUFFER_SIZE 64
|
||||||
|
#define BF_STACK_STEP_SIZE 32
|
||||||
|
|
||||||
|
enum brainfuckCustomEvent {
|
||||||
|
// Reserve first 100 events for button types and indexes, starting from 0
|
||||||
|
brainfuckCustomEventReserved = 100,
|
||||||
|
|
||||||
|
brainfuckCustomEventViewExit,
|
||||||
|
brainfuckCustomEventWorkerExit,
|
||||||
|
brainfuckCustomEventByteInputDone,
|
||||||
|
brainfuckCustomEventTextInputDone,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EventTypeTick,
|
||||||
|
EventTypeKey,
|
||||||
|
} EventType;
|
||||||
|
|
||||||
|
struct BFApp {
|
||||||
|
ViewDispatcher* view_dispatcher;
|
||||||
|
Gui* gui;
|
||||||
|
NotificationApp* notifications;
|
||||||
|
SceneManager* scene_manager;
|
||||||
|
Submenu* submenu;
|
||||||
|
Popup* popup;
|
||||||
|
TextInput* text_input;
|
||||||
|
TextBox* text_box;
|
||||||
|
FuriString* text_box_store;
|
||||||
|
FuriString* BF_file_path;
|
||||||
|
BFDevEnv* BF_dev_env;
|
||||||
|
int dataSize;
|
||||||
|
char dataBuffer[BF_INST_BUFFER_SIZE];
|
||||||
|
char inputBuffer[BF_INPUT_BUFFER_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
brainfuckViewMenu,
|
||||||
|
brainfuckViewPopup,
|
||||||
|
brainfuckViewLoading,
|
||||||
|
brainfuckViewTextInput,
|
||||||
|
brainfuckViewTextBox,
|
||||||
|
brainfuckViewWidget,
|
||||||
|
brainfuckViewDev,
|
||||||
|
brainfuckViewExec,
|
||||||
|
} brainfuckView;
|
||||||
BIN
applications/plugins/brainfuck/icons/ButtonRightSmall_3x5.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/plugins/brainfuck/icons/KeyBackspace_24x11.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/plugins/brainfuck/icons/KeyInputSelected_30x11.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/plugins/brainfuck/icons/KeyInput_30x11.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/plugins/brainfuck/icons/KeyRunSelected_24x11.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/plugins/brainfuck/icons/KeyRun_24x11.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
applications/plugins/brainfuck/icons/KeySaveSelected_24x11.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/plugins/brainfuck/icons/KeySave_24x11.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/plugins/brainfuck/icons/bfico.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
30
applications/plugins/brainfuck/scenes/brainfuck_scene.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "brainfuck_scene.h"
|
||||||
|
|
||||||
|
// Generate scene on_enter handlers array
|
||||||
|
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||||
|
void (*const brainfuck_on_enter_handlers[])(void*) = {
|
||||||
|
#include "brainfuck_scene_config.h"
|
||||||
|
};
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_event handlers array
|
||||||
|
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||||
|
bool (*const brainfuck_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||||
|
#include "brainfuck_scene_config.h"
|
||||||
|
};
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_exit handlers array
|
||||||
|
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||||
|
void (*const brainfuck_on_exit_handlers[])(void* context) = {
|
||||||
|
#include "brainfuck_scene_config.h"
|
||||||
|
};
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Initialize scene handlers configuration structure
|
||||||
|
const SceneManagerHandlers brainfuck_scene_handlers = {
|
||||||
|
.on_enter_handlers = brainfuck_on_enter_handlers,
|
||||||
|
.on_event_handlers = brainfuck_on_event_handlers,
|
||||||
|
.on_exit_handlers = brainfuck_on_exit_handlers,
|
||||||
|
.scene_num = brainfuckSceneNum,
|
||||||
|
};
|
||||||
29
applications/plugins/brainfuck/scenes/brainfuck_scene.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gui/scene_manager.h>
|
||||||
|
|
||||||
|
// Generate scene id and total number
|
||||||
|
#define ADD_SCENE(prefix, name, id) brainfuckScene##id,
|
||||||
|
typedef enum {
|
||||||
|
#include "brainfuck_scene_config.h"
|
||||||
|
brainfuckSceneNum,
|
||||||
|
} brainfuckScene;
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
extern const SceneManagerHandlers brainfuck_scene_handlers;
|
||||||
|
|
||||||
|
// Generate scene on_enter handlers declaration
|
||||||
|
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||||
|
#include "brainfuck_scene_config.h"
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_event handlers declaration
|
||||||
|
#define ADD_SCENE(prefix, name, id) \
|
||||||
|
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||||
|
#include "brainfuck_scene_config.h"
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_exit handlers declaration
|
||||||
|
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||||
|
#include "brainfuck_scene_config.h"
|
||||||
|
#undef ADD_SCENE
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
ADD_SCENE(brainfuck, start, Start)
|
||||||
|
ADD_SCENE(brainfuck, file_select, FileSelect)
|
||||||
|
ADD_SCENE(brainfuck, file_create, FileCreate)
|
||||||
|
ADD_SCENE(brainfuck, dev_env, DevEnv)
|
||||||
|
ADD_SCENE(brainfuck, exec_env, ExecEnv)
|
||||||
|
ADD_SCENE(brainfuck, set_input, SetInput)
|
||||||
16
applications/plugins/brainfuck/scenes/brainfuck_scene_dev.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include "../brainfuck_i.h"
|
||||||
|
|
||||||
|
void brainfuck_scene_dev_env_on_enter(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewDev);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brainfuck_scene_dev_env_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_scene_dev_env_on_exit(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
16
applications/plugins/brainfuck/scenes/brainfuck_scene_exec.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include "../brainfuck_i.h"
|
||||||
|
|
||||||
|
void brainfuck_scene_exec_env_on_enter(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brainfuck_scene_exec_env_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_scene_exec_env_on_exit(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#include "../brainfuck_i.h"
|
||||||
|
|
||||||
|
void file_name_text_input_callback(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
view_dispatcher_send_custom_event(app->view_dispatcher, brainfuckCustomEventTextInputDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
char tmpName[64] = {};
|
||||||
|
byte empty[1] = {0x00};
|
||||||
|
void brainfuck_scene_file_create_on_enter(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
TextInput* text_input = app->text_input;
|
||||||
|
|
||||||
|
text_input_set_header_text(text_input, "New script name");
|
||||||
|
text_input_set_result_callback(
|
||||||
|
text_input, file_name_text_input_callback, app, tmpName, 64, true);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brainfuck_scene_file_create_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
BFApp* app = context;
|
||||||
|
UNUSED(app);
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == brainfuckCustomEventTextInputDone) {
|
||||||
|
furi_string_cat_printf(app->BF_file_path, "/ext/brainfuck/%s.b", tmpName);
|
||||||
|
|
||||||
|
//remove old file
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
storage_simply_remove(storage, furi_string_get_cstr(app->BF_file_path));
|
||||||
|
|
||||||
|
//save new file
|
||||||
|
Stream* stream = buffered_file_stream_alloc(storage);
|
||||||
|
buffered_file_stream_open(
|
||||||
|
stream, furi_string_get_cstr(app->BF_file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS);
|
||||||
|
stream_write(stream, (const uint8_t*)empty, 1);
|
||||||
|
buffered_file_stream_close(stream);
|
||||||
|
|
||||||
|
//scene_manager_next_scene(app->scene_manager, brainfuckSceneFileSelect);
|
||||||
|
scene_manager_next_scene(app->scene_manager, brainfuckSceneDevEnv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_scene_file_create_on_exit(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#include "../brainfuck_i.h"
|
||||||
|
|
||||||
|
void brainfuck_scene_file_select_on_enter(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
|
||||||
|
DialogsApp* dialogs = furi_record_open("dialogs");
|
||||||
|
FuriString* path;
|
||||||
|
path = furi_string_alloc();
|
||||||
|
furi_string_set(path, "/ext/brainfuck");
|
||||||
|
|
||||||
|
DialogsFileBrowserOptions browser_options;
|
||||||
|
dialog_file_browser_set_basic_options(&browser_options, ".b", &I_bfico);
|
||||||
|
browser_options.base_path = "/ext/brainfuck";
|
||||||
|
browser_options.hide_ext = false;
|
||||||
|
|
||||||
|
bool selected = dialog_file_browser_show(dialogs, path, path, &browser_options);
|
||||||
|
|
||||||
|
if(selected) {
|
||||||
|
furi_string_set(app->BF_file_path, path);
|
||||||
|
scene_manager_next_scene(app->scene_manager, brainfuckSceneDevEnv);
|
||||||
|
} else {
|
||||||
|
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, brainfuckSceneStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brainfuck_scene_file_select_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_scene_file_select_on_exit(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "../brainfuck_i.h"
|
||||||
|
|
||||||
|
void set_input_text_input_callback(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
view_dispatcher_send_custom_event(app->view_dispatcher, brainfuckCustomEventTextInputDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_scene_set_input_on_enter(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
TextInput* text_input = app->text_input;
|
||||||
|
|
||||||
|
text_input_set_header_text(text_input, "Edit input buffer");
|
||||||
|
text_input_set_result_callback(
|
||||||
|
text_input, set_input_text_input_callback, app, app->inputBuffer, 64, true);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brainfuck_scene_set_input_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
BFApp* app = context;
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == brainfuckCustomEventTextInputDone) {
|
||||||
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
app->scene_manager, brainfuckSceneDevEnv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_scene_set_input_on_exit(void* context) {
|
||||||
|
BFApp* app = context;
|
||||||
|
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, brainfuckSceneDevEnv);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "../brainfuck_i.h"
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexNew,
|
||||||
|
SubmenuIndexOpen,
|
||||||
|
SubmenuIndexAbout,
|
||||||
|
};
|
||||||
|
|
||||||
|
void brainfuck_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||||
|
BFApp* brainfuck = context;
|
||||||
|
view_dispatcher_send_custom_event(brainfuck->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
void brainfuck_scene_start_on_enter(void* context) {
|
||||||
|
BFApp* brainfuck = context;
|
||||||
|
|
||||||
|
Submenu* submenu = brainfuck->submenu;
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "New", SubmenuIndexNew, brainfuck_scene_start_submenu_callback, brainfuck);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Open", SubmenuIndexOpen, brainfuck_scene_start_submenu_callback, brainfuck);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "About", SubmenuIndexAbout, brainfuck_scene_start_submenu_callback, brainfuck);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
submenu, scene_manager_get_scene_state(brainfuck->scene_manager, brainfuckSceneStart));
|
||||||
|
view_dispatcher_switch_to_view(brainfuck->view_dispatcher, brainfuckViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brainfuck_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
BFApp* brainfuck = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexNew) {
|
||||||
|
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneFileCreate);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexOpen) {
|
||||||
|
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneFileSelect);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexAbout) {
|
||||||
|
text_box_set_text(
|
||||||
|
brainfuck->text_box,
|
||||||
|
"FlipperBrainfuck\n\nAn F0 brainfuck intepretor\nBy github.com/Nymda");
|
||||||
|
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneExecEnv);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(brainfuck->scene_manager, brainfuckSceneStart, event.event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void brainfuck_scene_start_on_exit(void* context) {
|
||||||
|
BFApp* brainfuck = context;
|
||||||
|
submenu_reset(brainfuck->submenu);
|
||||||
|
}
|
||||||
419
applications/plugins/brainfuck/views/bf_dev_env.c
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
#include "bf_dev_env.h"
|
||||||
|
#include <gui/elements.h>
|
||||||
|
|
||||||
|
typedef struct BFDevEnv {
|
||||||
|
View* view;
|
||||||
|
DevEnvOkCallback callback;
|
||||||
|
void* context;
|
||||||
|
BFApp* appDev;
|
||||||
|
} BFDevEnv;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t row;
|
||||||
|
uint32_t col;
|
||||||
|
} BFDevEnvModel;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int up;
|
||||||
|
int down;
|
||||||
|
int left;
|
||||||
|
int right;
|
||||||
|
} bMapping;
|
||||||
|
|
||||||
|
static bool bf_dev_process_up(BFDevEnv* devEnv);
|
||||||
|
static bool bf_dev_process_down(BFDevEnv* devEnv);
|
||||||
|
static bool bf_dev_process_left(BFDevEnv* devEnv);
|
||||||
|
static bool bf_dev_process_right(BFDevEnv* devEnv);
|
||||||
|
static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event);
|
||||||
|
|
||||||
|
BFApp* appDev;
|
||||||
|
FuriThread* workerThread;
|
||||||
|
|
||||||
|
char bfChars[9] = {'<', '>', '[', ']', '+', '-', '.', ',', 0x00};
|
||||||
|
|
||||||
|
int selectedButton = 0;
|
||||||
|
int saveNotifyCountdown = 0;
|
||||||
|
int execCountdown = 0;
|
||||||
|
|
||||||
|
char dspLine0[25] = {};
|
||||||
|
char dspLine1[25] = {};
|
||||||
|
char dspLine2[25] = {};
|
||||||
|
|
||||||
|
static bMapping buttonMappings[12] = {
|
||||||
|
{8, 8, 7, 1}, //0
|
||||||
|
{8, 8, 0, 2}, //1
|
||||||
|
{9, 9, 1, 3}, //2
|
||||||
|
{9, 9, 2, 4}, //3
|
||||||
|
{10, 10, 3, 5}, //4
|
||||||
|
{10, 10, 4, 6}, //5
|
||||||
|
{11, 11, 5, 7}, //6
|
||||||
|
{11, 11, 6, 0}, //7
|
||||||
|
|
||||||
|
{0, 0, 11, 9}, //8
|
||||||
|
{3, 3, 8, 10}, //9
|
||||||
|
{5, 5, 9, 11}, //10
|
||||||
|
{6, 6, 10, 8} //11
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BT_X 14
|
||||||
|
#define BT_Y 14
|
||||||
|
static void bf_dev_draw_button(Canvas* canvas, int x, int y, bool selected, const char* lbl) {
|
||||||
|
UNUSED(lbl);
|
||||||
|
|
||||||
|
if(selected) {
|
||||||
|
canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3);
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
canvas_set_font(canvas, FontBatteryPercent);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl);
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
} else {
|
||||||
|
canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3);
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
canvas_draw_rbox(canvas, x + 2, y - 1, BT_X - 2, BT_Y - 1, 3);
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
canvas_draw_rframe(canvas, x, y, BT_X, BT_Y, 3);
|
||||||
|
canvas_set_font(canvas, FontBatteryPercent);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_save_changes() {
|
||||||
|
//remove old file
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
storage_simply_remove(storage, furi_string_get_cstr(appDev->BF_file_path));
|
||||||
|
|
||||||
|
//save new file
|
||||||
|
Stream* stream = buffered_file_stream_alloc(storage);
|
||||||
|
buffered_file_stream_open(
|
||||||
|
stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS);
|
||||||
|
stream_write(stream, (const uint8_t*)appDev->dataBuffer, appDev->dataSize);
|
||||||
|
buffered_file_stream_close(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bf_dev_draw_callback(Canvas* canvas, void* _model) {
|
||||||
|
UNUSED(_model);
|
||||||
|
|
||||||
|
if(saveNotifyCountdown > 0) {
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "SAVED");
|
||||||
|
saveNotifyCountdown--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bf_dev_draw_button(canvas, 1, 36, (selectedButton == 0), "+"); //T 0
|
||||||
|
bf_dev_draw_button(canvas, 17, 36, (selectedButton == 1), "-"); //T 1
|
||||||
|
bf_dev_draw_button(canvas, 33, 36, (selectedButton == 2), "<"); //T 2
|
||||||
|
bf_dev_draw_button(canvas, 49, 36, (selectedButton == 3), ">"); //T 3
|
||||||
|
bf_dev_draw_button(canvas, 65, 36, (selectedButton == 4), "["); //B 0
|
||||||
|
bf_dev_draw_button(canvas, 81, 36, (selectedButton == 5), "]"); //B 1
|
||||||
|
bf_dev_draw_button(canvas, 97, 36, (selectedButton == 6), "."); //B 2
|
||||||
|
bf_dev_draw_button(canvas, 113, 36, (selectedButton == 7), ","); //B 3
|
||||||
|
|
||||||
|
//backspace, input, run, save
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas,
|
||||||
|
1,
|
||||||
|
52,
|
||||||
|
(selectedButton == 8) ? &I_KeyBackspaceSelected_24x11 : &I_KeyBackspace_24x11);
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas, 45, 52, (selectedButton == 9) ? &I_KeyInputSelected_30x11 : &I_KeyInput_30x11);
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas, 77, 52, (selectedButton == 10) ? &I_KeyRunSelected_24x11 : &I_KeyRun_24x11);
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas, 103, 52, (selectedButton == 11) ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11);
|
||||||
|
|
||||||
|
if(saveNotifyCountdown > 0) {
|
||||||
|
canvas_draw_icon(canvas, 98, 54, &I_ButtonRightSmall_3x5);
|
||||||
|
saveNotifyCountdown--;
|
||||||
|
}
|
||||||
|
|
||||||
|
//textbox
|
||||||
|
//grossly overcomplicated. not fixing it.
|
||||||
|
canvas_draw_rframe(canvas, 1, 1, 126, 33, 2);
|
||||||
|
canvas_set_font(canvas, FontBatteryPercent);
|
||||||
|
|
||||||
|
int dbOffset = 0;
|
||||||
|
if(appDev->dataSize > 72) {
|
||||||
|
dbOffset = (appDev->dataSize - 72);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(dspLine0, 0x00, 25);
|
||||||
|
memset(dspLine1, 0x00, 25);
|
||||||
|
memset(dspLine2, 0x00, 25);
|
||||||
|
|
||||||
|
int tpM = 0;
|
||||||
|
int tp0 = 0;
|
||||||
|
int tp1 = 0;
|
||||||
|
int tp2 = 0;
|
||||||
|
|
||||||
|
for(int p = dbOffset; p < appDev->dataSize; p++) {
|
||||||
|
if(tpM < 24 * 1) {
|
||||||
|
dspLine0[tp0] = appDev->dataBuffer[p];
|
||||||
|
tp0++;
|
||||||
|
} else if(tpM < 24 * 2) {
|
||||||
|
dspLine1[tp1] = appDev->dataBuffer[p];
|
||||||
|
tp1++;
|
||||||
|
} else if(tpM < 24 * 3) {
|
||||||
|
dspLine2[tp2] = appDev->dataBuffer[p];
|
||||||
|
tp2++;
|
||||||
|
}
|
||||||
|
tpM++;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_draw_str_aligned(canvas, 3, 8, AlignLeft, AlignCenter, dspLine0);
|
||||||
|
canvas_draw_str_aligned(canvas, 3, 17, AlignLeft, AlignCenter, dspLine1);
|
||||||
|
canvas_draw_str_aligned(canvas, 3, 26, AlignLeft, AlignCenter, dspLine2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bf_dev_input_callback(InputEvent* event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
BFDevEnv* devEnv = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event->type == InputTypeShort) {
|
||||||
|
if(event->key == InputKeyRight) {
|
||||||
|
consumed = bf_dev_process_right(devEnv);
|
||||||
|
} else if(event->key == InputKeyLeft) {
|
||||||
|
consumed = bf_dev_process_left(devEnv);
|
||||||
|
} else if(event->key == InputKeyUp) {
|
||||||
|
consumed = bf_dev_process_up(devEnv);
|
||||||
|
} else if(event->key == InputKeyDown) {
|
||||||
|
consumed = bf_dev_process_down(devEnv);
|
||||||
|
}
|
||||||
|
} else if(event->key == InputKeyOk) {
|
||||||
|
consumed = bf_dev_process_ok(devEnv, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bf_dev_process_up(BFDevEnv* devEnv) {
|
||||||
|
UNUSED(devEnv);
|
||||||
|
selectedButton = buttonMappings[selectedButton].up;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bf_dev_process_down(BFDevEnv* devEnv) {
|
||||||
|
UNUSED(devEnv);
|
||||||
|
selectedButton = buttonMappings[selectedButton].down;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bf_dev_process_left(BFDevEnv* devEnv) {
|
||||||
|
UNUSED(devEnv);
|
||||||
|
selectedButton = buttonMappings[selectedButton].left;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bf_dev_process_right(BFDevEnv* devEnv) {
|
||||||
|
UNUSED(devEnv);
|
||||||
|
selectedButton = buttonMappings[selectedButton].right;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event) {
|
||||||
|
UNUSED(devEnv);
|
||||||
|
UNUSED(event);
|
||||||
|
|
||||||
|
if(event->type != InputTypePress) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(selectedButton) {
|
||||||
|
case 0: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = '+';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = '-';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = '<';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = '>';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 4: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = '[';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 5: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = ']';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 6: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = '.';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 7: {
|
||||||
|
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = ',';
|
||||||
|
appDev->dataSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 8: {
|
||||||
|
if(appDev->dataSize > 0) {
|
||||||
|
appDev->dataSize--;
|
||||||
|
appDev->dataBuffer[appDev->dataSize] = (uint32_t)0x00;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 9: {
|
||||||
|
scene_manager_next_scene(appDev->scene_manager, brainfuckSceneSetInput);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 10: {
|
||||||
|
if(getStatus() != 0) {
|
||||||
|
killThread();
|
||||||
|
furi_thread_join(workerThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
bf_save_changes();
|
||||||
|
|
||||||
|
initWorker(appDev);
|
||||||
|
text_box_set_focus(appDev->text_box, TextBoxFocusEnd);
|
||||||
|
text_box_set_text(appDev->text_box, workerGetOutput());
|
||||||
|
|
||||||
|
workerThread = furi_thread_alloc_ex("Worker", 2048, (void*)beginWorker, NULL);
|
||||||
|
furi_thread_start(workerThread);
|
||||||
|
|
||||||
|
scene_manager_next_scene(appDev->scene_manager, brainfuckSceneExecEnv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 11: {
|
||||||
|
bf_save_changes();
|
||||||
|
saveNotifyCountdown = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bf_dev_enter_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
BFDevEnv* devEnv = context;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
devEnv->view,
|
||||||
|
BFDevEnvModel * model,
|
||||||
|
{
|
||||||
|
model->col = 0;
|
||||||
|
model->row = 0;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
appDev = devEnv->appDev;
|
||||||
|
selectedButton = 0;
|
||||||
|
|
||||||
|
//exit the running thread if required
|
||||||
|
if(getStatus() != 0) {
|
||||||
|
killThread();
|
||||||
|
furi_thread_join(workerThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear the bf instruction buffer
|
||||||
|
memset(appDev->dataBuffer, 0x00, BF_INST_BUFFER_SIZE * sizeof(char));
|
||||||
|
|
||||||
|
//open the file
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
Stream* stream = buffered_file_stream_alloc(storage);
|
||||||
|
buffered_file_stream_open(
|
||||||
|
stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_READ, FSOM_OPEN_EXISTING);
|
||||||
|
|
||||||
|
//read into the buffer
|
||||||
|
appDev->dataSize = stream_size(stream);
|
||||||
|
stream_read(stream, (uint8_t*)appDev->dataBuffer, appDev->dataSize);
|
||||||
|
buffered_file_stream_close(stream);
|
||||||
|
|
||||||
|
//replaces any invalid characters with an underscore. strips out newlines, comments, etc
|
||||||
|
for(int i = 0; i < appDev->dataSize; i++) {
|
||||||
|
if(!strchr(bfChars, appDev->dataBuffer[i])) {
|
||||||
|
appDev->dataBuffer[i] = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//find the end of the file to begin editing
|
||||||
|
int tptr = 0;
|
||||||
|
while(appDev->dataBuffer[tptr] != 0x00) {
|
||||||
|
tptr++;
|
||||||
|
}
|
||||||
|
appDev->dataSize = tptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
BFDevEnv* bf_dev_env_alloc(BFApp* appDev) {
|
||||||
|
BFDevEnv* devEnv = malloc(sizeof(BFDevEnv));
|
||||||
|
|
||||||
|
devEnv->view = view_alloc();
|
||||||
|
devEnv->appDev = appDev;
|
||||||
|
view_allocate_model(devEnv->view, ViewModelTypeLocking, sizeof(BFDevEnvModel));
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
devEnv->view,
|
||||||
|
BFDevEnvModel * model,
|
||||||
|
{
|
||||||
|
model->col = 0;
|
||||||
|
model->row = 0;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
view_set_context(devEnv->view, devEnv);
|
||||||
|
view_set_draw_callback(devEnv->view, bf_dev_draw_callback);
|
||||||
|
view_set_input_callback(devEnv->view, bf_dev_input_callback);
|
||||||
|
view_set_enter_callback(devEnv->view, bf_dev_enter_callback);
|
||||||
|
return devEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_dev_env_free(BFDevEnv* devEnv) {
|
||||||
|
if(getStatus() != 0) {
|
||||||
|
killThread();
|
||||||
|
furi_thread_join(workerThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_assert(devEnv);
|
||||||
|
view_free(devEnv->view);
|
||||||
|
free(devEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
View* bf_dev_env_get_view(BFDevEnv* devEnv) {
|
||||||
|
furi_assert(devEnv);
|
||||||
|
return devEnv->view;
|
||||||
|
}
|
||||||
15
applications/plugins/brainfuck/views/bf_dev_env.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../brainfuck_i.h"
|
||||||
|
#include <gui/view.h>
|
||||||
|
|
||||||
|
typedef void (*DevEnvOkCallback)(InputType type, void* context);
|
||||||
|
|
||||||
|
BFDevEnv* bf_dev_env_alloc(BFApp* application);
|
||||||
|
|
||||||
|
void bf_dev_set_file_path(FuriString* path);
|
||||||
|
|
||||||
|
void bf_dev_env_free(BFDevEnv* devEnv);
|
||||||
|
|
||||||
|
View* bf_dev_env_get_view(BFDevEnv* devEnv);
|
||||||
|
|
||||||
|
void bf_dev_env_set_ok(BFDevEnv* devEnv, DevEnvOkCallback callback, void* context);
|
||||||
276
applications/plugins/brainfuck/worker.c
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
#include "worker.h"
|
||||||
|
|
||||||
|
bool killswitch = false;
|
||||||
|
|
||||||
|
int status = 0; //0: idle, 1: running, 2: failure
|
||||||
|
|
||||||
|
char* inst = 0;
|
||||||
|
int instCount = 0;
|
||||||
|
int instPtr = 0;
|
||||||
|
int runOpCount = 0;
|
||||||
|
|
||||||
|
char* wOutput = 0;
|
||||||
|
int wOutputPtr = 0;
|
||||||
|
|
||||||
|
char* wInput = 0;
|
||||||
|
int wInputPtr = 0;
|
||||||
|
|
||||||
|
uint8_t* bfStack = 0;
|
||||||
|
int stackPtr = 0;
|
||||||
|
int stackSize = BF_STACK_INITIAL_SIZE;
|
||||||
|
int stackSizeReal = 0;
|
||||||
|
|
||||||
|
BFApp* wrkrApp = 0;
|
||||||
|
|
||||||
|
void killThread() {
|
||||||
|
killswitch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validateInstPtr() {
|
||||||
|
if(instPtr > instCount || instPtr < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validateStackPtr() {
|
||||||
|
if(stackPtr > stackSize || stackPtr < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* workerGetOutput() {
|
||||||
|
return wOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getStackSize() {
|
||||||
|
return stackSizeReal;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getOpCount() {
|
||||||
|
return runOpCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initWorker(BFApp* app) {
|
||||||
|
wrkrApp = app;
|
||||||
|
|
||||||
|
//rebuild output
|
||||||
|
if(wOutput) {
|
||||||
|
free(wOutput);
|
||||||
|
}
|
||||||
|
wOutput = (char*)malloc(BF_OUTPUT_SIZE);
|
||||||
|
wOutputPtr = 0;
|
||||||
|
|
||||||
|
//rebuild stack
|
||||||
|
if(bfStack) {
|
||||||
|
free(bfStack);
|
||||||
|
}
|
||||||
|
bfStack = (uint8_t*)malloc(BF_STACK_INITIAL_SIZE);
|
||||||
|
memset(bfStack, 0x00, BF_STACK_INITIAL_SIZE);
|
||||||
|
stackSize = BF_STACK_INITIAL_SIZE;
|
||||||
|
stackSizeReal = 0;
|
||||||
|
stackPtr = 0;
|
||||||
|
|
||||||
|
//set instructions
|
||||||
|
inst = wrkrApp->dataBuffer;
|
||||||
|
instCount = wrkrApp->dataSize;
|
||||||
|
instPtr = 0;
|
||||||
|
runOpCount = 0;
|
||||||
|
|
||||||
|
//set input
|
||||||
|
wInput = wrkrApp->inputBuffer;
|
||||||
|
wInputPtr = 0;
|
||||||
|
|
||||||
|
//set status
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rShift() {
|
||||||
|
runOpCount++;
|
||||||
|
stackPtr++;
|
||||||
|
if(!validateStackPtr()) {
|
||||||
|
status = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(stackPtr > stackSize) {
|
||||||
|
stackSize += BF_STACK_STEP_SIZE;
|
||||||
|
void* tmp = realloc(bfStack, stackSize);
|
||||||
|
|
||||||
|
if(!tmp) {
|
||||||
|
status = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((tmp + stackSize) - BF_STACK_STEP_SIZE, 0x00, BF_STACK_STEP_SIZE);
|
||||||
|
bfStack = (uint8_t*)tmp;
|
||||||
|
};
|
||||||
|
if(stackPtr > stackSizeReal) {
|
||||||
|
stackSizeReal = stackPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lShift() {
|
||||||
|
runOpCount++;
|
||||||
|
stackPtr--;
|
||||||
|
if(!validateStackPtr()) {
|
||||||
|
status = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void inc() {
|
||||||
|
runOpCount++;
|
||||||
|
if(!validateStackPtr()) {
|
||||||
|
status = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bfStack[stackPtr]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dec() {
|
||||||
|
runOpCount++;
|
||||||
|
if(!validateStackPtr()) {
|
||||||
|
status = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bfStack[stackPtr]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
runOpCount++;
|
||||||
|
wOutput[wOutputPtr] = bfStack[stackPtr];
|
||||||
|
wOutputPtr++;
|
||||||
|
if(wOutputPtr > (BF_OUTPUT_SIZE - 1)) {
|
||||||
|
wOutputPtr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void input() {
|
||||||
|
runOpCount++;
|
||||||
|
|
||||||
|
bfStack[stackPtr] = (uint8_t)wInput[wInputPtr];
|
||||||
|
if(wInput[wInputPtr] == 0x00 || wInputPtr >= 64) {
|
||||||
|
wInputPtr = 0;
|
||||||
|
} else {
|
||||||
|
wInputPtr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
runOpCount++;
|
||||||
|
if(bfStack[stackPtr] == 0) {
|
||||||
|
int loopCount = 1;
|
||||||
|
while(loopCount > 0) {
|
||||||
|
instPtr++;
|
||||||
|
if(!validateInstPtr()) {
|
||||||
|
status = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(inst[instPtr] == '[') {
|
||||||
|
loopCount++;
|
||||||
|
} else if(inst[instPtr] == ']') {
|
||||||
|
loopCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void endLoop() {
|
||||||
|
runOpCount++;
|
||||||
|
if(bfStack[stackPtr] != 0) {
|
||||||
|
int loopCount = 1;
|
||||||
|
while(loopCount > 0) {
|
||||||
|
instPtr--;
|
||||||
|
if(!validateInstPtr()) {
|
||||||
|
status = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(inst[instPtr] == ']') {
|
||||||
|
loopCount++;
|
||||||
|
} else if(inst[instPtr] == '[') {
|
||||||
|
loopCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const NotificationSequence led_on = {
|
||||||
|
&message_blue_255,
|
||||||
|
&message_do_not_reset,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NotificationSequence led_off = {
|
||||||
|
&message_green_0,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void beginWorker() {
|
||||||
|
status = 1;
|
||||||
|
while(inst[instPtr] != 0x00) {
|
||||||
|
if(runOpCount % 500 == 0) {
|
||||||
|
text_box_set_text(wrkrApp->text_box, workerGetOutput());
|
||||||
|
notification_message(wrkrApp->notifications, &led_on);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status == 2) {
|
||||||
|
status = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(killswitch) {
|
||||||
|
status = 0;
|
||||||
|
killswitch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch(inst[instPtr]) {
|
||||||
|
case '>':
|
||||||
|
rShift();
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
lShift();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
inc();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
dec();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
print();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ',':
|
||||||
|
input();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
loop();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ']':
|
||||||
|
endLoop();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
instPtr++;
|
||||||
|
if(!validateInstPtr()) {
|
||||||
|
status = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification_message(wrkrApp->notifications, &led_off);
|
||||||
|
text_box_set_text(wrkrApp->text_box, workerGetOutput());
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
9
applications/plugins/brainfuck/worker.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "brainfuck_i.h"
|
||||||
|
|
||||||
|
void initWorker(BFApp* application);
|
||||||
|
char* workerGetOutput();
|
||||||
|
int getStackSize();
|
||||||
|
int getOpCount();
|
||||||
|
int getStatus();
|
||||||
|
void beginWorker();
|
||||||
|
void killThread();
|
||||||
13
applications/plugins/geigercounter/application.fam
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
App(
|
||||||
|
appid="Geiger_Coutner",
|
||||||
|
name="[GPIO] Geiger Counter",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
entry_point="flipper_geiger_app",
|
||||||
|
cdefines=["APP_GEIGER"],
|
||||||
|
requires=[
|
||||||
|
"gui",
|
||||||
|
],
|
||||||
|
stack_size=1 * 1024,
|
||||||
|
fap_icon="geiger.png",
|
||||||
|
fap_category="GPIO",
|
||||||
|
)
|
||||||
227
applications/plugins/geigercounter/flipper_geiger.c
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
// https://github.com/nmrr
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
#include <furi_hal_random.h>
|
||||||
|
#include <furi_hal_pwm.h>
|
||||||
|
#include <furi_hal_power.h>
|
||||||
|
|
||||||
|
#define SCREEN_SIZE_X 128
|
||||||
|
#define SCREEN_SIZE_Y 64
|
||||||
|
|
||||||
|
// FOR J305 GEIGER TUBE
|
||||||
|
#define CONVERSION_FACTOR 0.0081
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EventTypeInput,
|
||||||
|
ClockEventTypeTick,
|
||||||
|
EventGPIO,
|
||||||
|
} EventType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EventType type;
|
||||||
|
InputEvent input;
|
||||||
|
} EventApp;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t cps, cpm;
|
||||||
|
uint32_t line[SCREEN_SIZE_X / 2];
|
||||||
|
float coef;
|
||||||
|
uint8_t data;
|
||||||
|
} mutexStruct;
|
||||||
|
|
||||||
|
static void draw_callback(Canvas* canvas, void* ctx) {
|
||||||
|
UNUSED(ctx);
|
||||||
|
|
||||||
|
mutexStruct displayStruct;
|
||||||
|
mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block((ValueMutex*)ctx);
|
||||||
|
memcpy(&displayStruct, geigerMutex, sizeof(mutexStruct));
|
||||||
|
release_mutex((ValueMutex*)ctx, geigerMutex);
|
||||||
|
|
||||||
|
char buffer[32];
|
||||||
|
if(displayStruct.data == 0)
|
||||||
|
snprintf(
|
||||||
|
buffer, sizeof(buffer), "%ld cps - %ld cpm", displayStruct.cps, displayStruct.cpm);
|
||||||
|
else if(displayStruct.data == 1)
|
||||||
|
snprintf(
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"%ld cps - %.2f uSv/h",
|
||||||
|
displayStruct.cps,
|
||||||
|
((double)displayStruct.cpm * (double)CONVERSION_FACTOR));
|
||||||
|
else
|
||||||
|
snprintf(
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"%ld cps - %.2f mSv/y",
|
||||||
|
displayStruct.cps,
|
||||||
|
(((double)displayStruct.cpm * (double)CONVERSION_FACTOR)) * (double)8.76);
|
||||||
|
|
||||||
|
for(int i = 0; i < SCREEN_SIZE_X; i += 2) {
|
||||||
|
float Y = SCREEN_SIZE_Y - (displayStruct.line[i / 2] * displayStruct.coef);
|
||||||
|
|
||||||
|
canvas_draw_line(canvas, i, Y, i, SCREEN_SIZE_Y);
|
||||||
|
canvas_draw_line(canvas, i + 1, Y, i + 1, SCREEN_SIZE_Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignBottom, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
FuriMessageQueue* event_queue = ctx;
|
||||||
|
EventApp event = {.type = EventTypeInput, .input = *input_event};
|
||||||
|
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clock_tick(void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
|
||||||
|
uint32_t randomNumber = furi_hal_random_get();
|
||||||
|
randomNumber &= 0xFFF;
|
||||||
|
if(randomNumber == 0) randomNumber = 1;
|
||||||
|
|
||||||
|
furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, randomNumber, 50);
|
||||||
|
|
||||||
|
FuriMessageQueue* queue = ctx;
|
||||||
|
EventApp event = {.type = ClockEventTypeTick};
|
||||||
|
furi_message_queue_put(queue, &event, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gpiocallback(void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
FuriMessageQueue* queue = ctx;
|
||||||
|
EventApp event = {.type = EventGPIO};
|
||||||
|
furi_message_queue_put(queue, &event, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t flipper_geiger_app() {
|
||||||
|
EventApp event;
|
||||||
|
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp));
|
||||||
|
|
||||||
|
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInterruptFall, GpioPullUp, GpioSpeedVeryHigh);
|
||||||
|
furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 5, 50);
|
||||||
|
|
||||||
|
mutexStruct mutexVal;
|
||||||
|
mutexVal.cps = 0;
|
||||||
|
mutexVal.cpm = 0;
|
||||||
|
for(int i = 0; i < SCREEN_SIZE_X / 2; i++) mutexVal.line[i] = 0;
|
||||||
|
mutexVal.coef = 1;
|
||||||
|
mutexVal.data = 0;
|
||||||
|
|
||||||
|
uint32_t counter = 0;
|
||||||
|
|
||||||
|
ValueMutex state_mutex;
|
||||||
|
init_mutex(&state_mutex, &mutexVal, sizeof(mutexVal));
|
||||||
|
|
||||||
|
ViewPort* view_port = view_port_alloc();
|
||||||
|
view_port_draw_callback_set(view_port, draw_callback, &state_mutex);
|
||||||
|
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||||
|
|
||||||
|
furi_hal_gpio_add_int_callback(&gpio_ext_pa7, gpiocallback, event_queue);
|
||||||
|
|
||||||
|
Gui* gui = furi_record_open(RECORD_GUI);
|
||||||
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
|
FuriTimer* timer = furi_timer_alloc(clock_tick, FuriTimerTypePeriodic, event_queue);
|
||||||
|
furi_timer_start(timer, 1000);
|
||||||
|
|
||||||
|
// ENABLE 5V pin
|
||||||
|
furi_hal_power_enable_otg();
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever);
|
||||||
|
|
||||||
|
uint8_t screenRefresh = 0;
|
||||||
|
|
||||||
|
if(event_status == FuriStatusOk) {
|
||||||
|
if(event.type == EventTypeInput) {
|
||||||
|
if(event.input.key == InputKeyBack) {
|
||||||
|
break;
|
||||||
|
} else if(event.input.key == InputKeyOk && event.input.type == InputTypeShort) {
|
||||||
|
counter = 0;
|
||||||
|
mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex);
|
||||||
|
|
||||||
|
geigerMutex->cps = 0;
|
||||||
|
geigerMutex->cpm = 0;
|
||||||
|
for(int i = 0; i < SCREEN_SIZE_X / 2; i++) geigerMutex->line[i] = 0;
|
||||||
|
|
||||||
|
screenRefresh = 1;
|
||||||
|
release_mutex(&state_mutex, geigerMutex);
|
||||||
|
} else if((event.input.key == InputKeyLeft &&
|
||||||
|
event.input.type == InputTypeShort)) {
|
||||||
|
mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex);
|
||||||
|
|
||||||
|
if(geigerMutex->data != 0)
|
||||||
|
geigerMutex->data--;
|
||||||
|
else
|
||||||
|
geigerMutex->data = 2;
|
||||||
|
|
||||||
|
screenRefresh = 1;
|
||||||
|
release_mutex(&state_mutex, geigerMutex);
|
||||||
|
} else if((event.input.key == InputKeyRight &&
|
||||||
|
event.input.type == InputTypeShort)) {
|
||||||
|
mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex);
|
||||||
|
|
||||||
|
if(geigerMutex->data != 2)
|
||||||
|
geigerMutex->data++;
|
||||||
|
else
|
||||||
|
geigerMutex->data = 0;
|
||||||
|
|
||||||
|
screenRefresh = 1;
|
||||||
|
release_mutex(&state_mutex, geigerMutex);
|
||||||
|
}
|
||||||
|
} else if(event.type == ClockEventTypeTick) {
|
||||||
|
mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex);
|
||||||
|
|
||||||
|
for(int i = 0; i < SCREEN_SIZE_X / 2 - 1; i++)
|
||||||
|
geigerMutex->line[SCREEN_SIZE_X / 2 - 1 - i] =
|
||||||
|
geigerMutex->line[SCREEN_SIZE_X / 2 - 2 - i];
|
||||||
|
|
||||||
|
geigerMutex->line[0] = counter;
|
||||||
|
geigerMutex->cps = counter;
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
|
geigerMutex->cpm = geigerMutex->line[0];
|
||||||
|
uint32_t max = geigerMutex->line[0];
|
||||||
|
for(int i = 1; i < SCREEN_SIZE_X / 2; i++) {
|
||||||
|
if(i < 60) geigerMutex->cpm += geigerMutex->line[i];
|
||||||
|
if(geigerMutex->line[i] > max) max = geigerMutex->line[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(max > 0)
|
||||||
|
geigerMutex->coef = ((float)(SCREEN_SIZE_Y - 15)) / ((float)max);
|
||||||
|
else
|
||||||
|
geigerMutex->coef = 1;
|
||||||
|
|
||||||
|
screenRefresh = 1;
|
||||||
|
release_mutex(&state_mutex, geigerMutex);
|
||||||
|
} else if(event.type == EventGPIO) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(screenRefresh == 1) view_port_update(view_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_power_disable_otg();
|
||||||
|
|
||||||
|
furi_hal_gpio_disable_int_callback(&gpio_ext_pa7);
|
||||||
|
furi_hal_gpio_remove_int_callback(&gpio_ext_pa7);
|
||||||
|
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
|
||||||
|
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
delete_mutex(&state_mutex);
|
||||||
|
gui_remove_view_port(gui, view_port);
|
||||||
|
view_port_free(view_port);
|
||||||
|
furi_timer_free(timer);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
applications/plugins/geigercounter/geiger.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
applications/plugins/hid_app/assets/ButtonF10_5x8.png
Normal file
|
After Width: | Height: | Size: 172 B |
BIN
applications/plugins/hid_app/assets/ButtonF11_5x8.png
Normal file
|
After Width: | Height: | Size: 173 B |
BIN
applications/plugins/hid_app/assets/ButtonF12_5x8.png
Normal file
|
After Width: | Height: | Size: 180 B |
BIN
applications/plugins/hid_app/assets/ButtonF1_5x8.png
Normal file
|
After Width: | Height: | Size: 177 B |
BIN
applications/plugins/hid_app/assets/ButtonF2_5x8.png
Normal file
|
After Width: | Height: | Size: 179 B |
BIN
applications/plugins/hid_app/assets/ButtonF3_5x8.png
Normal file
|
After Width: | Height: | Size: 178 B |
BIN
applications/plugins/hid_app/assets/ButtonF4_5x8.png
Normal file
|
After Width: | Height: | Size: 177 B |
BIN
applications/plugins/hid_app/assets/ButtonF5_5x8.png
Normal file
|
After Width: | Height: | Size: 178 B |
BIN
applications/plugins/hid_app/assets/ButtonF6_5x8.png
Normal file
|
After Width: | Height: | Size: 177 B |
BIN
applications/plugins/hid_app/assets/ButtonF7_5x8.png
Normal file
|
After Width: | Height: | Size: 176 B |
BIN
applications/plugins/hid_app/assets/ButtonF8_5x8.png
Normal file
|
After Width: | Height: | Size: 176 B |
BIN
applications/plugins/hid_app/assets/ButtonF9_5x8.png
Normal file
|
After Width: | Height: | Size: 179 B |
@@ -46,11 +46,25 @@ typedef struct {
|
|||||||
#define KEY_WIDTH 9
|
#define KEY_WIDTH 9
|
||||||
#define KEY_HEIGHT 12
|
#define KEY_HEIGHT 12
|
||||||
#define KEY_PADDING 1
|
#define KEY_PADDING 1
|
||||||
#define ROW_COUNT 6
|
#define ROW_COUNT 7
|
||||||
#define COLUMN_COUNT 12
|
#define COLUMN_COUNT 12
|
||||||
|
|
||||||
// 0 width items are not drawn, but there value is used
|
// 0 width items are not drawn, but there value is used
|
||||||
const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = {
|
const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = {
|
||||||
|
{
|
||||||
|
{.width = 1, .icon = &I_ButtonF1_5x8, .value = HID_KEYBOARD_F1},
|
||||||
|
{.width = 1, .icon = &I_ButtonF2_5x8, .value = HID_KEYBOARD_F2},
|
||||||
|
{.width = 1, .icon = &I_ButtonF3_5x8, .value = HID_KEYBOARD_F3},
|
||||||
|
{.width = 1, .icon = &I_ButtonF4_5x8, .value = HID_KEYBOARD_F4},
|
||||||
|
{.width = 1, .icon = &I_ButtonF5_5x8, .value = HID_KEYBOARD_F5},
|
||||||
|
{.width = 1, .icon = &I_ButtonF6_5x8, .value = HID_KEYBOARD_F6},
|
||||||
|
{.width = 1, .icon = &I_ButtonF7_5x8, .value = HID_KEYBOARD_F7},
|
||||||
|
{.width = 1, .icon = &I_ButtonF8_5x8, .value = HID_KEYBOARD_F8},
|
||||||
|
{.width = 1, .icon = &I_ButtonF9_5x8, .value = HID_KEYBOARD_F9},
|
||||||
|
{.width = 1, .icon = &I_ButtonF10_5x8, .value = HID_KEYBOARD_F10},
|
||||||
|
{.width = 1, .icon = &I_ButtonF11_5x8, .value = HID_KEYBOARD_F11},
|
||||||
|
{.width = 1, .icon = &I_ButtonF12_5x8, .value = HID_KEYBOARD_F12},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
{.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1},
|
{.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1},
|
||||||
{.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2},
|
{.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2},
|
||||||
@@ -224,7 +238,12 @@ static void hid_keyboard_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
canvas_set_font(canvas, FontKeyboard);
|
canvas_set_font(canvas, FontKeyboard);
|
||||||
// Start shifting the all keys up if on the next row (Scrolling)
|
// Start shifting the all keys up if on the next row (Scrolling)
|
||||||
uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0;
|
uint8_t initY = model->y == 0 ? 0 : 1;
|
||||||
|
|
||||||
|
if(model->y > 5) {
|
||||||
|
initY = model->y - 4;
|
||||||
|
}
|
||||||
|
|
||||||
for(uint8_t y = initY; y < ROW_COUNT; y++) {
|
for(uint8_t y = initY; y < ROW_COUNT; y++) {
|
||||||
const HidKeyboardKey* keyboardKeyRow = hid_keyboard_keyset[y];
|
const HidKeyboardKey* keyboardKeyRow = hid_keyboard_keyset[y];
|
||||||
uint8_t x = 0;
|
uint8_t x = 0;
|
||||||
@@ -365,7 +384,10 @@ HidKeyboard* hid_keyboard_alloc(Hid* bt_hid) {
|
|||||||
with_view_model(
|
with_view_model(
|
||||||
hid_keyboard->view,
|
hid_keyboard->view,
|
||||||
HidKeyboardModel * model,
|
HidKeyboardModel * model,
|
||||||
{ model->transport = bt_hid->transport; },
|
{
|
||||||
|
model->transport = bt_hid->transport;
|
||||||
|
model->y = 1;
|
||||||
|
},
|
||||||
true);
|
true);
|
||||||
|
|
||||||
return hid_keyboard;
|
return hid_keyboard;
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ static bool mj_process_ducky_line(
|
|||||||
strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) {
|
strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) {
|
||||||
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4 | 2, dk.hid, plugin_state);
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1 | 2, dk.hid, plugin_state);
|
||||||
return true;
|
return true;
|
||||||
} else if(
|
} else if(
|
||||||
strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 ||
|
strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 ||
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <lib/flipper_format/flipper_format.h>
|
#include <lib/flipper_format/flipper_format.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <m-array.h>
|
#include <m-array.h>
|
||||||
|
|
||||||
#define TAG "MusicPlayerWorker"
|
#define TAG "MusicPlayerWorker"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ App(
|
|||||||
appid="NFC_Magic",
|
appid="NFC_Magic",
|
||||||
name="NFC Magic",
|
name="NFC Magic",
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
targets=["f7"],
|
||||||
entry_point="nfc_magic_app",
|
entry_point="nfc_magic_app",
|
||||||
requires=[
|
requires=[
|
||||||
"storage",
|
"storage",
|
||||||
|
|||||||