mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 01:58:36 -07:00
Merge remote-tracking branch 'upstream/dev' into nfcf
This commit is contained in:
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@@ -4,7 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
- "release*"
|
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -194,12 +193,14 @@ jobs:
|
|||||||
TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \
|
TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \
|
||||||
./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package
|
./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package
|
||||||
echo "sdk-file=$(ls dist/${{ matrix.target }}-*/flipper-z-${{ matrix.target }}-sdk-*.zip)" >> $GITHUB_OUTPUT
|
echo "sdk-file=$(ls dist/${{ matrix.target }}-*/flipper-z-${{ matrix.target }}-sdk-*.zip)" >> $GITHUB_OUTPUT
|
||||||
|
echo "hw-target-code=$TARGET" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Deploy uFBT with SDK
|
- name: Deploy uFBT with SDK
|
||||||
uses: flipperdevices/flipperzero-ufbt-action@v0.1.0
|
uses: flipperdevices/flipperzero-ufbt-action@v0.1.0
|
||||||
with:
|
with:
|
||||||
task: setup
|
task: setup
|
||||||
sdk-file: ${{ steps.build-fw.outputs.sdk-file }}
|
sdk-file: ${{ steps.build-fw.outputs.sdk-file }}
|
||||||
|
sdk-hw-target: ${{ steps.build-fw.outputs.hw-target-code }}
|
||||||
|
|
||||||
- name: Build test app with SDK
|
- name: Build test app with SDK
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
- "release*"
|
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|||||||
1
.github/workflows/pvs_studio.yml
vendored
1
.github/workflows/pvs_studio.yml
vendored
@@ -4,7 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
- "release*"
|
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@
|
|||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
*.gdb_history
|
*.gdb_history
|
||||||
|
*.old
|
||||||
|
|
||||||
|
|
||||||
# LSP
|
# LSP
|
||||||
|
|||||||
22
applications/external/hid_app/hid.c
vendored
22
applications/external/hid_app/hid.c
vendored
@@ -11,6 +11,7 @@ enum HidDebugSubmenuIndex {
|
|||||||
HidSubmenuIndexMedia,
|
HidSubmenuIndexMedia,
|
||||||
HidSubmenuIndexTikTok,
|
HidSubmenuIndexTikTok,
|
||||||
HidSubmenuIndexMouse,
|
HidSubmenuIndexMouse,
|
||||||
|
HidSubmenuIndexMouseClicker,
|
||||||
HidSubmenuIndexMouseJiggler,
|
HidSubmenuIndexMouseJiggler,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,6 +33,9 @@ static void hid_submenu_callback(void* context, uint32_t index) {
|
|||||||
} else if(index == HidSubmenuIndexTikTok) {
|
} else if(index == HidSubmenuIndexTikTok) {
|
||||||
app->view_id = BtHidViewTikTok;
|
app->view_id = BtHidViewTikTok;
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok);
|
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok);
|
||||||
|
} else if(index == HidSubmenuIndexMouseClicker) {
|
||||||
|
app->view_id = HidViewMouseClicker;
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker);
|
||||||
} else if(index == HidSubmenuIndexMouseJiggler) {
|
} else if(index == HidSubmenuIndexMouseJiggler) {
|
||||||
app->view_id = HidViewMouseJiggler;
|
app->view_id = HidViewMouseJiggler;
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
|
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
|
||||||
@@ -53,6 +57,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con
|
|||||||
hid_keyboard_set_connected_status(hid->hid_keyboard, connected);
|
hid_keyboard_set_connected_status(hid->hid_keyboard, connected);
|
||||||
hid_media_set_connected_status(hid->hid_media, connected);
|
hid_media_set_connected_status(hid->hid_media, connected);
|
||||||
hid_mouse_set_connected_status(hid->hid_mouse, connected);
|
hid_mouse_set_connected_status(hid->hid_mouse, connected);
|
||||||
|
hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected);
|
||||||
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
|
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
|
||||||
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
|
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
|
||||||
}
|
}
|
||||||
@@ -114,6 +119,12 @@ Hid* hid_alloc(HidTransport transport) {
|
|||||||
hid_submenu_callback,
|
hid_submenu_callback,
|
||||||
app);
|
app);
|
||||||
}
|
}
|
||||||
|
submenu_add_item(
|
||||||
|
app->device_type_submenu,
|
||||||
|
"Mouse Clicker",
|
||||||
|
HidSubmenuIndexMouseClicker,
|
||||||
|
hid_submenu_callback,
|
||||||
|
app);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
app->device_type_submenu,
|
app->device_type_submenu,
|
||||||
"Mouse Jiggler",
|
"Mouse Jiggler",
|
||||||
@@ -172,6 +183,15 @@ Hid* hid_app_alloc_view(void* context) {
|
|||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse));
|
app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse));
|
||||||
|
|
||||||
|
// Mouse clicker view
|
||||||
|
app->hid_mouse_clicker = hid_mouse_clicker_alloc(app);
|
||||||
|
view_set_previous_callback(
|
||||||
|
hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_exit_confirm_view);
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher,
|
||||||
|
HidViewMouseClicker,
|
||||||
|
hid_mouse_clicker_get_view(app->hid_mouse_clicker));
|
||||||
|
|
||||||
// Mouse jiggler view
|
// Mouse jiggler view
|
||||||
app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app);
|
app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app);
|
||||||
view_set_previous_callback(
|
view_set_previous_callback(
|
||||||
@@ -205,6 +225,8 @@ void hid_free(Hid* app) {
|
|||||||
hid_media_free(app->hid_media);
|
hid_media_free(app->hid_media);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse);
|
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse);
|
||||||
hid_mouse_free(app->hid_mouse);
|
hid_mouse_free(app->hid_mouse);
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseClicker);
|
||||||
|
hid_mouse_clicker_free(app->hid_mouse_clicker);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler);
|
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler);
|
||||||
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
|
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
|
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
|
||||||
|
|||||||
2
applications/external/hid_app/hid.h
vendored
2
applications/external/hid_app/hid.h
vendored
@@ -20,6 +20,7 @@
|
|||||||
#include "views/hid_keyboard.h"
|
#include "views/hid_keyboard.h"
|
||||||
#include "views/hid_media.h"
|
#include "views/hid_media.h"
|
||||||
#include "views/hid_mouse.h"
|
#include "views/hid_mouse.h"
|
||||||
|
#include "views/hid_mouse_clicker.h"
|
||||||
#include "views/hid_mouse_jiggler.h"
|
#include "views/hid_mouse_jiggler.h"
|
||||||
#include "views/hid_tiktok.h"
|
#include "views/hid_tiktok.h"
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ struct Hid {
|
|||||||
HidKeyboard* hid_keyboard;
|
HidKeyboard* hid_keyboard;
|
||||||
HidMedia* hid_media;
|
HidMedia* hid_media;
|
||||||
HidMouse* hid_mouse;
|
HidMouse* hid_mouse;
|
||||||
|
HidMouseClicker* hid_mouse_clicker;
|
||||||
HidMouseJiggler* hid_mouse_jiggler;
|
HidMouseJiggler* hid_mouse_jiggler;
|
||||||
HidTikTok* hid_tiktok;
|
HidTikTok* hid_tiktok;
|
||||||
|
|
||||||
|
|||||||
1
applications/external/hid_app/views.h
vendored
1
applications/external/hid_app/views.h
vendored
@@ -4,6 +4,7 @@ typedef enum {
|
|||||||
HidViewKeyboard,
|
HidViewKeyboard,
|
||||||
HidViewMedia,
|
HidViewMedia,
|
||||||
HidViewMouse,
|
HidViewMouse,
|
||||||
|
HidViewMouseClicker,
|
||||||
HidViewMouseJiggler,
|
HidViewMouseJiggler,
|
||||||
BtHidViewTikTok,
|
BtHidViewTikTok,
|
||||||
HidViewExitConfirm,
|
HidViewExitConfirm,
|
||||||
|
|||||||
214
applications/external/hid_app/views/hid_mouse_clicker.c
vendored
Normal file
214
applications/external/hid_app/views/hid_mouse_clicker.c
vendored
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
#include "hid_mouse_clicker.h"
|
||||||
|
#include <gui/elements.h>
|
||||||
|
#include "../hid.h"
|
||||||
|
|
||||||
|
#include "hid_icons.h"
|
||||||
|
|
||||||
|
#define TAG "HidMouseClicker"
|
||||||
|
#define DEFAULT_CLICK_RATE 1
|
||||||
|
#define MAXIMUM_CLICK_RATE 60
|
||||||
|
|
||||||
|
struct HidMouseClicker {
|
||||||
|
View* view;
|
||||||
|
Hid* hid;
|
||||||
|
FuriTimer* timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool connected;
|
||||||
|
bool running;
|
||||||
|
int rate;
|
||||||
|
HidTransport transport;
|
||||||
|
} HidMouseClickerModel;
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_start_or_restart_timer(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
|
||||||
|
if(furi_timer_is_running(hid_mouse_clicker->timer)) {
|
||||||
|
furi_timer_stop(hid_mouse_clicker->timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
furi_timer_start(
|
||||||
|
hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClickerModel* model = context;
|
||||||
|
|
||||||
|
// Header
|
||||||
|
if(model->transport == HidTransportBle) {
|
||||||
|
if(model->connected) {
|
||||||
|
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
|
||||||
|
} else {
|
||||||
|
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Clicker");
|
||||||
|
|
||||||
|
// Ok
|
||||||
|
canvas_draw_icon(canvas, 63, 25, &I_Space_65x18);
|
||||||
|
if(model->running) {
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
|
||||||
|
FuriString* rate_label = furi_string_alloc();
|
||||||
|
furi_string_printf(rate_label, "%d clicks/s\n\nUp / Down", model->rate);
|
||||||
|
elements_multiline_text(canvas, AlignLeft, 35, furi_string_get_cstr(rate_label));
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
furi_string_free(rate_label);
|
||||||
|
|
||||||
|
elements_slightly_rounded_box(canvas, 66, 27, 60, 13);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
|
} else {
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto start\nclicking");
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
}
|
||||||
|
canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9);
|
||||||
|
if(model->running) {
|
||||||
|
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop");
|
||||||
|
} else {
|
||||||
|
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start");
|
||||||
|
}
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
|
// Back
|
||||||
|
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
|
||||||
|
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_timer_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
if(model->running) {
|
||||||
|
hid_hal_mouse_press(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT);
|
||||||
|
hid_hal_mouse_release(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_enter_callback(void* context) {
|
||||||
|
hid_mouse_clicker_start_or_restart_timer(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hid_mouse_clicker_exit_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
furi_timer_stop(hid_mouse_clicker->timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
HidMouseClicker* hid_mouse_clicker = context;
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
bool rate_changed = false;
|
||||||
|
|
||||||
|
if(event->type != InputTypeShort && event->type != InputTypeRepeat) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
switch(event->key) {
|
||||||
|
case InputKeyOk:
|
||||||
|
model->running = !model->running;
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
case InputKeyUp:
|
||||||
|
if(model->rate < MAXIMUM_CLICK_RATE) {
|
||||||
|
model->rate++;
|
||||||
|
}
|
||||||
|
rate_changed = true;
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
case InputKeyDown:
|
||||||
|
if(model->rate > 1) {
|
||||||
|
model->rate--;
|
||||||
|
}
|
||||||
|
rate_changed = true;
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
if(rate_changed) {
|
||||||
|
hid_mouse_clicker_start_or_restart_timer(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
HidMouseClicker* hid_mouse_clicker_alloc(Hid* hid) {
|
||||||
|
HidMouseClicker* hid_mouse_clicker = malloc(sizeof(HidMouseClicker));
|
||||||
|
|
||||||
|
hid_mouse_clicker->view = view_alloc();
|
||||||
|
view_set_context(hid_mouse_clicker->view, hid_mouse_clicker);
|
||||||
|
view_allocate_model(
|
||||||
|
hid_mouse_clicker->view, ViewModelTypeLocking, sizeof(HidMouseClickerModel));
|
||||||
|
view_set_draw_callback(hid_mouse_clicker->view, hid_mouse_clicker_draw_callback);
|
||||||
|
view_set_input_callback(hid_mouse_clicker->view, hid_mouse_clicker_input_callback);
|
||||||
|
view_set_enter_callback(hid_mouse_clicker->view, hid_mouse_clicker_enter_callback);
|
||||||
|
view_set_exit_callback(hid_mouse_clicker->view, hid_mouse_clicker_exit_callback);
|
||||||
|
|
||||||
|
hid_mouse_clicker->hid = hid;
|
||||||
|
|
||||||
|
hid_mouse_clicker->timer = furi_timer_alloc(
|
||||||
|
hid_mouse_clicker_timer_callback, FuriTimerTypePeriodic, hid_mouse_clicker);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{
|
||||||
|
model->transport = hid->transport;
|
||||||
|
model->rate = DEFAULT_CLICK_RATE;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
return hid_mouse_clicker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker) {
|
||||||
|
furi_assert(hid_mouse_clicker);
|
||||||
|
|
||||||
|
furi_timer_stop(hid_mouse_clicker->timer);
|
||||||
|
furi_timer_free(hid_mouse_clicker->timer);
|
||||||
|
|
||||||
|
view_free(hid_mouse_clicker->view);
|
||||||
|
|
||||||
|
free(hid_mouse_clicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker) {
|
||||||
|
furi_assert(hid_mouse_clicker);
|
||||||
|
return hid_mouse_clicker->view;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected) {
|
||||||
|
furi_assert(hid_mouse_clicker);
|
||||||
|
with_view_model(
|
||||||
|
hid_mouse_clicker->view,
|
||||||
|
HidMouseClickerModel * model,
|
||||||
|
{ model->connected = connected; },
|
||||||
|
true);
|
||||||
|
}
|
||||||
14
applications/external/hid_app/views/hid_mouse_clicker.h
vendored
Normal file
14
applications/external/hid_app/views/hid_mouse_clicker.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gui/view.h>
|
||||||
|
|
||||||
|
typedef struct Hid Hid;
|
||||||
|
typedef struct HidMouseClicker HidMouseClicker;
|
||||||
|
|
||||||
|
HidMouseClicker* hid_mouse_clicker_alloc(Hid* bt_hid);
|
||||||
|
|
||||||
|
void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker);
|
||||||
|
|
||||||
|
View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker);
|
||||||
|
|
||||||
|
void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected);
|
||||||
@@ -95,7 +95,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) {
|
|||||||
|
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event->key == InputKeyOk) {
|
if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
hid_mouse_jiggler->view,
|
hid_mouse_jiggler->view,
|
||||||
HidMouseJigglerModel * model,
|
HidMouseJigglerModel * model,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|||||||
uint8_t csn[PICOPASS_BLOCK_LEN] = {0};
|
uint8_t csn[PICOPASS_BLOCK_LEN] = {0};
|
||||||
memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN);
|
memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN);
|
||||||
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
||||||
furi_string_cat_printf(csn_str, "%02X ", csn[i]);
|
furi_string_cat_printf(csn_str, "%02X", csn[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN);
|
bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = {
|
|||||||
&ws_protocol_auriol_th,
|
&ws_protocol_auriol_th,
|
||||||
&ws_protocol_oregon_v1,
|
&ws_protocol_oregon_v1,
|
||||||
&ws_protocol_tx_8300,
|
&ws_protocol_tx_8300,
|
||||||
|
&ws_protocol_wendox_w6726,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SubGhzProtocolRegistry weather_station_protocol_registry = {
|
const SubGhzProtocolRegistry weather_station_protocol_registry = {
|
||||||
|
|||||||
@@ -16,5 +16,6 @@
|
|||||||
#include "auriol_hg0601a.h"
|
#include "auriol_hg0601a.h"
|
||||||
#include "oregon_v1.h"
|
#include "oregon_v1.h"
|
||||||
#include "tx_8300.h"
|
#include "tx_8300.h"
|
||||||
|
#include "wendox_w6726.h"
|
||||||
|
|
||||||
extern const SubGhzProtocolRegistry weather_station_protocol_registry;
|
extern const SubGhzProtocolRegistry weather_station_protocol_registry;
|
||||||
|
|||||||
299
applications/external/weather_station/protocols/wendox_w6726.c
vendored
Normal file
299
applications/external/weather_station/protocols/wendox_w6726.c
vendored
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
#include "wendox_w6726.h"
|
||||||
|
|
||||||
|
#define TAG "WSProtocolWendoxW6726"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wendox W6726
|
||||||
|
*
|
||||||
|
* Temperature -50C to +70C
|
||||||
|
* _ _ _ __ _
|
||||||
|
* _| |___| |___| |___ ... | |_| |__...._______________
|
||||||
|
* preamble data guard time
|
||||||
|
*
|
||||||
|
* 3 reps every 3 minutes
|
||||||
|
* in the first message 11 bytes of the preamble in the rest by 7
|
||||||
|
*
|
||||||
|
* bit 0: 1955-hi, 5865-lo
|
||||||
|
* bit 1: 5865-hi, 1955-lo
|
||||||
|
* guard time: 12*1955+(lo last bit)
|
||||||
|
* data: 29 bit
|
||||||
|
*
|
||||||
|
* IIIII | ZTTTTTTTTT | uuuuuuuBuu | CCCC
|
||||||
|
*
|
||||||
|
* I: identification;
|
||||||
|
* Z: temperature sign;
|
||||||
|
* T: temperature sign dependent +12C;
|
||||||
|
* B: battery low; flag to indicate low battery voltage;
|
||||||
|
* C: CRC4 (polynomial = 0x9, start_data = 0xD);
|
||||||
|
* u: unknown;
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const SubGhzBlockConst ws_protocol_wendox_w6726_const = {
|
||||||
|
.te_short = 1955,
|
||||||
|
.te_long = 5865,
|
||||||
|
.te_delta = 300,
|
||||||
|
.min_count_bit_for_found = 29,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WSProtocolDecoderWendoxW6726 {
|
||||||
|
SubGhzProtocolDecoderBase base;
|
||||||
|
|
||||||
|
SubGhzBlockDecoder decoder;
|
||||||
|
WSBlockGeneric generic;
|
||||||
|
|
||||||
|
uint16_t header_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WSProtocolEncoderWendoxW6726 {
|
||||||
|
SubGhzProtocolEncoderBase base;
|
||||||
|
|
||||||
|
SubGhzProtocolBlockEncoder encoder;
|
||||||
|
WSBlockGeneric generic;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WendoxW6726DecoderStepReset = 0,
|
||||||
|
WendoxW6726DecoderStepCheckPreambule,
|
||||||
|
WendoxW6726DecoderStepSaveDuration,
|
||||||
|
WendoxW6726DecoderStepCheckDuration,
|
||||||
|
} WendoxW6726DecoderStep;
|
||||||
|
|
||||||
|
const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder = {
|
||||||
|
.alloc = ws_protocol_decoder_wendox_w6726_alloc,
|
||||||
|
.free = ws_protocol_decoder_wendox_w6726_free,
|
||||||
|
|
||||||
|
.feed = ws_protocol_decoder_wendox_w6726_feed,
|
||||||
|
.reset = ws_protocol_decoder_wendox_w6726_reset,
|
||||||
|
|
||||||
|
.get_hash_data = ws_protocol_decoder_wendox_w6726_get_hash_data,
|
||||||
|
.serialize = ws_protocol_decoder_wendox_w6726_serialize,
|
||||||
|
.deserialize = ws_protocol_decoder_wendox_w6726_deserialize,
|
||||||
|
.get_string = ws_protocol_decoder_wendox_w6726_get_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder = {
|
||||||
|
.alloc = NULL,
|
||||||
|
.free = NULL,
|
||||||
|
|
||||||
|
.deserialize = NULL,
|
||||||
|
.stop = NULL,
|
||||||
|
.yield = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubGhzProtocol ws_protocol_wendox_w6726 = {
|
||||||
|
.name = WS_PROTOCOL_WENDOX_W6726_NAME,
|
||||||
|
.type = SubGhzProtocolWeatherStation,
|
||||||
|
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
|
||||||
|
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
|
||||||
|
|
||||||
|
.decoder = &ws_protocol_wendox_w6726_decoder,
|
||||||
|
.encoder = &ws_protocol_wendox_w6726_encoder,
|
||||||
|
};
|
||||||
|
|
||||||
|
void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment) {
|
||||||
|
UNUSED(environment);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = malloc(sizeof(WSProtocolDecoderWendoxW6726));
|
||||||
|
instance->base.protocol = &ws_protocol_wendox_w6726;
|
||||||
|
instance->generic.protocol_name = instance->base.protocol->name;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_free(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_reset(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ws_protocol_wendox_w6726_check(WSProtocolDecoderWendoxW6726* instance) {
|
||||||
|
if(!instance->decoder.decode_data) return false;
|
||||||
|
uint8_t msg[] = {
|
||||||
|
instance->decoder.decode_data >> 28,
|
||||||
|
instance->decoder.decode_data >> 20,
|
||||||
|
instance->decoder.decode_data >> 12,
|
||||||
|
instance->decoder.decode_data >> 4};
|
||||||
|
|
||||||
|
uint8_t crc = subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD);
|
||||||
|
return (crc == (instance->decoder.decode_data & 0x0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analysis of received data
|
||||||
|
* @param instance Pointer to a WSBlockGeneric* instance
|
||||||
|
*/
|
||||||
|
static void ws_protocol_wendox_w6726_remote_controller(WSBlockGeneric* instance) {
|
||||||
|
instance->id = (instance->data >> 24) & 0xFF;
|
||||||
|
instance->battery_low = (instance->data >> 6) & 1;
|
||||||
|
instance->channel = WS_NO_CHANNEL;
|
||||||
|
|
||||||
|
if(((instance->data >> 23) & 1)) {
|
||||||
|
instance->temp = (float)(((instance->data >> 14) & 0x1FF) + 12) / 10.0f;
|
||||||
|
} else {
|
||||||
|
instance->temp = (float)((~(instance->data >> 14) & 0x1FF) + 1 - 12) / -10.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(instance->temp < -50.0f) {
|
||||||
|
instance->temp = -50.0f;
|
||||||
|
} else if(instance->temp > 70.0f) {
|
||||||
|
instance->temp = 70.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->btn = WS_NO_BTN;
|
||||||
|
instance->humidity = WS_NO_HUMIDITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
|
||||||
|
switch(instance->decoder.parser_step) {
|
||||||
|
case WendoxW6726DecoderStepReset:
|
||||||
|
if((level) && (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta)) {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepCheckPreambule;
|
||||||
|
instance->decoder.te_last = duration;
|
||||||
|
instance->header_count = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WendoxW6726DecoderStepCheckPreambule:
|
||||||
|
if(level) {
|
||||||
|
instance->decoder.te_last = duration;
|
||||||
|
} else {
|
||||||
|
if((DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 1) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2)) {
|
||||||
|
instance->header_count++;
|
||||||
|
} else if((instance->header_count > 4) && (instance->header_count < 12)) {
|
||||||
|
if((DURATION_DIFF(
|
||||||
|
instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta)) {
|
||||||
|
instance->decoder.decode_data = 0;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WendoxW6726DecoderStepSaveDuration:
|
||||||
|
if(level) {
|
||||||
|
instance->decoder.te_last = duration;
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepCheckDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WendoxW6726DecoderStepCheckDuration:
|
||||||
|
if(!level) {
|
||||||
|
if(duration >
|
||||||
|
ws_protocol_wendox_w6726_const.te_short + ws_protocol_wendox_w6726_const.te_long) {
|
||||||
|
if(DURATION_DIFF(
|
||||||
|
instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else if(
|
||||||
|
DURATION_DIFF(
|
||||||
|
instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
if((instance->decoder.decode_count_bit ==
|
||||||
|
ws_protocol_wendox_w6726_const.min_count_bit_for_found) &&
|
||||||
|
ws_protocol_wendox_w6726_check(instance)) {
|
||||||
|
instance->generic.data = instance->decoder.decode_data;
|
||||||
|
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
|
||||||
|
ws_protocol_wendox_w6726_remote_controller(&instance->generic);
|
||||||
|
if(instance->base.callback)
|
||||||
|
instance->base.callback(&instance->base, instance->base.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
} else if(
|
||||||
|
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 3)) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else if(
|
||||||
|
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta * 2) &&
|
||||||
|
(DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) <
|
||||||
|
ws_protocol_wendox_w6726_const.te_delta)) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration;
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = WendoxW6726DecoderStepReset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
return subghz_protocol_blocks_get_hash_data(
|
||||||
|
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize(
|
||||||
|
void* context,
|
||||||
|
FlipperFormat* flipper_format,
|
||||||
|
SubGhzRadioPreset* preset) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
return ws_block_generic_deserialize_check_count_bit(
|
||||||
|
&instance->generic,
|
||||||
|
flipper_format,
|
||||||
|
ws_protocol_wendox_w6726_const.min_count_bit_for_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderWendoxW6726* instance = context;
|
||||||
|
furi_string_printf(
|
||||||
|
output,
|
||||||
|
"%s %dbit\r\n"
|
||||||
|
"Key:0x%lX%08lX\r\n"
|
||||||
|
"Sn:0x%lX Ch:%d Bat:%d\r\n"
|
||||||
|
"Temp:%3.1f C Hum:%d%%",
|
||||||
|
instance->generic.protocol_name,
|
||||||
|
instance->generic.data_count_bit,
|
||||||
|
(uint32_t)(instance->generic.data >> 32),
|
||||||
|
(uint32_t)(instance->generic.data),
|
||||||
|
instance->generic.id,
|
||||||
|
instance->generic.channel,
|
||||||
|
instance->generic.battery_low,
|
||||||
|
(double)instance->generic.temp,
|
||||||
|
instance->generic.humidity);
|
||||||
|
}
|
||||||
80
applications/external/weather_station/protocols/wendox_w6726.h
vendored
Normal file
80
applications/external/weather_station/protocols/wendox_w6726.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lib/subghz/protocols/base.h>
|
||||||
|
|
||||||
|
#include <lib/subghz/blocks/const.h>
|
||||||
|
#include <lib/subghz/blocks/decoder.h>
|
||||||
|
#include <lib/subghz/blocks/encoder.h>
|
||||||
|
#include "ws_generic.h"
|
||||||
|
#include <lib/subghz/blocks/math.h>
|
||||||
|
|
||||||
|
#define WS_PROTOCOL_WENDOX_W6726_NAME "Wendox W6726"
|
||||||
|
|
||||||
|
typedef struct WSProtocolDecoderWendoxW6726 WSProtocolDecoderWendoxW6726;
|
||||||
|
typedef struct WSProtocolEncoderWendoxW6726 WSProtocolEncoderWendoxW6726;
|
||||||
|
|
||||||
|
extern const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder;
|
||||||
|
extern const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder;
|
||||||
|
extern const SubGhzProtocol ws_protocol_wendox_w6726;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param environment Pointer to a SubGhzEnvironment instance
|
||||||
|
* @return WSProtocolDecoderWendoxW6726* pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
*/
|
||||||
|
void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_free(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset decoder WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_reset(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a raw sequence of levels and durations received from the air.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param level Signal level true-high false-low
|
||||||
|
* @param duration Duration of this level in, us
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getting the hash sum of the last randomly received parcel.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @return hash Hash sum
|
||||||
|
*/
|
||||||
|
uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize data WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param flipper_format Pointer to a FlipperFormat instance
|
||||||
|
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
|
||||||
|
* @return status
|
||||||
|
*/
|
||||||
|
SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize(
|
||||||
|
void* context,
|
||||||
|
FlipperFormat* flipper_format,
|
||||||
|
SubGhzRadioPreset* preset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize data WSProtocolDecoderWendoxW6726.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param flipper_format Pointer to a FlipperFormat instance
|
||||||
|
* @return status
|
||||||
|
*/
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getting a textual representation of the received data.
|
||||||
|
* @param context Pointer to a WSProtocolDecoderWendoxW6726 instance
|
||||||
|
* @param output Resulting text
|
||||||
|
*/
|
||||||
|
void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output);
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#define MENU_ITEMS 4u
|
#define MENU_ITEMS 4u
|
||||||
#define UNLOCK_CNT 3
|
#define UNLOCK_CNT 3
|
||||||
|
|
||||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
|
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriString* item_str;
|
FuriString* item_str;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) {
|
|||||||
instance->view,
|
instance->view,
|
||||||
WSReceiverModel * model,
|
WSReceiverModel * model,
|
||||||
{
|
{
|
||||||
if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
|
if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
|
||||||
model->u_rssi = 0;
|
model->u_rssi = 0;
|
||||||
} else {
|
} else {
|
||||||
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
|
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
|
|||||||
@@ -152,22 +152,22 @@ static int32_t ducky_fnc_waitforbutton(BadUsbScript* bad_usb, const char* line,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const DuckyCmd ducky_commands[] = {
|
static const DuckyCmd ducky_commands[] = {
|
||||||
{"REM ", NULL, -1},
|
{"REM", NULL, -1},
|
||||||
{"ID ", NULL, -1},
|
{"ID", NULL, -1},
|
||||||
{"DELAY ", ducky_fnc_delay, -1},
|
{"DELAY", ducky_fnc_delay, -1},
|
||||||
{"STRING ", ducky_fnc_string, 0},
|
{"STRING", ducky_fnc_string, 0},
|
||||||
{"STRINGLN ", ducky_fnc_string, 1},
|
{"STRINGLN", ducky_fnc_string, 1},
|
||||||
{"DEFAULT_DELAY ", ducky_fnc_defdelay, -1},
|
{"DEFAULT_DELAY", ducky_fnc_defdelay, -1},
|
||||||
{"DEFAULTDELAY ", ducky_fnc_defdelay, -1},
|
{"DEFAULTDELAY", ducky_fnc_defdelay, -1},
|
||||||
{"STRINGDELAY ", ducky_fnc_strdelay, -1},
|
{"STRINGDELAY", ducky_fnc_strdelay, -1},
|
||||||
{"STRING_DELAY ", ducky_fnc_strdelay, -1},
|
{"STRING_DELAY", ducky_fnc_strdelay, -1},
|
||||||
{"REPEAT ", ducky_fnc_repeat, -1},
|
{"REPEAT", ducky_fnc_repeat, -1},
|
||||||
{"SYSRQ ", ducky_fnc_sysrq, -1},
|
{"SYSRQ", ducky_fnc_sysrq, -1},
|
||||||
{"ALTCHAR ", ducky_fnc_altchar, -1},
|
{"ALTCHAR", ducky_fnc_altchar, -1},
|
||||||
{"ALTSTRING ", ducky_fnc_altstring, -1},
|
{"ALTSTRING", ducky_fnc_altstring, -1},
|
||||||
{"ALTCODE ", ducky_fnc_altstring, -1},
|
{"ALTCODE", ducky_fnc_altstring, -1},
|
||||||
{"HOLD ", ducky_fnc_hold, -1},
|
{"HOLD", ducky_fnc_hold, -1},
|
||||||
{"RELEASE ", ducky_fnc_release, -1},
|
{"RELEASE", ducky_fnc_release, -1},
|
||||||
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
|
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -175,8 +175,15 @@ static const DuckyCmd ducky_commands[] = {
|
|||||||
#define WORKER_TAG TAG "Worker"
|
#define WORKER_TAG TAG "Worker"
|
||||||
|
|
||||||
int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) {
|
int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) {
|
||||||
|
size_t cmd_word_len = strcspn(line, " ");
|
||||||
for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) {
|
for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) {
|
||||||
if(strncmp(line, ducky_commands[i].name, strlen(ducky_commands[i].name)) == 0) {
|
size_t cmd_compare_len = strlen(ducky_commands[i].name);
|
||||||
|
|
||||||
|
if(cmd_compare_len != cmd_word_len) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strncmp(line, ducky_commands[i].name, cmd_compare_len) == 0) {
|
||||||
if(ducky_commands[i].callback == NULL) {
|
if(ducky_commands[i].callback == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ typedef enum {
|
|||||||
SubGhzCustomEventManagerSetRAW,
|
SubGhzCustomEventManagerSetRAW,
|
||||||
|
|
||||||
//SubmenuIndex
|
//SubmenuIndex
|
||||||
SubmenuIndexPricenton,
|
SubmenuIndexPricenton_433,
|
||||||
|
SubmenuIndexPricenton_315,
|
||||||
SubmenuIndexNiceFlo12bit,
|
SubmenuIndexNiceFlo12bit,
|
||||||
SubmenuIndexNiceFlo24bit,
|
SubmenuIndexNiceFlo24bit,
|
||||||
SubmenuIndexCAME12bit,
|
SubmenuIndexCAME12bit,
|
||||||
SubmenuIndexCAME24bit,
|
SubmenuIndexCAME24bit,
|
||||||
SubmenuIndexCAMETwee,
|
SubmenuIndexCAMETwee,
|
||||||
SubmenuIndexNeroSketch,
|
|
||||||
SubmenuIndexNeroRadio,
|
|
||||||
SubmenuIndexGateTX,
|
SubmenuIndexGateTX,
|
||||||
SubmenuIndexDoorHan_315_00,
|
SubmenuIndexDoorHan_315_00,
|
||||||
SubmenuIndexDoorHan_433_92,
|
SubmenuIndexDoorHan_433_92,
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont
|
|||||||
instance->thread = furi_thread_alloc_ex(
|
instance->thread = furi_thread_alloc_ex(
|
||||||
"SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance);
|
"SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance);
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
instance->setting = subghz->setting;
|
instance->setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
applications/main/subghz/helpers/subghz_threshold_rssi.c
Normal file
60
applications/main/subghz/helpers/subghz_threshold_rssi.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "subghz_threshold_rssi.h"
|
||||||
|
#include <float_tools.h>
|
||||||
|
#include "../subghz_i.h"
|
||||||
|
|
||||||
|
#define TAG "SubGhzThresholdRssi"
|
||||||
|
#define THRESHOLD_RSSI_LOW_COUNT 10
|
||||||
|
|
||||||
|
struct SubGhzThresholdRssi {
|
||||||
|
float threshold_rssi;
|
||||||
|
uint8_t threshold_rssi_low_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void) {
|
||||||
|
SubGhzThresholdRssi* instance = malloc(sizeof(SubGhzThresholdRssi));
|
||||||
|
instance->threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN;
|
||||||
|
instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi) {
|
||||||
|
furi_assert(instance);
|
||||||
|
instance->threshold_rssi = rssi;
|
||||||
|
}
|
||||||
|
|
||||||
|
float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->threshold_rssi;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
float rssi = furi_hal_subghz_get_rssi();
|
||||||
|
SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false};
|
||||||
|
|
||||||
|
if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) {
|
||||||
|
ret.is_above = true;
|
||||||
|
} else {
|
||||||
|
if(rssi < instance->threshold_rssi) {
|
||||||
|
instance->threshold_rssi_low_count++;
|
||||||
|
if(instance->threshold_rssi_low_count > THRESHOLD_RSSI_LOW_COUNT) {
|
||||||
|
instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT;
|
||||||
|
}
|
||||||
|
ret.is_above = false;
|
||||||
|
} else {
|
||||||
|
instance->threshold_rssi_low_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(instance->threshold_rssi_low_count == THRESHOLD_RSSI_LOW_COUNT) {
|
||||||
|
ret.is_above = false;
|
||||||
|
} else {
|
||||||
|
ret.is_above = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
43
applications/main/subghz/helpers/subghz_threshold_rssi.h
Normal file
43
applications/main/subghz/helpers/subghz_threshold_rssi.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float rssi; /**< Current RSSI */
|
||||||
|
bool is_above; /**< Exceeded threshold level */
|
||||||
|
} SubGhzThresholdRssiData;
|
||||||
|
|
||||||
|
typedef struct SubGhzThresholdRssi SubGhzThresholdRssi;
|
||||||
|
|
||||||
|
/** Allocate SubGhzThresholdRssi
|
||||||
|
*
|
||||||
|
* @return SubGhzThresholdRssi*
|
||||||
|
*/
|
||||||
|
SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void);
|
||||||
|
|
||||||
|
/** Free SubGhzThresholdRssi
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzThresholdRssi
|
||||||
|
*/
|
||||||
|
void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance);
|
||||||
|
|
||||||
|
/** Set threshold
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzThresholdRssi
|
||||||
|
* @param rssi RSSI threshold
|
||||||
|
*/
|
||||||
|
void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi);
|
||||||
|
|
||||||
|
/** Get threshold
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzThresholdRssi
|
||||||
|
* @return float RSSI threshold
|
||||||
|
*/
|
||||||
|
float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance);
|
||||||
|
|
||||||
|
/** Check threshold
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzThresholdRssi
|
||||||
|
* @return SubGhzThresholdRssiData
|
||||||
|
*/
|
||||||
|
SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance);
|
||||||
521
applications/main/subghz/helpers/subghz_txrx.c
Normal file
521
applications/main/subghz/helpers/subghz_txrx.c
Normal file
@@ -0,0 +1,521 @@
|
|||||||
|
#include "subghz_txrx_i.h"
|
||||||
|
|
||||||
|
#include <lib/subghz/protocols/protocol_items.h>
|
||||||
|
|
||||||
|
#define TAG "SubGhz"
|
||||||
|
|
||||||
|
SubGhzTxRx* subghz_txrx_alloc() {
|
||||||
|
SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx));
|
||||||
|
instance->setting = subghz_setting_alloc();
|
||||||
|
subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user"));
|
||||||
|
|
||||||
|
instance->preset = malloc(sizeof(SubGhzRadioPreset));
|
||||||
|
instance->preset->name = furi_string_alloc();
|
||||||
|
subghz_txrx_set_preset(
|
||||||
|
instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0);
|
||||||
|
|
||||||
|
instance->txrx_state = SubGhzTxRxStateSleep;
|
||||||
|
|
||||||
|
subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF);
|
||||||
|
subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable);
|
||||||
|
|
||||||
|
instance->worker = subghz_worker_alloc();
|
||||||
|
instance->fff_data = flipper_format_string_alloc();
|
||||||
|
|
||||||
|
instance->environment = subghz_environment_alloc();
|
||||||
|
instance->is_database_loaded = subghz_environment_load_keystore(
|
||||||
|
instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
|
||||||
|
subghz_environment_load_keystore(
|
||||||
|
instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
|
||||||
|
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
||||||
|
instance->environment, EXT_PATH("subghz/assets/came_atomo"));
|
||||||
|
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||||
|
instance->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
|
||||||
|
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||||
|
instance->environment, EXT_PATH("subghz/assets/nice_flor_s"));
|
||||||
|
subghz_environment_set_protocol_registry(
|
||||||
|
instance->environment, (void*)&subghz_protocol_registry);
|
||||||
|
instance->receiver = subghz_receiver_alloc_init(instance->environment);
|
||||||
|
|
||||||
|
subghz_worker_set_overrun_callback(
|
||||||
|
instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
|
||||||
|
subghz_worker_set_pair_callback(
|
||||||
|
instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
|
||||||
|
subghz_worker_set_context(instance->worker, instance->receiver);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_free(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
subghz_worker_free(instance->worker);
|
||||||
|
subghz_receiver_free(instance->receiver);
|
||||||
|
subghz_environment_free(instance->environment);
|
||||||
|
flipper_format_free(instance->fff_data);
|
||||||
|
furi_string_free(instance->preset->name);
|
||||||
|
subghz_setting_free(instance->setting);
|
||||||
|
free(instance->preset);
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->is_database_loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_set_preset(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
uint8_t* preset_data,
|
||||||
|
size_t preset_data_size) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_string_set(instance->preset->name, preset_name);
|
||||||
|
SubGhzRadioPreset* preset = instance->preset;
|
||||||
|
preset->frequency = frequency;
|
||||||
|
preset->data = preset_data;
|
||||||
|
preset->data_size = preset_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) {
|
||||||
|
UNUSED(instance);
|
||||||
|
const char* preset_name = "";
|
||||||
|
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
||||||
|
preset_name = "AM270";
|
||||||
|
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
||||||
|
preset_name = "AM650";
|
||||||
|
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
||||||
|
preset_name = "FM238";
|
||||||
|
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
||||||
|
preset_name = "FM476";
|
||||||
|
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
||||||
|
preset_name = "CUSTOM";
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Unknown preset");
|
||||||
|
}
|
||||||
|
return preset_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return *instance->preset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_get_frequency_and_modulation(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
FuriString* frequency,
|
||||||
|
FuriString* modulation) {
|
||||||
|
furi_assert(instance);
|
||||||
|
SubGhzRadioPreset* preset = instance->preset;
|
||||||
|
if(frequency != NULL) {
|
||||||
|
furi_string_printf(
|
||||||
|
frequency,
|
||||||
|
"%03ld.%02ld",
|
||||||
|
preset->frequency / 1000000 % 1000,
|
||||||
|
preset->frequency / 10000 % 100);
|
||||||
|
}
|
||||||
|
if(modulation != NULL) {
|
||||||
|
furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_hal_subghz_reset();
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
furi_hal_subghz_load_custom_preset(preset_data);
|
||||||
|
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||||
|
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
||||||
|
furi_crash("SubGhz: Incorrect RX frequency.");
|
||||||
|
}
|
||||||
|
furi_assert(
|
||||||
|
instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep);
|
||||||
|
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
|
||||||
|
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||||
|
furi_hal_subghz_flush_rx();
|
||||||
|
subghz_txrx_speaker_on(instance);
|
||||||
|
furi_hal_subghz_rx();
|
||||||
|
|
||||||
|
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker);
|
||||||
|
subghz_worker_start(instance->worker);
|
||||||
|
instance->txrx_state = SubGhzTxRxStateRx;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_txrx_idle(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
subghz_txrx_speaker_off(instance);
|
||||||
|
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_txrx_rx_end(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(instance->txrx_state == SubGhzTxRxStateRx);
|
||||||
|
|
||||||
|
if(subghz_worker_is_running(instance->worker)) {
|
||||||
|
subghz_worker_stop(instance->worker);
|
||||||
|
furi_hal_subghz_stop_async_rx();
|
||||||
|
}
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
subghz_txrx_speaker_off(instance);
|
||||||
|
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_sleep(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_hal_subghz_sleep();
|
||||||
|
instance->txrx_state = SubGhzTxRxStateSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
||||||
|
furi_crash("SubGhz: Incorrect TX frequency.");
|
||||||
|
}
|
||||||
|
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
furi_hal_subghz_set_frequency_and_path(frequency);
|
||||||
|
furi_hal_gpio_write(&gpio_cc1101_g0, false);
|
||||||
|
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||||
|
bool ret = furi_hal_subghz_tx();
|
||||||
|
if(ret) {
|
||||||
|
subghz_txrx_speaker_on(instance);
|
||||||
|
instance->txrx_state = SubGhzTxRxStateTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(flipper_format);
|
||||||
|
|
||||||
|
subghz_txrx_stop(instance);
|
||||||
|
|
||||||
|
SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||||
|
FuriString* temp_str = furi_string_alloc();
|
||||||
|
uint32_t repeat = 200;
|
||||||
|
do {
|
||||||
|
if(!flipper_format_rewind(flipper_format)) {
|
||||||
|
FURI_LOG_E(TAG, "Rewind error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
|
||||||
|
FURI_LOG_E(TAG, "Missing Protocol");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
|
||||||
|
FURI_LOG_E(TAG, "Unable Repeat");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = SubGhzTxRxStartTxStateOk;
|
||||||
|
|
||||||
|
SubGhzRadioPreset* preset = instance->preset;
|
||||||
|
instance->transmitter =
|
||||||
|
subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str));
|
||||||
|
|
||||||
|
if(instance->transmitter) {
|
||||||
|
if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) ==
|
||||||
|
SubGhzProtocolStatusOk) {
|
||||||
|
if(strcmp(furi_string_get_cstr(preset->name), "") != 0) {
|
||||||
|
subghz_txrx_begin(
|
||||||
|
instance,
|
||||||
|
subghz_setting_get_preset_data_by_name(
|
||||||
|
instance->setting, furi_string_get_cstr(preset->name)));
|
||||||
|
if(preset->frequency) {
|
||||||
|
if(!subghz_txrx_tx(instance, preset->frequency)) {
|
||||||
|
FURI_LOG_E(TAG, "Only Rx");
|
||||||
|
ret = SubGhzTxRxStartTxStateErrorOnlyRx;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(
|
||||||
|
TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name));
|
||||||
|
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret == SubGhzTxRxStartTxStateOk) {
|
||||||
|
//Start TX
|
||||||
|
furi_hal_subghz_start_async_tx(
|
||||||
|
subghz_transmitter_yield, instance->transmitter);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||||
|
}
|
||||||
|
if(ret != SubGhzTxRxStartTxStateOk) {
|
||||||
|
subghz_transmitter_free(instance->transmitter);
|
||||||
|
if(instance->txrx_state != SubGhzTxRxStateIDLE) {
|
||||||
|
subghz_txrx_idle(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while(false);
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_rx_start(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
subghz_txrx_stop(instance);
|
||||||
|
subghz_txrx_begin(
|
||||||
|
instance,
|
||||||
|
subghz_setting_get_preset_data_by_name(
|
||||||
|
subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name)));
|
||||||
|
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_set_need_save_callback(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
SubGhzTxRxNeedSaveCallback callback,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(instance);
|
||||||
|
instance->need_save_callback = callback;
|
||||||
|
instance->need_save_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(instance->txrx_state == SubGhzTxRxStateTx);
|
||||||
|
//Stop TX
|
||||||
|
furi_hal_subghz_stop_async_tx();
|
||||||
|
subghz_transmitter_stop(instance->transmitter);
|
||||||
|
subghz_transmitter_free(instance->transmitter);
|
||||||
|
|
||||||
|
//if protocol dynamic then we save the last upload
|
||||||
|
if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
|
||||||
|
if(instance->need_save_callback) {
|
||||||
|
instance->need_save_callback(instance->need_save_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subghz_txrx_idle(instance);
|
||||||
|
subghz_txrx_speaker_off(instance);
|
||||||
|
//Todo: Show message
|
||||||
|
// notification_message(notifications, &sequence_reset_red);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->fff_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_stop(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
switch(instance->txrx_state) {
|
||||||
|
case SubGhzTxRxStateTx:
|
||||||
|
subghz_txrx_tx_stop(instance);
|
||||||
|
subghz_txrx_speaker_unmute(instance);
|
||||||
|
break;
|
||||||
|
case SubGhzTxRxStateRx:
|
||||||
|
subghz_txrx_rx_end(instance);
|
||||||
|
subghz_txrx_speaker_mute(instance);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
switch(instance->hopper_state) {
|
||||||
|
case SubGhzHopperStateOFF:
|
||||||
|
case SubGhzHopperStatePause:
|
||||||
|
return;
|
||||||
|
case SubGhzHopperStateRSSITimeOut:
|
||||||
|
if(instance->hopper_timeout != 0) {
|
||||||
|
instance->hopper_timeout--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
float rssi = -127.0f;
|
||||||
|
if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) {
|
||||||
|
// See RSSI Calculation timings in CC1101 17.3 RSSI
|
||||||
|
rssi = furi_hal_subghz_get_rssi();
|
||||||
|
|
||||||
|
// Stay if RSSI is high enough
|
||||||
|
if(rssi > -90.0f) {
|
||||||
|
instance->hopper_timeout = 10;
|
||||||
|
instance->hopper_state = SubGhzHopperStateRSSITimeOut;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
instance->hopper_state = SubGhzHopperStateRunnig;
|
||||||
|
}
|
||||||
|
// Select next frequency
|
||||||
|
if(instance->hopper_idx_frequency <
|
||||||
|
subghz_setting_get_hopper_frequency_count(instance->setting) - 1) {
|
||||||
|
instance->hopper_idx_frequency++;
|
||||||
|
} else {
|
||||||
|
instance->hopper_idx_frequency = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(instance->txrx_state == SubGhzTxRxStateRx) {
|
||||||
|
subghz_txrx_rx_end(instance);
|
||||||
|
};
|
||||||
|
if(instance->txrx_state == SubGhzTxRxStateIDLE) {
|
||||||
|
subghz_receiver_reset(instance->receiver);
|
||||||
|
instance->preset->frequency =
|
||||||
|
subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency);
|
||||||
|
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->hopper_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) {
|
||||||
|
furi_assert(instance);
|
||||||
|
instance->hopper_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(instance->hopper_state == SubGhzHopperStatePause) {
|
||||||
|
instance->hopper_state = SubGhzHopperStateRunnig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(instance->hopper_state == SubGhzHopperStateRunnig) {
|
||||||
|
instance->hopper_state = SubGhzHopperStatePause;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_speaker_on(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||||
|
if(furi_hal_speaker_acquire(30)) {
|
||||||
|
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
||||||
|
} else {
|
||||||
|
instance->speaker_state = SubGhzSpeakerStateDisable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_speaker_off(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(instance->speaker_state != SubGhzSpeakerStateDisable) {
|
||||||
|
if(furi_hal_speaker_is_mine()) {
|
||||||
|
furi_hal_subghz_set_async_mirror_pin(NULL);
|
||||||
|
furi_hal_speaker_release();
|
||||||
|
if(instance->speaker_state == SubGhzSpeakerStateShutdown)
|
||||||
|
instance->speaker_state = SubGhzSpeakerStateDisable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_speaker_mute(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||||
|
if(furi_hal_speaker_is_mine()) {
|
||||||
|
furi_hal_subghz_set_async_mirror_pin(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||||
|
if(furi_hal_speaker_is_mine()) {
|
||||||
|
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) {
|
||||||
|
furi_assert(instance);
|
||||||
|
instance->speaker_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->speaker_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(name_protocol);
|
||||||
|
bool res = false;
|
||||||
|
instance->decoder_result =
|
||||||
|
subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol);
|
||||||
|
if(instance->decoder_result) {
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->decoder_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return (
|
||||||
|
(instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
|
||||||
|
SubGhzProtocolFlag_Save);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) {
|
||||||
|
furi_assert(instance);
|
||||||
|
const SubGhzProtocol* protocol = instance->decoder_result->protocol;
|
||||||
|
if(check_type) {
|
||||||
|
return (
|
||||||
|
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
|
||||||
|
protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
|
||||||
|
protocol->encoder->deserialize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) {
|
||||||
|
furi_assert(instance);
|
||||||
|
subghz_receiver_set_filter(instance->receiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_set_rx_calback(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
SubGhzReceiverCallback callback,
|
||||||
|
void* context) {
|
||||||
|
subghz_receiver_set_rx_callback(instance->receiver, callback, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
||||||
|
void* context) {
|
||||||
|
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
||||||
|
(SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter),
|
||||||
|
callback,
|
||||||
|
context);
|
||||||
|
}
|
||||||
290
applications/main/subghz/helpers/subghz_txrx.h
Normal file
290
applications/main/subghz/helpers/subghz_txrx.h
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "subghz_types.h"
|
||||||
|
|
||||||
|
#include <lib/subghz/subghz_worker.h>
|
||||||
|
#include <lib/subghz/subghz_setting.h>
|
||||||
|
#include <lib/subghz/receiver.h>
|
||||||
|
#include <lib/subghz/transmitter.h>
|
||||||
|
#include <lib/subghz/protocols/raw.h>
|
||||||
|
|
||||||
|
typedef struct SubGhzTxRx SubGhzTxRx;
|
||||||
|
|
||||||
|
typedef void (*SubGhzTxRxNeedSaveCallback)(void* context);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SubGhzTxRxStartTxStateOk,
|
||||||
|
SubGhzTxRxStartTxStateErrorOnlyRx,
|
||||||
|
SubGhzTxRxStartTxStateErrorParserOthers,
|
||||||
|
} SubGhzTxRxStartTxState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate SubGhzTxRx
|
||||||
|
*
|
||||||
|
* @return SubGhzTxRx* pointer to SubGhzTxRx
|
||||||
|
*/
|
||||||
|
SubGhzTxRx* subghz_txrx_alloc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free SubGhzTxRx
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_free(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the database is loaded
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return bool True if the database is loaded
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set preset
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset_name Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param preset_data Data of preset
|
||||||
|
* @param preset_data_size Size of preset data
|
||||||
|
*/
|
||||||
|
void subghz_txrx_set_preset(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
uint8_t* preset_data,
|
||||||
|
size_t preset_data_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get name of preset
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset String of preset
|
||||||
|
* @return const char* Name of preset
|
||||||
|
*/
|
||||||
|
const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get of preset
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzRadioPreset Preset
|
||||||
|
*/
|
||||||
|
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get string frequency and modulation
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param frequency Pointer to a string frequency
|
||||||
|
* @param modulation Pointer to a string modulation
|
||||||
|
*/
|
||||||
|
void subghz_txrx_get_frequency_and_modulation(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
FuriString* frequency,
|
||||||
|
FuriString* modulation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start TX CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param flipper_format Pointer to a FlipperFormat
|
||||||
|
* @return SubGhzTxRxStartTxState
|
||||||
|
*/
|
||||||
|
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start RX CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_rx_start(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop TX/RX CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_stop(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set sleep mode CC1101
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_sleep(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update frequency CC1101 in automatic mode (hopper)
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_hopper_update(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get state hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzHopperState
|
||||||
|
*/
|
||||||
|
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set state hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param state State hopper
|
||||||
|
*/
|
||||||
|
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpause hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_hopper_unpause(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set pause hopper
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker on
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_speaker_on(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker off
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_speaker_off(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker mute
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_speaker_mute(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speaker unmute
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
*/
|
||||||
|
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set state speaker
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param state State speaker
|
||||||
|
*/
|
||||||
|
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get state speaker
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzSpeakerState
|
||||||
|
*/
|
||||||
|
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load decoder by name protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param name_protocol Name protocol
|
||||||
|
* @return bool True if the decoder is loaded
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get decoder
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase
|
||||||
|
*/
|
||||||
|
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set callback for save data
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param callback Callback for save data
|
||||||
|
* @param context Context for callback
|
||||||
|
*/
|
||||||
|
void subghz_txrx_set_need_save_callback(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
SubGhzTxRxNeedSaveCallback callback,
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get pointer to a load data key
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return FlipperFormat*
|
||||||
|
*/
|
||||||
|
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get pointer to a SugGhzSetting
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return SubGhzSetting*
|
||||||
|
*/
|
||||||
|
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is it possible to save this protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return bool True if it is possible to save this protocol
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is it possible to send this protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @return bool True if it is possible to send this protocol
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set filter, what types of decoder to use
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param filter Filter
|
||||||
|
*/
|
||||||
|
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set callback for receive data
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param callback Callback for receive data
|
||||||
|
* @param context Context for callback
|
||||||
|
*/
|
||||||
|
void subghz_txrx_set_rx_calback(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
SubGhzReceiverCallback callback,
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set callback for Raw decoder, end of data transfer
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param callback Callback for Raw decoder, end of data transfer
|
||||||
|
* @param context Context for callback
|
||||||
|
*/
|
||||||
|
void subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
||||||
|
void* context);
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
#include "subghz_txrx_i.h"
|
||||||
|
#include "subghz_txrx_create_potocol_key.h"
|
||||||
|
#include <lib/subghz/transmitter.h>
|
||||||
|
#include <lib/subghz/protocols/protocol_items.h>
|
||||||
|
#include <lib/subghz/protocols/protocol_items.h>
|
||||||
|
#include <lib/subghz/protocols/keeloq.h>
|
||||||
|
#include <lib/subghz/protocols/secplus_v1.h>
|
||||||
|
#include <lib/subghz/protocols/secplus_v2.h>
|
||||||
|
|
||||||
|
#include <flipper_format/flipper_format_i.h>
|
||||||
|
#include <lib/toolbox/stream/stream.h>
|
||||||
|
#include <lib/subghz/protocols/raw.h>
|
||||||
|
|
||||||
|
#define TAG "SubGhzCreateProtocolKey"
|
||||||
|
|
||||||
|
bool subghz_txrx_gen_data_protocol(
|
||||||
|
void* context,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
const char* protocol_name,
|
||||||
|
uint64_t key,
|
||||||
|
uint32_t bit) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzTxRx* instance = context;
|
||||||
|
|
||||||
|
bool res = false;
|
||||||
|
|
||||||
|
subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0);
|
||||||
|
instance->decoder_result =
|
||||||
|
subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name);
|
||||||
|
|
||||||
|
if(instance->decoder_result == NULL) {
|
||||||
|
//TODO: Error
|
||||||
|
// furi_string_set(error_str, "Protocol not\nfound!");
|
||||||
|
// scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub);
|
||||||
|
FURI_LOG_E(TAG, "Protocol not found!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data);
|
||||||
|
stream_clean(fff_data_stream);
|
||||||
|
if(subghz_protocol_decoder_base_serialize(
|
||||||
|
instance->decoder_result, instance->fff_data, instance->preset) !=
|
||||||
|
SubGhzProtocolStatusOk) {
|
||||||
|
FURI_LOG_E(TAG, "Unable to serialize");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) {
|
||||||
|
FURI_LOG_E(TAG, "Unable to update Bit");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t key_data[sizeof(uint64_t)] = {0};
|
||||||
|
for(size_t i = 0; i < sizeof(uint64_t); i++) {
|
||||||
|
key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF;
|
||||||
|
}
|
||||||
|
if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) {
|
||||||
|
FURI_LOG_E(TAG, "Unable to update Key");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res = true;
|
||||||
|
} while(false);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_gen_data_protocol_and_te(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
const char* protocol_name,
|
||||||
|
uint64_t key,
|
||||||
|
uint32_t bit,
|
||||||
|
uint32_t te) {
|
||||||
|
furi_assert(instance);
|
||||||
|
bool ret = false;
|
||||||
|
if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) {
|
||||||
|
if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) {
|
||||||
|
FURI_LOG_E(TAG, "Unable to update Te");
|
||||||
|
} else {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_gen_keelog_protocol(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* name_preset,
|
||||||
|
uint32_t frequency,
|
||||||
|
const char* name_sysmem,
|
||||||
|
uint32_t serial,
|
||||||
|
uint8_t btn,
|
||||||
|
uint16_t cnt) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
serial &= 0x0FFFFFFF;
|
||||||
|
instance->transmitter =
|
||||||
|
subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
||||||
|
subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0);
|
||||||
|
if(instance->transmitter) {
|
||||||
|
subghz_protocol_keeloq_create_data(
|
||||||
|
subghz_transmitter_get_protocol_instance(instance->transmitter),
|
||||||
|
instance->fff_data,
|
||||||
|
serial,
|
||||||
|
btn,
|
||||||
|
cnt,
|
||||||
|
name_sysmem,
|
||||||
|
instance->preset);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
subghz_transmitter_free(instance->transmitter);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_gen_secplus_v2_protocol(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* name_preset,
|
||||||
|
uint32_t frequency,
|
||||||
|
uint32_t serial,
|
||||||
|
uint8_t btn,
|
||||||
|
uint32_t cnt) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
instance->transmitter =
|
||||||
|
subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
||||||
|
subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0);
|
||||||
|
if(instance->transmitter) {
|
||||||
|
subghz_protocol_secplus_v2_create_data(
|
||||||
|
subghz_transmitter_get_protocol_instance(instance->transmitter),
|
||||||
|
instance->fff_data,
|
||||||
|
serial,
|
||||||
|
btn,
|
||||||
|
cnt,
|
||||||
|
instance->preset);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_txrx_gen_secplus_v1_protocol(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* name_preset,
|
||||||
|
uint32_t frequency) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
uint32_t serial = (uint32_t)rand();
|
||||||
|
while(!subghz_protocol_secplus_v1_check_fixed(serial)) {
|
||||||
|
serial = (uint32_t)rand();
|
||||||
|
}
|
||||||
|
if(subghz_txrx_gen_data_protocol(
|
||||||
|
instance,
|
||||||
|
name_preset,
|
||||||
|
frequency,
|
||||||
|
SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
|
||||||
|
(uint64_t)serial << 32 | 0xE6000000,
|
||||||
|
42)) {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "subghz_types.h"
|
||||||
|
#include "subghz_txrx.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data for protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset_name Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param protocol_name Name of protocol
|
||||||
|
* @param key Key
|
||||||
|
* @param bit Bit
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_gen_data_protocol(
|
||||||
|
void* context,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
const char* protocol_name,
|
||||||
|
uint64_t key,
|
||||||
|
uint32_t bit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data for protocol and te
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param preset_name Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param protocol_name Name of protocol
|
||||||
|
* @param key Key
|
||||||
|
* @param bit Bit
|
||||||
|
* @param te Te
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_gen_data_protocol_and_te(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
const char* protocol_name,
|
||||||
|
uint64_t key,
|
||||||
|
uint32_t bit,
|
||||||
|
uint32_t te);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data Keeloq protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param name_preset Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param name_sysmem Name of Keeloq sysmem
|
||||||
|
* @param serial Serial number
|
||||||
|
* @param btn Button
|
||||||
|
* @param cnt Counter
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_gen_keelog_protocol(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* name_preset,
|
||||||
|
uint32_t frequency,
|
||||||
|
const char* name_sysmem,
|
||||||
|
uint32_t serial,
|
||||||
|
uint8_t btn,
|
||||||
|
uint16_t cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data SecPlus v2 protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param name_preset Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @param serial Serial number
|
||||||
|
* @param btn Button
|
||||||
|
* @param cnt Counter
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_gen_secplus_v2_protocol(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* name_preset,
|
||||||
|
uint32_t frequency,
|
||||||
|
uint32_t serial,
|
||||||
|
uint8_t btn,
|
||||||
|
uint32_t cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data SecPlus v1 protocol
|
||||||
|
*
|
||||||
|
* @param instance Pointer to a SubGhzTxRx
|
||||||
|
* @param name_preset Name of preset
|
||||||
|
* @param frequency Frequency in Hz
|
||||||
|
* @return bool True if success
|
||||||
|
*/
|
||||||
|
bool subghz_txrx_gen_secplus_v1_protocol(
|
||||||
|
SubGhzTxRx* instance,
|
||||||
|
const char* name_preset,
|
||||||
|
uint32_t frequency);
|
||||||
27
applications/main/subghz/helpers/subghz_txrx_i.h
Normal file
27
applications/main/subghz/helpers/subghz_txrx_i.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "subghz_txrx.h"
|
||||||
|
|
||||||
|
struct SubGhzTxRx {
|
||||||
|
SubGhzWorker* worker;
|
||||||
|
|
||||||
|
SubGhzEnvironment* environment;
|
||||||
|
SubGhzReceiver* receiver;
|
||||||
|
SubGhzTransmitter* transmitter;
|
||||||
|
SubGhzProtocolDecoderBase* decoder_result;
|
||||||
|
FlipperFormat* fff_data;
|
||||||
|
|
||||||
|
SubGhzRadioPreset* preset;
|
||||||
|
SubGhzSetting* setting;
|
||||||
|
|
||||||
|
uint8_t hopper_timeout;
|
||||||
|
uint8_t hopper_idx_frequency;
|
||||||
|
bool is_database_loaded;
|
||||||
|
SubGhzHopperState hopper_state;
|
||||||
|
|
||||||
|
SubGhzTxRxState txrx_state;
|
||||||
|
SubGhzSpeakerState speaker_state;
|
||||||
|
|
||||||
|
SubGhzTxRxNeedSaveCallback need_save_callback;
|
||||||
|
void* need_save_context;
|
||||||
|
};
|
||||||
@@ -77,3 +77,10 @@ typedef enum {
|
|||||||
SubGhzViewIdTestCarrier,
|
SubGhzViewIdTestCarrier,
|
||||||
SubGhzViewIdTestPacket,
|
SubGhzViewIdTestPacket,
|
||||||
} SubGhzViewId;
|
} SubGhzViewId;
|
||||||
|
|
||||||
|
/** SubGhz load type file */
|
||||||
|
typedef enum {
|
||||||
|
SubGhzLoadTypeFileNoLoad,
|
||||||
|
SubGhzLoadTypeFileKey,
|
||||||
|
SubGhzLoadTypeFileRaw,
|
||||||
|
} SubGhzLoadTypeFile;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ void subghz_scene_delete_on_enter(void* context) {
|
|||||||
modulation_str = furi_string_alloc();
|
modulation_str = furi_string_alloc();
|
||||||
text = furi_string_alloc();
|
text = furi_string_alloc();
|
||||||
|
|
||||||
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
|
subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
subghz->widget,
|
subghz->widget,
|
||||||
78,
|
78,
|
||||||
@@ -37,7 +37,7 @@ void subghz_scene_delete_on_enter(void* context) {
|
|||||||
AlignTop,
|
AlignTop,
|
||||||
FontSecondary,
|
FontSecondary,
|
||||||
furi_string_get_cstr(modulation_str));
|
furi_string_get_cstr(modulation_str));
|
||||||
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
|
subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text);
|
||||||
widget_add_string_multiline_element(
|
widget_add_string_multiline_element(
|
||||||
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
|
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ void subghz_scene_delete_raw_on_enter(void* context) {
|
|||||||
|
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
|
subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
|
||||||
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
|
subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
subghz->widget,
|
subghz->widget,
|
||||||
35,
|
35,
|
||||||
|
|||||||
@@ -37,27 +37,23 @@ void subghz_scene_need_saving_on_enter(void* context) {
|
|||||||
bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
|
bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
if(event.type == SceneManagerEventTypeBack) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
|
||||||
scene_manager_previous_scene(subghz->scene_manager);
|
scene_manager_previous_scene(subghz->scene_manager);
|
||||||
return true;
|
return true;
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubGhzCustomEventSceneStay) {
|
if(event.event == SubGhzCustomEventSceneStay) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
|
||||||
scene_manager_previous_scene(subghz->scene_manager);
|
scene_manager_previous_scene(subghz->scene_manager);
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventSceneExit) {
|
} else if(event.event == SubGhzCustomEventSceneExit) {
|
||||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
|
SubGhzRxKeyState state = subghz_rx_key_state_get(subghz);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
|
||||||
subghz_preset_init(
|
|
||||||
subghz,
|
if(state == SubGhzRxKeyStateExit) {
|
||||||
"AM650",
|
subghz_set_default_preset(subghz);
|
||||||
subghz_setting_get_default_frequency(subghz->setting),
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneStart);
|
subghz->scene_manager, SubGhzSceneStart);
|
||||||
} else {
|
} else {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
|
||||||
scene_manager_previous_scene(subghz->scene_manager);
|
scene_manager_previous_scene(subghz->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,9 @@
|
|||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
#include <lib/subghz/protocols/raw.h>
|
#include <lib/subghz/protocols/raw.h>
|
||||||
#include <lib/toolbox/path.h>
|
#include <lib/toolbox/path.h>
|
||||||
#include <float_tools.h>
|
|
||||||
|
|
||||||
#define RAW_FILE_NAME "Raw_signal_"
|
#define RAW_FILE_NAME "Raw_signal_"
|
||||||
#define TAG "SubGhzSceneReadRAW"
|
#define TAG "SubGhzSceneReadRAW"
|
||||||
#define RAW_THRESHOLD_RSSI_LOW_COUNT 10
|
|
||||||
|
|
||||||
bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
|
bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@@ -15,12 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
|
|||||||
FuriString* temp_str;
|
FuriString* temp_str;
|
||||||
temp_str = furi_string_alloc();
|
temp_str = furi_string_alloc();
|
||||||
do {
|
do {
|
||||||
if(!flipper_format_rewind(subghz->txrx->fff_data)) {
|
FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx);
|
||||||
|
if(!flipper_format_rewind(fff_data)) {
|
||||||
FURI_LOG_E(TAG, "Rewind error");
|
FURI_LOG_E(TAG, "Rewind error");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) {
|
if(!flipper_format_read_string(fff_data, "File_name", temp_str)) {
|
||||||
FURI_LOG_E(TAG, "Missing File_name");
|
FURI_LOG_E(TAG, "Missing File_name");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -38,13 +37,10 @@ static void subghz_scene_read_raw_update_statusbar(void* context) {
|
|||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
FuriString* frequency_str;
|
FuriString* frequency_str = furi_string_alloc();
|
||||||
FuriString* modulation_str;
|
FuriString* modulation_str = furi_string_alloc();
|
||||||
|
|
||||||
frequency_str = furi_string_alloc();
|
subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
|
||||||
modulation_str = furi_string_alloc();
|
|
||||||
|
|
||||||
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
|
|
||||||
subghz_read_raw_add_data_statusbar(
|
subghz_read_raw_add_data_statusbar(
|
||||||
subghz->subghz_read_raw,
|
subghz->subghz_read_raw,
|
||||||
furi_string_get_cstr(frequency_str),
|
furi_string_get_cstr(frequency_str),
|
||||||
@@ -69,13 +65,13 @@ void subghz_scene_read_raw_callback_end_tx(void* context) {
|
|||||||
|
|
||||||
void subghz_scene_read_raw_on_enter(void* context) {
|
void subghz_scene_read_raw_on_enter(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
FuriString* file_name;
|
FuriString* file_name = furi_string_alloc();
|
||||||
file_name = furi_string_alloc();
|
|
||||||
|
|
||||||
switch(subghz->txrx->rx_key_state) {
|
float threshold_rssi = subghz_threshold_rssi_get(subghz->threshold_rssi);
|
||||||
|
switch(subghz_rx_key_state_get(subghz)) {
|
||||||
case SubGhzRxKeyStateBack:
|
case SubGhzRxKeyStateBack:
|
||||||
subghz_read_raw_set_status(
|
subghz_read_raw_set_status(
|
||||||
subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi);
|
subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", threshold_rssi);
|
||||||
break;
|
break;
|
||||||
case SubGhzRxKeyStateRAWLoad:
|
case SubGhzRxKeyStateRAWLoad:
|
||||||
path_extract_filename(subghz->file_path, file_name, true);
|
path_extract_filename(subghz->file_path, file_name, true);
|
||||||
@@ -83,8 +79,7 @@ void subghz_scene_read_raw_on_enter(void* context) {
|
|||||||
subghz->subghz_read_raw,
|
subghz->subghz_read_raw,
|
||||||
SubGhzReadRAWStatusLoadKeyTX,
|
SubGhzReadRAWStatusLoadKeyTX,
|
||||||
furi_string_get_cstr(file_name),
|
furi_string_get_cstr(file_name),
|
||||||
subghz->txrx->raw_threshold_rssi);
|
threshold_rssi);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
|
||||||
break;
|
break;
|
||||||
case SubGhzRxKeyStateRAWSave:
|
case SubGhzRxKeyStateRAWSave:
|
||||||
path_extract_filename(subghz->file_path, file_name, true);
|
path_extract_filename(subghz->file_path, file_name, true);
|
||||||
@@ -92,66 +87,51 @@ void subghz_scene_read_raw_on_enter(void* context) {
|
|||||||
subghz->subghz_read_raw,
|
subghz->subghz_read_raw,
|
||||||
SubGhzReadRAWStatusSaveKey,
|
SubGhzReadRAWStatusSaveKey,
|
||||||
furi_string_get_cstr(file_name),
|
furi_string_get_cstr(file_name),
|
||||||
subghz->txrx->raw_threshold_rssi);
|
threshold_rssi);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
subghz_read_raw_set_status(
|
subghz_read_raw_set_status(
|
||||||
subghz->subghz_read_raw,
|
subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", threshold_rssi);
|
||||||
SubGhzReadRAWStatusStart,
|
|
||||||
"",
|
|
||||||
subghz->txrx->raw_threshold_rssi);
|
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) {
|
||||||
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
|
||||||
|
}
|
||||||
furi_string_free(file_name);
|
furi_string_free(file_name);
|
||||||
subghz_scene_read_raw_update_statusbar(subghz);
|
subghz_scene_read_raw_update_statusbar(subghz);
|
||||||
|
|
||||||
//set callback view raw
|
//set callback view raw
|
||||||
subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
|
subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
|
||||||
|
|
||||||
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
|
furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME));
|
||||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME);
|
|
||||||
furi_assert(subghz->txrx->decoder_result);
|
|
||||||
|
|
||||||
//set filter RAW feed
|
//set filter RAW feed
|
||||||
subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW);
|
subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW);
|
||||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
|
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
SubGhzProtocolDecoderRAW* decoder_raw =
|
||||||
|
(SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx);
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
switch(event.event) {
|
switch(event.event) {
|
||||||
case SubGhzCustomEventViewReadRAWBack:
|
case SubGhzCustomEventViewReadRAWBack:
|
||||||
//Stop TX
|
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_tx_stop(subghz);
|
|
||||||
subghz_sleep(subghz);
|
|
||||||
}
|
|
||||||
//Stop RX
|
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
|
||||||
subghz_rx_end(subghz);
|
|
||||||
subghz_sleep(subghz);
|
|
||||||
};
|
|
||||||
//Stop save file
|
//Stop save file
|
||||||
subghz_protocol_raw_save_to_file_stop(
|
subghz_protocol_raw_save_to_file_stop(decoder_raw);
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
//needed save?
|
//needed save?
|
||||||
if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) ||
|
if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) ||
|
||||||
(subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) {
|
(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateBack)) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||||
} else {
|
} else {
|
||||||
//Restore default setting
|
//Restore default setting
|
||||||
subghz_preset_init(
|
subghz_set_default_preset(subghz);
|
||||||
subghz,
|
|
||||||
"AM650",
|
|
||||||
subghz_setting_get_default_frequency(subghz->setting),
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneSaved)) {
|
subghz->scene_manager, SubGhzSceneSaved)) {
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
@@ -165,16 +145,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWTXRXStop:
|
case SubGhzCustomEventViewReadRAWTXRXStop:
|
||||||
//Stop TX
|
subghz_txrx_stop(subghz->txrx);
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
|
||||||
subghz_tx_stop(subghz);
|
|
||||||
subghz_sleep(subghz);
|
|
||||||
}
|
|
||||||
//Stop RX
|
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
|
||||||
subghz_rx_end(subghz);
|
|
||||||
subghz_sleep(subghz);
|
|
||||||
};
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
@@ -187,13 +158,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWErase:
|
case SubGhzCustomEventViewReadRAWErase:
|
||||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
|
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
|
||||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
if(subghz_scene_read_raw_update_filename(subghz)) {
|
||||||
furi_string_set(subghz->file_path_tmp, subghz->file_path);
|
furi_string_set(subghz->file_path_tmp, subghz->file_path);
|
||||||
subghz_delete_file(subghz);
|
subghz_delete_file(subghz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
|
||||||
notification_message(subghz->notifications, &sequence_reset_rgb);
|
notification_message(subghz->notifications, &sequence_reset_rgb);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
@@ -203,7 +174,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
if(subghz_scene_read_raw_update_filename(subghz)) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -223,33 +194,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
|
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
|
||||||
//start send
|
//start send
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
|
||||||
subghz_rx_end(subghz);
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
|
||||||
}
|
subghz_read_raw_set_status(
|
||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
subghz->subghz_read_raw,
|
||||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
SubGhzReadRAWStatusIDLE,
|
||||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
"",
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
subghz_threshold_rssi_get(subghz->threshold_rssi));
|
||||||
subghz_read_raw_set_status(
|
} else {
|
||||||
subghz->subghz_read_raw,
|
if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) ||
|
||||||
SubGhzReadRAWStatusIDLE,
|
!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
"",
|
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
||||||
subghz->txrx->raw_threshold_rssi);
|
|
||||||
} else {
|
|
||||||
if(scene_manager_has_previous_scene(
|
|
||||||
subghz->scene_manager, SubGhzSceneSaved) ||
|
|
||||||
!scene_manager_has_previous_scene(
|
|
||||||
subghz->scene_manager, SubGhzSceneStart)) {
|
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
|
||||||
}
|
|
||||||
// set callback end tx
|
|
||||||
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
|
||||||
(SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(
|
|
||||||
subghz->txrx->transmitter),
|
|
||||||
subghz_scene_read_raw_callback_end_tx,
|
|
||||||
subghz);
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
|
||||||
}
|
}
|
||||||
|
// set callback end tx
|
||||||
|
subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||||
|
subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz);
|
||||||
|
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
@@ -263,33 +223,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWSendStop:
|
case SubGhzCustomEventViewReadRAWSendStop:
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_speaker_unmute(subghz);
|
|
||||||
subghz_tx_stop(subghz);
|
|
||||||
subghz_sleep(subghz);
|
|
||||||
}
|
|
||||||
subghz_read_raw_stop_send(subghz->subghz_read_raw);
|
subghz_read_raw_stop_send(subghz->subghz_read_raw);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWIDLE:
|
case SubGhzCustomEventViewReadRAWIDLE:
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_rx_end(subghz);
|
size_t spl_count = subghz_protocol_raw_get_sample_write(decoder_raw);
|
||||||
subghz_sleep(subghz);
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t spl_count = subghz_protocol_raw_get_sample_write(
|
subghz_protocol_raw_save_to_file_stop(decoder_raw);
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
|
|
||||||
|
|
||||||
subghz_protocol_raw_save_to_file_stop(
|
FuriString* temp_str = furi_string_alloc();
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
|
|
||||||
|
|
||||||
FuriString* temp_str;
|
|
||||||
temp_str = furi_string_alloc();
|
|
||||||
furi_string_printf(
|
furi_string_printf(
|
||||||
temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
|
temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
|
||||||
subghz_protocol_raw_gen_fff_data(
|
subghz_protocol_raw_gen_fff_data(
|
||||||
subghz->txrx->fff_data, furi_string_get_cstr(temp_str));
|
subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str));
|
||||||
furi_string_free(temp_str);
|
furi_string_free(temp_str);
|
||||||
|
|
||||||
if(spl_count > 0) {
|
if(spl_count > 0) {
|
||||||
@@ -299,32 +248,21 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
|
||||||
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWREC:
|
case SubGhzCustomEventViewReadRAWREC:
|
||||||
if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) {
|
if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) {
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||||
} else {
|
} else {
|
||||||
subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT;
|
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||||
if(subghz_protocol_raw_save_to_file_init(
|
if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) {
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
|
|
||||||
RAW_FILE_NAME,
|
|
||||||
subghz->txrx->preset)) {
|
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
|
DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
|
||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
subghz_txrx_rx_start(subghz->txrx);
|
||||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
|
||||||
subghz_begin(
|
|
||||||
subghz,
|
|
||||||
subghz_setting_get_preset_data_by_name(
|
|
||||||
subghz->setting,
|
|
||||||
furi_string_get_cstr(subghz->txrx->preset->name)));
|
|
||||||
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
|
||||||
}
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
|
||||||
} else {
|
} else {
|
||||||
furi_string_set(subghz->error_str, "Function requires\nan SD card.");
|
furi_string_set(subghz->error_str, "Function requires\nan SD card.");
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||||
@@ -337,7 +275,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
|
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
|
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||||
} else {
|
} else {
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
@@ -356,41 +294,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
switch(subghz->state_notifications) {
|
switch(subghz->state_notifications) {
|
||||||
case SubGhzNotificationStateRx:
|
case SubGhzNotificationStateRx:
|
||||||
notification_message(subghz->notifications, &sequence_blink_cyan_10);
|
notification_message(subghz->notifications, &sequence_blink_cyan_10);
|
||||||
|
|
||||||
subghz_read_raw_update_sample_write(
|
subghz_read_raw_update_sample_write(
|
||||||
subghz->subghz_read_raw,
|
subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw));
|
||||||
subghz_protocol_raw_get_sample_write(
|
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result));
|
|
||||||
|
|
||||||
float rssi = furi_hal_subghz_get_rssi();
|
|
||||||
|
|
||||||
if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) {
|
|
||||||
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
|
|
||||||
subghz_protocol_raw_save_to_file_pause(
|
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
|
|
||||||
} else {
|
|
||||||
if(rssi < subghz->txrx->raw_threshold_rssi) {
|
|
||||||
subghz->txrx->raw_threshold_rssi_low_count++;
|
|
||||||
if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) {
|
|
||||||
subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT;
|
|
||||||
}
|
|
||||||
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false);
|
|
||||||
} else {
|
|
||||||
subghz->txrx->raw_threshold_rssi_low_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) {
|
|
||||||
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false);
|
|
||||||
subghz_protocol_raw_save_to_file_pause(
|
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true);
|
|
||||||
subghz_speaker_mute(subghz);
|
|
||||||
} else {
|
|
||||||
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
|
|
||||||
subghz_protocol_raw_save_to_file_pause(
|
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
|
|
||||||
subghz_speaker_unmute(subghz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
SubGhzThresholdRssiData ret_rssi =
|
||||||
|
subghz_threshold_get_rssi_data(subghz->threshold_rssi);
|
||||||
|
subghz_read_raw_add_data_rssi(
|
||||||
|
subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above);
|
||||||
|
subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above);
|
||||||
break;
|
break;
|
||||||
case SubGhzNotificationStateTx:
|
case SubGhzNotificationStateTx:
|
||||||
notification_message(subghz->notifications, &sequence_blink_magenta_10);
|
notification_message(subghz->notifications, &sequence_blink_magenta_10);
|
||||||
@@ -407,13 +319,10 @@ void subghz_scene_read_raw_on_exit(void* context) {
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
//Stop CC1101
|
//Stop CC1101
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_rx_end(subghz);
|
|
||||||
subghz_sleep(subghz);
|
|
||||||
};
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
notification_message(subghz->notifications, &sequence_reset_rgb);
|
notification_message(subghz->notifications, &sequence_reset_rgb);
|
||||||
|
|
||||||
//filter restoration
|
//filter restoration
|
||||||
subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
|
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,16 +35,12 @@ static const NotificationSequence subghs_sequence_rx_locked = {
|
|||||||
|
|
||||||
static void subghz_scene_receiver_update_statusbar(void* context) {
|
static void subghz_scene_receiver_update_statusbar(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
FuriString* history_stat_str;
|
FuriString* history_stat_str = furi_string_alloc();
|
||||||
history_stat_str = furi_string_alloc();
|
if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) {
|
||||||
if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) {
|
FuriString* frequency_str = furi_string_alloc();
|
||||||
FuriString* frequency_str;
|
FuriString* modulation_str = furi_string_alloc();
|
||||||
FuriString* modulation_str;
|
|
||||||
|
|
||||||
frequency_str = furi_string_alloc();
|
subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
|
||||||
modulation_str = furi_string_alloc();
|
|
||||||
|
|
||||||
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
|
|
||||||
|
|
||||||
subghz_view_receiver_add_data_statusbar(
|
subghz_view_receiver_add_data_statusbar(
|
||||||
subghz->subghz_receiver,
|
subghz->subghz_receiver,
|
||||||
@@ -74,80 +70,68 @@ static void subghz_scene_add_to_history_callback(
|
|||||||
void* context) {
|
void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
FuriString* str_buff;
|
SubGhzHistory* history = subghz->history;
|
||||||
str_buff = furi_string_alloc();
|
FuriString* str_buff = furi_string_alloc();
|
||||||
|
|
||||||
if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) {
|
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||||
|
|
||||||
|
if(subghz_history_add_to_history(history, decoder_base, &preset)) {
|
||||||
furi_string_reset(str_buff);
|
furi_string_reset(str_buff);
|
||||||
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateRxDone;
|
subghz->state_notifications = SubGhzNotificationStateRxDone;
|
||||||
|
uint16_t item_history = subghz_history_get_item(history);
|
||||||
subghz_history_get_text_item_menu(
|
subghz_history_get_text_item_menu(history, str_buff, item_history - 1);
|
||||||
subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
|
|
||||||
subghz_view_receiver_add_item_to_menu(
|
subghz_view_receiver_add_item_to_menu(
|
||||||
subghz->subghz_receiver,
|
subghz->subghz_receiver,
|
||||||
furi_string_get_cstr(str_buff),
|
furi_string_get_cstr(str_buff),
|
||||||
subghz_history_get_type_protocol(
|
subghz_history_get_type_protocol(history, item_history - 1));
|
||||||
subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
|
|
||||||
|
|
||||||
subghz_scene_receiver_update_statusbar(subghz);
|
subghz_scene_receiver_update_statusbar(subghz);
|
||||||
}
|
}
|
||||||
subghz_receiver_reset(receiver);
|
subghz_receiver_reset(receiver);
|
||||||
furi_string_free(str_buff);
|
furi_string_free(str_buff);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_scene_receiver_on_enter(void* context) {
|
void subghz_scene_receiver_on_enter(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
SubGhzHistory* history = subghz->history;
|
||||||
|
|
||||||
FuriString* str_buff;
|
FuriString* str_buff;
|
||||||
str_buff = furi_string_alloc();
|
str_buff = furi_string_alloc();
|
||||||
|
|
||||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
|
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) {
|
||||||
subghz_preset_init(
|
subghz_set_default_preset(subghz);
|
||||||
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
subghz_history_reset(history);
|
||||||
subghz_history_reset(subghz->txrx->history);
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock);
|
subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz));
|
||||||
|
|
||||||
//Load history to receiver
|
//Load history to receiver
|
||||||
subghz_view_receiver_exit(subghz->subghz_receiver);
|
subghz_view_receiver_exit(subghz->subghz_receiver);
|
||||||
for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
|
for(uint8_t i = 0; i < subghz_history_get_item(history); i++) {
|
||||||
furi_string_reset(str_buff);
|
furi_string_reset(str_buff);
|
||||||
subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
|
subghz_history_get_text_item_menu(history, str_buff, i);
|
||||||
subghz_view_receiver_add_item_to_menu(
|
subghz_view_receiver_add_item_to_menu(
|
||||||
subghz->subghz_receiver,
|
subghz->subghz_receiver,
|
||||||
furi_string_get_cstr(str_buff),
|
furi_string_get_cstr(str_buff),
|
||||||
subghz_history_get_type_protocol(subghz->txrx->history, i));
|
subghz_history_get_type_protocol(history, i));
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
|
||||||
}
|
}
|
||||||
furi_string_free(str_buff);
|
furi_string_free(str_buff);
|
||||||
subghz_scene_receiver_update_statusbar(subghz);
|
subghz_scene_receiver_update_statusbar(subghz);
|
||||||
subghz_view_receiver_set_callback(
|
subghz_view_receiver_set_callback(
|
||||||
subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
|
subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
|
||||||
subghz_receiver_set_rx_callback(
|
subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
|
||||||
subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz);
|
|
||||||
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
subghz_txrx_rx_start(subghz->txrx);
|
||||||
subghz_rx_end(subghz);
|
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen);
|
||||||
};
|
|
||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
|
||||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
|
||||||
subghz_begin(
|
|
||||||
subghz,
|
|
||||||
subghz_setting_get_preset_data_by_name(
|
|
||||||
subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
|
|
||||||
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
|
||||||
}
|
|
||||||
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
|
|
||||||
|
|
||||||
//to use a universal decoder, we are looking for a link to it
|
//to use a universal decoder, we are looking for a link to it
|
||||||
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
|
furi_check(
|
||||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME);
|
subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME));
|
||||||
furi_assert(subghz->txrx->decoder_result);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
|
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
|
||||||
}
|
}
|
||||||
@@ -160,41 +144,31 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubGhzCustomEventViewReceiverBack:
|
case SubGhzCustomEventViewReceiverBack:
|
||||||
// Stop CC1101 Rx
|
// Stop CC1101 Rx
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_rx_end(subghz);
|
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
|
||||||
subghz_sleep(subghz);
|
subghz->idx_menu_chosen = 0;
|
||||||
};
|
subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
|
||||||
subghz->txrx->idx_menu_chosen = 0;
|
|
||||||
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
|
|
||||||
|
|
||||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
|
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||||
} else {
|
} else {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
|
||||||
subghz_preset_init(
|
subghz_set_default_preset(subghz);
|
||||||
subghz,
|
|
||||||
"AM650",
|
|
||||||
subghz_setting_get_default_frequency(subghz->setting),
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneStart);
|
subghz->scene_manager, SubGhzSceneStart);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case SubGhzCustomEventViewReceiverOK:
|
case SubGhzCustomEventViewReceiverOK:
|
||||||
subghz->txrx->idx_menu_chosen =
|
subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
|
DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case SubGhzCustomEventViewReceiverConfig:
|
case SubGhzCustomEventViewReceiverConfig:
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
subghz->txrx->idx_menu_chosen =
|
subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
@@ -203,30 +177,30 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case SubGhzCustomEventViewReceiverUnlock:
|
case SubGhzCustomEventViewReceiverUnlock:
|
||||||
subghz->lock = SubGhzLockOff;
|
subghz_unlock(subghz);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
|
if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
|
||||||
subghz_hopper_update(subghz);
|
subghz_txrx_hopper_update(subghz->txrx);
|
||||||
subghz_scene_receiver_update_statusbar(subghz);
|
subghz_scene_receiver_update_statusbar(subghz);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get RSSI
|
SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi);
|
||||||
float rssi = furi_hal_subghz_get_rssi();
|
|
||||||
subghz_receiver_rssi(subghz->subghz_receiver, rssi);
|
subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi);
|
||||||
subghz_protocol_decoder_bin_raw_data_input_rssi(
|
subghz_protocol_decoder_bin_raw_data_input_rssi(
|
||||||
(SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi);
|
(SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi);
|
||||||
|
|
||||||
switch(subghz->state_notifications) {
|
switch(subghz->state_notifications) {
|
||||||
case SubGhzNotificationStateRx:
|
case SubGhzNotificationStateRx:
|
||||||
notification_message(subghz->notifications, &sequence_blink_cyan_10);
|
notification_message(subghz->notifications, &sequence_blink_cyan_10);
|
||||||
break;
|
break;
|
||||||
case SubGhzNotificationStateRxDone:
|
case SubGhzNotificationStateRxDone:
|
||||||
if(subghz->lock != SubGhzLockOn) {
|
if(!subghz_is_locked(subghz)) {
|
||||||
notification_message(subghz->notifications, &subghs_sequence_rx);
|
notification_message(subghz->notifications, &subghs_sequence_rx);
|
||||||
} else {
|
} else {
|
||||||
notification_message(subghz->notifications, &subghs_sequence_rx_locked);
|
notification_message(subghz->notifications, &subghs_sequence_rx_locked);
|
||||||
|
|||||||
@@ -72,13 +72,15 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = {
|
|||||||
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
|
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
|
|
||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) {
|
for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) {
|
||||||
if(value == subghz_setting_get_frequency(subghz->setting, i)) {
|
if(value == subghz_setting_get_frequency(setting, i)) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
index = subghz_setting_get_frequency_default_index(subghz->setting);
|
index = subghz_setting_get_frequency_default_index(setting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
@@ -87,13 +89,15 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void*
|
|||||||
uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) {
|
uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
|
|
||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) {
|
for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) {
|
||||||
if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) {
|
if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// index = subghz_setting_get_frequency_default_index(subghz->setting);
|
// index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
@@ -122,70 +126,84 @@ uint8_t subghz_scene_receiver_config_hopper_value_index(
|
|||||||
static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
||||||
SubGhz* subghz = variable_item_get_context(item);
|
SubGhz* subghz = variable_item_get_context(item);
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
|
|
||||||
if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) {
|
if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) {
|
||||||
char text_buf[10] = {0};
|
char text_buf[10] = {0};
|
||||||
|
uint32_t frequency = subghz_setting_get_frequency(setting, index);
|
||||||
|
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||||
|
|
||||||
snprintf(
|
snprintf(
|
||||||
text_buf,
|
text_buf,
|
||||||
sizeof(text_buf),
|
sizeof(text_buf),
|
||||||
"%lu.%02lu",
|
"%lu.%02lu",
|
||||||
subghz_setting_get_frequency(subghz->setting, index) / 1000000,
|
frequency / 1000000,
|
||||||
(subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
|
(frequency % 1000000) / 10000);
|
||||||
variable_item_set_current_value_text(item, text_buf);
|
variable_item_set_current_value_text(item, text_buf);
|
||||||
subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index);
|
subghz_txrx_set_preset(
|
||||||
|
subghz->txrx,
|
||||||
|
furi_string_get_cstr(preset.name),
|
||||||
|
frequency,
|
||||||
|
preset.data,
|
||||||
|
preset.data_size);
|
||||||
} else {
|
} else {
|
||||||
variable_item_set_current_value_index(
|
variable_item_set_current_value_index(
|
||||||
item, subghz_setting_get_frequency_default_index(subghz->setting));
|
item, subghz_setting_get_frequency_default_index(setting));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
|
||||||
SubGhz* subghz = variable_item_get_context(item);
|
SubGhz* subghz = variable_item_get_context(item);
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
variable_item_set_current_value_text(
|
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
item, subghz_setting_get_preset_name(subghz->setting, index));
|
|
||||||
subghz_preset_init(
|
variable_item_set_current_value_text(item, subghz_setting_get_preset_name(setting, index));
|
||||||
subghz,
|
|
||||||
subghz_setting_get_preset_name(subghz->setting, index),
|
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||||
subghz->txrx->preset->frequency,
|
subghz_txrx_set_preset(
|
||||||
subghz_setting_get_preset_data(subghz->setting, index),
|
subghz->txrx,
|
||||||
subghz_setting_get_preset_data_size(subghz->setting, index));
|
subghz_setting_get_preset_name(setting, index),
|
||||||
|
preset.frequency,
|
||||||
|
subghz_setting_get_preset_data(setting, index),
|
||||||
|
subghz_setting_get_preset_data_size(setting, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
|
||||||
SubGhz* subghz = variable_item_get_context(item);
|
SubGhz* subghz = variable_item_get_context(item);
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
|
VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state(
|
||||||
|
subghz->scene_manager, SubGhzSceneReceiverConfig);
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, hopping_text[index]);
|
variable_item_set_current_value_text(item, hopping_text[index]);
|
||||||
if(hopping_value[index] == SubGhzHopperStateOFF) {
|
if(hopping_value[index] == SubGhzHopperStateOFF) {
|
||||||
char text_buf[10] = {0};
|
char text_buf[10] = {0};
|
||||||
|
uint32_t frequency = subghz_setting_get_default_frequency(setting);
|
||||||
|
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||||
|
|
||||||
snprintf(
|
snprintf(
|
||||||
text_buf,
|
text_buf,
|
||||||
sizeof(text_buf),
|
sizeof(text_buf),
|
||||||
"%lu.%02lu",
|
"%lu.%02lu",
|
||||||
subghz_setting_get_default_frequency(subghz->setting) / 1000000,
|
frequency / 1000000,
|
||||||
(subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000);
|
(frequency % 1000000) / 10000);
|
||||||
variable_item_set_current_value_text(
|
variable_item_set_current_value_text(frequency_item, text_buf);
|
||||||
(VariableItem*)scene_manager_get_scene_state(
|
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
subghz_txrx_set_preset(
|
||||||
text_buf);
|
subghz->txrx,
|
||||||
subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
furi_string_get_cstr(preset.name),
|
||||||
|
frequency,
|
||||||
|
preset.data,
|
||||||
|
preset.data_size);
|
||||||
variable_item_set_current_value_index(
|
variable_item_set_current_value_index(
|
||||||
(VariableItem*)scene_manager_get_scene_state(
|
frequency_item, subghz_setting_get_frequency_default_index(setting));
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
|
||||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
|
||||||
} else {
|
} else {
|
||||||
variable_item_set_current_value_text(
|
variable_item_set_current_value_text(frequency_item, " -----");
|
||||||
(VariableItem*)scene_manager_get_scene_state(
|
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
|
||||||
" -----");
|
|
||||||
variable_item_set_current_value_index(
|
variable_item_set_current_value_index(
|
||||||
(VariableItem*)scene_manager_get_scene_state(
|
frequency_item, subghz_setting_get_frequency_default_index(setting));
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
|
||||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subghz->txrx->hopper_state = hopping_value[index];
|
subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
|
||||||
@@ -193,7 +211,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
|
|||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, speaker_text[index]);
|
variable_item_set_current_value_text(item, speaker_text[index]);
|
||||||
subghz->txrx->speaker_state = speaker_value[index];
|
subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
|
||||||
@@ -201,8 +219,8 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
|
|||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, bin_raw_text[index]);
|
variable_item_set_current_value_text(item, bin_raw_text[index]);
|
||||||
subghz->txrx->filter = bin_raw_value[index];
|
subghz->filter = bin_raw_value[index];
|
||||||
subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
|
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
|
||||||
@@ -210,7 +228,7 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it
|
|||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]);
|
variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]);
|
||||||
subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index];
|
subghz_threshold_rssi_set(subghz->threshold_rssi, raw_theshold_rssi_value[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
|
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
|
||||||
@@ -226,25 +244,27 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
VariableItem* item;
|
VariableItem* item;
|
||||||
uint8_t value_index;
|
uint8_t value_index;
|
||||||
|
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
|
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
subghz->variable_item_list,
|
subghz->variable_item_list,
|
||||||
"Frequency:",
|
"Frequency:",
|
||||||
subghz_setting_get_frequency_count(subghz->setting),
|
subghz_setting_get_frequency_count(setting),
|
||||||
subghz_scene_receiver_config_set_frequency,
|
subghz_scene_receiver_config_set_frequency,
|
||||||
subghz);
|
subghz);
|
||||||
value_index =
|
value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz);
|
||||||
subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz);
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
|
subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
char text_buf[10] = {0};
|
char text_buf[10] = {0};
|
||||||
|
uint32_t frequency = subghz_setting_get_frequency(setting, value_index);
|
||||||
snprintf(
|
snprintf(
|
||||||
text_buf,
|
text_buf,
|
||||||
sizeof(text_buf),
|
sizeof(text_buf),
|
||||||
"%lu.%02lu",
|
"%lu.%02lu",
|
||||||
subghz_setting_get_frequency(subghz->setting, value_index) / 1000000,
|
frequency / 1000000,
|
||||||
(subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000);
|
(frequency % 1000000) / 10000);
|
||||||
variable_item_set_current_value_text(item, text_buf);
|
variable_item_set_current_value_text(item, text_buf);
|
||||||
|
|
||||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||||
@@ -256,7 +276,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
subghz_scene_receiver_config_set_hopping_running,
|
subghz_scene_receiver_config_set_hopping_running,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = subghz_scene_receiver_config_hopper_value_index(
|
value_index = subghz_scene_receiver_config_hopper_value_index(
|
||||||
subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz);
|
subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, hopping_text[value_index]);
|
variable_item_set_current_value_text(item, hopping_text[value_index]);
|
||||||
}
|
}
|
||||||
@@ -264,14 +284,14 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
subghz->variable_item_list,
|
subghz->variable_item_list,
|
||||||
"Modulation:",
|
"Modulation:",
|
||||||
subghz_setting_get_preset_count(subghz->setting),
|
subghz_setting_get_preset_count(setting),
|
||||||
subghz_scene_receiver_config_set_preset,
|
subghz_scene_receiver_config_set_preset,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = subghz_scene_receiver_config_next_preset(
|
value_index =
|
||||||
furi_string_get_cstr(subghz->txrx->preset->name), subghz);
|
subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(
|
variable_item_set_current_value_text(
|
||||||
item, subghz_setting_get_preset_name(subghz->setting, value_index));
|
item, subghz_setting_get_preset_name(setting, value_index));
|
||||||
|
|
||||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||||
SubGhzCustomEventManagerSet) {
|
SubGhzCustomEventManagerSet) {
|
||||||
@@ -281,7 +301,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
BIN_RAW_COUNT,
|
BIN_RAW_COUNT,
|
||||||
subghz_scene_receiver_config_set_bin_raw,
|
subghz_scene_receiver_config_set_bin_raw,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT);
|
value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, bin_raw_text[value_index]);
|
variable_item_set_current_value_text(item, bin_raw_text[value_index]);
|
||||||
}
|
}
|
||||||
@@ -292,7 +312,8 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
SPEAKER_COUNT,
|
SPEAKER_COUNT,
|
||||||
subghz_scene_receiver_config_set_speaker,
|
subghz_scene_receiver_config_set_speaker,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT);
|
value_index = value_index_uint32(
|
||||||
|
subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, speaker_text[value_index]);
|
variable_item_set_current_value_text(item, speaker_text[value_index]);
|
||||||
|
|
||||||
@@ -313,7 +334,9 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
subghz_scene_receiver_config_set_raw_threshold_rssi,
|
subghz_scene_receiver_config_set_raw_threshold_rssi,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = value_index_float(
|
value_index = value_index_float(
|
||||||
subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT);
|
subghz_threshold_rssi_get(subghz->threshold_rssi),
|
||||||
|
raw_theshold_rssi_value,
|
||||||
|
RAW_THRESHOLD_RSSI_COUNT);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]);
|
variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]);
|
||||||
}
|
}
|
||||||
@@ -326,7 +349,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubGhzCustomEventSceneSettingLock) {
|
if(event.event == SubGhzCustomEventSceneSettingLock) {
|
||||||
subghz->lock = SubGhzLockOn;
|
subghz_lock(subghz);
|
||||||
scene_manager_previous_scene(subghz->scene_manager);
|
scene_manager_previous_scene(subghz->scene_manager);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,20 +19,19 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v
|
|||||||
|
|
||||||
static bool subghz_scene_receiver_info_update_parser(void* context) {
|
static bool subghz_scene_receiver_info_update_parser(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
|
|
||||||
subghz->txrx->receiver,
|
|
||||||
subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
|
|
||||||
|
|
||||||
if(subghz->txrx->decoder_result) {
|
if(subghz_txrx_load_decoder_by_name_protocol(
|
||||||
|
subghz->txrx,
|
||||||
|
subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) {
|
||||||
//todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
|
//todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
|
||||||
subghz_protocol_decoder_base_deserialize(
|
subghz_protocol_decoder_base_deserialize(
|
||||||
subghz->txrx->decoder_result,
|
subghz_txrx_get_decoder(subghz->txrx),
|
||||||
subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
|
subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen));
|
||||||
|
|
||||||
SubGhzRadioPreset* preset =
|
SubGhzRadioPreset* preset =
|
||||||
subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
|
subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen);
|
||||||
subghz_preset_init(
|
subghz_txrx_set_preset(
|
||||||
subghz,
|
subghz->txrx,
|
||||||
furi_string_get_cstr(preset->name),
|
furi_string_get_cstr(preset->name),
|
||||||
preset->frequency,
|
preset->frequency,
|
||||||
preset->data,
|
preset->data,
|
||||||
@@ -47,15 +46,11 @@ void subghz_scene_receiver_info_on_enter(void* context) {
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
if(subghz_scene_receiver_info_update_parser(subghz)) {
|
if(subghz_scene_receiver_info_update_parser(subghz)) {
|
||||||
FuriString* frequency_str;
|
FuriString* frequency_str = furi_string_alloc();
|
||||||
FuriString* modulation_str;
|
FuriString* modulation_str = furi_string_alloc();
|
||||||
FuriString* text;
|
FuriString* text = furi_string_alloc();
|
||||||
|
|
||||||
frequency_str = furi_string_alloc();
|
subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
|
||||||
modulation_str = furi_string_alloc();
|
|
||||||
text = furi_string_alloc();
|
|
||||||
|
|
||||||
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
|
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
subghz->widget,
|
subghz->widget,
|
||||||
78,
|
78,
|
||||||
@@ -73,7 +68,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
|
|||||||
AlignTop,
|
AlignTop,
|
||||||
FontSecondary,
|
FontSecondary,
|
||||||
furi_string_get_cstr(modulation_str));
|
furi_string_get_cstr(modulation_str));
|
||||||
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
|
subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text);
|
||||||
widget_add_string_multiline_element(
|
widget_add_string_multiline_element(
|
||||||
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
|
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
|
||||||
|
|
||||||
@@ -81,8 +76,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
|
|||||||
furi_string_free(modulation_str);
|
furi_string_free(modulation_str);
|
||||||
furi_string_free(text);
|
furi_string_free(text);
|
||||||
|
|
||||||
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
|
if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
|
||||||
SubGhzProtocolFlag_Save) {
|
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
subghz->widget,
|
subghz->widget,
|
||||||
GuiButtonTypeRight,
|
GuiButtonTypeRight,
|
||||||
@@ -90,10 +84,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
|
|||||||
subghz_scene_receiver_info_callback,
|
subghz_scene_receiver_info_callback,
|
||||||
subghz);
|
subghz);
|
||||||
}
|
}
|
||||||
if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
|
if(subghz_txrx_protocol_is_transmittable(subghz->txrx, true)) {
|
||||||
SubGhzProtocolFlag_Send) &&
|
|
||||||
subghz->txrx->decoder_result->protocol->encoder->deserialize &&
|
|
||||||
subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) {
|
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
subghz->widget,
|
subghz->widget,
|
||||||
GuiButtonTypeCenter,
|
GuiButtonTypeCenter,
|
||||||
@@ -114,82 +105,49 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) {
|
if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) {
|
||||||
//CC1101 Stop RX -> Start TX
|
|
||||||
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
|
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStatePause;
|
|
||||||
}
|
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
|
||||||
subghz_rx_end(subghz);
|
|
||||||
}
|
|
||||||
if(!subghz_scene_receiver_info_update_parser(subghz)) {
|
if(!subghz_scene_receiver_info_update_parser(subghz)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE ||
|
//CC1101 Stop RX -> Start TX
|
||||||
subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
|
subghz_txrx_hopper_pause(subghz->txrx);
|
||||||
if(!subghz_tx_start(
|
if(!subghz_tx_start(
|
||||||
subghz,
|
subghz,
|
||||||
subghz_history_get_raw_data(
|
subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) {
|
||||||
subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
|
subghz_txrx_rx_start(subghz->txrx);
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
subghz_txrx_hopper_unpause(subghz->txrx);
|
||||||
subghz_tx_stop(subghz);
|
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||||
}
|
} else {
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||||
subghz_begin(
|
|
||||||
subghz,
|
|
||||||
subghz_setting_get_preset_data_by_name(
|
|
||||||
subghz->setting,
|
|
||||||
furi_string_get_cstr(subghz->txrx->preset->name)));
|
|
||||||
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
|
||||||
}
|
|
||||||
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
|
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
|
|
||||||
}
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
|
||||||
} else {
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
|
} else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
|
||||||
//CC1101 Stop Tx -> Start RX
|
//CC1101 Stop Tx -> Start RX
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
|
||||||
subghz_tx_stop(subghz);
|
subghz_txrx_rx_start(subghz->txrx);
|
||||||
}
|
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
subghz_txrx_hopper_unpause(subghz->txrx);
|
||||||
subghz_begin(
|
|
||||||
subghz,
|
|
||||||
subghz_setting_get_preset_data_by_name(
|
|
||||||
subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
|
|
||||||
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
|
||||||
}
|
|
||||||
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
|
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
|
|
||||||
}
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
|
} else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
|
||||||
//CC1101 Stop RX -> Save
|
//CC1101 Stop RX -> Save
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
|
||||||
subghz_rx_end(subghz);
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_sleep(subghz);
|
|
||||||
}
|
|
||||||
if(!subghz_scene_receiver_info_update_parser(subghz)) {
|
if(!subghz_scene_receiver_info_update_parser(subghz)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
|
if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
|
||||||
SubGhzProtocolFlag_Save) {
|
|
||||||
subghz_file_name_clear(subghz);
|
subghz_file_name_clear(subghz);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
|
if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
|
||||||
subghz_hopper_update(subghz);
|
subghz_txrx_hopper_update(subghz->txrx);
|
||||||
}
|
}
|
||||||
switch(subghz->state_notifications) {
|
switch(subghz->state_notifications) {
|
||||||
case SubGhzNotificationStateTx:
|
case SubGhzNotificationStateTx:
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
void subghz_scene_region_info_on_enter(void* context) {
|
void subghz_scene_region_info_on_enter(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
const FuriHalRegion* const region = furi_hal_region_get();
|
const FuriHalRegion* const region = furi_hal_region_get();
|
||||||
FuriString* buffer;
|
FuriString* buffer = furi_string_alloc();
|
||||||
buffer = furi_string_alloc();
|
|
||||||
if(region) {
|
if(region) {
|
||||||
furi_string_cat_printf(buffer, "Region: %s, bands:\n", region->country_code);
|
furi_string_cat_printf(buffer, "Region: %s, bands:\n", region->country_code);
|
||||||
for(uint16_t i = 0; i < region->bands_count; ++i) {
|
for(uint16_t i = 0; i < region->bands_count; ++i) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
SubGhzRpcStateIdle,
|
SubGhzRpcStateIdle,
|
||||||
SubGhzRpcStateLoaded,
|
SubGhzRpcStateLoaded,
|
||||||
|
SubGhzRpcStateTx,
|
||||||
} SubGhzRpcState;
|
} SubGhzRpcState;
|
||||||
|
|
||||||
void subghz_scene_rpc_on_enter(void* context) {
|
void subghz_scene_rpc_on_enter(void* context) {
|
||||||
@@ -38,9 +39,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
view_dispatcher_stop(subghz->view_dispatcher);
|
view_dispatcher_stop(subghz->view_dispatcher);
|
||||||
} else if(event.event == SubGhzCustomEventSceneRpcButtonPress) {
|
} else if(event.event == SubGhzCustomEventSceneRpcButtonPress) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) &&
|
if((state == SubGhzRpcStateLoaded)) {
|
||||||
(state == SubGhzRpcStateLoaded)) {
|
result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||||
result = subghz_tx_start(subghz, subghz->txrx->fff_data);
|
state = SubGhzRpcStateTx;
|
||||||
if(result) subghz_blink_start(subghz);
|
if(result) subghz_blink_start(subghz);
|
||||||
}
|
}
|
||||||
if(!result) {
|
if(!result) {
|
||||||
@@ -52,10 +53,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
|
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
|
||||||
} else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
|
} else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
if(state == SubGhzRpcStateTx) {
|
||||||
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_blink_stop(subghz);
|
subghz_blink_stop(subghz);
|
||||||
subghz_tx_stop(subghz);
|
state = SubGhzRpcStateIdle;
|
||||||
subghz_sleep(subghz);
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result);
|
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result);
|
||||||
@@ -93,10 +94,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
void subghz_scene_rpc_on_exit(void* context) {
|
void subghz_scene_rpc_on_exit(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc);
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
if(state != SubGhzRpcStateIdle) {
|
||||||
subghz_tx_stop(subghz);
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_sleep(subghz);
|
|
||||||
subghz_blink_stop(subghz);
|
subghz_blink_stop(subghz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,8 @@ void subghz_scene_save_name_on_enter(void* context) {
|
|||||||
TextInput* text_input = subghz->text_input;
|
TextInput* text_input = subghz->text_input;
|
||||||
bool dev_name_empty = false;
|
bool dev_name_empty = false;
|
||||||
|
|
||||||
FuriString* file_name;
|
FuriString* file_name = furi_string_alloc();
|
||||||
FuriString* dir_name;
|
FuriString* dir_name = furi_string_alloc();
|
||||||
file_name = furi_string_alloc();
|
|
||||||
dir_name = furi_string_alloc();
|
|
||||||
|
|
||||||
if(!subghz_path_is_file(subghz->file_path)) {
|
if(!subghz_path_is_file(subghz->file_path)) {
|
||||||
char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0};
|
char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0};
|
||||||
@@ -69,7 +67,7 @@ void subghz_scene_save_name_on_enter(void* context) {
|
|||||||
subghz_scene_save_name_text_input_callback,
|
subghz_scene_save_name_text_input_callback,
|
||||||
subghz,
|
subghz,
|
||||||
subghz->file_name_tmp,
|
subghz->file_name_tmp,
|
||||||
MAX_TEXT_INPUT_LEN, // buffer size
|
MAX_TEXT_INPUT_LEN,
|
||||||
dev_name_empty);
|
dev_name_empty);
|
||||||
|
|
||||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||||
@@ -106,7 +104,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
SubGhzCustomEventManagerNoSet) {
|
SubGhzCustomEventManagerNoSet) {
|
||||||
subghz_save_protocol_to_file(
|
subghz_save_protocol_to_file(
|
||||||
subghz,
|
subghz,
|
||||||
subghz->txrx->fff_data,
|
subghz_txrx_get_fff_data(subghz->txrx),
|
||||||
furi_string_get_cstr(subghz->file_path));
|
furi_string_get_cstr(subghz->file_path));
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager,
|
subghz->scene_manager,
|
||||||
@@ -115,8 +113,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else {
|
} else {
|
||||||
subghz_save_protocol_to_file(
|
subghz_save_protocol_to_file(
|
||||||
subghz,
|
subghz,
|
||||||
subghz_history_get_raw_data(
|
subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen),
|
||||||
subghz->txrx->history, subghz->txrx->idx_menu_chosen),
|
|
||||||
furi_string_get_cstr(subghz->file_path));
|
furi_string_get_cstr(subghz->file_path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +121,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||||
SubGhzCustomEventManagerNoSet) {
|
SubGhzCustomEventManagerNoSet) {
|
||||||
subghz_protocol_raw_gen_fff_data(
|
subghz_protocol_raw_gen_fff_data(
|
||||||
subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path));
|
subghz_txrx_get_fff_data(subghz->txrx),
|
||||||
|
furi_string_get_cstr(subghz->file_path));
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
|
|||||||
if(event.event == SubGhzCustomEventSceneSaveSuccess) {
|
if(event.event == SubGhzCustomEventSceneSaveSuccess) {
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneReceiver)) {
|
subghz->scene_manager, SubGhzSceneReceiver)) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave);
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneReadRAW)) {
|
subghz->scene_manager, SubGhzSceneReadRAW)) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneSaved)) {
|
subghz->scene_manager, SubGhzSceneSaved)) {
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ void subghz_scene_saved_on_enter(void* context) {
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
if(subghz_load_protocol_from_file(subghz)) {
|
if(subghz_load_protocol_from_file(subghz)) {
|
||||||
if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
|
if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu);
|
||||||
|
|||||||
@@ -1,63 +1,10 @@
|
|||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
#include <lib/subghz/protocols/keeloq.h>
|
#include "../helpers/subghz_txrx_create_potocol_key.h"
|
||||||
#include <lib/subghz/protocols/secplus_v1.h>
|
|
||||||
#include <lib/subghz/protocols/secplus_v2.h>
|
|
||||||
#include <lib/subghz/blocks/math.h>
|
#include <lib/subghz/blocks/math.h>
|
||||||
#include <flipper_format/flipper_format_i.h>
|
|
||||||
#include <lib/toolbox/stream/stream.h>
|
|
||||||
#include <lib/subghz/protocols/protocol_items.h>
|
#include <lib/subghz/protocols/protocol_items.h>
|
||||||
|
|
||||||
#define TAG "SubGhzSetType"
|
#define TAG "SubGhzSetType"
|
||||||
|
|
||||||
bool subghz_scene_set_type_submenu_gen_data_protocol(
|
|
||||||
void* context,
|
|
||||||
const char* protocol_name,
|
|
||||||
uint64_t key,
|
|
||||||
uint32_t bit,
|
|
||||||
uint32_t frequency,
|
|
||||||
const char* preset_name) {
|
|
||||||
furi_assert(context);
|
|
||||||
SubGhz* subghz = context;
|
|
||||||
|
|
||||||
bool res = false;
|
|
||||||
|
|
||||||
subghz_preset_init(subghz, preset_name, frequency, NULL, 0);
|
|
||||||
subghz->txrx->decoder_result =
|
|
||||||
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name);
|
|
||||||
|
|
||||||
if(subghz->txrx->decoder_result == NULL) {
|
|
||||||
furi_string_set(subghz->error_str, "Protocol not\nfound!");
|
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
|
|
||||||
stream_clean(fff_data_stream);
|
|
||||||
if(subghz_protocol_decoder_base_serialize(
|
|
||||||
subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) !=
|
|
||||||
SubGhzProtocolStatusOk) {
|
|
||||||
FURI_LOG_E(TAG, "Unable to serialize");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) {
|
|
||||||
FURI_LOG_E(TAG, "Unable to update Bit");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t key_data[sizeof(uint64_t)] = {0};
|
|
||||||
for(size_t i = 0; i < sizeof(uint64_t); i++) {
|
|
||||||
key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF;
|
|
||||||
}
|
|
||||||
if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) {
|
|
||||||
FURI_LOG_E(TAG, "Unable to update Key");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
res = true;
|
|
||||||
} while(false);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) {
|
void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
|
view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
|
||||||
@@ -69,7 +16,13 @@ void subghz_scene_set_type_on_enter(void* context) {
|
|||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
subghz->submenu,
|
subghz->submenu,
|
||||||
"Princeton_433",
|
"Princeton_433",
|
||||||
SubmenuIndexPricenton,
|
SubmenuIndexPricenton_433,
|
||||||
|
subghz_scene_set_type_submenu_callback,
|
||||||
|
subghz);
|
||||||
|
submenu_add_item(
|
||||||
|
subghz->submenu,
|
||||||
|
"Princeton_315",
|
||||||
|
SubmenuIndexPricenton_315,
|
||||||
subghz_scene_set_type_submenu_callback,
|
subghz_scene_set_type_submenu_callback,
|
||||||
subghz);
|
subghz);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
@@ -108,10 +61,6 @@ void subghz_scene_set_type_on_enter(void* context) {
|
|||||||
SubmenuIndexCAMETwee,
|
SubmenuIndexCAMETwee,
|
||||||
subghz_scene_set_type_submenu_callback,
|
subghz_scene_set_type_submenu_callback,
|
||||||
subghz);
|
subghz);
|
||||||
// submenu_add_item(
|
|
||||||
// subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
|
|
||||||
// submenu_add_item(
|
|
||||||
// subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz);
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
subghz->submenu,
|
subghz->submenu,
|
||||||
"Gate TX_433",
|
"Gate TX_433",
|
||||||
@@ -172,94 +121,59 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
bool generated_protocol = false;
|
bool generated_protocol = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
//ToDo Fix
|
uint32_t key = (uint32_t)rand();
|
||||||
uint32_t key = subghz_random_serial();
|
|
||||||
switch(event.event) {
|
switch(event.event) {
|
||||||
case SubmenuIndexPricenton:
|
case SubmenuIndexPricenton_433:
|
||||||
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
generated_protocol = subghz_txrx_gen_data_protocol_and_te(
|
||||||
subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) {
|
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400);
|
||||||
uint32_t te = 400;
|
break;
|
||||||
flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
|
case SubmenuIndexPricenton_315:
|
||||||
generated_protocol = true;
|
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||||
}
|
generated_protocol = subghz_txrx_gen_data_protocol_and_te(
|
||||||
|
subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400);
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexNiceFlo12bit:
|
case SubmenuIndexNiceFlo12bit:
|
||||||
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||||
subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) {
|
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12);
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexNiceFlo24bit:
|
case SubmenuIndexNiceFlo24bit:
|
||||||
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||||
subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) {
|
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24);
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexCAME12bit:
|
case SubmenuIndexCAME12bit:
|
||||||
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||||
subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) {
|
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12);
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexCAME24bit:
|
case SubmenuIndexCAME24bit:
|
||||||
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||||
subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) {
|
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24);
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexLinear_300_00:
|
case SubmenuIndexLinear_300_00:
|
||||||
key = (key & 0x3FF);
|
key = (key & 0x3FF);
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||||
subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) {
|
subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10);
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexCAMETwee:
|
case SubmenuIndexCAMETwee:
|
||||||
key = (key & 0x0FFFFFF0);
|
key = (key & 0x0FFFFFF0);
|
||||||
key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
|
key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
|
||||||
subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) {
|
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||||
generated_protocol = true;
|
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
// case SubmenuIndexNeroSketch:
|
|
||||||
// /* code */
|
|
||||||
// break;
|
|
||||||
// case SubmenuIndexNeroRadio:
|
|
||||||
// /* code */
|
|
||||||
// break;
|
|
||||||
case SubmenuIndexGateTX:
|
case SubmenuIndexGateTX:
|
||||||
key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
|
key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
|
||||||
uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
|
uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||||
subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) {
|
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24);
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexDoorHan_433_92:
|
case SubmenuIndexDoorHan_433_92:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
generated_protocol = subghz_txrx_gen_keelog_protocol(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
subghz->txrx, "AM650", 433920000, "DoorHan", key, 0x2, 0x0003);
|
||||||
subghz_preset_init(
|
|
||||||
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
|
||||||
if(subghz->txrx->transmitter) {
|
|
||||||
subghz_protocol_keeloq_create_data(
|
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
|
||||||
subghz->txrx->fff_data,
|
|
||||||
key & 0x0FFFFFFF,
|
|
||||||
0x2,
|
|
||||||
0x0003,
|
|
||||||
"DoorHan",
|
|
||||||
subghz->txrx->preset);
|
|
||||||
generated_protocol = true;
|
|
||||||
} else {
|
|
||||||
generated_protocol = false;
|
|
||||||
}
|
|
||||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
|
||||||
if(!generated_protocol) {
|
if(!generated_protocol) {
|
||||||
furi_string_set(
|
furi_string_set(
|
||||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||||
@@ -267,23 +181,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexDoorHan_315_00:
|
case SubmenuIndexDoorHan_315_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
generated_protocol = subghz_txrx_gen_keelog_protocol(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
subghz->txrx, "AM650", 315000000, "DoorHan", key, 0x2, 0x0003);
|
||||||
subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
|
|
||||||
if(subghz->txrx->transmitter) {
|
|
||||||
subghz_protocol_keeloq_create_data(
|
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
|
||||||
subghz->txrx->fff_data,
|
|
||||||
key & 0x0FFFFFFF,
|
|
||||||
0x2,
|
|
||||||
0x0003,
|
|
||||||
"DoorHan",
|
|
||||||
subghz->txrx->preset);
|
|
||||||
generated_protocol = true;
|
|
||||||
} else {
|
|
||||||
generated_protocol = false;
|
|
||||||
}
|
|
||||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
|
||||||
if(!generated_protocol) {
|
if(!generated_protocol) {
|
||||||
furi_string_set(
|
furi_string_set(
|
||||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||||
@@ -291,86 +190,24 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexLiftMaster_315_00:
|
case SubmenuIndexLiftMaster_315_00:
|
||||||
while(!subghz_protocol_secplus_v1_check_fixed(key)) {
|
generated_protocol =
|
||||||
key = subghz_random_serial();
|
subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000);
|
||||||
}
|
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
|
||||||
subghz,
|
|
||||||
SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
|
|
||||||
(uint64_t)key << 32 | 0xE6000000,
|
|
||||||
42,
|
|
||||||
315000000,
|
|
||||||
"AM650")) {
|
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexLiftMaster_390_00:
|
case SubmenuIndexLiftMaster_390_00:
|
||||||
while(!subghz_protocol_secplus_v1_check_fixed(key)) {
|
generated_protocol =
|
||||||
key = subghz_random_serial();
|
subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000);
|
||||||
}
|
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
|
||||||
subghz,
|
|
||||||
SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
|
|
||||||
(uint64_t)key << 32 | 0xE6000000,
|
|
||||||
42,
|
|
||||||
390000000,
|
|
||||||
"AM650")) {
|
|
||||||
generated_protocol = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexSecPlus_v2_310_00:
|
case SubmenuIndexSecPlus_v2_310_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000);
|
||||||
subghz_preset_init(subghz, "AM650", 310000000, NULL, 0);
|
|
||||||
if(subghz->txrx->transmitter) {
|
|
||||||
subghz_protocol_secplus_v2_create_data(
|
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
|
||||||
subghz->txrx->fff_data,
|
|
||||||
key,
|
|
||||||
0x68,
|
|
||||||
0xE500000,
|
|
||||||
subghz->txrx->preset);
|
|
||||||
generated_protocol = true;
|
|
||||||
} else {
|
|
||||||
generated_protocol = false;
|
|
||||||
}
|
|
||||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexSecPlus_v2_315_00:
|
case SubmenuIndexSecPlus_v2_315_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000);
|
||||||
subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
|
|
||||||
if(subghz->txrx->transmitter) {
|
|
||||||
subghz_protocol_secplus_v2_create_data(
|
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
|
||||||
subghz->txrx->fff_data,
|
|
||||||
key,
|
|
||||||
0x68,
|
|
||||||
0xE500000,
|
|
||||||
subghz->txrx->preset);
|
|
||||||
generated_protocol = true;
|
|
||||||
} else {
|
|
||||||
generated_protocol = false;
|
|
||||||
}
|
|
||||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexSecPlus_v2_390_00:
|
case SubmenuIndexSecPlus_v2_390_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000);
|
||||||
subghz_preset_init(subghz, "AM650", 390000000, NULL, 0);
|
|
||||||
if(subghz->txrx->transmitter) {
|
|
||||||
subghz_protocol_secplus_v2_create_data(
|
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
|
||||||
subghz->txrx->fff_data,
|
|
||||||
key,
|
|
||||||
0x68,
|
|
||||||
0xE500000,
|
|
||||||
subghz->txrx->preset);
|
|
||||||
generated_protocol = true;
|
|
||||||
} else {
|
|
||||||
generated_protocol = false;
|
|
||||||
}
|
|
||||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) {
|
|||||||
|
|
||||||
bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
|
bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
SubGhzCustomEvent scene_state =
|
||||||
|
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError);
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
if(event.type == SceneManagerEventTypeBack) {
|
||||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
|
if(scene_state == SubGhzCustomEventManagerSet) {
|
||||||
SubGhzCustomEventManagerSet) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
@@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
|
|||||||
return true;
|
return true;
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubGhzCustomEventSceneShowErrorOk) {
|
if(event.event == SubGhzCustomEventSceneShowErrorOk) {
|
||||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
|
if(scene_state == SubGhzCustomEventManagerSet) {
|
||||||
SubGhzCustomEventManagerSet) {
|
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventSceneShowErrorBack) {
|
} else if(event.event == SubGhzCustomEventSceneShowErrorBack) {
|
||||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
|
if(scene_state == SubGhzCustomEventManagerSet) {
|
||||||
SubGhzCustomEventManagerSet) {
|
|
||||||
//exit app
|
//exit app
|
||||||
if(!scene_manager_previous_scene(subghz->scene_manager)) {
|
if(!scene_manager_previous_scene(subghz->scene_manager)) {
|
||||||
scene_manager_stop(subghz->scene_manager);
|
scene_manager_stop(subghz->scene_manager);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == SubmenuIndexReadRAW) {
|
if(event.event == SubmenuIndexReadRAW) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
|
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubmenuIndexRead) {
|
} else if(event.event == SubmenuIndexRead) {
|
||||||
|
|||||||
@@ -11,32 +11,24 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
|
|||||||
bool subghz_scene_transmitter_update_data_show(void* context) {
|
bool subghz_scene_transmitter_update_data_show(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if(subghz->txrx->decoder_result) {
|
SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
|
||||||
FuriString* key_str;
|
|
||||||
FuriString* frequency_str;
|
|
||||||
FuriString* modulation_str;
|
|
||||||
|
|
||||||
key_str = furi_string_alloc();
|
if(decoder) {
|
||||||
frequency_str = furi_string_alloc();
|
FuriString* key_str = furi_string_alloc();
|
||||||
modulation_str = furi_string_alloc();
|
FuriString* frequency_str = furi_string_alloc();
|
||||||
uint8_t show_button = 0;
|
FuriString* modulation_str = furi_string_alloc();
|
||||||
|
|
||||||
if(subghz_protocol_decoder_base_deserialize(
|
if(subghz_protocol_decoder_base_deserialize(
|
||||||
subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) {
|
decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) {
|
||||||
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str);
|
subghz_protocol_decoder_base_get_string(decoder, key_str);
|
||||||
|
|
||||||
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
|
subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
|
||||||
SubGhzProtocolFlag_Send) {
|
|
||||||
show_button = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
|
|
||||||
subghz_view_transmitter_add_data_to_show(
|
subghz_view_transmitter_add_data_to_show(
|
||||||
subghz->subghz_transmitter,
|
subghz->subghz_transmitter,
|
||||||
furi_string_get_cstr(key_str),
|
furi_string_get_cstr(key_str),
|
||||||
furi_string_get_cstr(frequency_str),
|
furi_string_get_cstr(frequency_str),
|
||||||
furi_string_get_cstr(modulation_str),
|
furi_string_get_cstr(modulation_str),
|
||||||
show_button);
|
subghz_txrx_protocol_is_transmittable(subghz->txrx, false));
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
furi_string_free(frequency_str);
|
furi_string_free(frequency_str);
|
||||||
@@ -65,24 +57,16 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubGhzCustomEventViewTransmitterSendStart) {
|
if(event.event == SubGhzCustomEventViewTransmitterSendStart) {
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
|
||||||
subghz_rx_end(subghz);
|
if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
|
||||||
}
|
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
subghz_scene_transmitter_update_data_show(subghz);
|
||||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
||||||
if(subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
|
||||||
subghz_scene_transmitter_update_data_show(subghz);
|
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
|
} else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
subghz_txrx_stop(subghz->txrx);
|
||||||
subghz_tx_stop(subghz);
|
|
||||||
subghz_sleep(subghz);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventViewTransmitterBack) {
|
} else if(event.event == SubGhzCustomEventViewTransmitterBack) {
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
/* Abandon hope, all ye who enter here. */
|
/* Abandon hope, all ye who enter here. */
|
||||||
|
|
||||||
#include "subghz/types.h"
|
|
||||||
#include "subghz_i.h"
|
#include "subghz_i.h"
|
||||||
#include <lib/toolbox/path.h>
|
|
||||||
#include <lib/subghz/protocols/protocol_items.h>
|
|
||||||
|
|
||||||
bool subghz_custom_event_callback(void* context, uint32_t event) {
|
bool subghz_custom_event_callback(void* context, uint32_t event) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
@@ -49,16 +46,6 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_blink_start(SubGhz* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
notification_message(instance->notifications, &sequence_blink_start_magenta);
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_blink_stop(SubGhz* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
notification_message(instance->notifications, &sequence_blink_stop);
|
|
||||||
}
|
|
||||||
|
|
||||||
SubGhz* subghz_alloc() {
|
SubGhz* subghz_alloc() {
|
||||||
SubGhz* subghz = malloc(sizeof(SubGhz));
|
SubGhz* subghz = malloc(sizeof(SubGhz));
|
||||||
|
|
||||||
@@ -163,45 +150,18 @@ SubGhz* subghz_alloc() {
|
|||||||
SubGhzViewIdStatic,
|
SubGhzViewIdStatic,
|
||||||
subghz_test_static_get_view(subghz->subghz_test_static));
|
subghz_test_static_get_view(subghz->subghz_test_static));
|
||||||
|
|
||||||
//init setting
|
//init threshold rssi
|
||||||
subghz->setting = subghz_setting_alloc();
|
subghz->threshold_rssi = subghz_threshold_rssi_alloc();
|
||||||
subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user"));
|
|
||||||
|
|
||||||
//init Worker & Protocol & History & KeyBoard
|
subghz_unlock(subghz);
|
||||||
subghz->lock = SubGhzLockOff;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
|
||||||
subghz->txrx = malloc(sizeof(SubGhzTxRx));
|
subghz->history = subghz_history_alloc();
|
||||||
subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset));
|
subghz->filter = SubGhzProtocolFlag_Decodable;
|
||||||
subghz->txrx->preset->name = furi_string_alloc();
|
|
||||||
subghz_preset_init(
|
|
||||||
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
|
||||||
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
|
//init TxRx & History & KeyBoard
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
subghz->txrx = subghz_txrx_alloc();
|
||||||
subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
|
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz);
|
||||||
subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN;
|
|
||||||
subghz->txrx->history = subghz_history_alloc();
|
|
||||||
subghz->txrx->worker = subghz_worker_alloc();
|
|
||||||
subghz->txrx->fff_data = flipper_format_string_alloc();
|
|
||||||
|
|
||||||
subghz->txrx->environment = subghz_environment_alloc();
|
|
||||||
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
|
||||||
subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo"));
|
|
||||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
|
||||||
subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
|
|
||||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
|
||||||
subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s"));
|
|
||||||
subghz_environment_set_protocol_registry(
|
|
||||||
subghz->txrx->environment, (void*)&subghz_protocol_registry);
|
|
||||||
subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment);
|
|
||||||
subghz->txrx->filter = SubGhzProtocolFlag_Decodable;
|
|
||||||
subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
|
|
||||||
|
|
||||||
subghz_worker_set_overrun_callback(
|
|
||||||
subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
|
|
||||||
subghz_worker_set_pair_callback(
|
|
||||||
subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
|
|
||||||
subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver);
|
|
||||||
|
|
||||||
//Init Error_str
|
//Init Error_str
|
||||||
subghz->error_str = furi_string_alloc();
|
subghz->error_str = furi_string_alloc();
|
||||||
@@ -219,7 +179,9 @@ void subghz_free(SubGhz* subghz) {
|
|||||||
subghz->rpc_ctx = NULL;
|
subghz->rpc_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
subghz_speaker_off(subghz);
|
subghz_txrx_speaker_off(subghz->txrx);
|
||||||
|
subghz_txrx_stop(subghz->txrx);
|
||||||
|
subghz_txrx_sleep(subghz->txrx);
|
||||||
|
|
||||||
// Packet Test
|
// Packet Test
|
||||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
|
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
|
||||||
@@ -282,18 +244,14 @@ void subghz_free(SubGhz* subghz) {
|
|||||||
furi_record_close(RECORD_GUI);
|
furi_record_close(RECORD_GUI);
|
||||||
subghz->gui = NULL;
|
subghz->gui = NULL;
|
||||||
|
|
||||||
//setting
|
// threshold rssi
|
||||||
subghz_setting_free(subghz->setting);
|
subghz_threshold_rssi_free(subghz->threshold_rssi);
|
||||||
|
|
||||||
//Worker & Protocol & History
|
//Worker & Protocol & History
|
||||||
subghz_receiver_free(subghz->txrx->receiver);
|
subghz_history_free(subghz->history);
|
||||||
subghz_environment_free(subghz->txrx->environment);
|
|
||||||
subghz_worker_free(subghz->txrx->worker);
|
//TxRx
|
||||||
flipper_format_free(subghz->txrx->fff_data);
|
subghz_txrx_free(subghz->txrx);
|
||||||
subghz_history_free(subghz->txrx->history);
|
|
||||||
furi_string_free(subghz->txrx->preset->name);
|
|
||||||
free(subghz->txrx->preset);
|
|
||||||
free(subghz->txrx);
|
|
||||||
|
|
||||||
//Error string
|
//Error string
|
||||||
furi_string_free(subghz->error_str);
|
furi_string_free(subghz->error_str);
|
||||||
@@ -319,11 +277,6 @@ int32_t subghz_app(void* p) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load database
|
|
||||||
bool load_database = subghz_environment_load_keystore(
|
|
||||||
subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
|
|
||||||
subghz_environment_load_keystore(
|
|
||||||
subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
|
|
||||||
// Check argument and run corresponding scene
|
// Check argument and run corresponding scene
|
||||||
if(p && strlen(p)) {
|
if(p && strlen(p)) {
|
||||||
uint32_t rpc_ctx = 0;
|
uint32_t rpc_ctx = 0;
|
||||||
@@ -340,9 +293,9 @@ int32_t subghz_app(void* p) {
|
|||||||
if(subghz_key_load(subghz, p, true)) {
|
if(subghz_key_load(subghz, p, true)) {
|
||||||
furi_string_set(subghz->file_path, (const char*)p);
|
furi_string_set(subghz->file_path, (const char*)p);
|
||||||
|
|
||||||
if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
|
if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) {
|
||||||
//Load Raw TX
|
//Load Raw TX
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
||||||
} else {
|
} else {
|
||||||
//Load transmitter TX
|
//Load transmitter TX
|
||||||
@@ -358,7 +311,7 @@ int32_t subghz_app(void* p) {
|
|||||||
view_dispatcher_attach_to_gui(
|
view_dispatcher_attach_to_gui(
|
||||||
subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
|
subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
|
||||||
furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
|
furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
|
||||||
if(load_database) {
|
if(subghz_txrx_is_database_loaded(subghz->txrx)) {
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
|
|||||||
@@ -18,214 +18,42 @@
|
|||||||
|
|
||||||
#define TAG "SubGhz"
|
#define TAG "SubGhz"
|
||||||
|
|
||||||
void subghz_preset_init(
|
void subghz_set_default_preset(SubGhz* subghz) {
|
||||||
void* context,
|
|
||||||
const char* preset_name,
|
|
||||||
uint32_t frequency,
|
|
||||||
uint8_t* preset_data,
|
|
||||||
size_t preset_data_size) {
|
|
||||||
furi_assert(context);
|
|
||||||
SubGhz* subghz = context;
|
|
||||||
furi_string_set(subghz->txrx->preset->name, preset_name);
|
|
||||||
subghz->txrx->preset->frequency = frequency;
|
|
||||||
subghz->txrx->preset->data = preset_data;
|
|
||||||
subghz->txrx->preset->data_size = preset_data_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool subghz_set_preset(SubGhz* subghz, const char* preset) {
|
|
||||||
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
|
||||||
furi_string_set(subghz->txrx->preset->name, "AM270");
|
|
||||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
|
||||||
furi_string_set(subghz->txrx->preset->name, "AM650");
|
|
||||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
|
||||||
furi_string_set(subghz->txrx->preset->name, "FM238");
|
|
||||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
|
||||||
furi_string_set(subghz->txrx->preset->name, "FM476");
|
|
||||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
|
||||||
furi_string_set(subghz->txrx->preset->name, "CUSTOM");
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(TAG, "Unknown preset");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) {
|
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
if(frequency != NULL) {
|
subghz_txrx_set_preset(
|
||||||
furi_string_printf(
|
subghz->txrx,
|
||||||
frequency,
|
"AM650",
|
||||||
"%03ld.%02ld",
|
subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)),
|
||||||
subghz->txrx->preset->frequency / 1000000 % 1000,
|
NULL,
|
||||||
subghz->txrx->preset->frequency / 10000 % 100);
|
0);
|
||||||
}
|
|
||||||
if(modulation != NULL) {
|
|
||||||
furi_string_printf(modulation, "%.2s", furi_string_get_cstr(subghz->txrx->preset->name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_begin(SubGhz* subghz, uint8_t* preset_data) {
|
void subghz_blink_start(SubGhz* subghz) {
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
furi_hal_subghz_reset();
|
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||||
furi_hal_subghz_idle();
|
notification_message(subghz->notifications, &sequence_blink_start_magenta);
|
||||||
furi_hal_subghz_load_custom_preset(preset_data);
|
|
||||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) {
|
void subghz_blink_stop(SubGhz* subghz) {
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||||
furi_crash("SubGhz: Incorrect RX frequency.");
|
|
||||||
}
|
|
||||||
furi_assert(
|
|
||||||
subghz->txrx->txrx_state != SubGhzTxRxStateRx &&
|
|
||||||
subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
|
|
||||||
|
|
||||||
furi_hal_subghz_idle();
|
|
||||||
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
|
|
||||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_subghz_flush_rx();
|
|
||||||
subghz_speaker_on(subghz);
|
|
||||||
furi_hal_subghz_rx();
|
|
||||||
|
|
||||||
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker);
|
|
||||||
subghz_worker_start(subghz->txrx->worker);
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateRx;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool subghz_tx(SubGhz* subghz, uint32_t frequency) {
|
|
||||||
furi_assert(subghz);
|
|
||||||
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
|
||||||
furi_crash("SubGhz: Incorrect TX frequency.");
|
|
||||||
}
|
|
||||||
furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
|
|
||||||
furi_hal_subghz_idle();
|
|
||||||
furi_hal_subghz_set_frequency_and_path(frequency);
|
|
||||||
furi_hal_gpio_write(&gpio_cc1101_g0, false);
|
|
||||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
|
||||||
bool ret = furi_hal_subghz_tx();
|
|
||||||
if(ret) {
|
|
||||||
subghz_speaker_on(subghz);
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_idle(SubGhz* subghz) {
|
|
||||||
furi_assert(subghz);
|
|
||||||
furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
|
|
||||||
furi_hal_subghz_idle();
|
|
||||||
subghz_speaker_off(subghz);
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_rx_end(SubGhz* subghz) {
|
|
||||||
furi_assert(subghz);
|
|
||||||
furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx);
|
|
||||||
|
|
||||||
if(subghz_worker_is_running(subghz->txrx->worker)) {
|
|
||||||
subghz_worker_stop(subghz->txrx->worker);
|
|
||||||
furi_hal_subghz_stop_async_rx();
|
|
||||||
}
|
|
||||||
furi_hal_subghz_idle();
|
|
||||||
subghz_speaker_off(subghz);
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_sleep(SubGhz* subghz) {
|
|
||||||
furi_assert(subghz);
|
|
||||||
furi_hal_subghz_sleep();
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
|
bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
|
||||||
furi_assert(subghz);
|
switch(subghz_txrx_tx_start(subghz->txrx, flipper_format)) {
|
||||||
|
case SubGhzTxRxStartTxStateErrorParserOthers:
|
||||||
|
dialog_message_show_storage_error(
|
||||||
|
subghz->dialogs, "Error in protocol\nparameters\ndescription");
|
||||||
|
break;
|
||||||
|
case SubGhzTxRxStartTxStateErrorOnlyRx:
|
||||||
|
subghz_dialog_message_show_only_rx(subghz);
|
||||||
|
break;
|
||||||
|
|
||||||
bool ret = false;
|
default:
|
||||||
FuriString* temp_str;
|
return true;
|
||||||
temp_str = furi_string_alloc();
|
break;
|
||||||
uint32_t repeat = 200;
|
|
||||||
do {
|
|
||||||
if(!flipper_format_rewind(flipper_format)) {
|
|
||||||
FURI_LOG_E(TAG, "Rewind error");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
|
|
||||||
FURI_LOG_E(TAG, "Missing Protocol");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
|
|
||||||
FURI_LOG_E(TAG, "Unable Repeat");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
|
||||||
subghz->txrx->environment, furi_string_get_cstr(temp_str));
|
|
||||||
|
|
||||||
if(subghz->txrx->transmitter) {
|
|
||||||
if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) ==
|
|
||||||
SubGhzProtocolStatusOk) {
|
|
||||||
if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) {
|
|
||||||
subghz_begin(
|
|
||||||
subghz,
|
|
||||||
subghz_setting_get_preset_data_by_name(
|
|
||||||
subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(
|
|
||||||
TAG,
|
|
||||||
"Unknown name preset \" %s \"",
|
|
||||||
furi_string_get_cstr(subghz->txrx->preset->name));
|
|
||||||
subghz_begin(
|
|
||||||
subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650"));
|
|
||||||
}
|
|
||||||
if(subghz->txrx->preset->frequency) {
|
|
||||||
ret = subghz_tx(subghz, subghz->txrx->preset->frequency);
|
|
||||||
} else {
|
|
||||||
ret = subghz_tx(subghz, 433920000);
|
|
||||||
}
|
|
||||||
if(ret) {
|
|
||||||
//Start TX
|
|
||||||
furi_hal_subghz_start_async_tx(
|
|
||||||
subghz_transmitter_yield, subghz->txrx->transmitter);
|
|
||||||
} else {
|
|
||||||
subghz_dialog_message_show_only_rx(subghz);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dialog_message_show_storage_error(
|
|
||||||
subghz->dialogs, "Error in protocol\nparameters\ndescription");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!ret) {
|
|
||||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
|
||||||
if(subghz->txrx->txrx_state != SubGhzTxRxStateSleep) {
|
|
||||||
subghz_idle(subghz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} while(false);
|
|
||||||
furi_string_free(temp_str);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_tx_stop(SubGhz* subghz) {
|
|
||||||
furi_assert(subghz);
|
|
||||||
furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx);
|
|
||||||
//Stop TX
|
|
||||||
furi_hal_subghz_stop_async_tx();
|
|
||||||
subghz_transmitter_stop(subghz->txrx->transmitter);
|
|
||||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
|
||||||
|
|
||||||
//if protocol dynamic then we save the last upload
|
|
||||||
if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) &&
|
|
||||||
(subghz_path_is_file(subghz->file_path))) {
|
|
||||||
subghz_save_protocol_to_file(
|
|
||||||
subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path));
|
|
||||||
}
|
}
|
||||||
subghz_idle(subghz);
|
return false;
|
||||||
subghz_speaker_off(subghz);
|
|
||||||
notification_message(subghz->notifications, &sequence_reset_red);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_dialog_message_show_only_rx(SubGhz* subghz) {
|
void subghz_dialog_message_show_only_rx(SubGhz* subghz) {
|
||||||
@@ -254,11 +82,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
|
|||||||
|
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||||
Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
|
Stream* fff_data_stream =
|
||||||
|
flipper_format_get_raw_stream(subghz_txrx_get_fff_data(subghz->txrx));
|
||||||
|
|
||||||
SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr;
|
SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr;
|
||||||
FuriString* temp_str;
|
FuriString* temp_str = furi_string_alloc();
|
||||||
temp_str = furi_string_alloc();
|
|
||||||
uint32_t temp_data32;
|
uint32_t temp_data32;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -281,6 +109,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Load frequency
|
||||||
if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
|
if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
|
||||||
FURI_LOG_E(TAG, "Missing Frequency");
|
FURI_LOG_E(TAG, "Missing Frequency");
|
||||||
break;
|
break;
|
||||||
@@ -291,58 +120,61 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
subghz->txrx->preset->frequency = temp_data32;
|
//Load preset
|
||||||
|
|
||||||
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
||||||
FURI_LOG_E(TAG, "Missing Preset");
|
FURI_LOG_E(TAG, "Missing Preset");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!subghz_set_preset(subghz, furi_string_get_cstr(temp_str))) {
|
furi_string_set_str(
|
||||||
|
temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str)));
|
||||||
|
if(!strcmp(furi_string_get_cstr(temp_str), "")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||||
|
|
||||||
if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
|
if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) {
|
||||||
//Todo add Custom_preset_module
|
//Todo add Custom_preset_module
|
||||||
//delete preset if it already exists
|
//delete preset if it already exists
|
||||||
subghz_setting_delete_custom_preset(
|
subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str));
|
||||||
subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name));
|
|
||||||
//load custom preset from file
|
//load custom preset from file
|
||||||
if(!subghz_setting_load_custom_preset(
|
if(!subghz_setting_load_custom_preset(
|
||||||
subghz->setting,
|
setting, furi_string_get_cstr(temp_str), fff_data_file)) {
|
||||||
furi_string_get_cstr(subghz->txrx->preset->name),
|
|
||||||
fff_data_file)) {
|
|
||||||
FURI_LOG_E(TAG, "Missing Custom preset");
|
FURI_LOG_E(TAG, "Missing Custom preset");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t preset_index = subghz_setting_get_inx_preset_by_name(
|
size_t preset_index =
|
||||||
subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name));
|
subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str));
|
||||||
subghz_preset_init(
|
subghz_txrx_set_preset(
|
||||||
subghz,
|
subghz->txrx,
|
||||||
furi_string_get_cstr(subghz->txrx->preset->name),
|
furi_string_get_cstr(temp_str),
|
||||||
subghz->txrx->preset->frequency,
|
temp_data32,
|
||||||
subghz_setting_get_preset_data(subghz->setting, preset_index),
|
subghz_setting_get_preset_data(setting, preset_index),
|
||||||
subghz_setting_get_preset_data_size(subghz->setting, preset_index));
|
subghz_setting_get_preset_data_size(setting, preset_index));
|
||||||
|
|
||||||
|
//Load protocol
|
||||||
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
||||||
FURI_LOG_E(TAG, "Missing Protocol");
|
FURI_LOG_E(TAG, "Missing Protocol");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx);
|
||||||
if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
|
if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
|
||||||
//if RAW
|
//if RAW
|
||||||
subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path);
|
subghz->load_type_file = SubGhzLoadTypeFileRaw;
|
||||||
|
subghz_protocol_raw_gen_fff_data(fff_data, file_path);
|
||||||
} else {
|
} else {
|
||||||
|
subghz->load_type_file = SubGhzLoadTypeFileKey;
|
||||||
stream_copy_full(
|
stream_copy_full(
|
||||||
flipper_format_get_raw_stream(fff_data_file),
|
flipper_format_get_raw_stream(fff_data_file),
|
||||||
flipper_format_get_raw_stream(subghz->txrx->fff_data));
|
flipper_format_get_raw_stream(fff_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
|
if(subghz_txrx_load_decoder_by_name_protocol(
|
||||||
subghz->txrx->receiver, furi_string_get_cstr(temp_str));
|
subghz->txrx, furi_string_get_cstr(temp_str))) {
|
||||||
if(subghz->txrx->decoder_result) {
|
|
||||||
SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
|
SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
|
||||||
subghz->txrx->decoder_result, subghz->txrx->fff_data);
|
subghz_txrx_get_decoder(subghz->txrx), fff_data);
|
||||||
if(status != SubGhzProtocolStatusOk) {
|
if(status != SubGhzProtocolStatusOk) {
|
||||||
load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
|
load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
|
||||||
break;
|
break;
|
||||||
@@ -381,17 +213,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) {
|
||||||
|
furi_assert(subghz);
|
||||||
|
return subghz->load_type_file;
|
||||||
|
}
|
||||||
|
|
||||||
bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) {
|
bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) {
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
|
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
FuriString* temp_str;
|
FuriString* temp_str = furi_string_alloc();
|
||||||
FuriString* file_name;
|
FuriString* file_name = furi_string_alloc();
|
||||||
FuriString* file_path;
|
FuriString* file_path = furi_string_alloc();
|
||||||
|
|
||||||
temp_str = furi_string_alloc();
|
|
||||||
file_name = furi_string_alloc();
|
|
||||||
file_path = furi_string_alloc();
|
|
||||||
|
|
||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
@@ -438,8 +271,7 @@ bool subghz_save_protocol_to_file(
|
|||||||
Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
|
Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
|
||||||
|
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
FuriString* file_dir;
|
FuriString* file_dir = furi_string_alloc();
|
||||||
file_dir = furi_string_alloc();
|
|
||||||
|
|
||||||
path_extract_dirname(dev_file_name, file_dir);
|
path_extract_dirname(dev_file_name, file_dir);
|
||||||
do {
|
do {
|
||||||
@@ -467,11 +299,21 @@ bool subghz_save_protocol_to_file(
|
|||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void subghz_save_to_file(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhz* subghz = context;
|
||||||
|
if(subghz_path_is_file(subghz->file_path)) {
|
||||||
|
subghz_save_protocol_to_file(
|
||||||
|
subghz,
|
||||||
|
subghz_txrx_get_fff_data(subghz->txrx),
|
||||||
|
furi_string_get_cstr(subghz->file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool subghz_load_protocol_from_file(SubGhz* subghz) {
|
bool subghz_load_protocol_from_file(SubGhz* subghz) {
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
|
|
||||||
FuriString* file_path;
|
FuriString* file_path = furi_string_alloc();
|
||||||
file_path = furi_string_alloc();
|
|
||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
|
dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
|
||||||
@@ -551,92 +393,27 @@ bool subghz_path_is_file(FuriString* path) {
|
|||||||
return furi_string_end_with(path, SUBGHZ_APP_EXTENSION);
|
return furi_string_end_with(path, SUBGHZ_APP_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t subghz_random_serial(void) {
|
void subghz_lock(SubGhz* subghz) {
|
||||||
return (uint32_t)rand();
|
|
||||||
}
|
|
||||||
|
|
||||||
void subghz_hopper_update(SubGhz* subghz) {
|
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
|
subghz->lock = SubGhzLockOn;
|
||||||
switch(subghz->txrx->hopper_state) {
|
|
||||||
case SubGhzHopperStateOFF:
|
|
||||||
case SubGhzHopperStatePause:
|
|
||||||
return;
|
|
||||||
case SubGhzHopperStateRSSITimeOut:
|
|
||||||
if(subghz->txrx->hopper_timeout != 0) {
|
|
||||||
subghz->txrx->hopper_timeout--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
float rssi = -127.0f;
|
|
||||||
if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) {
|
|
||||||
// See RSSI Calculation timings in CC1101 17.3 RSSI
|
|
||||||
rssi = furi_hal_subghz_get_rssi();
|
|
||||||
|
|
||||||
// Stay if RSSI is high enough
|
|
||||||
if(rssi > -90.0f) {
|
|
||||||
subghz->txrx->hopper_timeout = 10;
|
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
|
|
||||||
}
|
|
||||||
// Select next frequency
|
|
||||||
if(subghz->txrx->hopper_idx_frequency <
|
|
||||||
subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) {
|
|
||||||
subghz->txrx->hopper_idx_frequency++;
|
|
||||||
} else {
|
|
||||||
subghz->txrx->hopper_idx_frequency = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
|
||||||
subghz_rx_end(subghz);
|
|
||||||
};
|
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
|
||||||
subghz_receiver_reset(subghz->txrx->receiver);
|
|
||||||
subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency(
|
|
||||||
subghz->setting, subghz->txrx->hopper_idx_frequency);
|
|
||||||
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_speaker_on(SubGhz* subghz) {
|
void subghz_unlock(SubGhz* subghz) {
|
||||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
furi_assert(subghz);
|
||||||
if(furi_hal_speaker_acquire(30)) {
|
subghz->lock = SubGhzLockOff;
|
||||||
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
|
||||||
} else {
|
|
||||||
subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_speaker_off(SubGhz* subghz) {
|
bool subghz_is_locked(SubGhz* subghz) {
|
||||||
if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) {
|
furi_assert(subghz);
|
||||||
if(furi_hal_speaker_is_mine()) {
|
return (subghz->lock == SubGhzLockOn);
|
||||||
furi_hal_subghz_set_async_mirror_pin(NULL);
|
|
||||||
furi_hal_speaker_release();
|
|
||||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown)
|
|
||||||
subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_speaker_mute(SubGhz* subghz) {
|
void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) {
|
||||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
furi_assert(subghz);
|
||||||
if(furi_hal_speaker_is_mine()) {
|
subghz->rx_key_state = state;
|
||||||
furi_hal_subghz_set_async_mirror_pin(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_speaker_unmute(SubGhz* subghz) {
|
SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) {
|
||||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
furi_assert(subghz);
|
||||||
if(furi_hal_speaker_is_mine()) {
|
return subghz->rx_key_state;
|
||||||
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,6 @@
|
|||||||
#include <gui/modules/widget.h>
|
#include <gui/modules/widget.h>
|
||||||
|
|
||||||
#include <subghz/scenes/subghz_scene.h>
|
#include <subghz/scenes/subghz_scene.h>
|
||||||
#include <lib/subghz/subghz_worker.h>
|
|
||||||
#include <lib/subghz/subghz_setting.h>
|
|
||||||
#include <lib/subghz/receiver.h>
|
|
||||||
#include <lib/subghz/transmitter.h>
|
|
||||||
|
|
||||||
#include "subghz_history.h"
|
#include "subghz_history.h"
|
||||||
|
|
||||||
@@ -37,34 +33,12 @@
|
|||||||
|
|
||||||
#include "rpc/rpc_app.h"
|
#include "rpc/rpc_app.h"
|
||||||
|
|
||||||
|
#include "helpers/subghz_threshold_rssi.h"
|
||||||
|
|
||||||
|
#include "helpers/subghz_txrx.h"
|
||||||
|
|
||||||
#define SUBGHZ_MAX_LEN_NAME 64
|
#define SUBGHZ_MAX_LEN_NAME 64
|
||||||
|
|
||||||
struct SubGhzTxRx {
|
|
||||||
SubGhzWorker* worker;
|
|
||||||
|
|
||||||
SubGhzEnvironment* environment;
|
|
||||||
SubGhzReceiver* receiver;
|
|
||||||
SubGhzTransmitter* transmitter;
|
|
||||||
SubGhzProtocolFlag filter;
|
|
||||||
SubGhzProtocolDecoderBase* decoder_result;
|
|
||||||
FlipperFormat* fff_data;
|
|
||||||
|
|
||||||
SubGhzRadioPreset* preset;
|
|
||||||
SubGhzHistory* history;
|
|
||||||
uint16_t idx_menu_chosen;
|
|
||||||
SubGhzTxRxState txrx_state;
|
|
||||||
SubGhzHopperState hopper_state;
|
|
||||||
SubGhzSpeakerState speaker_state;
|
|
||||||
uint8_t hopper_timeout;
|
|
||||||
uint8_t hopper_idx_frequency;
|
|
||||||
SubGhzRxKeyState rx_key_state;
|
|
||||||
|
|
||||||
float raw_threshold_rssi;
|
|
||||||
uint8_t raw_threshold_rssi_low_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct SubGhzTxRx SubGhzTxRx;
|
|
||||||
|
|
||||||
struct SubGhz {
|
struct SubGhz {
|
||||||
Gui* gui;
|
Gui* gui;
|
||||||
NotificationApp* notifications;
|
NotificationApp* notifications;
|
||||||
@@ -93,47 +67,43 @@ struct SubGhz {
|
|||||||
SubGhzTestStatic* subghz_test_static;
|
SubGhzTestStatic* subghz_test_static;
|
||||||
SubGhzTestCarrier* subghz_test_carrier;
|
SubGhzTestCarrier* subghz_test_carrier;
|
||||||
SubGhzTestPacket* subghz_test_packet;
|
SubGhzTestPacket* subghz_test_packet;
|
||||||
FuriString* error_str;
|
|
||||||
SubGhzSetting* setting;
|
|
||||||
SubGhzLock lock;
|
|
||||||
|
|
||||||
|
SubGhzProtocolFlag filter;
|
||||||
|
FuriString* error_str;
|
||||||
|
SubGhzLock lock;
|
||||||
|
SubGhzThresholdRssi* threshold_rssi;
|
||||||
|
SubGhzRxKeyState rx_key_state;
|
||||||
|
SubGhzHistory* history;
|
||||||
|
uint16_t idx_menu_chosen;
|
||||||
|
SubGhzLoadTypeFile load_type_file;
|
||||||
void* rpc_ctx;
|
void* rpc_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
void subghz_preset_init(
|
void subghz_set_default_preset(SubGhz* subghz);
|
||||||
void* context,
|
void subghz_blink_start(SubGhz* subghz);
|
||||||
const char* preset_name,
|
void subghz_blink_stop(SubGhz* subghz);
|
||||||
uint32_t frequency,
|
|
||||||
uint8_t* preset_data,
|
|
||||||
size_t preset_data_size);
|
|
||||||
bool subghz_set_preset(SubGhz* subghz, const char* preset);
|
|
||||||
void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation);
|
|
||||||
void subghz_begin(SubGhz* subghz, uint8_t* preset_data);
|
|
||||||
uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
|
|
||||||
void subghz_rx_end(SubGhz* subghz);
|
|
||||||
void subghz_sleep(SubGhz* subghz);
|
|
||||||
|
|
||||||
void subghz_blink_start(SubGhz* instance);
|
|
||||||
void subghz_blink_stop(SubGhz* instance);
|
|
||||||
|
|
||||||
bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format);
|
bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format);
|
||||||
void subghz_tx_stop(SubGhz* subghz);
|
|
||||||
void subghz_dialog_message_show_only_rx(SubGhz* subghz);
|
void subghz_dialog_message_show_only_rx(SubGhz* subghz);
|
||||||
|
|
||||||
bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog);
|
bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog);
|
||||||
bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len);
|
bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len);
|
||||||
bool subghz_save_protocol_to_file(
|
bool subghz_save_protocol_to_file(
|
||||||
SubGhz* subghz,
|
SubGhz* subghz,
|
||||||
FlipperFormat* flipper_format,
|
FlipperFormat* flipper_format,
|
||||||
const char* dev_file_name);
|
const char* dev_file_name);
|
||||||
|
void subghz_save_to_file(void* context);
|
||||||
bool subghz_load_protocol_from_file(SubGhz* subghz);
|
bool subghz_load_protocol_from_file(SubGhz* subghz);
|
||||||
bool subghz_rename_file(SubGhz* subghz);
|
bool subghz_rename_file(SubGhz* subghz);
|
||||||
bool subghz_file_available(SubGhz* subghz);
|
bool subghz_file_available(SubGhz* subghz);
|
||||||
bool subghz_delete_file(SubGhz* subghz);
|
bool subghz_delete_file(SubGhz* subghz);
|
||||||
void subghz_file_name_clear(SubGhz* subghz);
|
void subghz_file_name_clear(SubGhz* subghz);
|
||||||
bool subghz_path_is_file(FuriString* path);
|
bool subghz_path_is_file(FuriString* path);
|
||||||
uint32_t subghz_random_serial(void);
|
SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz);
|
||||||
void subghz_hopper_update(SubGhz* subghz);
|
|
||||||
void subghz_speaker_on(SubGhz* subghz);
|
void subghz_lock(SubGhz* subghz);
|
||||||
void subghz_speaker_off(SubGhz* subghz);
|
void subghz_unlock(SubGhz* subghz);
|
||||||
void subghz_speaker_mute(SubGhz* subghz);
|
bool subghz_is_locked(SubGhz* subghz);
|
||||||
void subghz_speaker_unmute(SubGhz* subghz);
|
|
||||||
|
void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state);
|
||||||
|
SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#define MENU_ITEMS 4u
|
#define MENU_ITEMS 4u
|
||||||
#define UNLOCK_CNT 3
|
#define UNLOCK_CNT 3
|
||||||
|
|
||||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
|
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriString* item_str;
|
FuriString* item_str;
|
||||||
@@ -44,7 +44,7 @@ typedef enum {
|
|||||||
} SubGhzViewReceiverBarShow;
|
} SubGhzViewReceiverBarShow;
|
||||||
|
|
||||||
struct SubGhzViewReceiver {
|
struct SubGhzViewReceiver {
|
||||||
SubGhzLock lock;
|
bool lock;
|
||||||
uint8_t lock_count;
|
uint8_t lock_count;
|
||||||
FuriTimer* timer;
|
FuriTimer* timer;
|
||||||
View* view;
|
View* view;
|
||||||
@@ -70,20 +70,21 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) {
|
|||||||
instance->view,
|
instance->view,
|
||||||
SubGhzViewReceiverModel * model,
|
SubGhzViewReceiverModel * model,
|
||||||
{
|
{
|
||||||
if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
|
if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
|
||||||
model->u_rssi = 0;
|
model->u_rssi = 0;
|
||||||
} else {
|
} else {
|
||||||
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
|
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) {
|
void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) {
|
||||||
furi_assert(subghz_receiver);
|
furi_assert(subghz_receiver);
|
||||||
subghz_receiver->lock_count = 0;
|
subghz_receiver->lock_count = 0;
|
||||||
if(lock == SubGhzLockOn) {
|
|
||||||
subghz_receiver->lock = lock;
|
if(lock == true) {
|
||||||
|
subghz_receiver->lock = true;
|
||||||
with_view_model(
|
with_view_model(
|
||||||
subghz_receiver->view,
|
subghz_receiver->view,
|
||||||
SubGhzViewReceiverModel * model,
|
SubGhzViewReceiverModel * model,
|
||||||
@@ -280,7 +281,7 @@ static void subghz_view_receiver_timer_callback(void* context) {
|
|||||||
subghz_receiver->callback(
|
subghz_receiver->callback(
|
||||||
SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context);
|
SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context);
|
||||||
} else {
|
} else {
|
||||||
subghz_receiver->lock = SubGhzLockOff;
|
subghz_receiver->lock = false;
|
||||||
subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context);
|
subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context);
|
||||||
}
|
}
|
||||||
subghz_receiver->lock_count = 0;
|
subghz_receiver->lock_count = 0;
|
||||||
@@ -290,7 +291,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
|||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhzViewReceiver* subghz_receiver = context;
|
SubGhzViewReceiver* subghz_receiver = context;
|
||||||
|
|
||||||
if(subghz_receiver->lock == SubGhzLockOn) {
|
if(subghz_receiver->lock == true) {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
subghz_receiver->view,
|
subghz_receiver->view,
|
||||||
SubGhzViewReceiverModel * model,
|
SubGhzViewReceiverModel * model,
|
||||||
@@ -310,7 +311,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
|||||||
SubGhzViewReceiverModel * model,
|
SubGhzViewReceiverModel * model,
|
||||||
{ model->bar_show = SubGhzViewReceiverBarShowUnlock; },
|
{ model->bar_show = SubGhzViewReceiverBarShowUnlock; },
|
||||||
true);
|
true);
|
||||||
//subghz_receiver->lock = SubGhzLockOff;
|
//subghz_receiver->lock = false;
|
||||||
furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650));
|
furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,7 +395,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
|
|||||||
// View allocation and configuration
|
// View allocation and configuration
|
||||||
subghz_receiver->view = view_alloc();
|
subghz_receiver->view = view_alloc();
|
||||||
|
|
||||||
subghz_receiver->lock = SubGhzLockOff;
|
subghz_receiver->lock = false;
|
||||||
subghz_receiver->lock_count = 0;
|
subghz_receiver->lock_count = 0;
|
||||||
view_allocate_model(
|
view_allocate_model(
|
||||||
subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel));
|
subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel));
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* contex
|
|||||||
|
|
||||||
void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi);
|
void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi);
|
||||||
|
|
||||||
void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard);
|
void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool keyboard);
|
||||||
|
|
||||||
void subghz_view_receiver_set_callback(
|
void subghz_view_receiver_set_callback(
|
||||||
SubGhzViewReceiver* subghz_receiver,
|
SubGhzViewReceiver* subghz_receiver,
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra
|
|||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
uint8_t u_rssi = 0;
|
uint8_t u_rssi = 0;
|
||||||
|
|
||||||
if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
|
if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
|
||||||
u_rssi = 0;
|
u_rssi = 0;
|
||||||
} else {
|
} else {
|
||||||
u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
|
u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
with_view_model(
|
with_view_model(
|
||||||
@@ -261,9 +261,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod
|
|||||||
uint8_t x = 118;
|
uint8_t x = 118;
|
||||||
uint8_t y = 48;
|
uint8_t y = 48;
|
||||||
|
|
||||||
if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) {
|
if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) {
|
||||||
uint8_t x = 118;
|
uint8_t x = 118;
|
||||||
y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
|
y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
|
||||||
|
|
||||||
uint8_t width = 3;
|
uint8_t width = 3;
|
||||||
for(uint8_t i = 0; i < x; i += width * 2) {
|
for(uint8_t i = 0; i < x; i += width * 2) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
#include "../helpers/subghz_custom_event.h"
|
#include "../helpers/subghz_custom_event.h"
|
||||||
|
|
||||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
|
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
|
||||||
|
|
||||||
typedef struct SubGhzReadRAW SubGhzReadRAW;
|
typedef struct SubGhzReadRAW SubGhzReadRAW;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ typedef struct {
|
|||||||
FuriString* frequency_str;
|
FuriString* frequency_str;
|
||||||
FuriString* preset_str;
|
FuriString* preset_str;
|
||||||
FuriString* key_str;
|
FuriString* key_str;
|
||||||
uint8_t show_button;
|
bool show_button;
|
||||||
} SubGhzViewTransmitterModel;
|
} SubGhzViewTransmitterModel;
|
||||||
|
|
||||||
void subghz_view_transmitter_set_callback(
|
void subghz_view_transmitter_set_callback(
|
||||||
@@ -32,7 +32,7 @@ void subghz_view_transmitter_add_data_to_show(
|
|||||||
const char* key_str,
|
const char* key_str,
|
||||||
const char* frequency_str,
|
const char* frequency_str,
|
||||||
const char* preset_str,
|
const char* preset_str,
|
||||||
uint8_t show_button) {
|
bool show_button) {
|
||||||
furi_assert(subghz_transmitter);
|
furi_assert(subghz_transmitter);
|
||||||
with_view_model(
|
with_view_model(
|
||||||
subghz_transmitter->view,
|
subghz_transmitter->view,
|
||||||
@@ -104,7 +104,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
|
|||||||
furi_string_reset(model->frequency_str);
|
furi_string_reset(model->frequency_str);
|
||||||
furi_string_reset(model->preset_str);
|
furi_string_reset(model->preset_str);
|
||||||
furi_string_reset(model->key_str);
|
furi_string_reset(model->key_str);
|
||||||
model->show_button = 0;
|
model->show_button = false;
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show(
|
|||||||
const char* key_str,
|
const char* key_str,
|
||||||
const char* frequency_str,
|
const char* frequency_str,
|
||||||
const char* preset_str,
|
const char* preset_str,
|
||||||
uint8_t show_button);
|
bool show_button);
|
||||||
|
|||||||
@@ -220,11 +220,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) {
|
|||||||
UNUSED(context);
|
UNUSED(context);
|
||||||
if(!furi_string_cmp(args, "0")) {
|
if(!furi_string_cmp(args, "0")) {
|
||||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
|
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
|
||||||
loader_update_menu();
|
|
||||||
printf("Debug disabled.");
|
printf("Debug disabled.");
|
||||||
} else if(!furi_string_cmp(args, "1")) {
|
} else if(!furi_string_cmp(args, "1")) {
|
||||||
furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
|
furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
|
||||||
loader_update_menu();
|
|
||||||
printf("Debug enabled.");
|
printf("Debug enabled.");
|
||||||
} else {
|
} else {
|
||||||
cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args));
|
cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args));
|
||||||
|
|||||||
@@ -106,10 +106,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
switch(event.event) {
|
switch(event.event) {
|
||||||
case DesktopMainEventOpenMenu:
|
case DesktopMainEventOpenMenu: {
|
||||||
loader_show_menu();
|
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||||
|
loader_show_menu(loader);
|
||||||
|
furi_record_close(RECORD_LOADER);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
} break;
|
||||||
|
|
||||||
case DesktopMainEventOpenLockMenu:
|
case DesktopMainEventOpenLockMenu:
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu);
|
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu);
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ Menu* menu_alloc() {
|
|||||||
void menu_free(Menu* menu) {
|
void menu_free(Menu* menu) {
|
||||||
furi_assert(menu);
|
furi_assert(menu);
|
||||||
menu_reset(menu);
|
menu_reset(menu);
|
||||||
|
with_view_model(
|
||||||
|
menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false);
|
||||||
view_free(menu->view);
|
view_free(menu->view);
|
||||||
free(menu);
|
free(menu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,19 +19,16 @@ void view_tie_icon_animation(View* view, IconAnimation* icon_animation) {
|
|||||||
|
|
||||||
void view_set_draw_callback(View* view, ViewDrawCallback callback) {
|
void view_set_draw_callback(View* view, ViewDrawCallback callback) {
|
||||||
furi_assert(view);
|
furi_assert(view);
|
||||||
furi_assert(view->draw_callback == NULL);
|
|
||||||
view->draw_callback = callback;
|
view->draw_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void view_set_input_callback(View* view, ViewInputCallback callback) {
|
void view_set_input_callback(View* view, ViewInputCallback callback) {
|
||||||
furi_assert(view);
|
furi_assert(view);
|
||||||
furi_assert(view->input_callback == NULL);
|
|
||||||
view->input_callback = callback;
|
view->input_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void view_set_custom_callback(View* view, ViewCustomCallback callback) {
|
void view_set_custom_callback(View* view, ViewCustomCallback callback) {
|
||||||
furi_assert(view);
|
furi_assert(view);
|
||||||
furi_assert(callback);
|
|
||||||
view->custom_callback = callback;
|
view->custom_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +59,6 @@ void view_set_update_callback_context(View* view, void* context) {
|
|||||||
|
|
||||||
void view_set_context(View* view, void* context) {
|
void view_set_context(View* view, void* context) {
|
||||||
furi_assert(view);
|
furi_assert(view);
|
||||||
furi_assert(context);
|
|
||||||
view->context = context;
|
view->context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ App(
|
|||||||
entry_point="loader_srv",
|
entry_point="loader_srv",
|
||||||
cdefines=["SRV_LOADER"],
|
cdefines=["SRV_LOADER"],
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
|
provides=["loader_start"],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
order=90,
|
order=90,
|
||||||
sdk_headers=[
|
sdk_headers=[
|
||||||
@@ -12,3 +13,11 @@ App(
|
|||||||
"firmware_api/firmware_api.h",
|
"firmware_api/firmware_api.h",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="loader_start",
|
||||||
|
apptype=FlipperAppType.STARTUP,
|
||||||
|
entry_point="loader_on_system_start",
|
||||||
|
requires=["loader"],
|
||||||
|
order=90,
|
||||||
|
)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
/* Generated table */
|
/* Generated table */
|
||||||
#include <firmware_api_table.h>
|
#include <firmware_api_table.h>
|
||||||
|
|
||||||
|
#include <furi_hal_info.h>
|
||||||
|
|
||||||
static_assert(!has_hash_collisions(elf_api_table), "Detected API method hash collision!");
|
static_assert(!has_hash_collisions(elf_api_table), "Detected API method hash collision!");
|
||||||
|
|
||||||
constexpr HashtableApiInterface elf_api_interface{
|
constexpr HashtableApiInterface elf_api_interface{
|
||||||
@@ -19,3 +21,8 @@ constexpr HashtableApiInterface elf_api_interface{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ElfApiInterface* const firmware_api_interface = &elf_api_interface;
|
const ElfApiInterface* const firmware_api_interface = &elf_api_interface;
|
||||||
|
|
||||||
|
extern "C" void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) {
|
||||||
|
*major = elf_api_interface.api_version_major;
|
||||||
|
*minor = elf_api_interface.api_version_minor;
|
||||||
|
}
|
||||||
@@ -1,76 +1,114 @@
|
|||||||
#include "applications.h"
|
#include "loader.h"
|
||||||
#include <furi.h>
|
|
||||||
#include "loader/loader.h"
|
|
||||||
#include "loader_i.h"
|
#include "loader_i.h"
|
||||||
|
#include "loader_menu.h"
|
||||||
|
#include <applications.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
|
||||||
#define TAG "LoaderSrv"
|
#define TAG "Loader"
|
||||||
|
#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF
|
||||||
|
// api
|
||||||
|
|
||||||
#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0)
|
LoaderStatus loader_start(Loader* loader, const char* name, const char* args) {
|
||||||
#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU)
|
LoaderMessage message;
|
||||||
|
LoaderMessageLoaderStatusResult result;
|
||||||
|
|
||||||
static Loader* loader_instance = NULL;
|
message.type = LoaderMessageTypeStartByName;
|
||||||
|
message.start.name = name;
|
||||||
static bool
|
message.start.args = args;
|
||||||
loader_start_application(const FlipperApplication* application, const char* arguments) {
|
message.api_lock = api_lock_alloc_locked();
|
||||||
loader_instance->application = application;
|
message.status_value = &result;
|
||||||
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
furi_assert(loader_instance->application_arguments == NULL);
|
api_lock_wait_unlock_and_free(message.api_lock);
|
||||||
if(arguments && strlen(arguments) > 0) {
|
return result.value;
|
||||||
loader_instance->application_arguments = strdup(arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name);
|
|
||||||
|
|
||||||
FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
|
|
||||||
if(mode > FuriHalRtcHeapTrackModeNone) {
|
|
||||||
furi_thread_enable_heap_trace(loader_instance->application_thread);
|
|
||||||
} else {
|
|
||||||
furi_thread_disable_heap_trace(loader_instance->application_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name);
|
|
||||||
furi_thread_set_appid(
|
|
||||||
loader_instance->application_thread, loader_instance->application->appid);
|
|
||||||
furi_thread_set_stack_size(
|
|
||||||
loader_instance->application_thread, loader_instance->application->stack_size);
|
|
||||||
furi_thread_set_context(
|
|
||||||
loader_instance->application_thread, loader_instance->application_arguments);
|
|
||||||
furi_thread_set_callback(
|
|
||||||
loader_instance->application_thread, loader_instance->application->app);
|
|
||||||
|
|
||||||
furi_thread_start(loader_instance->application_thread);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_menu_callback(void* _ctx, uint32_t index) {
|
bool loader_lock(Loader* loader) {
|
||||||
UNUSED(index);
|
LoaderMessage message;
|
||||||
const FlipperApplication* application = _ctx;
|
LoaderMessageBoolResult result;
|
||||||
|
message.type = LoaderMessageTypeLock;
|
||||||
|
message.api_lock = api_lock_alloc_locked();
|
||||||
|
message.bool_value = &result;
|
||||||
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
|
api_lock_wait_unlock_and_free(message.api_lock);
|
||||||
|
return result.value;
|
||||||
|
}
|
||||||
|
|
||||||
furi_assert(application->app);
|
void loader_unlock(Loader* loader) {
|
||||||
furi_assert(application->name);
|
LoaderMessage message;
|
||||||
|
message.type = LoaderMessageTypeUnlock;
|
||||||
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
if(!loader_lock(loader_instance)) {
|
bool loader_is_locked(Loader* loader) {
|
||||||
FURI_LOG_E(TAG, "Loader is locked");
|
LoaderMessage message;
|
||||||
return;
|
LoaderMessageBoolResult result;
|
||||||
|
message.type = LoaderMessageTypeIsLocked;
|
||||||
|
message.api_lock = api_lock_alloc_locked();
|
||||||
|
message.bool_value = &result;
|
||||||
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
|
api_lock_wait_unlock_and_free(message.api_lock);
|
||||||
|
return result.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_show_menu(Loader* loader) {
|
||||||
|
LoaderMessage message;
|
||||||
|
message.type = LoaderMessageTypeShowMenu;
|
||||||
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
|
FuriPubSub* loader_get_pubsub(Loader* loader) {
|
||||||
|
furi_assert(loader);
|
||||||
|
// it's safe to return pubsub without locking
|
||||||
|
// because it's never freed and loader is never exited
|
||||||
|
// also the loader instance cannot be obtained until the pubsub is created
|
||||||
|
return loader->pubsub;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
|
||||||
|
static void loader_menu_closed_callback(void* context) {
|
||||||
|
Loader* loader = context;
|
||||||
|
LoaderMessage message;
|
||||||
|
message.type = LoaderMessageTypeMenuClosed;
|
||||||
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_menu_click_callback(const char* name, void* context) {
|
||||||
|
Loader* loader = context;
|
||||||
|
loader_start(loader, name, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_thread_state_callback(FuriThreadState thread_state, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
|
||||||
|
Loader* loader = context;
|
||||||
|
LoaderEvent event;
|
||||||
|
|
||||||
|
if(thread_state == FuriThreadStateRunning) {
|
||||||
|
event.type = LoaderEventTypeApplicationStarted;
|
||||||
|
furi_pubsub_publish(loader->pubsub, &event);
|
||||||
|
} else if(thread_state == FuriThreadStateStopped) {
|
||||||
|
LoaderMessage message;
|
||||||
|
message.type = LoaderMessageTypeAppClosed;
|
||||||
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
|
|
||||||
|
event.type = LoaderEventTypeApplicationStopped;
|
||||||
|
furi_pubsub_publish(loader->pubsub, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
loader_start_application(application, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_submenu_callback(void* context, uint32_t index) {
|
// implementation
|
||||||
UNUSED(index);
|
|
||||||
uint32_t view_id = (uint32_t)context;
|
|
||||||
view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loader_cli_print_usage() {
|
static Loader* loader_alloc() {
|
||||||
printf("Usage:\r\n");
|
Loader* loader = malloc(sizeof(Loader));
|
||||||
printf("loader <cmd> <args>\r\n");
|
loader->pubsub = furi_pubsub_alloc();
|
||||||
printf("Cmd list:\r\n");
|
loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage));
|
||||||
printf("\tlist\t - List available applications\r\n");
|
loader->loader_menu = NULL;
|
||||||
printf("\topen <Application Name:string>\t - Open application by name\r\n");
|
loader->app.args = NULL;
|
||||||
printf("\tinfo\t - Show loader state\r\n");
|
loader->app.name = NULL;
|
||||||
|
loader->app.thread = NULL;
|
||||||
|
loader->app.insomniac = false;
|
||||||
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FlipperApplication const* loader_find_application_by_name_in_list(
|
static FlipperApplication const* loader_find_application_by_name_in_list(
|
||||||
@@ -85,7 +123,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FlipperApplication* loader_find_application_by_name(const char* name) {
|
static const FlipperApplication* loader_find_application_by_name(const char* name) {
|
||||||
const FlipperApplication* application = NULL;
|
const FlipperApplication* application = NULL;
|
||||||
application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT);
|
application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT);
|
||||||
if(!application) {
|
if(!application) {
|
||||||
@@ -100,346 +138,168 @@ const FlipperApplication* loader_find_application_by_name(const char* name) {
|
|||||||
return application;
|
return application;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) {
|
static void
|
||||||
UNUSED(cli);
|
loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) {
|
||||||
if(loader_is_locked(instance)) {
|
FURI_LOG_I(TAG, "Starting %s", app->name);
|
||||||
if(instance->application) {
|
|
||||||
furi_assert(instance->application->name);
|
// store args
|
||||||
printf("Can't start, %s application is running", instance->application->name);
|
furi_assert(loader->app.args == NULL);
|
||||||
} else {
|
if(args && strlen(args) > 0) {
|
||||||
printf("Can't start, furi application is running");
|
loader->app.args = strdup(args);
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FuriString* application_name;
|
// store name
|
||||||
application_name = furi_string_alloc();
|
furi_assert(loader->app.name == NULL);
|
||||||
|
loader->app.name = strdup(app->name);
|
||||||
|
|
||||||
do {
|
// setup app thread
|
||||||
if(!args_read_probably_quoted_string_and_trim(args, application_name)) {
|
loader->app.thread =
|
||||||
printf("No application provided\r\n");
|
furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args);
|
||||||
break;
|
furi_thread_set_appid(loader->app.thread, app->appid);
|
||||||
}
|
|
||||||
|
|
||||||
const FlipperApplication* application =
|
// setup heap trace
|
||||||
loader_find_application_by_name(furi_string_get_cstr(application_name));
|
FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
|
||||||
if(!application) {
|
if(mode > FuriHalRtcHeapTrackModeNone) {
|
||||||
printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name));
|
furi_thread_enable_heap_trace(loader->app.thread);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_trim(args);
|
|
||||||
if(!loader_start_application(application, furi_string_get_cstr(args))) {
|
|
||||||
printf("Can't start, furi application is running");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// We must to increment lock counter to keep balance
|
|
||||||
// TODO: rewrite whole thing, it's complex as hell
|
|
||||||
FURI_CRITICAL_ENTER();
|
|
||||||
instance->lock_count++;
|
|
||||||
FURI_CRITICAL_EXIT();
|
|
||||||
}
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
furi_string_free(application_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) {
|
|
||||||
UNUSED(cli);
|
|
||||||
UNUSED(args);
|
|
||||||
UNUSED(instance);
|
|
||||||
printf("Applications:\r\n");
|
|
||||||
for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
|
||||||
printf("\t%s\r\n", FLIPPER_APPS[i].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) {
|
|
||||||
UNUSED(cli);
|
|
||||||
UNUSED(args);
|
|
||||||
if(!loader_is_locked(instance)) {
|
|
||||||
printf("No application is running\r\n");
|
|
||||||
} else {
|
} else {
|
||||||
printf("Running application: ");
|
furi_thread_disable_heap_trace(loader->app.thread);
|
||||||
if(instance->application) {
|
}
|
||||||
furi_assert(instance->application->name);
|
|
||||||
printf("%s\r\n", instance->application->name);
|
// setup insomnia
|
||||||
} else {
|
if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) {
|
||||||
printf("unknown\r\n");
|
furi_hal_power_insomnia_enter();
|
||||||
}
|
loader->app.insomniac = true;
|
||||||
|
} else {
|
||||||
|
loader->app.insomniac = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup app thread callbacks
|
||||||
|
furi_thread_set_state_context(loader->app.thread, loader);
|
||||||
|
furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback);
|
||||||
|
|
||||||
|
// start app thread
|
||||||
|
furi_thread_start(loader->app.thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process messages
|
||||||
|
|
||||||
|
static void loader_do_menu_show(Loader* loader) {
|
||||||
|
if(!loader->loader_menu) {
|
||||||
|
loader->loader_menu = loader_menu_alloc();
|
||||||
|
loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader);
|
||||||
|
loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader);
|
||||||
|
loader_menu_start(loader->loader_menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_cli(Cli* cli, FuriString* args, void* _ctx) {
|
static void loader_do_menu_closed(Loader* loader) {
|
||||||
furi_assert(_ctx);
|
if(loader->loader_menu) {
|
||||||
Loader* instance = _ctx;
|
loader_menu_stop(loader->loader_menu);
|
||||||
|
loader_menu_free(loader->loader_menu);
|
||||||
FuriString* cmd;
|
loader->loader_menu = NULL;
|
||||||
cmd = furi_string_alloc();
|
}
|
||||||
|
|
||||||
do {
|
|
||||||
if(!args_read_string_and_trim(args, cmd)) {
|
|
||||||
loader_cli_print_usage();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(furi_string_cmp_str(cmd, "list") == 0) {
|
|
||||||
loader_cli_list(cli, args, instance);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(furi_string_cmp_str(cmd, "open") == 0) {
|
|
||||||
loader_cli_open(cli, args, instance);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(furi_string_cmp_str(cmd, "info") == 0) {
|
|
||||||
loader_cli_info(cli, args, instance);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
loader_cli_print_usage();
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
furi_string_free(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LoaderStatus loader_start(Loader* instance, const char* name, const char* args) {
|
static bool loader_do_is_locked(Loader* loader) {
|
||||||
UNUSED(instance);
|
return loader->app.thread != NULL;
|
||||||
furi_assert(name);
|
}
|
||||||
|
|
||||||
const FlipperApplication* application = loader_find_application_by_name(name);
|
static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) {
|
||||||
|
if(loader_do_is_locked(loader)) {
|
||||||
if(!application) {
|
|
||||||
FURI_LOG_E(TAG, "Can't find application with name %s", name);
|
|
||||||
return LoaderStatusErrorUnknownApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!loader_lock(loader_instance)) {
|
|
||||||
FURI_LOG_E(TAG, "Loader is locked");
|
|
||||||
return LoaderStatusErrorAppStarted;
|
return LoaderStatusErrorAppStarted;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!loader_start_application(application, args)) {
|
const FlipperApplication* app = loader_find_application_by_name(name);
|
||||||
return LoaderStatusErrorInternal;
|
|
||||||
|
if(!app) {
|
||||||
|
return LoaderStatusErrorUnknownApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loader_start_internal_app(loader, app, args);
|
||||||
return LoaderStatusOk;
|
return LoaderStatusOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loader_lock(Loader* instance) {
|
static bool loader_do_lock(Loader* loader) {
|
||||||
FURI_CRITICAL_ENTER();
|
if(loader->app.thread) {
|
||||||
bool result = false;
|
return false;
|
||||||
if(instance->lock_count == 0) {
|
|
||||||
instance->lock_count++;
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
FURI_CRITICAL_EXIT();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loader_unlock(Loader* instance) {
|
|
||||||
FURI_CRITICAL_ENTER();
|
|
||||||
if(instance->lock_count > 0) instance->lock_count--;
|
|
||||||
FURI_CRITICAL_EXIT();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loader_is_locked(const Loader* instance) {
|
|
||||||
return instance->lock_count > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loader_thread_state_callback(FuriThreadState thread_state, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
Loader* instance = context;
|
|
||||||
LoaderEvent event;
|
|
||||||
|
|
||||||
if(thread_state == FuriThreadStateRunning) {
|
|
||||||
event.type = LoaderEventTypeApplicationStarted;
|
|
||||||
furi_pubsub_publish(loader_instance->pubsub, &event);
|
|
||||||
|
|
||||||
if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) {
|
|
||||||
furi_hal_power_insomnia_enter();
|
|
||||||
}
|
|
||||||
} else if(thread_state == FuriThreadStateStopped) {
|
|
||||||
FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap());
|
|
||||||
|
|
||||||
if(loader_instance->application_arguments) {
|
|
||||||
free(loader_instance->application_arguments);
|
|
||||||
loader_instance->application_arguments = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) {
|
|
||||||
furi_hal_power_insomnia_exit();
|
|
||||||
}
|
|
||||||
loader_unlock(instance);
|
|
||||||
|
|
||||||
event.type = LoaderEventTypeApplicationStopped;
|
|
||||||
furi_pubsub_publish(loader_instance->pubsub, &event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t loader_hide_menu(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
return VIEW_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t loader_back_to_primary_menu(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
Submenu* submenu = context;
|
|
||||||
submenu_set_selected_item(submenu, 0);
|
|
||||||
return LoaderMenuViewPrimary;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Loader* loader_alloc() {
|
|
||||||
Loader* instance = malloc(sizeof(Loader));
|
|
||||||
|
|
||||||
instance->application_thread = furi_thread_alloc();
|
|
||||||
|
|
||||||
furi_thread_set_state_context(instance->application_thread, instance);
|
|
||||||
furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback);
|
|
||||||
|
|
||||||
instance->pubsub = furi_pubsub_alloc();
|
|
||||||
|
|
||||||
#ifdef SRV_CLI
|
|
||||||
instance->cli = furi_record_open(RECORD_CLI);
|
|
||||||
cli_add_command(
|
|
||||||
instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance);
|
|
||||||
#else
|
|
||||||
UNUSED(loader_cli);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
instance->loader_thread = furi_thread_get_current_id();
|
|
||||||
|
|
||||||
// Gui
|
|
||||||
instance->gui = furi_record_open(RECORD_GUI);
|
|
||||||
instance->view_dispatcher = view_dispatcher_alloc();
|
|
||||||
view_dispatcher_attach_to_gui(
|
|
||||||
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);
|
|
||||||
// Primary menu
|
|
||||||
instance->primary_menu = menu_alloc();
|
|
||||||
view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu);
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu));
|
|
||||||
// Settings menu
|
|
||||||
instance->settings_menu = submenu_alloc();
|
|
||||||
view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu);
|
|
||||||
view_set_previous_callback(
|
|
||||||
submenu_get_view(instance->settings_menu), loader_back_to_primary_menu);
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
instance->view_dispatcher,
|
|
||||||
LoaderMenuViewSettings,
|
|
||||||
submenu_get_view(instance->settings_menu));
|
|
||||||
|
|
||||||
view_dispatcher_enable_queue(instance->view_dispatcher);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loader_free(Loader* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(instance->cli) {
|
|
||||||
furi_record_close(RECORD_CLI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_pubsub_free(instance->pubsub);
|
loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE;
|
||||||
|
return true;
|
||||||
furi_thread_free(instance->application_thread);
|
|
||||||
|
|
||||||
menu_free(loader_instance->primary_menu);
|
|
||||||
view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary);
|
|
||||||
submenu_free(loader_instance->settings_menu);
|
|
||||||
view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings);
|
|
||||||
view_dispatcher_free(loader_instance->view_dispatcher);
|
|
||||||
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
|
|
||||||
free(instance);
|
|
||||||
instance = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_build_menu() {
|
static void loader_do_unlock(Loader* loader) {
|
||||||
FURI_LOG_I(TAG, "Building main menu");
|
furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE);
|
||||||
size_t i;
|
loader->app.thread = NULL;
|
||||||
for(i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
}
|
||||||
menu_add_item(
|
|
||||||
loader_instance->primary_menu,
|
static void loader_do_app_closed(Loader* loader) {
|
||||||
FLIPPER_APPS[i].name,
|
furi_assert(loader->app.thread);
|
||||||
FLIPPER_APPS[i].icon,
|
FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap());
|
||||||
i,
|
if(loader->app.args) {
|
||||||
loader_menu_callback,
|
free(loader->app.args);
|
||||||
(void*)&FLIPPER_APPS[i]);
|
loader->app.args = NULL;
|
||||||
}
|
}
|
||||||
menu_add_item(
|
|
||||||
loader_instance->primary_menu,
|
|
||||||
"Settings",
|
|
||||||
&A_Settings_14,
|
|
||||||
i++,
|
|
||||||
loader_submenu_callback,
|
|
||||||
(void*)LoaderMenuViewSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loader_build_submenu() {
|
if(loader->app.insomniac) {
|
||||||
FURI_LOG_I(TAG, "Building settings menu");
|
furi_hal_power_insomnia_exit();
|
||||||
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
|
|
||||||
submenu_add_item(
|
|
||||||
loader_instance->settings_menu,
|
|
||||||
FLIPPER_SETTINGS_APPS[i].name,
|
|
||||||
i,
|
|
||||||
loader_menu_callback,
|
|
||||||
(void*)&FLIPPER_SETTINGS_APPS[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(loader->app.name);
|
||||||
|
loader->app.name = NULL;
|
||||||
|
|
||||||
|
furi_thread_join(loader->app.thread);
|
||||||
|
furi_thread_free(loader->app.thread);
|
||||||
|
loader->app.thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loader_show_menu() {
|
// app
|
||||||
furi_assert(loader_instance);
|
|
||||||
furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loader_update_menu() {
|
|
||||||
menu_reset(loader_instance->primary_menu);
|
|
||||||
loader_build_menu();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t loader_srv(void* p) {
|
int32_t loader_srv(void* p) {
|
||||||
UNUSED(p);
|
UNUSED(p);
|
||||||
|
Loader* loader = loader_alloc();
|
||||||
|
furi_record_create(RECORD_LOADER, loader);
|
||||||
|
|
||||||
FURI_LOG_I(TAG, "Executing system start hooks");
|
FURI_LOG_I(TAG, "Executing system start hooks");
|
||||||
for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) {
|
for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) {
|
||||||
FLIPPER_ON_SYSTEM_START[i]();
|
FLIPPER_ON_SYSTEM_START[i]();
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_I(TAG, "Starting");
|
|
||||||
loader_instance = loader_alloc();
|
|
||||||
|
|
||||||
loader_build_menu();
|
|
||||||
loader_build_submenu();
|
|
||||||
|
|
||||||
FURI_LOG_I(TAG, "Started");
|
|
||||||
|
|
||||||
furi_record_create(RECORD_LOADER, loader_instance);
|
|
||||||
|
|
||||||
if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) {
|
if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) {
|
||||||
loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL);
|
loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(1) {
|
LoaderMessage message;
|
||||||
uint32_t flags =
|
while(true) {
|
||||||
furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever);
|
if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) {
|
||||||
if(flags & LOADER_THREAD_FLAG_SHOW_MENU) {
|
switch(message.type) {
|
||||||
menu_set_selected_item(loader_instance->primary_menu, 0);
|
case LoaderMessageTypeStartByName:
|
||||||
view_dispatcher_switch_to_view(
|
message.status_value->value =
|
||||||
loader_instance->view_dispatcher, LoaderMenuViewPrimary);
|
loader_do_start_by_name(loader, message.start.name, message.start.args);
|
||||||
view_dispatcher_run(loader_instance->view_dispatcher);
|
api_lock_unlock(message.api_lock);
|
||||||
|
break;
|
||||||
|
case LoaderMessageTypeShowMenu:
|
||||||
|
loader_do_menu_show(loader);
|
||||||
|
break;
|
||||||
|
case LoaderMessageTypeMenuClosed:
|
||||||
|
loader_do_menu_closed(loader);
|
||||||
|
break;
|
||||||
|
case LoaderMessageTypeIsLocked:
|
||||||
|
message.bool_value->value = loader_do_is_locked(loader);
|
||||||
|
api_lock_unlock(message.api_lock);
|
||||||
|
break;
|
||||||
|
case LoaderMessageTypeAppClosed:
|
||||||
|
loader_do_app_closed(loader);
|
||||||
|
break;
|
||||||
|
case LoaderMessageTypeLock:
|
||||||
|
message.bool_value->value = loader_do_lock(loader);
|
||||||
|
api_lock_unlock(message.api_lock);
|
||||||
|
break;
|
||||||
|
case LoaderMessageTypeUnlock:
|
||||||
|
loader_do_unlock(loader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_record_destroy(RECORD_LOADER);
|
|
||||||
loader_free(loader_instance);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FuriPubSub* loader_get_pubsub(Loader* instance) {
|
|
||||||
return instance->pubsub;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <furi.h>
|
||||||
#include <core/pubsub.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -43,13 +41,10 @@ bool loader_lock(Loader* instance);
|
|||||||
void loader_unlock(Loader* instance);
|
void loader_unlock(Loader* instance);
|
||||||
|
|
||||||
/** Get loader lock status */
|
/** Get loader lock status */
|
||||||
bool loader_is_locked(const Loader* instance);
|
bool loader_is_locked(Loader* instance);
|
||||||
|
|
||||||
/** Show primary loader */
|
/** Show primary loader */
|
||||||
void loader_show_menu();
|
void loader_show_menu(Loader* instance);
|
||||||
|
|
||||||
/** Show primary loader */
|
|
||||||
void loader_update_menu();
|
|
||||||
|
|
||||||
/** Show primary loader */
|
/** Show primary loader */
|
||||||
FuriPubSub* loader_get_pubsub(Loader* instance);
|
FuriPubSub* loader_get_pubsub(Loader* instance);
|
||||||
|
|||||||
117
applications/services/loader/loader_cli.c
Normal file
117
applications/services/loader/loader_cli.c
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <cli/cli.h>
|
||||||
|
#include <applications.h>
|
||||||
|
#include <lib/toolbox/args.h>
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
|
static void loader_cli_print_usage() {
|
||||||
|
printf("Usage:\r\n");
|
||||||
|
printf("loader <cmd> <args>\r\n");
|
||||||
|
printf("Cmd list:\r\n");
|
||||||
|
printf("\tlist\t - List available applications\r\n");
|
||||||
|
printf("\topen <Application Name:string>\t - Open application by name\r\n");
|
||||||
|
printf("\tinfo\t - Show loader state\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_cli_list() {
|
||||||
|
printf("Applications:\r\n");
|
||||||
|
for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
||||||
|
printf("\t%s\r\n", FLIPPER_APPS[i].name);
|
||||||
|
}
|
||||||
|
printf("Settings:\r\n");
|
||||||
|
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
|
||||||
|
printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_cli_info(Loader* loader) {
|
||||||
|
if(!loader_is_locked(loader)) {
|
||||||
|
printf("No application is running\r\n");
|
||||||
|
} else {
|
||||||
|
// TODO: print application name ???
|
||||||
|
printf("Application is running\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_cli_open(FuriString* args, Loader* loader) {
|
||||||
|
FuriString* app_name = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!args_read_probably_quoted_string_and_trim(args, app_name)) {
|
||||||
|
printf("No application provided\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
furi_string_trim(args);
|
||||||
|
|
||||||
|
const char* args_str = furi_string_get_cstr(args);
|
||||||
|
if(strlen(args_str) == 0) {
|
||||||
|
args_str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* app_name_str = furi_string_get_cstr(app_name);
|
||||||
|
|
||||||
|
LoaderStatus status = loader_start(loader, app_name_str, args_str);
|
||||||
|
|
||||||
|
switch(status) {
|
||||||
|
case LoaderStatusOk:
|
||||||
|
break;
|
||||||
|
case LoaderStatusErrorAppStarted:
|
||||||
|
printf("Can't start, application is running");
|
||||||
|
break;
|
||||||
|
case LoaderStatusErrorUnknownApp:
|
||||||
|
printf("%s doesn't exists\r\n", app_name_str);
|
||||||
|
break;
|
||||||
|
case LoaderStatusErrorInternal:
|
||||||
|
printf("Internal error\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
furi_string_free(app_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_cli(Cli* cli, FuriString* args, void* context) {
|
||||||
|
UNUSED(cli);
|
||||||
|
UNUSED(context);
|
||||||
|
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||||
|
|
||||||
|
FuriString* cmd;
|
||||||
|
cmd = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!args_read_string_and_trim(args, cmd)) {
|
||||||
|
loader_cli_print_usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_string_cmp_str(cmd, "list") == 0) {
|
||||||
|
loader_cli_list();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_string_cmp_str(cmd, "open") == 0) {
|
||||||
|
loader_cli_open(args, loader);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_string_cmp_str(cmd, "info") == 0) {
|
||||||
|
loader_cli_info(loader);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
loader_cli_print_usage();
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
furi_string_free(cmd);
|
||||||
|
furi_record_close(RECORD_LOADER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_on_system_start() {
|
||||||
|
#ifdef SRV_CLI
|
||||||
|
Cli* cli = furi_record_open(RECORD_CLI);
|
||||||
|
cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL);
|
||||||
|
furi_record_close(RECORD_CLI);
|
||||||
|
#else
|
||||||
|
UNUSED(loader_cli);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -1,39 +1,56 @@
|
|||||||
#include "loader.h"
|
#pragma once
|
||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <toolbox/api_lock.h>
|
||||||
#include <core/pubsub.h>
|
#include "loader.h"
|
||||||
#include <cli/cli.h>
|
#include "loader_menu.h"
|
||||||
#include <lib/toolbox/args.h>
|
|
||||||
|
|
||||||
#include <gui/view_dispatcher.h>
|
typedef struct {
|
||||||
|
char* args;
|
||||||
#include <gui/modules/menu.h>
|
char* name;
|
||||||
#include <gui/modules/submenu.h>
|
FuriThread* thread;
|
||||||
|
bool insomniac;
|
||||||
#include <applications.h>
|
} LoaderAppData;
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
struct Loader {
|
struct Loader {
|
||||||
FuriThreadId loader_thread;
|
|
||||||
|
|
||||||
const FlipperApplication* application;
|
|
||||||
FuriThread* application_thread;
|
|
||||||
char* application_arguments;
|
|
||||||
|
|
||||||
Cli* cli;
|
|
||||||
Gui* gui;
|
|
||||||
|
|
||||||
ViewDispatcher* view_dispatcher;
|
|
||||||
Menu* primary_menu;
|
|
||||||
Submenu* settings_menu;
|
|
||||||
|
|
||||||
volatile uint8_t lock_count;
|
|
||||||
|
|
||||||
FuriPubSub* pubsub;
|
FuriPubSub* pubsub;
|
||||||
|
FuriMessageQueue* queue;
|
||||||
|
LoaderMenu* loader_menu;
|
||||||
|
LoaderAppData app;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LoaderMenuViewPrimary,
|
LoaderMessageTypeStartByName,
|
||||||
LoaderMenuViewSettings,
|
LoaderMessageTypeAppClosed,
|
||||||
} LoaderMenuView;
|
LoaderMessageTypeShowMenu,
|
||||||
|
LoaderMessageTypeMenuClosed,
|
||||||
|
LoaderMessageTypeLock,
|
||||||
|
LoaderMessageTypeUnlock,
|
||||||
|
LoaderMessageTypeIsLocked,
|
||||||
|
} LoaderMessageType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
const char* args;
|
||||||
|
} LoaderMessageStartByName;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LoaderStatus value;
|
||||||
|
} LoaderMessageLoaderStatusResult;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool value;
|
||||||
|
} LoaderMessageBoolResult;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FuriApiLock api_lock;
|
||||||
|
LoaderMessageType type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
LoaderMessageStartByName start;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
LoaderMessageLoaderStatusResult* status_value;
|
||||||
|
LoaderMessageBoolResult* bool_value;
|
||||||
|
};
|
||||||
|
} LoaderMessage;
|
||||||
|
|||||||
187
applications/services/loader/loader_menu.c
Normal file
187
applications/services/loader/loader_menu.c
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <gui/modules/menu.h>
|
||||||
|
#include <gui/modules/submenu.h>
|
||||||
|
#include <assets_icons.h>
|
||||||
|
#include <applications.h>
|
||||||
|
|
||||||
|
#include "loader_menu.h"
|
||||||
|
|
||||||
|
#define TAG "LoaderMenu"
|
||||||
|
|
||||||
|
struct LoaderMenu {
|
||||||
|
Gui* gui;
|
||||||
|
ViewDispatcher* view_dispatcher;
|
||||||
|
Menu* primary_menu;
|
||||||
|
Submenu* settings_menu;
|
||||||
|
|
||||||
|
void (*closed_callback)(void*);
|
||||||
|
void* closed_callback_context;
|
||||||
|
|
||||||
|
void (*click_callback)(const char*, void*);
|
||||||
|
void* click_callback_context;
|
||||||
|
|
||||||
|
FuriThread* thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LoaderMenuViewPrimary,
|
||||||
|
LoaderMenuViewSettings,
|
||||||
|
} LoaderMenuView;
|
||||||
|
|
||||||
|
static int32_t loader_menu_thread(void* p);
|
||||||
|
|
||||||
|
LoaderMenu* loader_menu_alloc() {
|
||||||
|
LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu));
|
||||||
|
loader_menu->gui = furi_record_open(RECORD_GUI);
|
||||||
|
loader_menu->view_dispatcher = view_dispatcher_alloc();
|
||||||
|
loader_menu->primary_menu = menu_alloc();
|
||||||
|
loader_menu->settings_menu = submenu_alloc();
|
||||||
|
loader_menu->thread = NULL;
|
||||||
|
return loader_menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_menu_free(LoaderMenu* loader_menu) {
|
||||||
|
furi_assert(loader_menu);
|
||||||
|
// check if thread is running
|
||||||
|
furi_assert(!loader_menu->thread);
|
||||||
|
|
||||||
|
submenu_free(loader_menu->settings_menu);
|
||||||
|
menu_free(loader_menu->primary_menu);
|
||||||
|
view_dispatcher_free(loader_menu->view_dispatcher);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
free(loader_menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_menu_start(LoaderMenu* loader_menu) {
|
||||||
|
furi_assert(loader_menu);
|
||||||
|
furi_assert(!loader_menu->thread);
|
||||||
|
loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu);
|
||||||
|
furi_thread_start(loader_menu->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_menu_stop(LoaderMenu* loader_menu) {
|
||||||
|
furi_assert(loader_menu);
|
||||||
|
furi_assert(loader_menu->thread);
|
||||||
|
view_dispatcher_stop(loader_menu->view_dispatcher);
|
||||||
|
furi_thread_join(loader_menu->thread);
|
||||||
|
furi_thread_free(loader_menu->thread);
|
||||||
|
loader_menu->thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_menu_set_closed_callback(
|
||||||
|
LoaderMenu* loader_menu,
|
||||||
|
void (*callback)(void*),
|
||||||
|
void* context) {
|
||||||
|
loader_menu->closed_callback = callback;
|
||||||
|
loader_menu->closed_callback_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_menu_set_click_callback(
|
||||||
|
LoaderMenu* loader_menu,
|
||||||
|
void (*callback)(const char*, void*),
|
||||||
|
void* context) {
|
||||||
|
loader_menu->click_callback = callback;
|
||||||
|
loader_menu->click_callback_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_menu_callback(void* context, uint32_t index) {
|
||||||
|
LoaderMenu* loader_menu = context;
|
||||||
|
const char* name = FLIPPER_APPS[index].name;
|
||||||
|
if(loader_menu->click_callback) {
|
||||||
|
loader_menu->click_callback(name, loader_menu->click_callback_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_menu_settings_menu_callback(void* context, uint32_t index) {
|
||||||
|
LoaderMenu* loader_menu = context;
|
||||||
|
const char* name = FLIPPER_SETTINGS_APPS[index].name;
|
||||||
|
if(loader_menu->click_callback) {
|
||||||
|
loader_menu->click_callback(name, loader_menu->click_callback_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_menu_switch_to_settings(void* context, uint32_t index) {
|
||||||
|
UNUSED(index);
|
||||||
|
LoaderMenu* loader_menu = context;
|
||||||
|
view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t loader_menu_switch_to_primary(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
return LoaderMenuViewPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t loader_menu_exit(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
return VIEW_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_menu_build_menu(LoaderMenu* loader_menu) {
|
||||||
|
size_t i;
|
||||||
|
for(i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
||||||
|
menu_add_item(
|
||||||
|
loader_menu->primary_menu,
|
||||||
|
FLIPPER_APPS[i].name,
|
||||||
|
FLIPPER_APPS[i].icon,
|
||||||
|
i,
|
||||||
|
loader_menu_callback,
|
||||||
|
(void*)loader_menu);
|
||||||
|
}
|
||||||
|
menu_add_item(
|
||||||
|
loader_menu->primary_menu,
|
||||||
|
"Settings",
|
||||||
|
&A_Settings_14,
|
||||||
|
i++,
|
||||||
|
loader_menu_switch_to_settings,
|
||||||
|
loader_menu);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void loader_menu_build_submenu(LoaderMenu* loader_menu) {
|
||||||
|
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
|
||||||
|
submenu_add_item(
|
||||||
|
loader_menu->settings_menu,
|
||||||
|
FLIPPER_SETTINGS_APPS[i].name,
|
||||||
|
i,
|
||||||
|
loader_menu_settings_menu_callback,
|
||||||
|
loader_menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t loader_menu_thread(void* p) {
|
||||||
|
LoaderMenu* loader_menu = p;
|
||||||
|
furi_assert(loader_menu);
|
||||||
|
|
||||||
|
loader_menu_build_menu(loader_menu);
|
||||||
|
loader_menu_build_submenu(loader_menu);
|
||||||
|
|
||||||
|
view_dispatcher_attach_to_gui(
|
||||||
|
loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen);
|
||||||
|
|
||||||
|
// Primary menu
|
||||||
|
View* primary_view = menu_get_view(loader_menu->primary_menu);
|
||||||
|
view_set_context(primary_view, loader_menu->primary_menu);
|
||||||
|
view_set_previous_callback(primary_view, loader_menu_exit);
|
||||||
|
view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view);
|
||||||
|
|
||||||
|
// Settings menu
|
||||||
|
View* settings_view = submenu_get_view(loader_menu->settings_menu);
|
||||||
|
view_set_context(settings_view, loader_menu->settings_menu);
|
||||||
|
view_set_previous_callback(settings_view, loader_menu_switch_to_primary);
|
||||||
|
view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view);
|
||||||
|
|
||||||
|
view_dispatcher_enable_queue(loader_menu->view_dispatcher);
|
||||||
|
view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary);
|
||||||
|
|
||||||
|
// run view dispatcher
|
||||||
|
view_dispatcher_run(loader_menu->view_dispatcher);
|
||||||
|
|
||||||
|
view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary);
|
||||||
|
view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings);
|
||||||
|
|
||||||
|
if(loader_menu->closed_callback) {
|
||||||
|
loader_menu->closed_callback(loader_menu->closed_callback_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
30
applications/services/loader/loader_menu.h
Normal file
30
applications/services/loader/loader_menu.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct LoaderMenu LoaderMenu;
|
||||||
|
|
||||||
|
LoaderMenu* loader_menu_alloc();
|
||||||
|
|
||||||
|
void loader_menu_free(LoaderMenu* loader_menu);
|
||||||
|
|
||||||
|
void loader_menu_start(LoaderMenu* loader_menu);
|
||||||
|
|
||||||
|
void loader_menu_stop(LoaderMenu* loader_menu);
|
||||||
|
|
||||||
|
void loader_menu_set_closed_callback(
|
||||||
|
LoaderMenu* loader_menu,
|
||||||
|
void (*callback)(void*),
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
void loader_menu_set_click_callback(
|
||||||
|
LoaderMenu* loader_menu,
|
||||||
|
void (*callback)(const char*, void*),
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -326,31 +326,35 @@ static int32_t rpc_session_worker(void* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rpc_session_free_callback(FuriThreadState thread_state, void* context) {
|
static void rpc_session_thread_pending_callback(void* context, uint32_t arg) {
|
||||||
furi_assert(context);
|
UNUSED(arg);
|
||||||
|
|
||||||
RpcSession* session = (RpcSession*)context;
|
RpcSession* session = (RpcSession*)context;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
||||||
|
if(rpc_systems[i].free) {
|
||||||
|
(rpc_systems[i].free)(session->system_contexts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(session->system_contexts);
|
||||||
|
free(session->decoded_message);
|
||||||
|
RpcHandlerDict_clear(session->handlers);
|
||||||
|
furi_stream_buffer_free(session->stream);
|
||||||
|
|
||||||
|
furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever);
|
||||||
|
if(session->terminated_callback) {
|
||||||
|
session->terminated_callback(session->context);
|
||||||
|
}
|
||||||
|
furi_mutex_release(session->callbacks_mutex);
|
||||||
|
|
||||||
|
furi_mutex_free(session->callbacks_mutex);
|
||||||
|
furi_thread_join(session->thread);
|
||||||
|
furi_thread_free(session->thread);
|
||||||
|
free(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpc_session_thread_state_callback(FuriThreadState thread_state, void* context) {
|
||||||
if(thread_state == FuriThreadStateStopped) {
|
if(thread_state == FuriThreadStateStopped) {
|
||||||
for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0);
|
||||||
if(rpc_systems[i].free) {
|
|
||||||
rpc_systems[i].free(session->system_contexts[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(session->system_contexts);
|
|
||||||
free(session->decoded_message);
|
|
||||||
RpcHandlerDict_clear(session->handlers);
|
|
||||||
furi_stream_buffer_free(session->stream);
|
|
||||||
|
|
||||||
furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever);
|
|
||||||
if(session->terminated_callback) {
|
|
||||||
session->terminated_callback(session->context);
|
|
||||||
}
|
|
||||||
furi_mutex_release(session->callbacks_mutex);
|
|
||||||
|
|
||||||
furi_mutex_free(session->callbacks_mutex);
|
|
||||||
furi_thread_free(session->thread);
|
|
||||||
free(session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +389,7 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) {
|
|||||||
session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session);
|
session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session);
|
||||||
|
|
||||||
furi_thread_set_state_context(session->thread, session);
|
furi_thread_set_state_context(session->thread, session);
|
||||||
furi_thread_set_state_callback(session->thread, rpc_session_free_callback);
|
furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback);
|
||||||
|
|
||||||
furi_thread_start(session->thread);
|
furi_thread_start(session->thread);
|
||||||
|
|
||||||
|
|||||||
@@ -803,6 +803,7 @@ void storage_file_free(File* file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FuriPubSub* storage_get_pubsub(Storage* storage) {
|
FuriPubSub* storage_get_pubsub(Storage* storage) {
|
||||||
|
furi_assert(storage);
|
||||||
return storage->pubsub;
|
return storage->pubsub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -337,6 +337,7 @@ static bool storage_ext_file_close(void* ctx, File* file) {
|
|||||||
file->internal_error_id = f_close(file_data);
|
file->internal_error_id = f_close(file_data);
|
||||||
file->error_id = storage_ext_parse_error(file->internal_error_id);
|
file->error_id = storage_ext_parse_error(file->internal_error_id);
|
||||||
free(file_data);
|
free(file_data);
|
||||||
|
storage_set_storage_file_data(file, NULL, storage);
|
||||||
return (file->error_id == FSE_OK);
|
return (file->error_id == FSE_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
|||||||
(uint32_t)(data->vbus_voltage),
|
(uint32_t)(data->vbus_voltage),
|
||||||
(uint32_t)(data->vbus_voltage * 10) % 10,
|
(uint32_t)(data->vbus_voltage * 10) % 10,
|
||||||
current);
|
current);
|
||||||
} else if(current < 0) {
|
} else if(current < -5) {
|
||||||
|
// Often gauge reports anything in the range 1~5ma as 5ma
|
||||||
|
// That brings confusion, so we'll treat it as Napping
|
||||||
snprintf(
|
snprintf(
|
||||||
emote,
|
emote,
|
||||||
sizeof(emote),
|
sizeof(emote),
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) {
|
|||||||
} else {
|
} else {
|
||||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
|
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
|
||||||
}
|
}
|
||||||
loader_update_menu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* const heap_trace_mode_text[] = {
|
const char* const heap_trace_mode_text[] = {
|
||||||
@@ -137,8 +136,6 @@ static void hand_orient_changed(VariableItem* item) {
|
|||||||
} else {
|
} else {
|
||||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient);
|
furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient);
|
||||||
}
|
}
|
||||||
|
|
||||||
loader_update_menu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* const sleep_method[] = {
|
const char* const sleep_method[] = {
|
||||||
|
|||||||
@@ -85,22 +85,10 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) {
|
|||||||
updater_cli_help(args);
|
updater_cli_help(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t updater_spawner_thread_worker(void* arg) {
|
static void updater_start_app(void* context, uint32_t arg) {
|
||||||
|
UNUSED(context);
|
||||||
UNUSED(arg);
|
UNUSED(arg);
|
||||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
|
||||||
loader_start(loader, "UpdaterApp", NULL);
|
|
||||||
furi_record_close(RECORD_LOADER);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updater_spawner_thread_cleanup(FuriThreadState state, void* context) {
|
|
||||||
FuriThread* thread = context;
|
|
||||||
if(state == FuriThreadStateStopped) {
|
|
||||||
furi_thread_free(thread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updater_start_app() {
|
|
||||||
FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode();
|
FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode();
|
||||||
if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) {
|
if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) {
|
||||||
return;
|
return;
|
||||||
@@ -110,11 +98,9 @@ static void updater_start_app() {
|
|||||||
* inside loader process, at startup.
|
* inside loader process, at startup.
|
||||||
* So, accessing its record would cause a deadlock
|
* So, accessing its record would cause a deadlock
|
||||||
*/
|
*/
|
||||||
FuriThread* thread =
|
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||||
furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL);
|
loader_start(loader, "UpdaterApp", NULL);
|
||||||
furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup);
|
furi_record_close(RECORD_LOADER);
|
||||||
furi_thread_set_state_context(thread, thread);
|
|
||||||
furi_thread_start(thread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updater_on_system_start() {
|
void updater_on_system_start() {
|
||||||
@@ -126,7 +112,7 @@ void updater_on_system_start() {
|
|||||||
UNUSED(updater_cli_ep);
|
UNUSED(updater_cli_ep);
|
||||||
#endif
|
#endif
|
||||||
#ifndef FURI_RAM_EXEC
|
#ifndef FURI_RAM_EXEC
|
||||||
updater_start_app();
|
furi_timer_pending_callback(updater_start_app, NULL, 0);
|
||||||
#else
|
#else
|
||||||
UNUSED(updater_start_app);
|
UNUSED(updater_start_app);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -346,7 +346,11 @@ int32_t update_task_worker_flash_writer(void* context) {
|
|||||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate);
|
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate);
|
||||||
// Format LFS before restoring backup on next boot
|
// Format LFS before restoring backup on next boot
|
||||||
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset);
|
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset);
|
||||||
|
#ifdef FURI_NDEBUG
|
||||||
|
// Production
|
||||||
|
furi_hal_rtc_set_log_level(FuriLogLevelDefault);
|
||||||
|
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
|
||||||
|
#endif
|
||||||
update_task_set_progress(update_task, UpdateTaskStageCompleted, 100);
|
update_task_set_progress(update_task, UpdateTaskStageCompleted, 100);
|
||||||
success = true;
|
success = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Import("env")
|
|
||||||
|
|
||||||
from fbt.version import get_git_commit_unix_timestamp
|
from fbt.version import get_git_commit_unix_timestamp
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
assetsenv = env.Clone(
|
assetsenv = env.Clone(
|
||||||
tools=["fbt_assets"],
|
tools=["fbt_assets"],
|
||||||
FW_LIB_NAME="assets",
|
FW_LIB_NAME="assets",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ DIST_SUFFIX = "local"
|
|||||||
COPRO_OB_DATA = "scripts/ob.data"
|
COPRO_OB_DATA = "scripts/ob.data"
|
||||||
|
|
||||||
# Must match lib/STM32CubeWB version
|
# Must match lib/STM32CubeWB version
|
||||||
COPRO_CUBE_VERSION = "1.16.0"
|
COPRO_CUBE_VERSION = "1.15.0"
|
||||||
|
|
||||||
COPRO_CUBE_DIR = "lib/STM32CubeWB"
|
COPRO_CUBE_DIR = "lib/STM32CubeWB"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
Import("ENV", "fw_build_meta")
|
|
||||||
|
|
||||||
from SCons.Errors import UserError
|
from SCons.Errors import UserError
|
||||||
from SCons.Node import FS
|
from SCons.Node import FS
|
||||||
|
|
||||||
@@ -10,6 +8,8 @@ from fbt_extra.util import (
|
|||||||
link_elf_dir_as_latest,
|
link_elf_dir_as_latest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Import("ENV", "fw_build_meta")
|
||||||
|
|
||||||
# Building initial C environment for libs
|
# Building initial C environment for libs
|
||||||
env = ENV.Clone(
|
env = ENV.Clone(
|
||||||
tools=[
|
tools=[
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,23.0,,
|
Version,+,26.0,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
Header,+,applications/services/cli/cli_vcp.h,,
|
Header,+,applications/services/cli/cli_vcp.h,,
|
||||||
@@ -36,6 +36,7 @@ Header,+,applications/services/notification/notification_messages.h,,
|
|||||||
Header,+,applications/services/power/power_service/power.h,,
|
Header,+,applications/services/power/power_service/power.h,,
|
||||||
Header,+,applications/services/rpc/rpc_app.h,,
|
Header,+,applications/services/rpc/rpc_app.h,,
|
||||||
Header,+,applications/services/storage/storage.h,,
|
Header,+,applications/services/storage/storage.h,,
|
||||||
|
Header,-,firmware/targets/f18/furi_hal/furi_hal_power_calibration.h,,
|
||||||
Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,,
|
Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,,
|
||||||
Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,,
|
Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,,
|
||||||
Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,,
|
Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,,
|
||||||
@@ -111,6 +112,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,,
|
|||||||
Header,+,lib/flipper_application/plugins/plugin_manager.h,,
|
Header,+,lib/flipper_application/plugins/plugin_manager.h,,
|
||||||
Header,+,lib/flipper_format/flipper_format.h,,
|
Header,+,lib/flipper_format/flipper_format.h,,
|
||||||
Header,+,lib/flipper_format/flipper_format_i.h,,
|
Header,+,lib/flipper_format/flipper_format_i.h,,
|
||||||
|
Header,+,lib/flipper_format/flipper_format_stream.h,,
|
||||||
Header,+,lib/libusb_stm32/inc/hid_usage_button.h,,
|
Header,+,lib/libusb_stm32/inc/hid_usage_button.h,,
|
||||||
Header,+,lib/libusb_stm32/inc/hid_usage_consumer.h,,
|
Header,+,lib/libusb_stm32/inc/hid_usage_consumer.h,,
|
||||||
Header,+,lib/libusb_stm32/inc/hid_usage_desktop.h,,
|
Header,+,lib/libusb_stm32/inc/hid_usage_desktop.h,,
|
||||||
@@ -199,8 +201,8 @@ Function,-,LL_EXTI_StructInit,void,LL_EXTI_InitTypeDef*
|
|||||||
Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef*
|
Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef*
|
||||||
Function,+,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*"
|
Function,+,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*"
|
||||||
Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef*
|
Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef*
|
||||||
Function,-,LL_I2C_DeInit,ErrorStatus,const I2C_TypeDef*
|
Function,-,LL_I2C_DeInit,ErrorStatus,I2C_TypeDef*
|
||||||
Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, const LL_I2C_InitTypeDef*"
|
Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, LL_I2C_InitTypeDef*"
|
||||||
Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef*
|
Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef*
|
||||||
Function,-,LL_Init1msTick,void,uint32_t
|
Function,-,LL_Init1msTick,void,uint32_t
|
||||||
Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef*
|
Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef*
|
||||||
@@ -754,6 +756,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32
|
|||||||
Function,+,flipper_format_rewind,_Bool,FlipperFormat*
|
Function,+,flipper_format_rewind,_Bool,FlipperFormat*
|
||||||
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
|
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
|
||||||
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
|
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
|
||||||
|
Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool"
|
||||||
|
Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool"
|
||||||
|
Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool"
|
||||||
|
Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*"
|
||||||
|
Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*"
|
||||||
Function,+,flipper_format_string_alloc,FlipperFormat*,
|
Function,+,flipper_format_string_alloc,FlipperFormat*,
|
||||||
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
|
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
|
||||||
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"
|
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"
|
||||||
@@ -885,6 +892,8 @@ Function,+,furi_hal_console_puts,void,const char*
|
|||||||
Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*"
|
Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*"
|
||||||
Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t"
|
Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t"
|
||||||
Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t"
|
Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t"
|
||||||
|
Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize"
|
||||||
|
Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp
|
||||||
Function,+,furi_hal_cortex_delay_us,void,uint32_t
|
Function,+,furi_hal_cortex_delay_us,void,uint32_t
|
||||||
Function,-,furi_hal_cortex_init_early,void,
|
Function,-,furi_hal_cortex_init_early,void,
|
||||||
Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t,
|
Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t,
|
||||||
@@ -959,6 +968,7 @@ Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t,
|
|||||||
Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t"
|
Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t"
|
||||||
Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t"
|
Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t"
|
||||||
Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*"
|
Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*"
|
||||||
|
Function,+,furi_hal_info_get_api_version,void,"uint16_t*, uint16_t*"
|
||||||
Function,-,furi_hal_init,void,
|
Function,-,furi_hal_init,void,
|
||||||
Function,-,furi_hal_init_early,void,
|
Function,-,furi_hal_init_early,void,
|
||||||
Function,-,furi_hal_interrupt_init,void,
|
Function,-,furi_hal_interrupt_init,void,
|
||||||
@@ -1270,7 +1280,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority"
|
|||||||
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
||||||
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
||||||
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
||||||
Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback
|
Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback
|
||||||
Function,+,furi_thread_start,void,FuriThread*
|
Function,+,furi_thread_start,void,FuriThread*
|
||||||
Function,+,furi_thread_stdout_flush,int32_t,
|
Function,+,furi_thread_stdout_flush,int32_t,
|
||||||
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
||||||
@@ -1279,6 +1289,7 @@ Function,+,furi_thread_yield,void,
|
|||||||
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
||||||
Function,+,furi_timer_free,void,FuriTimer*
|
Function,+,furi_timer_free,void,FuriTimer*
|
||||||
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
||||||
|
Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t"
|
||||||
Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t"
|
Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t"
|
||||||
Function,+,furi_timer_stop,FuriStatus,FuriTimer*
|
Function,+,furi_timer_stop,FuriStatus,FuriTimer*
|
||||||
Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*"
|
Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*"
|
||||||
@@ -1367,12 +1378,11 @@ Function,-,ldiv,ldiv_t,"long, long"
|
|||||||
Function,-,llabs,long long,long long
|
Function,-,llabs,long long,long long
|
||||||
Function,-,lldiv,lldiv_t,"long long, long long"
|
Function,-,lldiv,lldiv_t,"long long, long long"
|
||||||
Function,+,loader_get_pubsub,FuriPubSub*,Loader*
|
Function,+,loader_get_pubsub,FuriPubSub*,Loader*
|
||||||
Function,+,loader_is_locked,_Bool,const Loader*
|
Function,+,loader_is_locked,_Bool,Loader*
|
||||||
Function,+,loader_lock,_Bool,Loader*
|
Function,+,loader_lock,_Bool,Loader*
|
||||||
Function,+,loader_show_menu,void,
|
Function,+,loader_show_menu,void,Loader*
|
||||||
Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*"
|
Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*"
|
||||||
Function,+,loader_unlock,void,Loader*
|
Function,+,loader_unlock,void,Loader*
|
||||||
Function,+,loader_update_menu,void,
|
|
||||||
Function,+,loading_alloc,Loading*,
|
Function,+,loading_alloc,Loading*,
|
||||||
Function,+,loading_free,void,Loading*
|
Function,+,loading_free,void,Loading*
|
||||||
Function,+,loading_get_view,View*,Loading*
|
Function,+,loading_get_view,View*,Loading*
|
||||||
|
|||||||
|
37
firmware/targets/f18/furi_hal/furi_hal_power_calibration.h
Normal file
37
firmware/targets/f18/furi_hal/furi_hal_power_calibration.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const ParamCEDV cedv = {
|
||||||
|
.cedv_conf.gauge_conf =
|
||||||
|
{
|
||||||
|
.CCT = 1,
|
||||||
|
.CSYNC = 0,
|
||||||
|
.EDV_CMP = 0,
|
||||||
|
.SC = 1,
|
||||||
|
.FIXED_EDV0 = 1,
|
||||||
|
.FCC_LIM = 1,
|
||||||
|
.FC_FOR_VDQ = 1,
|
||||||
|
.IGNORE_SD = 1,
|
||||||
|
.SME0 = 0,
|
||||||
|
},
|
||||||
|
.full_charge_cap = 1300,
|
||||||
|
.design_cap = 1300,
|
||||||
|
.EDV0 = 3300,
|
||||||
|
.EDV1 = 3321,
|
||||||
|
.EDV2 = 3355,
|
||||||
|
.EMF = 3679,
|
||||||
|
.C0 = 430,
|
||||||
|
.C1 = 0,
|
||||||
|
.R1 = 408,
|
||||||
|
.R0 = 334,
|
||||||
|
.T0 = 4626,
|
||||||
|
.TC = 11,
|
||||||
|
.DOD0 = 4044,
|
||||||
|
.DOD10 = 3905,
|
||||||
|
.DOD20 = 3807,
|
||||||
|
.DOD30 = 3718,
|
||||||
|
.DOD40 = 3642,
|
||||||
|
.DOD50 = 3585,
|
||||||
|
.DOD60 = 3546,
|
||||||
|
.DOD70 = 3514,
|
||||||
|
.DOD80 = 3477,
|
||||||
|
.DOD90 = 3411,
|
||||||
|
.DOD100 = 3299,
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,23.1,,
|
Version,+,26.1,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
Header,+,applications/services/cli/cli_vcp.h,,
|
Header,+,applications/services/cli/cli_vcp.h,,
|
||||||
@@ -47,6 +47,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,,
|
|||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,,
|
Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,,
|
||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,,
|
Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,,
|
||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,,
|
Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,,
|
||||||
|
Header,-,firmware/targets/f7/furi_hal/furi_hal_power_calibration.h,,
|
||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,,
|
Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,,
|
||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,,
|
Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,,
|
||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,,
|
Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,,
|
||||||
@@ -117,6 +118,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,,
|
|||||||
Header,+,lib/flipper_application/plugins/plugin_manager.h,,
|
Header,+,lib/flipper_application/plugins/plugin_manager.h,,
|
||||||
Header,+,lib/flipper_format/flipper_format.h,,
|
Header,+,lib/flipper_format/flipper_format.h,,
|
||||||
Header,+,lib/flipper_format/flipper_format_i.h,,
|
Header,+,lib/flipper_format/flipper_format_i.h,,
|
||||||
|
Header,+,lib/flipper_format/flipper_format_stream.h,,
|
||||||
Header,+,lib/ibutton/ibutton_key.h,,
|
Header,+,lib/ibutton/ibutton_key.h,,
|
||||||
Header,+,lib/ibutton/ibutton_protocols.h,,
|
Header,+,lib/ibutton/ibutton_protocols.h,,
|
||||||
Header,+,lib/ibutton/ibutton_worker.h,,
|
Header,+,lib/ibutton/ibutton_worker.h,,
|
||||||
@@ -231,8 +233,8 @@ Function,-,LL_EXTI_StructInit,void,LL_EXTI_InitTypeDef*
|
|||||||
Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef*
|
Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef*
|
||||||
Function,+,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*"
|
Function,+,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*"
|
||||||
Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef*
|
Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef*
|
||||||
Function,-,LL_I2C_DeInit,ErrorStatus,const I2C_TypeDef*
|
Function,-,LL_I2C_DeInit,ErrorStatus,I2C_TypeDef*
|
||||||
Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, const LL_I2C_InitTypeDef*"
|
Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, LL_I2C_InitTypeDef*"
|
||||||
Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef*
|
Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef*
|
||||||
Function,-,LL_Init1msTick,void,uint32_t
|
Function,-,LL_Init1msTick,void,uint32_t
|
||||||
Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef*
|
Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef*
|
||||||
@@ -935,6 +937,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32
|
|||||||
Function,+,flipper_format_rewind,_Bool,FlipperFormat*
|
Function,+,flipper_format_rewind,_Bool,FlipperFormat*
|
||||||
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
|
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
|
||||||
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
|
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
|
||||||
|
Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool"
|
||||||
|
Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool"
|
||||||
|
Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool"
|
||||||
|
Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*"
|
||||||
|
Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*"
|
||||||
Function,+,flipper_format_string_alloc,FlipperFormat*,
|
Function,+,flipper_format_string_alloc,FlipperFormat*,
|
||||||
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
|
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
|
||||||
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"
|
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"
|
||||||
@@ -1084,6 +1091,8 @@ Function,+,furi_hal_console_puts,void,const char*
|
|||||||
Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*"
|
Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*"
|
||||||
Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t"
|
Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t"
|
||||||
Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t"
|
Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t"
|
||||||
|
Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize"
|
||||||
|
Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp
|
||||||
Function,+,furi_hal_cortex_delay_us,void,uint32_t
|
Function,+,furi_hal_cortex_delay_us,void,uint32_t
|
||||||
Function,-,furi_hal_cortex_init_early,void,
|
Function,-,furi_hal_cortex_init_early,void,
|
||||||
Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t,
|
Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t,
|
||||||
@@ -1165,6 +1174,7 @@ Function,+,furi_hal_ibutton_pin_configure,void,
|
|||||||
Function,+,furi_hal_ibutton_pin_reset,void,
|
Function,+,furi_hal_ibutton_pin_reset,void,
|
||||||
Function,+,furi_hal_ibutton_pin_write,void,const _Bool
|
Function,+,furi_hal_ibutton_pin_write,void,const _Bool
|
||||||
Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*"
|
Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*"
|
||||||
|
Function,+,furi_hal_info_get_api_version,void,"uint16_t*, uint16_t*"
|
||||||
Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*"
|
Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*"
|
||||||
Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t
|
Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t
|
||||||
Function,+,furi_hal_infrared_async_rx_set_timeout_isr_callback,void,"FuriHalInfraredRxTimeoutCallback, void*"
|
Function,+,furi_hal_infrared_async_rx_set_timeout_isr_callback,void,"FuriHalInfraredRxTimeoutCallback, void*"
|
||||||
@@ -1572,7 +1582,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority"
|
|||||||
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
||||||
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
||||||
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
||||||
Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback
|
Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback
|
||||||
Function,+,furi_thread_start,void,FuriThread*
|
Function,+,furi_thread_start,void,FuriThread*
|
||||||
Function,+,furi_thread_stdout_flush,int32_t,
|
Function,+,furi_thread_stdout_flush,int32_t,
|
||||||
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
||||||
@@ -1581,6 +1591,7 @@ Function,+,furi_thread_yield,void,
|
|||||||
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
||||||
Function,+,furi_timer_free,void,FuriTimer*
|
Function,+,furi_timer_free,void,FuriTimer*
|
||||||
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
||||||
|
Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t"
|
||||||
Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t"
|
Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t"
|
||||||
Function,+,furi_timer_stop,FuriStatus,FuriTimer*
|
Function,+,furi_timer_stop,FuriStatus,FuriTimer*
|
||||||
Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*"
|
Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*"
|
||||||
@@ -1805,12 +1816,11 @@ Function,-,llround,long long int,double
|
|||||||
Function,-,llroundf,long long int,float
|
Function,-,llroundf,long long int,float
|
||||||
Function,-,llroundl,long long int,long double
|
Function,-,llroundl,long long int,long double
|
||||||
Function,+,loader_get_pubsub,FuriPubSub*,Loader*
|
Function,+,loader_get_pubsub,FuriPubSub*,Loader*
|
||||||
Function,+,loader_is_locked,_Bool,const Loader*
|
Function,+,loader_is_locked,_Bool,Loader*
|
||||||
Function,+,loader_lock,_Bool,Loader*
|
Function,+,loader_lock,_Bool,Loader*
|
||||||
Function,+,loader_show_menu,void,
|
Function,+,loader_show_menu,void,Loader*
|
||||||
Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*"
|
Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*"
|
||||||
Function,+,loader_unlock,void,Loader*
|
Function,+,loader_unlock,void,Loader*
|
||||||
Function,+,loader_update_menu,void,
|
|
||||||
Function,+,loading_alloc,Loading*,
|
Function,+,loading_alloc,Loading*,
|
||||||
Function,+,loading_free,void,Loading*
|
Function,+,loading_free,void,Loading*
|
||||||
Function,+,loading_get_view,View*,Loading*
|
Function,+,loading_get_view,View*,Loading*
|
||||||
|
|||||||
|
@@ -18,8 +18,8 @@ PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer;
|
|||||||
PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE];
|
PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE];
|
||||||
|
|
||||||
_Static_assert(
|
_Static_assert(
|
||||||
sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 58,
|
sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 57,
|
||||||
"Ble stack config structure size mismatch (check new config options - last updated for v.1.16.0)");
|
"Ble stack config structure size mismatch (check new config options - last updated for v.1.15.0)");
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriMutex* hci_mtx;
|
FuriMutex* hci_mtx;
|
||||||
@@ -88,7 +88,7 @@ bool ble_app_init() {
|
|||||||
.min_tx_power = 0,
|
.min_tx_power = 0,
|
||||||
.max_tx_power = 0,
|
.max_tx_power = 0,
|
||||||
.rx_model_config = 1,
|
.rx_model_config = 1,
|
||||||
/* New stack (13.3->16.0)*/
|
/* New stack (13.3->15.0) */
|
||||||
.max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set
|
.max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set
|
||||||
.max_adv_data_len = 31, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set
|
.max_adv_data_len = 31, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set
|
||||||
.tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB
|
.tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB
|
||||||
|
|||||||
@@ -84,9 +84,7 @@ void furi_hal_bt_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Explicitly tell that we are in charge of CLK48 domain
|
// Explicitly tell that we are in charge of CLK48 domain
|
||||||
if(!LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_CLK48_CONFIG_SEMID)) {
|
furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0);
|
||||||
furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start Core2
|
// Start Core2
|
||||||
ble_glue_init();
|
ble_glue_init();
|
||||||
@@ -129,9 +127,7 @@ bool furi_hal_bt_start_radio_stack() {
|
|||||||
furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever);
|
furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever);
|
||||||
|
|
||||||
// Explicitly tell that we are in charge of CLK48 domain
|
// Explicitly tell that we are in charge of CLK48 domain
|
||||||
if(!LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_CLK48_CONFIG_SEMID)) {
|
furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0);
|
||||||
furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Wait until C2 is started or timeout
|
// Wait until C2 is started or timeout
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ void furi_hal_clock_init() {
|
|||||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48);
|
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48);
|
||||||
LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1);
|
LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1);
|
||||||
LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1);
|
LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1);
|
||||||
|
LL_RCC_HSI_EnableInStopMode(); // Ensure that MR is capable of work in STOP0
|
||||||
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
|
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
|
||||||
LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1);
|
LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1);
|
||||||
LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE);
|
LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE);
|
||||||
@@ -207,13 +208,17 @@ void furi_hal_clock_switch_to_hsi() {
|
|||||||
while(!LL_RCC_HSI_IsReady())
|
while(!LL_RCC_HSI_IsReady())
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
|
|
||||||
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI);
|
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI);
|
||||||
|
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
|
||||||
|
|
||||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
|
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
|
LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||||
|
|
||||||
|
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
||||||
|
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_clock_switch_to_pll() {
|
void furi_hal_clock_switch_to_pll() {
|
||||||
@@ -228,7 +233,11 @@ void furi_hal_clock_switch_to_pll() {
|
|||||||
while(!LL_RCC_PLLSAI1_IsReady())
|
while(!LL_RCC_PLLSAI1_IsReady())
|
||||||
;
|
;
|
||||||
|
|
||||||
|
LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2);
|
||||||
|
|
||||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
||||||
|
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3)
|
||||||
|
;
|
||||||
|
|
||||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
|
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
|
||||||
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
|
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#include <furi_hal_cortex.h>
|
#include <furi_hal_cortex.h>
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
#include <stm32wbxx.h>
|
#include <stm32wbxx.h>
|
||||||
|
|
||||||
#define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000)
|
#define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000)
|
||||||
|
|
||||||
void furi_hal_cortex_init_early() {
|
void furi_hal_cortex_init_early() {
|
||||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
CoreDebug->DEMCR |= (CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk);
|
||||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||||
DWT->CYCCNT = 0U;
|
DWT->CYCCNT = 0U;
|
||||||
|
|
||||||
@@ -39,3 +40,70 @@ void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) {
|
|||||||
while(!furi_hal_cortex_timer_is_expired(cortex_timer))
|
while(!furi_hal_cortex_timer_is_expired(cortex_timer))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Duck ST
|
||||||
|
#undef COMP0
|
||||||
|
#undef COMP1
|
||||||
|
#undef COMP2
|
||||||
|
#undef COMP3
|
||||||
|
|
||||||
|
void furi_hal_cortex_comp_enable(
|
||||||
|
FuriHalCortexComp comp,
|
||||||
|
FuriHalCortexCompFunction function,
|
||||||
|
uint32_t value,
|
||||||
|
uint32_t mask,
|
||||||
|
FuriHalCortexCompSize size) {
|
||||||
|
uint32_t function_reg = (uint32_t)function | ((uint32_t)size << 10);
|
||||||
|
|
||||||
|
switch(comp) {
|
||||||
|
case FuriHalCortexComp0:
|
||||||
|
(DWT->COMP0) = value;
|
||||||
|
(DWT->MASK0) = mask;
|
||||||
|
(DWT->FUNCTION0) = function_reg;
|
||||||
|
break;
|
||||||
|
case FuriHalCortexComp1:
|
||||||
|
(DWT->COMP1) = value;
|
||||||
|
(DWT->MASK1) = mask;
|
||||||
|
(DWT->FUNCTION1) = function_reg;
|
||||||
|
break;
|
||||||
|
case FuriHalCortexComp2:
|
||||||
|
(DWT->COMP2) = value;
|
||||||
|
(DWT->MASK2) = mask;
|
||||||
|
(DWT->FUNCTION2) = function_reg;
|
||||||
|
break;
|
||||||
|
case FuriHalCortexComp3:
|
||||||
|
(DWT->COMP3) = value;
|
||||||
|
(DWT->MASK3) = mask;
|
||||||
|
(DWT->FUNCTION3) = function_reg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_crash("Invalid parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void furi_hal_cortex_comp_reset(FuriHalCortexComp comp) {
|
||||||
|
switch(comp) {
|
||||||
|
case FuriHalCortexComp0:
|
||||||
|
(DWT->COMP0) = 0;
|
||||||
|
(DWT->MASK0) = 0;
|
||||||
|
(DWT->FUNCTION0) = 0;
|
||||||
|
break;
|
||||||
|
case FuriHalCortexComp1:
|
||||||
|
(DWT->COMP1) = 0;
|
||||||
|
(DWT->MASK1) = 0;
|
||||||
|
(DWT->FUNCTION1) = 0;
|
||||||
|
break;
|
||||||
|
case FuriHalCortexComp2:
|
||||||
|
(DWT->COMP2) = 0;
|
||||||
|
(DWT->MASK2) = 0;
|
||||||
|
(DWT->FUNCTION2) = 0;
|
||||||
|
break;
|
||||||
|
case FuriHalCortexComp3:
|
||||||
|
(DWT->COMP3) = 0;
|
||||||
|
(DWT->MASK3) = 0;
|
||||||
|
(DWT->FUNCTION3) = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_crash("Invalid parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <furi_hal_flash.h>
|
#include <furi_hal_flash.h>
|
||||||
#include <furi_hal_bt.h>
|
#include <furi_hal_bt.h>
|
||||||
#include <furi_hal_power.h>
|
#include <furi_hal_power.h>
|
||||||
|
#include <furi_hal_cortex.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <ble/ble.h>
|
#include <ble/ble.h>
|
||||||
#include <interface/patterns/ble_thread/shci/shci.h>
|
#include <interface/patterns/ble_thread/shci/shci.h>
|
||||||
@@ -26,6 +27,16 @@
|
|||||||
#define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F
|
#define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F
|
||||||
#define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2))
|
#define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2))
|
||||||
|
|
||||||
|
/* lib/STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c
|
||||||
|
* ProcessSingleFlashOperation, quote:
|
||||||
|
> In most BLE application, the flash should not be blocked by the CPU2 longer than FLASH_TIMEOUT_VALUE (1000ms)
|
||||||
|
> However, it could be that for some marginal application, this time is longer.
|
||||||
|
> ... there is no other way than waiting the operation to be completed.
|
||||||
|
> If for any reason this test is never passed, this means there is a failure in the system and there is no other
|
||||||
|
> way to recover than applying a device reset.
|
||||||
|
*/
|
||||||
|
#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS 3000u /* 3 seconds */
|
||||||
|
|
||||||
#define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL))
|
#define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL))
|
||||||
#define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
|
#define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
|
||||||
(((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \
|
(((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \
|
||||||
@@ -131,9 +142,11 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) {
|
|||||||
for(volatile uint32_t i = 0; i < 35; i++)
|
for(volatile uint32_t i = 0; i < 35; i++)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS * 1000);
|
||||||
while(true) {
|
while(true) {
|
||||||
/* Wait till flash controller become usable */
|
/* Wait till flash controller become usable */
|
||||||
while(LL_FLASH_IsActiveFlag_OperationSuspended()) {
|
while(LL_FLASH_IsActiveFlag_OperationSuspended()) {
|
||||||
|
furi_check(!furi_hal_cortex_timer_is_expired(timer));
|
||||||
furi_thread_yield();
|
furi_thread_yield();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -143,6 +156,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) {
|
|||||||
/* Actually we already have mutex for it, but specification is specification */
|
/* Actually we already have mutex for it, but specification is specification */
|
||||||
if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) {
|
if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) {
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
|
furi_check(!furi_hal_cortex_timer_is_expired(timer));
|
||||||
furi_thread_yield();
|
furi_thread_yield();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -150,6 +164,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) {
|
|||||||
/* Take sempahopre and prevent core2 from anything funky */
|
/* Take sempahopre and prevent core2 from anything funky */
|
||||||
if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) {
|
if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) {
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
|
furi_check(!furi_hal_cortex_timer_is_expired(timer));
|
||||||
furi_thread_yield();
|
furi_thread_yield();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -231,17 +246,13 @@ static void furi_hal_flush_cache(void) {
|
|||||||
|
|
||||||
bool furi_hal_flash_wait_last_operation(uint32_t timeout) {
|
bool furi_hal_flash_wait_last_operation(uint32_t timeout) {
|
||||||
uint32_t error = 0;
|
uint32_t error = 0;
|
||||||
uint32_t countdown = 0;
|
|
||||||
|
|
||||||
/* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
|
/* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
|
||||||
Even if the FLASH operation fails, the BUSY flag will be reset and an error
|
Even if the FLASH operation fails, the BUSY flag will be reset and an error
|
||||||
flag will be set */
|
flag will be set */
|
||||||
countdown = timeout;
|
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(timeout * 1000);
|
||||||
while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) {
|
while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) {
|
||||||
if(LL_SYSTICK_IsActiveCounterFlag()) {
|
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||||
countdown--;
|
|
||||||
}
|
|
||||||
if(countdown == 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,12 +275,9 @@ bool furi_hal_flash_wait_last_operation(uint32_t timeout) {
|
|||||||
CLEAR_BIT(FLASH->SR, error);
|
CLEAR_BIT(FLASH->SR, error);
|
||||||
|
|
||||||
/* Wait for control register to be written */
|
/* Wait for control register to be written */
|
||||||
countdown = timeout;
|
timer = furi_hal_cortex_timer_get(timeout * 1000);
|
||||||
while(READ_BIT(FLASH->SR, FLASH_SR_CFGBSY)) {
|
while(READ_BIT(FLASH->SR, FLASH_SR_CFGBSY)) {
|
||||||
if(LL_SYSTICK_IsActiveCounterFlag()) {
|
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||||
countdown--;
|
|
||||||
}
|
|
||||||
if(countdown == 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <protobuf_version.h>
|
#include <protobuf_version.h>
|
||||||
|
|
||||||
|
FURI_WEAK void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) {
|
||||||
|
*major = 0;
|
||||||
|
*minor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) {
|
void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) {
|
||||||
FuriString* key = furi_string_alloc();
|
FuriString* key = furi_string_alloc();
|
||||||
FuriString* value = furi_string_alloc();
|
FuriString* value = furi_string_alloc();
|
||||||
@@ -18,10 +23,10 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) {
|
|||||||
// Device Info version
|
// Device Info version
|
||||||
if(sep == '.') {
|
if(sep == '.') {
|
||||||
property_value_out(&property_context, NULL, 2, "format", "major", "3");
|
property_value_out(&property_context, NULL, 2, "format", "major", "3");
|
||||||
property_value_out(&property_context, NULL, 2, "format", "minor", "0");
|
property_value_out(&property_context, NULL, 2, "format", "minor", "1");
|
||||||
} else {
|
} else {
|
||||||
property_value_out(&property_context, NULL, 3, "device", "info", "major", "2");
|
property_value_out(&property_context, NULL, 3, "device", "info", "major", "2");
|
||||||
property_value_out(&property_context, NULL, 3, "device", "info", "minor", "0");
|
property_value_out(&property_context, NULL, 3, "device", "info", "minor", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Model name
|
// Model name
|
||||||
@@ -161,6 +166,13 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) {
|
|||||||
version_get_builddate(firmware_version));
|
version_get_builddate(firmware_version));
|
||||||
property_value_out(
|
property_value_out(
|
||||||
&property_context, "%d", 2, "firmware", "target", version_get_target(firmware_version));
|
&property_context, "%d", 2, "firmware", "target", version_get_target(firmware_version));
|
||||||
|
|
||||||
|
uint16_t api_version_major, api_version_minor;
|
||||||
|
furi_hal_info_get_api_version(&api_version_major, &api_version_minor);
|
||||||
|
property_value_out(
|
||||||
|
&property_context, "%d", 3, "firmware", "api", "major", api_version_major);
|
||||||
|
property_value_out(
|
||||||
|
&property_context, "%d", 3, "firmware", "api", "minor", api_version_minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_hal_bt_is_alive()) {
|
if(furi_hal_bt_is_alive()) {
|
||||||
|
|||||||
@@ -29,10 +29,6 @@
|
|||||||
#define FURI_HAL_POWER_DEBUG_STOP_GPIO (&gpio_ext_pc3)
|
#define FURI_HAL_POWER_DEBUG_STOP_GPIO (&gpio_ext_pc3)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO
|
|
||||||
#define FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO (&gpio_ext_pb3)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FURI_HAL_POWER_STOP_MODE
|
#ifndef FURI_HAL_POWER_STOP_MODE
|
||||||
#define FURI_HAL_POWER_STOP_MODE (LL_PWR_MODE_STOP2)
|
#define FURI_HAL_POWER_STOP_MODE (LL_PWR_MODE_STOP2)
|
||||||
#endif
|
#endif
|
||||||
@@ -50,56 +46,19 @@ static volatile FuriHalPower furi_hal_power = {
|
|||||||
.suppress_charge = 0,
|
.suppress_charge = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ParamCEDV cedv = {
|
#include <furi_hal_power_calibration.h>
|
||||||
.cedv_conf.gauge_conf =
|
|
||||||
{
|
|
||||||
.CCT = 1,
|
|
||||||
.CSYNC = 0,
|
|
||||||
.EDV_CMP = 0,
|
|
||||||
.SC = 1,
|
|
||||||
.FIXED_EDV0 = 1,
|
|
||||||
.FCC_LIM = 1,
|
|
||||||
.FC_FOR_VDQ = 1,
|
|
||||||
.IGNORE_SD = 1,
|
|
||||||
.SME0 = 0,
|
|
||||||
},
|
|
||||||
.full_charge_cap = 2101,
|
|
||||||
.design_cap = 2101,
|
|
||||||
.EDV0 = 3300,
|
|
||||||
.EDV1 = 3321,
|
|
||||||
.EDV2 = 3355,
|
|
||||||
.EMF = 3679,
|
|
||||||
.C0 = 430,
|
|
||||||
.C1 = 0,
|
|
||||||
.R1 = 408,
|
|
||||||
.R0 = 334,
|
|
||||||
.T0 = 4626,
|
|
||||||
.TC = 11,
|
|
||||||
.DOD0 = 4044,
|
|
||||||
.DOD10 = 3905,
|
|
||||||
.DOD20 = 3807,
|
|
||||||
.DOD30 = 3718,
|
|
||||||
.DOD40 = 3642,
|
|
||||||
.DOD50 = 3585,
|
|
||||||
.DOD60 = 3546,
|
|
||||||
.DOD70 = 3514,
|
|
||||||
.DOD80 = 3477,
|
|
||||||
.DOD90 = 3411,
|
|
||||||
.DOD100 = 3299,
|
|
||||||
};
|
|
||||||
|
|
||||||
void furi_hal_power_init() {
|
void furi_hal_power_init() {
|
||||||
#ifdef FURI_HAL_POWER_DEBUG
|
#ifdef FURI_HAL_POWER_DEBUG
|
||||||
furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_WFI_GPIO, GpioModeOutputPushPull);
|
furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_WFI_GPIO, GpioModeOutputPushPull);
|
||||||
furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_STOP_GPIO, GpioModeOutputPushPull);
|
furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_STOP_GPIO, GpioModeOutputPushPull);
|
||||||
furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO, GpioModeOutputPushPull);
|
|
||||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0);
|
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0);
|
||||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0);
|
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0);
|
||||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO, 0);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
||||||
|
|
||||||
LL_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE);
|
LL_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE);
|
||||||
LL_C2_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE);
|
LL_C2_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE);
|
||||||
|
|
||||||
@@ -158,9 +117,7 @@ bool furi_hal_power_sleep_available() {
|
|||||||
|
|
||||||
static inline bool furi_hal_power_deep_sleep_available() {
|
static inline bool furi_hal_power_deep_sleep_available() {
|
||||||
return furi_hal_bt_is_alive() && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) &&
|
return furi_hal_bt_is_alive() && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) &&
|
||||||
!furi_hal_debug_is_gdb_session_active() && !LL_PWR_IsActiveFlag_CRPE() &&
|
!furi_hal_debug_is_gdb_session_active();
|
||||||
!LL_PWR_IsActiveFlag_CRP() && !LL_PWR_IsActiveFlag_BLEA() &&
|
|
||||||
!LL_PWR_IsActiveFlag_BLEWU();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void furi_hal_power_light_sleep() {
|
static inline void furi_hal_power_light_sleep() {
|
||||||
@@ -211,16 +168,7 @@ static inline void furi_hal_power_deep_sleep() {
|
|||||||
__force_stores();
|
__force_stores();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool should_abort_sleep = LL_PWR_IsActiveFlag_CRPE() || LL_PWR_IsActiveFlag_CRP() ||
|
__WFI();
|
||||||
LL_PWR_IsActiveFlag_BLEA() || LL_PWR_IsActiveFlag_BLEWU();
|
|
||||||
|
|
||||||
if(should_abort_sleep) {
|
|
||||||
#ifdef FURI_HAL_POWER_DEBUG
|
|
||||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO, 1);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
__WFI();
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_LPM_EnableSleep();
|
LL_LPM_EnableSleep();
|
||||||
|
|
||||||
|
|||||||
37
firmware/targets/f7/furi_hal/furi_hal_power_calibration.h
Normal file
37
firmware/targets/f7/furi_hal/furi_hal_power_calibration.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const ParamCEDV cedv = {
|
||||||
|
.cedv_conf.gauge_conf =
|
||||||
|
{
|
||||||
|
.CCT = 1,
|
||||||
|
.CSYNC = 0,
|
||||||
|
.EDV_CMP = 0,
|
||||||
|
.SC = 1,
|
||||||
|
.FIXED_EDV0 = 1,
|
||||||
|
.FCC_LIM = 1,
|
||||||
|
.FC_FOR_VDQ = 1,
|
||||||
|
.IGNORE_SD = 1,
|
||||||
|
.SME0 = 0,
|
||||||
|
},
|
||||||
|
.full_charge_cap = 2101,
|
||||||
|
.design_cap = 2101,
|
||||||
|
.EDV0 = 3300,
|
||||||
|
.EDV1 = 3321,
|
||||||
|
.EDV2 = 3355,
|
||||||
|
.EMF = 3679,
|
||||||
|
.C0 = 430,
|
||||||
|
.C1 = 0,
|
||||||
|
.R1 = 408,
|
||||||
|
.R0 = 334,
|
||||||
|
.T0 = 4626,
|
||||||
|
.TC = 11,
|
||||||
|
.DOD0 = 4044,
|
||||||
|
.DOD10 = 3905,
|
||||||
|
.DOD20 = 3807,
|
||||||
|
.DOD30 = 3718,
|
||||||
|
.DOD40 = 3642,
|
||||||
|
.DOD50 = 3585,
|
||||||
|
.DOD60 = 3546,
|
||||||
|
.DOD70 = 3514,
|
||||||
|
.DOD80 = 3477,
|
||||||
|
.DOD90 = 3411,
|
||||||
|
.DOD100 = 3299,
|
||||||
|
};
|
||||||
@@ -56,6 +56,53 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer);
|
|||||||
*/
|
*/
|
||||||
void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer);
|
void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FuriHalCortexComp0,
|
||||||
|
FuriHalCortexComp1,
|
||||||
|
FuriHalCortexComp2,
|
||||||
|
FuriHalCortexComp3,
|
||||||
|
} FuriHalCortexComp;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FuriHalCortexCompSizeWord = 0b10,
|
||||||
|
FuriHalCortexCompSizeHalfWord = 0b01,
|
||||||
|
FuriHalCortexCompSizeByte = 0b00,
|
||||||
|
} FuriHalCortexCompSize;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FuriHalCortexCompFunctionPC = 0b100,
|
||||||
|
FuriHalCortexCompFunctionRead = 0b101,
|
||||||
|
FuriHalCortexCompFunctionWrite = 0b110,
|
||||||
|
FuriHalCortexCompFunctionReadWrite = 0b110,
|
||||||
|
} FuriHalCortexCompFunction;
|
||||||
|
|
||||||
|
/** Enable DWT comparator
|
||||||
|
*
|
||||||
|
* Allows to programmatically set instruction/data breakpoints.
|
||||||
|
*
|
||||||
|
* More details on how it works can be found in armv7m official documentation:
|
||||||
|
* https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/The-DWT-comparators
|
||||||
|
* https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Comparator-Function-registers--DWT-FUNCTIONn
|
||||||
|
*
|
||||||
|
* @param[in] comp The Comparator
|
||||||
|
* @param[in] function The Comparator Function to use
|
||||||
|
* @param[in] value The value
|
||||||
|
* @param[in] mask The mask
|
||||||
|
* @param[in] size The size
|
||||||
|
*/
|
||||||
|
void furi_hal_cortex_comp_enable(
|
||||||
|
FuriHalCortexComp comp,
|
||||||
|
FuriHalCortexCompFunction function,
|
||||||
|
uint32_t value,
|
||||||
|
uint32_t mask,
|
||||||
|
FuriHalCortexCompSize size);
|
||||||
|
|
||||||
|
/** Reset DWT comparator
|
||||||
|
*
|
||||||
|
* @param[in] comp The Comparator
|
||||||
|
*/
|
||||||
|
void furi_hal_cortex_comp_reset(FuriHalCortexComp comp);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor);
|
||||||
|
|
||||||
/** Get device information
|
/** Get device information
|
||||||
*
|
*
|
||||||
* @param[in] callback callback to provide with new data
|
* @param[in] callback callback to provide with new data
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
PLACE_IN_SECTION("MB_MEM2") const char* __furi_check_message = NULL;
|
PLACE_IN_SECTION("MB_MEM2") const char* __furi_check_message = NULL;
|
||||||
PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[12] = {0};
|
PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[13] = {0};
|
||||||
|
|
||||||
/** Load r12 value to __furi_check_message and store registers to __furi_check_registers */
|
/** Load r12 value to __furi_check_message and store registers to __furi_check_registers */
|
||||||
#define GET_MESSAGE_AND_STORE_REGISTERS() \
|
#define GET_MESSAGE_AND_STORE_REGISTERS() \
|
||||||
@@ -22,6 +22,7 @@ PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[12] = {0};
|
|||||||
"str r12, [r11] \n" \
|
"str r12, [r11] \n" \
|
||||||
"ldr r12, =__furi_check_registers \n" \
|
"ldr r12, =__furi_check_registers \n" \
|
||||||
"stm r12, {r0-r11} \n" \
|
"stm r12, {r0-r11} \n" \
|
||||||
|
"str lr, [r12, #48] \n" \
|
||||||
: \
|
: \
|
||||||
: \
|
: \
|
||||||
: "memory");
|
: "memory");
|
||||||
@@ -62,6 +63,25 @@ static void __furi_put_uint32_as_text(uint32_t data) {
|
|||||||
furi_hal_console_puts(tmp_str);
|
furi_hal_console_puts(tmp_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __furi_put_uint32_as_hex(uint32_t data) {
|
||||||
|
char tmp_str[] = "0xFFFFFFFF";
|
||||||
|
itoa(data, tmp_str, 16);
|
||||||
|
furi_hal_console_puts(tmp_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __furi_print_register_info() {
|
||||||
|
// Print registers
|
||||||
|
for(uint8_t i = 0; i < 12; i++) {
|
||||||
|
furi_hal_console_puts("\r\n\tr");
|
||||||
|
__furi_put_uint32_as_text(i);
|
||||||
|
furi_hal_console_puts(" : ");
|
||||||
|
__furi_put_uint32_as_hex(__furi_check_registers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_console_puts("\r\n\tlr : ");
|
||||||
|
__furi_put_uint32_as_hex(__furi_check_registers[12]);
|
||||||
|
}
|
||||||
|
|
||||||
static void __furi_print_stack_info() {
|
static void __furi_print_stack_info() {
|
||||||
furi_hal_console_puts("\r\n\tstack watermark: ");
|
furi_hal_console_puts("\r\n\tstack watermark: ");
|
||||||
__furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4);
|
__furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4);
|
||||||
@@ -101,32 +121,41 @@ FURI_NORETURN void __furi_crash() {
|
|||||||
|
|
||||||
if(__furi_check_message == NULL) {
|
if(__furi_check_message == NULL) {
|
||||||
__furi_check_message = "Fatal Error";
|
__furi_check_message = "Fatal Error";
|
||||||
|
} else if(__furi_check_message == (void*)__FURI_ASSERT_MESSAGE_FLAG) {
|
||||||
|
__furi_check_message = "furi_assert failed";
|
||||||
|
} else if(__furi_check_message == (void*)__FURI_CHECK_MESSAGE_FLAG) {
|
||||||
|
__furi_check_message = "furi_check failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_console_puts("\r\n\033[0;31m[CRASH]");
|
furi_hal_console_puts("\r\n\033[0;31m[CRASH]");
|
||||||
__furi_print_name(isr);
|
__furi_print_name(isr);
|
||||||
furi_hal_console_puts(__furi_check_message);
|
furi_hal_console_puts(__furi_check_message);
|
||||||
|
|
||||||
|
__furi_print_register_info();
|
||||||
if(!isr) {
|
if(!isr) {
|
||||||
__furi_print_stack_info();
|
__furi_print_stack_info();
|
||||||
}
|
}
|
||||||
__furi_print_heap_info();
|
__furi_print_heap_info();
|
||||||
|
|
||||||
|
#ifndef FURI_DEBUG
|
||||||
// Check if debug enabled by DAP
|
// Check if debug enabled by DAP
|
||||||
// https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/Debug-register-support-in-the-SCS/Debug-Halting-Control-and-Status-Register--DHCSR?lang=en
|
// https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/Debug-register-support-in-the-SCS/Debug-Halting-Control-and-Status-Register--DHCSR?lang=en
|
||||||
bool debug = CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk;
|
bool debug = CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk;
|
||||||
if(debug) {
|
if(debug) {
|
||||||
|
#endif
|
||||||
furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n");
|
furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n");
|
||||||
furi_hal_console_puts("\033[0m\r\n");
|
furi_hal_console_puts("\033[0m\r\n");
|
||||||
furi_hal_debug_enable();
|
furi_hal_debug_enable();
|
||||||
|
|
||||||
RESTORE_REGISTERS_AND_HALT_MCU(true);
|
RESTORE_REGISTERS_AND_HALT_MCU(true);
|
||||||
|
#ifndef FURI_DEBUG
|
||||||
} else {
|
} else {
|
||||||
furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message);
|
furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message);
|
||||||
furi_hal_console_puts("\r\nRebooting system.\r\n");
|
furi_hal_console_puts("\r\nRebooting system.\r\n");
|
||||||
furi_hal_console_puts("\033[0m\r\n");
|
furi_hal_console_puts("\033[0m\r\n");
|
||||||
furi_hal_power_reset();
|
furi_hal_power_reset();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ extern "C" {
|
|||||||
#define FURI_NORETURN noreturn
|
#define FURI_NORETURN noreturn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Flags instead of pointers will save ~4 bytes on furi_assert and furi_check calls.
|
||||||
|
#define __FURI_ASSERT_MESSAGE_FLAG (0x01)
|
||||||
|
#define __FURI_CHECK_MESSAGE_FLAG (0x02)
|
||||||
|
|
||||||
/** Crash system */
|
/** Crash system */
|
||||||
FURI_NORETURN void __furi_crash();
|
FURI_NORETURN void __furi_crash();
|
||||||
|
|
||||||
@@ -44,20 +48,20 @@ FURI_NORETURN void __furi_halt();
|
|||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/** Check condition and crash if check failed */
|
/** Check condition and crash if check failed */
|
||||||
#define furi_check(__e) \
|
#define furi_check(__e) \
|
||||||
do { \
|
do { \
|
||||||
if(!(__e)) { \
|
if(!(__e)) { \
|
||||||
furi_crash("furi_check failed\r\n"); \
|
furi_crash(__FURI_CHECK_MESSAGE_FLAG); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/** Only in debug build: Assert condition and crash if assert failed */
|
/** Only in debug build: Assert condition and crash if assert failed */
|
||||||
#ifdef FURI_DEBUG
|
#ifdef FURI_DEBUG
|
||||||
#define furi_assert(__e) \
|
#define furi_assert(__e) \
|
||||||
do { \
|
do { \
|
||||||
if(!(__e)) { \
|
if(!(__e)) { \
|
||||||
furi_crash("furi_assert failed\r\n"); \
|
furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
#else
|
#else
|
||||||
#define furi_assert(__e) \
|
#define furi_assert(__e) \
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ extern "C" {
|
|||||||
#define FURI_WARN_UNUSED __attribute__((warn_unused_result))
|
#define FURI_WARN_UNUSED __attribute__((warn_unused_result))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef FURI_WEAK
|
||||||
|
#define FURI_WEAK __attribute__((weak))
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FURI_IS_IRQ_MASKED
|
#ifndef FURI_IS_IRQ_MASKED
|
||||||
#define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
|
#define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -164,10 +164,13 @@ FuriThread* furi_thread_alloc_ex(
|
|||||||
|
|
||||||
void furi_thread_free(FuriThread* thread) {
|
void furi_thread_free(FuriThread* thread) {
|
||||||
furi_assert(thread);
|
furi_assert(thread);
|
||||||
furi_assert(thread->state == FuriThreadStateStopped);
|
|
||||||
|
|
||||||
if(thread->name) free((void*)thread->name);
|
// Ensure that use join before free
|
||||||
if(thread->appid) free((void*)thread->appid);
|
furi_assert(thread->state == FuriThreadStateStopped);
|
||||||
|
furi_assert(thread->task_handle == NULL);
|
||||||
|
|
||||||
|
if(thread->name) free(thread->name);
|
||||||
|
if(thread->appid) free(thread->appid);
|
||||||
furi_string_free(thread->output.buffer);
|
furi_string_free(thread->output.buffer);
|
||||||
|
|
||||||
free(thread);
|
free(thread);
|
||||||
@@ -176,14 +179,14 @@ void furi_thread_free(FuriThread* thread) {
|
|||||||
void furi_thread_set_name(FuriThread* thread, const char* name) {
|
void furi_thread_set_name(FuriThread* thread, const char* name) {
|
||||||
furi_assert(thread);
|
furi_assert(thread);
|
||||||
furi_assert(thread->state == FuriThreadStateStopped);
|
furi_assert(thread->state == FuriThreadStateStopped);
|
||||||
if(thread->name) free((void*)thread->name);
|
if(thread->name) free(thread->name);
|
||||||
thread->name = name ? strdup(name) : NULL;
|
thread->name = name ? strdup(name) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_thread_set_appid(FuriThread* thread, const char* appid) {
|
void furi_thread_set_appid(FuriThread* thread, const char* appid) {
|
||||||
furi_assert(thread);
|
furi_assert(thread);
|
||||||
furi_assert(thread->state == FuriThreadStateStopped);
|
furi_assert(thread->state == FuriThreadStateStopped);
|
||||||
if(thread->appid) free((void*)thread->appid);
|
if(thread->appid) free(thread->appid);
|
||||||
thread->appid = appid ? strdup(appid) : NULL;
|
thread->appid = appid ? strdup(appid) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +279,7 @@ void furi_thread_cleanup_tcb_event(TaskHandle_t task) {
|
|||||||
if(thread) {
|
if(thread) {
|
||||||
// clear thread local storage
|
// clear thread local storage
|
||||||
vTaskSetThreadLocalStoragePointer(task, 0, NULL);
|
vTaskSetThreadLocalStoragePointer(task, 0, NULL);
|
||||||
|
furi_assert(thread->task_handle == task);
|
||||||
thread->task_handle = NULL;
|
thread->task_handle = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,7 +335,6 @@ FuriThreadId furi_thread_get_current_id() {
|
|||||||
|
|
||||||
FuriThread* furi_thread_get_current() {
|
FuriThread* furi_thread_get_current() {
|
||||||
FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0);
|
FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0);
|
||||||
furi_assert(thread != NULL);
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,24 +581,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) {
|
void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) {
|
||||||
FuriThread* thread = furi_thread_get_current();
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
furi_assert(thread);
|
||||||
__furi_thread_stdout_flush(thread);
|
__furi_thread_stdout_flush(thread);
|
||||||
thread->output.write_callback = callback;
|
thread->output.write_callback = callback;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() {
|
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() {
|
||||||
FuriThread* thread = furi_thread_get_current();
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
furi_assert(thread);
|
||||||
return thread->output.write_callback;
|
return thread->output.write_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t furi_thread_stdout_write(const char* data, size_t size) {
|
size_t furi_thread_stdout_write(const char* data, size_t size) {
|
||||||
FuriThread* thread = furi_thread_get_current();
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
furi_assert(thread);
|
||||||
if(size == 0 || data == NULL) {
|
if(size == 0 || data == NULL) {
|
||||||
return __furi_thread_stdout_flush(thread);
|
return __furi_thread_stdout_flush(thread);
|
||||||
} else {
|
} else {
|
||||||
@@ -619,7 +619,9 @@ size_t furi_thread_stdout_write(const char* data, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t furi_thread_stdout_flush() {
|
int32_t furi_thread_stdout_flush() {
|
||||||
return __furi_thread_stdout_flush(furi_thread_get_current());
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
furi_assert(thread);
|
||||||
|
return __furi_thread_stdout_flush(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_thread_suspend(FuriThreadId thread_id) {
|
void furi_thread_suspend(FuriThreadId thread_id) {
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ FuriThreadId furi_thread_get_current_id();
|
|||||||
|
|
||||||
/** Get FuriThread instance for current thread
|
/** Get FuriThread instance for current thread
|
||||||
*
|
*
|
||||||
* @return FuriThread*
|
* @return pointer to FuriThread or NULL if this thread doesn't belongs to Furi
|
||||||
*/
|
*/
|
||||||
FuriThread* furi_thread_get_current();
|
FuriThread* furi_thread_get_current();
|
||||||
|
|
||||||
@@ -290,10 +290,8 @@ FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback();
|
|||||||
/** Set STDOUT callback for thread
|
/** Set STDOUT callback for thread
|
||||||
*
|
*
|
||||||
* @param callback callback or NULL to clear
|
* @param callback callback or NULL to clear
|
||||||
*
|
|
||||||
* @return true on success, otherwise fail
|
|
||||||
*/
|
*/
|
||||||
bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback);
|
void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback);
|
||||||
|
|
||||||
/** Write data to buffered STDOUT
|
/** Write data to buffered STDOUT
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -124,3 +124,13 @@ uint32_t furi_timer_is_running(FuriTimer* instance) {
|
|||||||
/* Return 0: not running, 1: running */
|
/* Return 0: not running, 1: running */
|
||||||
return (uint32_t)xTimerIsTimerActive(hTimer);
|
return (uint32_t)xTimerIsTimerActive(hTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) {
|
||||||
|
BaseType_t ret = pdFAIL;
|
||||||
|
if(furi_kernel_is_irq_or_masked()) {
|
||||||
|
ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL);
|
||||||
|
} else {
|
||||||
|
ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever);
|
||||||
|
}
|
||||||
|
furi_check(ret == pdPASS);
|
||||||
|
}
|
||||||
@@ -56,6 +56,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance);
|
|||||||
*/
|
*/
|
||||||
uint32_t furi_timer_is_running(FuriTimer* instance);
|
uint32_t furi_timer_is_running(FuriTimer* instance);
|
||||||
|
|
||||||
|
typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg);
|
||||||
|
|
||||||
|
void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Submodule lib/STM32CubeWB updated: a9e29b431f...c4cec8ae57
@@ -7,6 +7,7 @@ env.Append(
|
|||||||
SDK_HEADERS=[
|
SDK_HEADERS=[
|
||||||
File("flipper_format.h"),
|
File("flipper_format.h"),
|
||||||
File("flipper_format_i.h"),
|
File("flipper_format_i.h"),
|
||||||
|
File("flipper_format_stream.h"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ env.Append(
|
|||||||
"#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F",
|
"#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F",
|
||||||
"#/lib/FreeRTOS-glue",
|
"#/lib/FreeRTOS-glue",
|
||||||
],
|
],
|
||||||
CPPDEFINES=[
|
|
||||||
"HAVE_FREERTOS",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ env.Append(
|
|||||||
CPPPATH=[
|
CPPPATH=[
|
||||||
"#/lib/libusb_stm32/inc",
|
"#/lib/libusb_stm32/inc",
|
||||||
],
|
],
|
||||||
CPPDEFINES=[
|
|
||||||
("USB_PMASIZE", "0x400"),
|
|
||||||
],
|
|
||||||
SDK_HEADERS=env.GlobRecursive(
|
SDK_HEADERS=env.GlobRecursive(
|
||||||
"*.h",
|
"*.h",
|
||||||
Dir("libusb_stm32/inc"),
|
Dir("libusb_stm32/inc"),
|
||||||
@@ -16,6 +13,11 @@ env.Append(
|
|||||||
|
|
||||||
libenv = env.Clone(FW_LIB_NAME="usb_stm32")
|
libenv = env.Clone(FW_LIB_NAME="usb_stm32")
|
||||||
libenv.ApplyLibFlags()
|
libenv.ApplyLibFlags()
|
||||||
|
libenv.Append(
|
||||||
|
CPPDEFINES=[
|
||||||
|
("USB_PMASIZE", "0x400"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
|
|||||||
@@ -4,14 +4,16 @@ env.Append(
|
|||||||
CPPPATH=[
|
CPPPATH=[
|
||||||
"#/lib/littlefs",
|
"#/lib/littlefs",
|
||||||
],
|
],
|
||||||
CPPDEFINES=[
|
|
||||||
("LFS_CONFIG", "lfs_config.h"),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
libenv = env.Clone(FW_LIB_NAME="littlefs")
|
libenv = env.Clone(FW_LIB_NAME="littlefs")
|
||||||
libenv.ApplyLibFlags()
|
libenv.ApplyLibFlags()
|
||||||
|
libenv.Append(
|
||||||
|
CPPDEFINES=[
|
||||||
|
("LFS_CONFIG", "lfs_config.h"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
sources = Glob("littlefs/*.c", source=True)
|
sources = Glob("littlefs/*.c", source=True)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Import("env")
|
|
||||||
|
|
||||||
from fbt.util import GLOB_FILE_EXCLUSION
|
from fbt.util import GLOB_FILE_EXCLUSION
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
env.Append(
|
env.Append(
|
||||||
CPPPATH=[
|
CPPPATH=[
|
||||||
"#/lib/digital_signal",
|
"#/lib/digital_signal",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user