mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-17 20:19:43 -07:00
Merge branch 'dev' into badusb-ble
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
name: 'Build'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- "release*"
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
TARGETS: f7
|
||||
DEFAULT_TARGET: f7
|
||||
FBT_TOOLCHAIN_PATH: /home/runner/work
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
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"
|
||||
echo random_hash=$(openssl rand -base64 40 | shasum -a 256 | awk '{print $1}') >> $GITHUB_OUTPUT
|
||||
echo "event_type=$TYPE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: 'Make artifacts directory'
|
||||
run: |
|
||||
rm -rf artifacts
|
||||
mkdir artifacts
|
||||
|
||||
- name: 'Bundle scripts'
|
||||
run: |
|
||||
tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts debug
|
||||
|
||||
- name: 'Build the firmware'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}; do
|
||||
./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
|
||||
copro_dist updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
||||
done
|
||||
|
||||
- name: 'Move upload files'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}; do
|
||||
mv dist/${TARGET}-*/* artifacts/
|
||||
done
|
||||
|
||||
- name: "Check for uncommitted changes"
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: 'Bundle resources'
|
||||
run: |
|
||||
tar czpf "artifacts/flipper-z-any-resources-${SUFFIX}.tgz" -C assets resources
|
||||
|
||||
- name: 'Bundle core2 firmware'
|
||||
run: |
|
||||
cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz"
|
||||
|
||||
- name: 'Updater artifact'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: updater
|
||||
path: |
|
||||
artifacts/f7-*
|
||||
|
||||
- name: 'Firmware artifact'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware
|
||||
path: |
|
||||
artifacts
|
||||
|
||||
- name: 'Find Previous Comment'
|
||||
if: ${{ github.event.pull_request }}
|
||||
uses: peter-evans/find-comment@v1
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
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'
|
||||
if: ${{ github.event.pull_request}}
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
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:
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags') }}
|
||||
runs-on: ubuntu-latest
|
||||
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
|
||||
submodules: true
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: 'Get commit details'
|
||||
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: 'Build the firmware'
|
||||
run: |
|
||||
set -e
|
||||
for TARGET in ${TARGETS}; do
|
||||
./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
|
||||
updater_package DEBUG=0 COMPACT=1
|
||||
done
|
||||
@@ -0,0 +1,47 @@
|
||||
name: 'Check submodules branch'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- "release*"
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check_protobuf:
|
||||
runs-on: ubuntu-latest
|
||||
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: 'Check protobuf branch'
|
||||
run: |
|
||||
git submodule update --init
|
||||
SUB_PATH="assets/protobuf";
|
||||
SUB_BRANCH="dev";
|
||||
SUB_COMMITS_MIN=40;
|
||||
cd "$SUB_PATH";
|
||||
SUBMODULE_HASH="$(git rev-parse HEAD)";
|
||||
BRANCHES=$(git branch -r --contains "$SUBMODULE_HASH");
|
||||
COMMITS_IN_BRANCH="$(git rev-list --count dev)";
|
||||
if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then
|
||||
echo "name=fails::error" >> $GITHUB_OUTPUT
|
||||
echo "::error::Error: Too low commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)";
|
||||
exit 1;
|
||||
fi
|
||||
if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then
|
||||
echo "name=fails::error" >> $GITHUB_OUTPUT
|
||||
echo "::error::Error: Submodule $SUB_PATH is not on branch $SUB_BRANCH";
|
||||
exit 1;
|
||||
fi
|
||||
@@ -0,0 +1,46 @@
|
||||
name: 'Lint C/C++ with clang-format'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- "release*"
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
TARGETS: f7
|
||||
SET_GH_OUTPUT: 1
|
||||
|
||||
jobs:
|
||||
lint_c_cpp:
|
||||
runs-on: ubuntu-latest
|
||||
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: 'Check code formatting'
|
||||
id: syntax_check
|
||||
run: ./fbt lint
|
||||
|
||||
- name: Report code formatting errors
|
||||
if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
Please fix following code formatting errors:
|
||||
```
|
||||
${{ steps.syntax_check.outputs.errors }}
|
||||
```
|
||||
You might want to run `./fbt format` for an auto-fix.
|
||||
@@ -0,0 +1,32 @@
|
||||
name: 'Python Lint'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- "release*"
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
SET_GH_OUTPUT: 1
|
||||
|
||||
jobs:
|
||||
lint_python:
|
||||
runs-on: ubuntu-latest
|
||||
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: 'Check code formatting'
|
||||
run: ./fbt lint_py
|
||||
@@ -7,7 +7,7 @@
|
||||
[Intro](https://github.com/ClaraCrazy/Flipper-Xtreme#What-makes-it-special) | [Animations](https://github.com/ClaraCrazy/Flipper-Xtreme#Animations--Asset-Packs) | [Docs](https://github.com/ClaraCrazy/Flipper-Xtreme/wiki) | [Changelog](https://github.com/ClaraCrazy/Flipper-Xtreme#list-of-changes) | [Known bugs](https://github.com/ClaraCrazy/Flipper-Xtreme#Known-bugs) | [Install](https://github.com/ClaraCrazy/Flipper-Xtreme#Install) | [Build](https://github.com/ClaraCrazy/Flipper-Xtreme#build-it-yourself) | [Discord](https://discord.gg/flipper-xtreme)
|
||||
-----
|
||||
|
||||
This firmware is a complete overhaul of the [Official Firmware](https://github.com/flipperdevices/flipperzero-firmware), it also features some of the badly implemented ideas from RogueMaster, and lots of awesome code-bits from [Unleashed](https://github.com/DarkFlippers/unleashed-firmware).
|
||||
This firmware is a complete overhaul of the [Official Firmware](https://github.com/flipperdevices/flipperzero-firmware), it also features lots of awesome code-bits from [Unleashed](https://github.com/DarkFlippers/unleashed-firmware).
|
||||
|
||||
-----
|
||||
<br>
|
||||
@@ -19,9 +19,11 @@ The goal of this Firmware is to regularly bring out amazing updates based on wha
|
||||
<br><br>
|
||||
- The focus of this firmware is functionality & stability: If an App doesnt work, its gone
|
||||
|
||||
- Asset Packs: Are you tired of having to remake your custom animations after every update, switching manifests and having a hard time sharing them, especially once you modify scanning assets too? Those times are over. Scroll down to learn more
|
||||
|
||||
- Giving the level system a purpose: Right now, each level unlocks a new wallpaper. More on that below
|
||||
|
||||
- Clean upgraded code: RM wrote some updates to certain files. These are... painful, to say the least. Here its all built with perfection in mind and integrated in a mostly clean way. I invite you all to compare the code with theirs.
|
||||
- Clean upgraded code: Some people wrote updates to certain files. These are... painful, to say the least. Here its all built with perfection in mind and integrated in a mostly clean way. I invite you all to compare the code with theirs.
|
||||
|
||||
- Up2Date: This firmware receives updates from a few repositories, not just from its Upstream. If there are functional, but yet un-merged Pull requests on another flipper firmware that are good, they will be in here!
|
||||
|
||||
@@ -37,12 +39,16 @@ You can easily create your own pack, or find some user made ones in the discord
|
||||
|
||||
<br clear="left"/>
|
||||
|
||||
<br>
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/55334727/214016338-95a619c7-88d2-4db5-bb7a-75282d9082b8.png" align="left" width="200px"/>
|
||||
Once you have some packs, upload them to your Flipper in <code>SD/dolphin_custom</code> (if you did this right you should see <code>SD/dolphin_custom/PackName/Anims</code> and/or <code>SD/dolphin_custom/PackName/Icons</code>).
|
||||
|
||||
|
||||
<br clear="left"/>
|
||||
|
||||
<br>
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/55334727/214013624-25dad48e-72ea-4a90-9060-66e137e0d61a.png" align="left" width="200px"/>
|
||||
After installing the packs to Flipper, hit the <code>Arrow UP</code> button on the main menu and go to <code>Xtreme Settings</code>. Here choose which pack you want and tweak the other settings how you prefer, then press back to reboot and enjoy your new assets & animations!
|
||||
|
||||
@@ -179,4 +185,4 @@ This helps us a lot, thanks for the free license for this project!
|
||||
[PVS-Studio](https://pvs-studio.com/en/pvs-studio/?utm_source=github&utm_medium=organic&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
|
||||
|
||||
----
|
||||
<p align="center"> "What we do for ourselves dies with us. What we do for others and the world remains and is immortal.” ― Albert Pike </p>
|
||||
<p align="center"> "What we do for ourselves dies with us. What we do for others and the world remains and is immortal.” ― Albert Pine </p>
|
||||
|
||||
@@ -11,4 +11,5 @@ App(
|
||||
stack_size=1 * 1024,
|
||||
order=130,
|
||||
fap_category="Debug",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
#include "battery_info.h"
|
||||
#include <furi.h>
|
||||
#include <gui/elements.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#define LOW_CHARGE_THRESHOLD 10
|
||||
#define HIGH_DRAIN_CURRENT_THRESHOLD 100
|
||||
|
||||
struct BatteryInfo {
|
||||
View* view;
|
||||
};
|
||||
|
||||
static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) {
|
||||
canvas_draw_frame(canvas, x - 7, y + 7, 30, 13);
|
||||
canvas_draw_icon(canvas, x, y, icon);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, x - 4, y + 16, 24, 6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val);
|
||||
};
|
||||
|
||||
static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
||||
char emote[20] = {};
|
||||
char header[20] = {};
|
||||
char value[20] = {};
|
||||
|
||||
int32_t drain_current = data->gauge_current * (-1000);
|
||||
uint32_t charge_current = data->gauge_current * 1000;
|
||||
|
||||
// Draw battery
|
||||
canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28);
|
||||
if(charge_current > 0) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14);
|
||||
} else if(drain_current > HIGH_DRAIN_CURRENT_THRESHOLD) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14);
|
||||
} else if(data->charge < LOW_CHARGE_THRESHOLD) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNormal_29x14);
|
||||
}
|
||||
|
||||
// Draw bubble
|
||||
elements_bubble(canvas, 53, 0, 71, 39);
|
||||
|
||||
// Set text
|
||||
if(charge_current > 0) {
|
||||
snprintf(emote, sizeof(emote), "%s", "Yummy!");
|
||||
snprintf(header, sizeof(header), "%s", "Charging at");
|
||||
snprintf(
|
||||
value,
|
||||
sizeof(value),
|
||||
"%lu.%luV %lumA",
|
||||
(uint32_t)(data->vbus_voltage),
|
||||
(uint32_t)(data->vbus_voltage * 10) % 10,
|
||||
charge_current);
|
||||
} else if(drain_current > 0) {
|
||||
snprintf(
|
||||
emote,
|
||||
sizeof(emote),
|
||||
"%s",
|
||||
drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!");
|
||||
snprintf(header, sizeof(header), "%s", "Consumption is");
|
||||
snprintf(
|
||||
value,
|
||||
sizeof(value),
|
||||
"%ld %s",
|
||||
drain_current,
|
||||
drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA");
|
||||
} else if(drain_current != 0) {
|
||||
snprintf(header, 20, "...");
|
||||
} else if(data->charging_voltage < 4.2) {
|
||||
// Non-default battery charging limit, mention it
|
||||
snprintf(emote, sizeof(emote), "Charged!");
|
||||
snprintf(header, sizeof(header), "Limited to");
|
||||
snprintf(
|
||||
value,
|
||||
sizeof(value),
|
||||
"%lu.%luV",
|
||||
(uint32_t)(data->charging_voltage),
|
||||
(uint32_t)(data->charging_voltage * 10) % 10);
|
||||
} else {
|
||||
snprintf(header, sizeof(header), "Charged!");
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote);
|
||||
canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header);
|
||||
canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value);
|
||||
};
|
||||
|
||||
static void battery_info_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
BatteryInfoModel* model = context;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
draw_battery(canvas, model, 0, 5);
|
||||
|
||||
char batt_level[10];
|
||||
char temperature[10];
|
||||
char voltage[10];
|
||||
char health[10];
|
||||
|
||||
snprintf(batt_level, sizeof(batt_level), "%lu%%", (uint32_t)model->charge);
|
||||
snprintf(temperature, sizeof(temperature), "%lu C", (uint32_t)model->gauge_temperature);
|
||||
snprintf(
|
||||
voltage,
|
||||
sizeof(voltage),
|
||||
"%lu.%01lu V",
|
||||
(uint32_t)model->gauge_voltage,
|
||||
(uint32_t)(model->gauge_voltage * 10) % 10UL);
|
||||
snprintf(health, sizeof(health), "%d%%", model->health);
|
||||
|
||||
draw_stat(canvas, 8, 42, &I_Battery_16x16, batt_level);
|
||||
draw_stat(canvas, 40, 42, &I_Temperature_16x16, temperature);
|
||||
draw_stat(canvas, 72, 42, &I_Voltage_16x16, voltage);
|
||||
draw_stat(canvas, 104, 42, &I_Health_16x16, health);
|
||||
}
|
||||
|
||||
BatteryInfo* battery_info_alloc() {
|
||||
BatteryInfo* battery_info = malloc(sizeof(BatteryInfo));
|
||||
battery_info->view = view_alloc();
|
||||
view_set_context(battery_info->view, battery_info);
|
||||
view_allocate_model(battery_info->view, ViewModelTypeLocking, sizeof(BatteryInfoModel));
|
||||
view_set_draw_callback(battery_info->view, battery_info_draw_callback);
|
||||
|
||||
return battery_info;
|
||||
}
|
||||
|
||||
void battery_info_free(BatteryInfo* battery_info) {
|
||||
furi_assert(battery_info);
|
||||
view_free(battery_info->view);
|
||||
free(battery_info);
|
||||
}
|
||||
|
||||
View* battery_info_get_view(BatteryInfo* battery_info) {
|
||||
furi_assert(battery_info);
|
||||
return battery_info->view;
|
||||
}
|
||||
|
||||
void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data) {
|
||||
furi_assert(battery_info);
|
||||
furi_assert(data);
|
||||
with_view_model(
|
||||
battery_info->view,
|
||||
BatteryInfoModel * model,
|
||||
{ memcpy(model, data, sizeof(BatteryInfoModel)); },
|
||||
true);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct BatteryInfo BatteryInfo;
|
||||
|
||||
typedef struct {
|
||||
float vbus_voltage;
|
||||
float gauge_voltage;
|
||||
float gauge_current;
|
||||
float gauge_temperature;
|
||||
float charging_voltage;
|
||||
uint8_t charge;
|
||||
uint8_t health;
|
||||
} BatteryInfoModel;
|
||||
|
||||
BatteryInfo* battery_info_alloc();
|
||||
|
||||
void battery_info_free(BatteryInfo* battery_info);
|
||||
|
||||
View* battery_info_get_view(BatteryInfo* battery_info);
|
||||
|
||||
void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data);
|
||||
@@ -31,9 +31,6 @@ uint32_t bt_debug_start_view(void* context) {
|
||||
BtDebugApp* bt_debug_app_alloc() {
|
||||
BtDebugApp* app = malloc(sizeof(BtDebugApp));
|
||||
|
||||
// Load settings
|
||||
bt_settings_load(&app->settings);
|
||||
|
||||
// Gui
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
@@ -105,13 +102,15 @@ int32_t bt_debug_app(void* p) {
|
||||
}
|
||||
|
||||
BtDebugApp* app = bt_debug_app_alloc();
|
||||
// Was bt active?
|
||||
const bool was_active = furi_hal_bt_is_active();
|
||||
// Stop advertising
|
||||
furi_hal_bt_stop_advertising();
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
// Restart advertising
|
||||
if(app->settings.enabled) {
|
||||
if(was_active) {
|
||||
furi_hal_bt_start_advertising();
|
||||
}
|
||||
bt_debug_app_free(app);
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
|
||||
#include <dialogs/dialogs.h>
|
||||
|
||||
#include <gui/modules/submenu.h>
|
||||
#include "views/bt_carrier_test.h"
|
||||
#include "views/bt_packet_test.h"
|
||||
#include <bt/bt_settings.h>
|
||||
|
||||
typedef struct {
|
||||
BtSettings settings;
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Submenu* submenu;
|
||||
|
||||
@@ -5,6 +5,7 @@ App(
|
||||
entry_point="display_test_app",
|
||||
cdefines=["APP_DISPLAY_TEST"],
|
||||
requires=["gui"],
|
||||
fap_libs=["misc"],
|
||||
stack_size=1 * 1024,
|
||||
order=120,
|
||||
fap_category="Debug",
|
||||
|
||||
@@ -91,7 +91,6 @@ static void display_test_reload_config(DisplayTest* instance) {
|
||||
instance->config_contrast,
|
||||
instance->config_regulation_ratio,
|
||||
instance->config_bias);
|
||||
gui_update(instance->gui);
|
||||
}
|
||||
|
||||
static void display_config_set_bias(VariableItem* item) {
|
||||
|
||||
@@ -44,7 +44,11 @@ bool rpc_debug_app_scene_input_error_code_on_event(void* context, SceneManagerEv
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == RpcDebugAppCustomEventInputErrorCode) {
|
||||
rpc_system_app_set_error_code(app->rpc, (uint32_t)atol(app->text_store));
|
||||
char* end;
|
||||
int error_code = strtol(app->text_store, &end, 10);
|
||||
if(!*end) {
|
||||
rpc_system_app_set_error_code(app->rpc, error_code);
|
||||
}
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
@@ -466,6 +466,10 @@ static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) {
|
||||
nfc_device_free(nfc_keys);
|
||||
}
|
||||
|
||||
MU_TEST(mf_mini_file_test) {
|
||||
mf_classic_generator_test(4, MfClassicTypeMini);
|
||||
}
|
||||
|
||||
MU_TEST(mf_classic_1k_4b_file_test) {
|
||||
mf_classic_generator_test(4, MfClassicType1k);
|
||||
}
|
||||
@@ -486,6 +490,7 @@ MU_TEST_SUITE(nfc) {
|
||||
nfc_test_alloc();
|
||||
|
||||
MU_RUN_TEST(nfca_file_test);
|
||||
MU_RUN_TEST(mf_mini_file_test);
|
||||
MU_RUN_TEST(mf_classic_1k_4b_file_test);
|
||||
MU_RUN_TEST(mf_classic_4k_4b_file_test);
|
||||
MU_RUN_TEST(mf_classic_1k_7b_file_test);
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
} BtSettings;
|
||||
@@ -12,3 +16,7 @@ typedef struct {
|
||||
bool bt_settings_load(BtSettings* bt_settings);
|
||||
|
||||
bool bt_settings_save(BtSettings* bt_settings);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,v,12.12,,
|
||||
Version,+,12.4,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
@@ -2150,7 +2150,7 @@ Function,-,posix_memalign,int,"void**, size_t, size_t"
|
||||
Function,-,pow,double,"double, double"
|
||||
Function,-,pow10,double,double
|
||||
Function,-,pow10f,float,float
|
||||
Function,-,power_enable_low_battery_level_notification,void,"Power*, _Bool"
|
||||
Function,+,power_enable_low_battery_level_notification,void,"Power*, _Bool"
|
||||
Function,+,power_get_info,void,"Power*, PowerInfo*"
|
||||
Function,+,power_get_pubsub,FuriPubSub*,Power*
|
||||
Function,+,power_get_settings_events_pubsub,FuriPubSub*,Power*
|
||||
@@ -4422,7 +4422,6 @@ Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*"
|
||||
Function,+,validator_is_file_free,void,ValidatorIsFile*
|
||||
Function,+,value_index_bool,uint8_t,"const _Bool, const _Bool[], uint8_t"
|
||||
Function,+,value_index_float,uint8_t,"const float, const float[], uint8_t"
|
||||
Function,+,value_index_int32,uint8_t,"const int32_t, const int32_t[], uint8_t"
|
||||
Function,+,value_index_uint32,uint8_t,"const uint32_t, const uint32_t[], uint8_t"
|
||||
Function,+,variable_item_get_context,void*,VariableItem*
|
||||
Function,+,variable_item_get_current_value_index,uint8_t,VariableItem*
|
||||
|
||||
|
@@ -163,6 +163,7 @@ void reader_analyzer_stop(ReaderAnalyzer* instance) {
|
||||
}
|
||||
if(instance->pcap) {
|
||||
nfc_debug_pcap_free(instance->pcap);
|
||||
instance->pcap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-6
@@ -142,21 +142,44 @@ static bool emv_decode_response(uint8_t* buff, uint16_t len, EmvApplication* app
|
||||
success = true;
|
||||
FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen);
|
||||
break;
|
||||
case EMV_TAG_CARD_NUM: // Track 2 Equivalent Data. 0xD0 delimits PAN from expiry (YYMM)
|
||||
case EMV_TAG_TRACK_1_EQUIV: {
|
||||
char track_1_equiv[80];
|
||||
memcpy(track_1_equiv, &buff[i], tlen);
|
||||
track_1_equiv[tlen] = '\0';
|
||||
success = true;
|
||||
FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv);
|
||||
break;
|
||||
}
|
||||
case EMV_TAG_TRACK_2_EQUIV: {
|
||||
// 0xD0 delimits PAN from expiry (YYMM)
|
||||
for(int x = 1; x < tlen; x++) {
|
||||
if(buff[i + x + 1] > 0xD0) {
|
||||
memcpy(app->card_number, &buff[i], x + 1);
|
||||
app->card_number_len = x + 1;
|
||||
app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4);
|
||||
app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert 4-bit to ASCII representation
|
||||
char track_2_equiv[41];
|
||||
uint8_t track_2_equiv_len = 0;
|
||||
for(int x = 0; x < tlen; x++) {
|
||||
char top = (buff[i + x] >> 4) + '0';
|
||||
char bottom = (buff[i + x] & 0x0F) + '0';
|
||||
track_2_equiv[x * 2] = top;
|
||||
track_2_equiv_len++;
|
||||
if(top == '?') break;
|
||||
track_2_equiv[x * 2 + 1] = bottom;
|
||||
track_2_equiv_len++;
|
||||
if(bottom == '?') break;
|
||||
}
|
||||
track_2_equiv[track_2_equiv_len] = '\0';
|
||||
success = true;
|
||||
FURI_LOG_T(
|
||||
TAG,
|
||||
"found EMV_TAG_CARD_NUM %x (len=%d)",
|
||||
EMV_TAG_CARD_NUM,
|
||||
app->card_number_len);
|
||||
FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv);
|
||||
break;
|
||||
}
|
||||
case EMV_TAG_PAN:
|
||||
memcpy(app->card_number, &buff[i], tlen);
|
||||
app->card_number_len = tlen;
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
#define EMV_TAG_CARD_NAME 0x50
|
||||
#define EMV_TAG_FCI 0xBF0C
|
||||
#define EMV_TAG_LOG_CTRL 0x9F4D
|
||||
#define EMV_TAG_CARD_NUM 0x57
|
||||
#define EMV_TAG_TRACK_1_EQUIV 0x56
|
||||
#define EMV_TAG_TRACK_2_EQUIV 0x57
|
||||
#define EMV_TAG_PAN 0x5A
|
||||
#define EMV_TAG_AFL 0x94
|
||||
#define EMV_TAG_EXP_DATE 0x5F24
|
||||
|
||||
@@ -605,6 +605,14 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u
|
||||
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
|
||||
mf_classic_set_block_read(data, i, &block_tmp);
|
||||
blocks_read++;
|
||||
} else if(i > start_block) {
|
||||
// Try to re-auth to read block in case prevous block was protected from read
|
||||
furi_hal_nfc_sleep();
|
||||
if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyA, &crypto, false, 0)) break;
|
||||
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
|
||||
mf_classic_set_block_read(data, i, &block_tmp);
|
||||
blocks_read++;
|
||||
}
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
} else {
|
||||
@@ -618,12 +626,21 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u
|
||||
if(!key_b_found) break;
|
||||
FURI_LOG_D(TAG, "Try to read blocks with key B");
|
||||
key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b));
|
||||
if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break;
|
||||
for(size_t i = start_block; i < start_block + total_blocks; i++) {
|
||||
if(!mf_classic_is_block_read(data, i)) {
|
||||
if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyB, &crypto, false, 0)) continue;
|
||||
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
|
||||
mf_classic_set_block_read(data, i, &block_tmp);
|
||||
blocks_read++;
|
||||
} else if(i > start_block) {
|
||||
// Try to re-auth to read block in case prevous block was protected from read
|
||||
furi_hal_nfc_sleep();
|
||||
if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyB, &crypto, false, 0)) break;
|
||||
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
|
||||
mf_classic_set_block_read(data, i, &block_tmp);
|
||||
blocks_read++;
|
||||
}
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
} else {
|
||||
@@ -676,6 +693,11 @@ static bool mf_classic_read_sector_with_reader(
|
||||
|
||||
// Read blocks
|
||||
for(uint8_t i = 0; i < sector->total_blocks; i++) {
|
||||
if(mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) continue;
|
||||
if(i == 0) continue;
|
||||
// Try to auth to read next block in case previous is locked
|
||||
furi_hal_nfc_sleep();
|
||||
if(!mf_classic_auth(tx_rx, first_block + i, key, key_type, crypto, false, 0)) continue;
|
||||
mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i]);
|
||||
}
|
||||
// Save sector keys in last block
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#define MF_CLASSIC_BLOCK_SIZE (16)
|
||||
#define MF_CLASSIC_TOTAL_BLOCKS_MAX (256)
|
||||
#define MF_MINI_TOTAL_SECTORS_NUM (5)
|
||||
#define MF_CLASSIC_1K_TOTAL_SECTORS_NUM (16)
|
||||
#define MF_CLASSIC_4K_TOTAL_SECTORS_NUM (40)
|
||||
#define MF_MINI_TOTAL_SECTORS_NUM (5)
|
||||
@@ -22,6 +23,7 @@ typedef enum {
|
||||
MfClassicTypeMini,
|
||||
MfClassicType1k,
|
||||
MfClassicType4k,
|
||||
MfClassicTypeMini,
|
||||
} MfClassicType;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -21,6 +21,7 @@ env.Append(
|
||||
File("saved_struct.h"),
|
||||
File("version.h"),
|
||||
File("float_tools.h"),
|
||||
File("value_index.h"),
|
||||
File("tar/tar_archive.h"),
|
||||
File("stream/stream.h"),
|
||||
File("stream/file_stream.h"),
|
||||
|
||||
Reference in New Issue
Block a user