This commit is contained in:
yocvito
2023-02-10 20:05:47 +01:00
2702 changed files with 20993 additions and 1695 deletions

View File

@@ -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
View 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
View File

@@ -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/

View File

@@ -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"
]
}

View File

@@ -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"],

View File

@@ -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;

View File

@@ -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;

View 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",
)

View 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;
}

View File

@@ -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);

View File

@@ -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",

View 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.

View 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",
)

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -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;

View File

@@ -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,
}; };

View File

@@ -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() \

View File

@@ -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",
}; };

View File

@@ -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;

View File

@@ -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(

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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");

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);

View 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;
}
}

View 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

View File

@@ -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,

View File

@@ -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);
} }

View File

@@ -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,

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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=[

View File

@@ -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",

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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=[

View File

@@ -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=[

View File

@@ -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) {

View File

@@ -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=[

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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(

View File

@@ -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();

View 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",
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View 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;
}

View File

@@ -0,0 +1,3 @@
#pragma once
typedef struct BFApp BFApp;

View 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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View 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,
};

View 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

View File

@@ -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)

View 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);
}

View 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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View 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;
}

View 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);

View 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;
}

View 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();

View 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",
)

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

View File

@@ -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;

View File

@@ -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 ||

View File

@@ -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"

View File

@@ -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",

Some files were not shown because too many files have changed in this diff Show More