mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Compare commits
38 Commits
unlshd-028
...
subghz_pro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc6adcbeb1 | ||
|
|
842b497829 | ||
|
|
928d57b050 | ||
|
|
641934f8dd | ||
|
|
de07313173 | ||
|
|
921db0bb22 | ||
|
|
f93462667c | ||
|
|
c56eaae89d | ||
|
|
185bb3277a | ||
|
|
b5a60dc10b | ||
|
|
f4af57d15a | ||
|
|
0abb88842a | ||
|
|
bc06d407f3 | ||
|
|
cb89bb9628 | ||
|
|
fbf99d6cb3 | ||
|
|
d0c6c3402c | ||
|
|
5a730e3adc | ||
|
|
628f089c42 | ||
|
|
3accc005e7 | ||
|
|
e08b10fa3c | ||
|
|
9007f0e360 | ||
|
|
8608ba01aa | ||
|
|
3747f95d5a | ||
|
|
6c4334e7cb | ||
|
|
d247eb43de | ||
|
|
ca12057426 | ||
|
|
8b22952dac | ||
|
|
70af1e3bfb | ||
|
|
896a78c645 | ||
|
|
37b84a9dbb | ||
|
|
5a2f693551 | ||
|
|
82f77edc70 | ||
|
|
80b8a0dddb | ||
|
|
d179199a42 | ||
|
|
f388a7ecab | ||
|
|
92d55ec90f | ||
|
|
f86582b99e | ||
|
|
c2545a2f7b |
24
.drone.yml
24
.drone.yml
@@ -222,6 +222,18 @@ steps:
|
||||
- chmod +x ./discord.sh
|
||||
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
|
||||
|
||||
- name: "Send extra pack build to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
settings:
|
||||
token:
|
||||
from_secret: tgtoken
|
||||
to:
|
||||
from_secret: tgid
|
||||
format: markdown
|
||||
message: "Build with extra apps pack:"
|
||||
document:
|
||||
- flipper-z-f7-update-${DRONE_TAG}e.tgz
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
@@ -380,6 +392,18 @@ steps:
|
||||
document:
|
||||
- dev/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz
|
||||
|
||||
- name: "Send extra pack build to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
settings:
|
||||
token:
|
||||
from_secret: tgtoken
|
||||
to:
|
||||
from_secret: tgid_dev
|
||||
format: markdown
|
||||
message: "Build with extra apps pack:"
|
||||
document:
|
||||
- flipper-z-f7-update-${DRONE_BUILD_NUMBER}e.tgz
|
||||
|
||||
- name: "Send discord notification"
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,8 +1,12 @@
|
||||
### New changes
|
||||
* iButton: **Temp Fix of non working emulation on Metakom and Cyfral protocols**
|
||||
* Archive and FileBrowser: **Sort files and folders alphabetically.** Added a "Internal" tab to the Browser (only in DEBUG mode), other misc changes (by @ClaraCrazy and @Willy-JL | PR #327)
|
||||
* SubGHz: Custom modulation for lrs pagers and added frequency 467.75 to default list (by @jbohack | PR #328)
|
||||
* SubGHz: **Small fixes in SubGHz HAL**
|
||||
* SubGHz: **Nice ON2E (Nice One)** support (by @assasinfil | PR #335)
|
||||
* SubGHz: Remove 467.75 From freq analyzer since it has too much noise (Frequency is still can be used, just excluded from FA to avoid false detections)
|
||||
* Archive and FileBrowser: **Fixed more navigation issues** (by @Willy-JL | PR #334)
|
||||
* Plugins -> SubGHz Bruteforcer: Fix Linear Delta 3 repeats (now its more stable and we will be sure signal is received correctly)
|
||||
* Plugins: Updated TOTP (Authenticator) [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||
* OFW: **Fix Cyfral & Metakom emulation (My temp fix removed and proper fix from OFW applied)**
|
||||
* OFW: BadUSB: disable CDC mode, USB mode switch fix
|
||||
* OFW: Updater visual fixes
|
||||
|
||||
#### [🎲 Download latest extra apps pack](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)
|
||||
|
||||
|
||||
16
ReadMe.md
16
ReadMe.md
@@ -56,6 +56,10 @@ Our Discord Community:
|
||||
Also check the changelog in releases for latest updates!
|
||||
|
||||
### Current modified and new Sub-GHz protocols list:
|
||||
Thanks to Official team (to thier SubGHz Developer, Skorp) for implementing decoders for these protocols.
|
||||
|
||||
Encoders/sending made by Eng1n33r & @xMasterX:
|
||||
|
||||
- Keeloq [Not ALL systems supported for decode or emulation yet!] - [Supported manufacturers list](https://0bin.net/paste/VwR2lNJY#WH9vnPgvcp7w6zVKucFCuNREKAcOij8KsJ6vqLfMn3b)
|
||||
- Keeloq: HCS101
|
||||
- Keeloq: AN-Motors
|
||||
@@ -72,15 +76,19 @@ Also check the changelog in releases for latest updates!
|
||||
- BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)]
|
||||
- Security+ v1 & v2
|
||||
- Star Line
|
||||
- Somfy Telis (encoder by @assasinfil & @TQMatvey)
|
||||
- Somfy Keytis (encoder by @assasinfil)
|
||||
- KingGates Stylo 4k (encoder by @assasinfil)
|
||||
- Alutech AT-4N (encoder by @assasinfil)
|
||||
|
||||
Encoders made by @assasinfil & @xMasterX:
|
||||
- Somfy Telis
|
||||
- Somfy Keytis
|
||||
- KingGates Stylo 4k
|
||||
- Alutech AT-4N
|
||||
- Nice ON2E (Nice One)
|
||||
|
||||
## Please support development of the project
|
||||
The majority of this project is developed and maintained by me, @xMasterX.
|
||||
I'm unemployed because of the war, and the only income I receive is from your donations.
|
||||
Our team is small and the guys are working on this project as much as they can solely based on the enthusiasm they have for this project and the community.
|
||||
- @assasinfil - SubGHz
|
||||
- @Svaarich - UI design and animations
|
||||
- @Amec0e - Infrared assets
|
||||
- Community moderators in Telegram, Discord, and Reddit
|
||||
|
||||
@@ -57,9 +57,14 @@ static void archive_list_load_cb(void* context, uint32_t list_load_offset) {
|
||||
false);
|
||||
}
|
||||
|
||||
static void
|
||||
archive_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last) {
|
||||
static void archive_list_item_cb(
|
||||
void* context,
|
||||
FuriString* item_path,
|
||||
uint32_t idx,
|
||||
bool is_folder,
|
||||
bool is_last) {
|
||||
furi_assert(context);
|
||||
UNUSED(idx);
|
||||
ArchiveBrowserView* browser = (ArchiveBrowserView*)context;
|
||||
|
||||
if(!is_last) {
|
||||
@@ -69,7 +74,9 @@ static void
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
files_array_sort(model->files);
|
||||
if(model->item_cnt <= BROWSER_SORT_THRESHOLD) {
|
||||
files_array_sort(model->files);
|
||||
}
|
||||
model->list_loading = false;
|
||||
},
|
||||
true);
|
||||
|
||||
@@ -398,15 +398,20 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
|
||||
bool in_menu;
|
||||
bool move_fav_mode;
|
||||
bool is_loading;
|
||||
with_view_model(
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
in_menu = model->menu;
|
||||
move_fav_mode = model->move_fav;
|
||||
is_loading = model->folder_loading || model->list_loading;
|
||||
},
|
||||
false);
|
||||
|
||||
if(is_loading) {
|
||||
return false;
|
||||
}
|
||||
if(in_menu) {
|
||||
if(event->type != InputTypeShort) {
|
||||
return true; // RETURN
|
||||
@@ -482,7 +487,7 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
model->scroll_counter = 0;
|
||||
}
|
||||
},
|
||||
true);
|
||||
false);
|
||||
archive_update_offset(browser);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,8 +115,12 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
|
||||
if(furi_hal_usb_is_locked()) {
|
||||
app->error = BadUsbAppErrorCloseRpc;
|
||||
app->usb_if_prev = NULL;
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneError);
|
||||
} else {
|
||||
app->usb_if_prev = furi_hal_usb_get_config();
|
||||
furi_check(furi_hal_usb_set_config(NULL, NULL));
|
||||
|
||||
if(!furi_string_empty(app->file_path)) {
|
||||
app->bad_usb_script = bad_usb_script_open(app->file_path);
|
||||
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
|
||||
@@ -138,6 +142,10 @@ void bad_usb_app_free(BadUsbApp* app) {
|
||||
app->bad_usb_script = NULL;
|
||||
}
|
||||
|
||||
if(app->usb_if_prev) {
|
||||
furi_check(furi_hal_usb_set_config(app->usb_if_prev, NULL));
|
||||
}
|
||||
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
|
||||
bad_usb_free(app->bad_usb_view);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include "views/bad_usb_view.h"
|
||||
#include <furi_hal_usb.h>
|
||||
|
||||
#define BAD_USB_APP_BASE_FOLDER ANY_PATH("badusb")
|
||||
#define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/assets/layouts"
|
||||
@@ -39,6 +40,8 @@ struct BadUsbApp {
|
||||
FuriString* keyboard_layout;
|
||||
BadUsb* bad_usb_view;
|
||||
BadUsbScript* bad_usb_script;
|
||||
|
||||
FuriHalUsbInterface* usb_if_prev;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -490,8 +490,6 @@ static int32_t bad_usb_worker(void* context) {
|
||||
BadUsbWorkerState worker_state = BadUsbStateInit;
|
||||
int32_t delay_val = 0;
|
||||
|
||||
FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "Init");
|
||||
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
||||
bad_usb->line = furi_string_alloc();
|
||||
@@ -642,8 +640,6 @@ static int32_t bad_usb_worker(void* context) {
|
||||
|
||||
furi_hal_hid_set_state_callback(NULL, NULL);
|
||||
|
||||
furi_hal_usb_set_config(usb_mode_prev, NULL);
|
||||
|
||||
storage_file_close(script_file);
|
||||
storage_file_free(script_file);
|
||||
furi_string_free(bad_usb->line);
|
||||
|
||||
@@ -117,16 +117,15 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
|
||||
|
||||
// First stage: coarse scan
|
||||
for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) {
|
||||
if(furi_hal_subghz_is_frequency_valid(
|
||||
subghz_setting_get_frequency(instance->setting, i)) &&
|
||||
uint32_t current_frequnecy = subghz_setting_get_frequency(instance->setting, i);
|
||||
if(furi_hal_subghz_is_frequency_valid(current_frequnecy) &&
|
||||
(current_frequnecy != 467750000) &&
|
||||
!((furi_hal_subghz.radio_type == SubGhzRadioExternal) &&
|
||||
(subghz_setting_get_frequency(instance->setting, i) >= 311900000 &&
|
||||
subghz_setting_get_frequency(instance->setting, i) <= 312200000))) {
|
||||
(current_frequnecy >= 311900000 && current_frequnecy <= 312200000))) {
|
||||
furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle);
|
||||
cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle);
|
||||
frequency = cc1101_set_frequency(
|
||||
furi_hal_subghz.spi_bus_handle,
|
||||
subghz_setting_get_frequency(instance->setting, i));
|
||||
frequency =
|
||||
cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequnecy);
|
||||
|
||||
cc1101_calibrate(furi_hal_subghz.spi_bus_handle);
|
||||
do {
|
||||
|
||||
@@ -13,7 +13,7 @@ const char* const radio_modules_variables_text[] = {
|
||||
#define DEBUG_P_COUNT 2
|
||||
const char* const debug_pin_text[DEBUG_P_COUNT] = {
|
||||
"OFF",
|
||||
"A7",
|
||||
"17(1W)",
|
||||
};
|
||||
|
||||
static void subghz_scene_ext_module_changed(VariableItem* item) {
|
||||
|
||||
@@ -598,7 +598,7 @@ void subghz_hopper_update(SubGhz* subghz) {
|
||||
|
||||
void subghz_speaker_on(SubGhz* subghz) {
|
||||
if(subghz->txrx->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_ext_pa7);
|
||||
furi_hal_subghz_set_async_mirror_pin(&ibutton_gpio);
|
||||
}
|
||||
|
||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
@@ -643,7 +643,7 @@ void subghz_speaker_mute(SubGhz* subghz) {
|
||||
|
||||
void subghz_speaker_unmute(SubGhz* subghz) {
|
||||
if(subghz->txrx->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_ext_pa7);
|
||||
furi_hal_subghz_set_async_mirror_pin(&ibutton_gpio);
|
||||
}
|
||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
|
||||
@@ -25,7 +25,7 @@ static const uint32_t subghz_frequency_list[] = {
|
||||
310000000, 312000000, 312100000, 313000000, 313850000, 314000000, 314350000, 314980000,
|
||||
315000000, 318000000, 330000000, 345000000, 348000000, 350000000, 387000000, 390000000,
|
||||
418000000, 433075000, 433220000, 433420000, 433657070, 433889000, 433920000, 434075000,
|
||||
434176948, 434390000, 434420000, 434775000, 438900000, 440175000, 464000000, 467750000, 779000000,
|
||||
434176948, 434390000, 434420000, 434775000, 438900000, 440175000, 464000000, 779000000,
|
||||
868350000, 868400000, 868800000, 868950000, 906400000, 915000000, 925000000, 928000000};
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -195,6 +195,10 @@ bool pocsag_pager_scene_receiver_on_event(void* context, SceneManagerEvent event
|
||||
pcsg_hopper_update(app);
|
||||
pocsag_pager_scene_receiver_update_statusbar(app);
|
||||
}
|
||||
// Get current RSSI
|
||||
float rssi = furi_hal_subghz_get_rssi();
|
||||
pcsg_receiver_rssi(app->pcsg_receiver, rssi);
|
||||
|
||||
if(app->txrx->txrx_state == PCSGTxRxStateRx) {
|
||||
notification_message(app->notifications, &sequence_blink_cyan_10);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#define MENU_ITEMS 4u
|
||||
#define UNLOCK_CNT 3
|
||||
|
||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
|
||||
|
||||
typedef struct {
|
||||
FuriString* item_str;
|
||||
uint8_t type;
|
||||
@@ -58,8 +60,24 @@ typedef struct {
|
||||
uint16_t list_offset;
|
||||
uint16_t history_item;
|
||||
PCSGReceiverBarShow bar_show;
|
||||
uint8_t u_rssi;
|
||||
} PCSGReceiverModel;
|
||||
|
||||
void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) {
|
||||
furi_assert(instance);
|
||||
with_view_model(
|
||||
instance->view,
|
||||
PCSGReceiverModel * model,
|
||||
{
|
||||
if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
|
||||
model->u_rssi = 0;
|
||||
} else {
|
||||
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock lock) {
|
||||
furi_assert(pcsg_receiver);
|
||||
pcsg_receiver->lock_count = 0;
|
||||
@@ -167,13 +185,23 @@ static void pcsg_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scr
|
||||
canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
|
||||
}
|
||||
|
||||
static void pcsg_view_rssi_draw(Canvas* canvas, PCSGReceiverModel* model) {
|
||||
for(uint8_t i = 1; i < model->u_rssi; i++) {
|
||||
if(i % 5) {
|
||||
canvas_draw_dot(canvas, 46 + i, 50);
|
||||
canvas_draw_dot(canvas, 47 + i, 51);
|
||||
canvas_draw_dot(canvas, 46 + i, 52);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pcsg_view_receiver_draw(Canvas* canvas, PCSGReceiverModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
elements_button_left(canvas, "Config");
|
||||
canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
//canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
|
||||
bool scrollbar = model->history_item > 4;
|
||||
FuriString* str_buff;
|
||||
@@ -207,10 +235,13 @@ void pcsg_view_receiver_draw(Canvas* canvas, PCSGReceiverModel* model) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 63, 46, "Scanning...");
|
||||
canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
//canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
}
|
||||
|
||||
// Draw RSSI
|
||||
pcsg_view_rssi_draw(canvas, model);
|
||||
|
||||
switch(model->bar_show) {
|
||||
case PCSGReceiverBarShowLock:
|
||||
canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8);
|
||||
|
||||
@@ -8,6 +8,8 @@ typedef struct PCSGReceiver PCSGReceiver;
|
||||
|
||||
typedef void (*PCSGReceiverCallback)(PCSGCustomEvent event, void* context);
|
||||
|
||||
void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi);
|
||||
|
||||
void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock keyboard);
|
||||
|
||||
void pcsg_view_receiver_set_callback(
|
||||
|
||||
Submodule applications/plugins/subbrute updated: 94d417e6a4...819b532937
@@ -34,10 +34,10 @@ void totp_cli_command_move_docopt_usage() {
|
||||
void totp_cli_command_move_docopt_options() {
|
||||
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
|
||||
TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME_PREFIX,
|
||||
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME)) " New token name.\r\n");
|
||||
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_NAME)) " New token name\r\n");
|
||||
TOTP_CLI_PRINTF(" " DOCOPT_OPTION(
|
||||
TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX_PREFIX,
|
||||
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX)) " New token index.\r\n");
|
||||
DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_MOVE_ARG_NEW_INDEX)) " New token index\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_command_move_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
||||
|
||||
@@ -20,7 +20,7 @@ void totp_cli_command_timezone_docopt_usage() {
|
||||
|
||||
void totp_cli_command_timezone_docopt_arguments() {
|
||||
TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_TIMEZONE_ARG_TIMEZONE
|
||||
" Timezone offset in hours to be set.\r\n");
|
||||
" Timezone offset in hours to be set\r\n");
|
||||
}
|
||||
|
||||
void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
|
||||
|
||||
@@ -196,7 +196,7 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF
|
||||
return TotpConfigFileOpenSuccess;
|
||||
}
|
||||
|
||||
TotpConfigFileUpdateResult
|
||||
static TotpConfigFileUpdateResult
|
||||
totp_config_file_save_new_token_i(FlipperFormat* file, const TokenInfo* token_info) {
|
||||
TotpConfigFileUpdateResult update_result;
|
||||
do {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include "services/config/config.h"
|
||||
#include "types/plugin_state.h"
|
||||
#include "types/token_info.h"
|
||||
@@ -151,6 +152,9 @@ int32_t totp_app() {
|
||||
return 253;
|
||||
}
|
||||
|
||||
// Affecting dolphin level
|
||||
DOLPHIN_DEED(DolphinDeedPluginStart);
|
||||
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
|
||||
|
||||
@@ -195,6 +195,10 @@ bool weather_station_scene_receiver_on_event(void* context, SceneManagerEvent ev
|
||||
ws_hopper_update(app);
|
||||
weather_station_scene_receiver_update_statusbar(app);
|
||||
}
|
||||
// Get current RSSI
|
||||
float rssi = furi_hal_subghz_get_rssi();
|
||||
ws_receiver_rssi(app->ws_receiver, rssi);
|
||||
|
||||
if(app->txrx->txrx_state == WSTxRxStateRx) {
|
||||
notification_message(app->notifications, &sequence_blink_cyan_10);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define MENU_ITEMS 4u
|
||||
#define UNLOCK_CNT 3
|
||||
|
||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
|
||||
typedef struct {
|
||||
FuriString* item_str;
|
||||
uint8_t type;
|
||||
@@ -59,8 +60,24 @@ typedef struct {
|
||||
uint16_t list_offset;
|
||||
uint16_t history_item;
|
||||
WSReceiverBarShow bar_show;
|
||||
uint8_t u_rssi;
|
||||
} WSReceiverModel;
|
||||
|
||||
void ws_receiver_rssi(WSReceiver* instance, float rssi) {
|
||||
furi_assert(instance);
|
||||
with_view_model(
|
||||
instance->view,
|
||||
WSReceiverModel * model,
|
||||
{
|
||||
if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
|
||||
model->u_rssi = 0;
|
||||
} else {
|
||||
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock lock) {
|
||||
furi_assert(ws_receiver);
|
||||
ws_receiver->lock_count = 0;
|
||||
@@ -164,13 +181,23 @@ static void ws_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrol
|
||||
canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
|
||||
}
|
||||
|
||||
static void ws_view_rssi_draw(Canvas* canvas, WSReceiverModel* model) {
|
||||
for(uint8_t i = 1; i < model->u_rssi; i++) {
|
||||
if(i % 5) {
|
||||
canvas_draw_dot(canvas, 46 + i, 50);
|
||||
canvas_draw_dot(canvas, 47 + i, 51);
|
||||
canvas_draw_dot(canvas, 46 + i, 52);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
elements_button_left(canvas, "Config");
|
||||
canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
//canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
|
||||
bool scrollbar = model->history_item > 4;
|
||||
FuriString* str_buff;
|
||||
@@ -203,10 +230,13 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 63, 46, "Scanning...");
|
||||
canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
//canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
}
|
||||
|
||||
// Draw RSSI
|
||||
ws_view_rssi_draw(canvas, model);
|
||||
|
||||
switch(model->bar_show) {
|
||||
case WSReceiverBarShowLock:
|
||||
canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8);
|
||||
|
||||
@@ -8,6 +8,8 @@ typedef struct WSReceiver WSReceiver;
|
||||
|
||||
typedef void (*WSReceiverCallback)(WSCustomEvent event, void* context);
|
||||
|
||||
void ws_receiver_rssi(WSReceiver* instance, float rssi);
|
||||
|
||||
void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock keyboard);
|
||||
|
||||
void ws_view_receiver_set_callback(
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef enum {
|
||||
} BrowserItemType;
|
||||
|
||||
typedef struct {
|
||||
uint32_t unsorted_idx;
|
||||
FuriString* path;
|
||||
BrowserItemType type;
|
||||
uint8_t* custom_icon_data;
|
||||
@@ -41,6 +42,7 @@ typedef struct {
|
||||
} BrowserItem_t;
|
||||
|
||||
static void BrowserItem_t_init(BrowserItem_t* obj) {
|
||||
obj->unsorted_idx = 0;
|
||||
obj->type = BrowserItemTypeLoading;
|
||||
obj->path = furi_string_alloc();
|
||||
obj->display_name = furi_string_alloc();
|
||||
@@ -48,6 +50,7 @@ static void BrowserItem_t_init(BrowserItem_t* obj) {
|
||||
}
|
||||
|
||||
static void BrowserItem_t_init_set(BrowserItem_t* obj, const BrowserItem_t* src) {
|
||||
obj->unsorted_idx = src->unsorted_idx;
|
||||
obj->type = src->type;
|
||||
obj->path = furi_string_alloc_set(src->path);
|
||||
obj->display_name = furi_string_alloc_set(src->display_name);
|
||||
@@ -60,6 +63,7 @@ static void BrowserItem_t_init_set(BrowserItem_t* obj, const BrowserItem_t* src)
|
||||
}
|
||||
|
||||
static void BrowserItem_t_set(BrowserItem_t* obj, const BrowserItem_t* src) {
|
||||
obj->unsorted_idx = src->unsorted_idx;
|
||||
obj->type = src->type;
|
||||
furi_string_set(obj->path, src->path);
|
||||
furi_string_set(obj->display_name, src->display_name);
|
||||
@@ -157,8 +161,12 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context);
|
||||
static void
|
||||
browser_folder_open_cb(void* context, uint32_t item_cnt, int32_t file_idx, bool is_root);
|
||||
static void browser_list_load_cb(void* context, uint32_t list_load_offset);
|
||||
static void
|
||||
browser_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last);
|
||||
static void browser_list_item_cb(
|
||||
void* context,
|
||||
FuriString* item_path,
|
||||
uint32_t idx,
|
||||
bool is_folder,
|
||||
bool is_last);
|
||||
static void browser_long_load_cb(void* context);
|
||||
|
||||
static void file_browser_scroll_timer_callback(void* context) {
|
||||
@@ -347,7 +355,7 @@ static void browser_update_offset(FileBrowser* browser) {
|
||||
CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0);
|
||||
}
|
||||
},
|
||||
false);
|
||||
true);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -379,7 +387,7 @@ static void
|
||||
model->list_loading = true;
|
||||
model->folder_loading = false;
|
||||
},
|
||||
true);
|
||||
false);
|
||||
browser_update_offset(browser);
|
||||
|
||||
file_browser_worker_load(browser->worker, load_offset, ITEM_LIST_LEN_MAX);
|
||||
@@ -412,13 +420,18 @@ static void browser_list_load_cb(void* context, uint32_t list_load_offset) {
|
||||
BrowserItem_t_clear(&back_item);
|
||||
}
|
||||
|
||||
static void
|
||||
browser_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last) {
|
||||
static void browser_list_item_cb(
|
||||
void* context,
|
||||
FuriString* item_path,
|
||||
uint32_t idx,
|
||||
bool is_folder,
|
||||
bool is_last) {
|
||||
furi_assert(context);
|
||||
FileBrowser* browser = (FileBrowser*)context;
|
||||
|
||||
BrowserItem_t item;
|
||||
item.custom_icon_data = NULL;
|
||||
item.unsorted_idx = idx;
|
||||
|
||||
if(!is_last) {
|
||||
item.path = furi_string_alloc_set(item_path);
|
||||
@@ -454,7 +467,7 @@ static void
|
||||
items_array_push_back(model->items, item);
|
||||
// TODO: calculate if element is visible
|
||||
},
|
||||
true);
|
||||
false);
|
||||
furi_string_free(item.display_name);
|
||||
furi_string_free(item.path);
|
||||
if(item.custom_icon_data) {
|
||||
@@ -465,10 +478,28 @@ static void
|
||||
browser->view,
|
||||
FileBrowserModel * model,
|
||||
{
|
||||
items_array_sort(model->items);
|
||||
if(model->item_cnt <= BROWSER_SORT_THRESHOLD) {
|
||||
FuriString* selected = NULL;
|
||||
if(model->item_idx > 0) {
|
||||
selected = furi_string_alloc_set(
|
||||
items_array_get(model->items, model->item_idx)->path);
|
||||
}
|
||||
|
||||
items_array_sort(model->items);
|
||||
|
||||
if(selected != NULL) {
|
||||
for(uint32_t i = 0; i < model->item_cnt; i++) {
|
||||
if(!furi_string_cmp(items_array_get(model->items, i)->path, selected)) {
|
||||
model->item_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
model->list_loading = false;
|
||||
},
|
||||
true);
|
||||
false);
|
||||
browser_update_offset(browser);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,7 +646,10 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
|
||||
bool is_loading = false;
|
||||
|
||||
with_view_model(
|
||||
browser->view, FileBrowserModel * model, { is_loading = model->folder_loading; }, false);
|
||||
browser->view,
|
||||
FileBrowserModel * model,
|
||||
{ is_loading = model->folder_loading || model->list_loading; },
|
||||
false);
|
||||
|
||||
if(is_loading) {
|
||||
return false;
|
||||
@@ -652,7 +686,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
|
||||
model->scroll_counter = 0;
|
||||
}
|
||||
},
|
||||
true);
|
||||
false);
|
||||
browser_update_offset(browser);
|
||||
consumed = true;
|
||||
}
|
||||
@@ -667,10 +701,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
|
||||
if(browser_is_item_in_array(model, model->item_idx)) {
|
||||
selected_item =
|
||||
items_array_get(model->items, model->item_idx - model->array_offset);
|
||||
select_index = model->item_idx;
|
||||
if((!model->is_root) && (select_index > 0)) {
|
||||
select_index -= 1;
|
||||
}
|
||||
select_index = selected_item->unsorted_idx;
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
||||
@@ -189,8 +189,90 @@ static bool browser_folder_init(
|
||||
return state;
|
||||
}
|
||||
|
||||
static bool
|
||||
browser_folder_load(BrowserWorker* browser, FuriString* path, uint32_t offset, uint32_t count) {
|
||||
// Load files list by chunks, like it was originally, not compatible with sorting, sorting needs to be disabled to use this
|
||||
static bool browser_folder_load_chunked(
|
||||
BrowserWorker* browser,
|
||||
FuriString* path,
|
||||
uint32_t offset,
|
||||
uint32_t count) {
|
||||
FileInfo file_info;
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* directory = storage_file_alloc(storage);
|
||||
|
||||
char name_temp[FILE_NAME_LEN_MAX];
|
||||
FuriString* name_str;
|
||||
name_str = furi_string_alloc();
|
||||
|
||||
uint32_t items_cnt = 0;
|
||||
|
||||
do {
|
||||
if(!storage_dir_open(directory, furi_string_get_cstr(path))) {
|
||||
break;
|
||||
}
|
||||
|
||||
items_cnt = 0;
|
||||
while(items_cnt < offset) {
|
||||
if(!storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX)) {
|
||||
break;
|
||||
}
|
||||
if(storage_file_get_error(directory) == FSE_OK) {
|
||||
furi_string_set(name_str, name_temp);
|
||||
if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) {
|
||||
items_cnt++;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(items_cnt != offset) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(browser->list_load_cb) {
|
||||
browser->list_load_cb(browser->cb_ctx, offset);
|
||||
}
|
||||
|
||||
items_cnt = 0;
|
||||
while(items_cnt < count) {
|
||||
if(!storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX)) {
|
||||
break;
|
||||
}
|
||||
if(storage_file_get_error(directory) == FSE_OK) {
|
||||
furi_string_set(name_str, name_temp);
|
||||
if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) {
|
||||
furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp);
|
||||
if(browser->list_item_cb) {
|
||||
browser->list_item_cb(
|
||||
browser->cb_ctx,
|
||||
name_str,
|
||||
items_cnt,
|
||||
(file_info.flags & FSF_DIRECTORY),
|
||||
false);
|
||||
}
|
||||
items_cnt++;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(browser->list_item_cb) {
|
||||
browser->list_item_cb(browser->cb_ctx, NULL, 0, false, true);
|
||||
}
|
||||
} while(0);
|
||||
|
||||
furi_string_free(name_str);
|
||||
|
||||
storage_dir_close(directory);
|
||||
storage_file_free(directory);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return (items_cnt == count);
|
||||
}
|
||||
|
||||
// Load all files at once, may cause memory overflow so need to limit that to about 400 files
|
||||
static bool browser_folder_load_full(BrowserWorker* browser, FuriString* path) {
|
||||
FileInfo file_info;
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
@@ -207,34 +289,6 @@ static bool
|
||||
if(!storage_dir_open(directory, furi_string_get_cstr(path))) {
|
||||
break;
|
||||
}
|
||||
|
||||
// items_cnt = 0;
|
||||
// while(items_cnt < offset) {
|
||||
// if(!storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX)) {
|
||||
// break;
|
||||
// }
|
||||
// if(storage_file_get_error(directory) == FSE_OK) {
|
||||
// furi_string_set(name_str, name_temp);
|
||||
// if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) {
|
||||
// items_cnt++;
|
||||
// }
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if(items_cnt != offset) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
// FLIPPER DEVS MOMENT
|
||||
// this used to load the file list in chunks, and then sort it...
|
||||
// so while scrolling, it loads more files and sorts them...
|
||||
// chances are, the new files are higher in the sorted list...
|
||||
// so the files keep shifting around while scrolling...
|
||||
// now this does something intelligent and loads all in one go.
|
||||
// might take a few milliseconds longer, but atleast it works :kekw:
|
||||
UNUSED(offset);
|
||||
UNUSED(count);
|
||||
if(browser->list_load_cb) {
|
||||
browser->list_load_cb(browser->cb_ctx, 0);
|
||||
}
|
||||
@@ -245,13 +299,17 @@ static bool
|
||||
furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp);
|
||||
if(browser->list_item_cb) {
|
||||
browser->list_item_cb(
|
||||
browser->cb_ctx, name_str, (file_info.flags & FSF_DIRECTORY), false);
|
||||
browser->cb_ctx,
|
||||
name_str,
|
||||
items_cnt,
|
||||
(file_info.flags & FSF_DIRECTORY),
|
||||
false);
|
||||
}
|
||||
items_cnt++;
|
||||
}
|
||||
}
|
||||
if(browser->list_item_cb) {
|
||||
browser->list_item_cb(browser->cb_ctx, NULL, false, true);
|
||||
browser->list_item_cb(browser->cb_ctx, NULL, 0, false, true);
|
||||
}
|
||||
ret = true;
|
||||
} while(0);
|
||||
@@ -360,7 +418,12 @@ static int32_t browser_worker(void* context) {
|
||||
if(flags & WorkerEvtLoad) {
|
||||
FURI_LOG_D(
|
||||
TAG, "Load offset: %lu cnt: %lu", browser->load_offset, browser->load_count);
|
||||
browser_folder_load(browser, path, browser->load_offset, browser->load_count);
|
||||
if(items_cnt > BROWSER_SORT_THRESHOLD) {
|
||||
browser_folder_load_chunked(
|
||||
browser, path, browser->load_offset, browser->load_count);
|
||||
} else {
|
||||
browser_folder_load_full(browser, path);
|
||||
}
|
||||
}
|
||||
|
||||
if(flags & WorkerEvtStop) {
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BROWSER_SORT_THRESHOLD 400
|
||||
|
||||
typedef struct BrowserWorker BrowserWorker;
|
||||
typedef void (*BrowserWorkerFolderOpenCallback)(
|
||||
void* context,
|
||||
@@ -17,6 +19,7 @@ typedef void (*BrowserWorkerListLoadCallback)(void* context, uint32_t list_load_
|
||||
typedef void (*BrowserWorkerListItemCallback)(
|
||||
void* context,
|
||||
FuriString* item_path,
|
||||
uint32_t idx,
|
||||
bool is_folder,
|
||||
bool is_last);
|
||||
typedef void (*BrowserWorkerLongLoadCallback)(void* context);
|
||||
|
||||
@@ -58,8 +58,12 @@ bool updater_scene_error_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
|
||||
void updater_scene_error_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
Updater* updater = (Updater*)context;
|
||||
|
||||
widget_reset(updater->widget);
|
||||
free(updater->pending_update);
|
||||
|
||||
if(updater->loaded_manifest) {
|
||||
update_manifest_free(updater->loaded_manifest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,9 @@ void updater_scene_loadcfg_apply_callback(GuiButtonType result, InputType type,
|
||||
|
||||
void updater_scene_loadcfg_on_enter(void* context) {
|
||||
Updater* updater = (Updater*)context;
|
||||
UpdaterManifestProcessingState* pending_upd = updater->pending_update =
|
||||
malloc(sizeof(UpdaterManifestProcessingState));
|
||||
pending_upd->manifest = update_manifest_alloc();
|
||||
UpdateManifest* loaded_manifest = updater->loaded_manifest = update_manifest_alloc();
|
||||
|
||||
if(update_manifest_init(pending_upd->manifest, furi_string_get_cstr(updater->startup_arg))) {
|
||||
if(update_manifest_init(loaded_manifest, furi_string_get_cstr(updater->startup_arg))) {
|
||||
widget_add_string_element(
|
||||
updater->widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, "Update");
|
||||
|
||||
@@ -37,7 +35,7 @@ void updater_scene_loadcfg_on_enter(void* context) {
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
furi_string_get_cstr(pending_upd->manifest->version),
|
||||
furi_string_get_cstr(loaded_manifest->version),
|
||||
true);
|
||||
|
||||
widget_add_button_element(
|
||||
@@ -95,13 +93,12 @@ bool updater_scene_loadcfg_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
|
||||
void updater_scene_loadcfg_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
Updater* updater = (Updater*)context;
|
||||
|
||||
if(updater->pending_update) {
|
||||
update_manifest_free(updater->pending_update->manifest);
|
||||
furi_string_free(updater->pending_update->message);
|
||||
}
|
||||
|
||||
widget_reset(updater->widget);
|
||||
free(updater->pending_update);
|
||||
|
||||
if(updater->loaded_manifest) {
|
||||
update_manifest_free(updater->loaded_manifest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,6 @@ typedef enum {
|
||||
UpdaterCustomEventSdUnmounted,
|
||||
} UpdaterCustomEvent;
|
||||
|
||||
typedef struct UpdaterManifestProcessingState {
|
||||
UpdateManifest* manifest;
|
||||
FuriString* message;
|
||||
bool ready_to_be_applied;
|
||||
} UpdaterManifestProcessingState;
|
||||
|
||||
typedef struct {
|
||||
// GUI
|
||||
Gui* gui;
|
||||
@@ -49,7 +43,7 @@ typedef struct {
|
||||
|
||||
UpdaterMainView* main_view;
|
||||
|
||||
UpdaterManifestProcessingState* pending_update;
|
||||
UpdateManifest* loaded_manifest;
|
||||
UpdatePrepareResult preparation_result;
|
||||
|
||||
UpdateTask* update_task;
|
||||
|
||||
@@ -41,22 +41,22 @@ typedef struct {
|
||||
static const UpdateTaskStageGroupMap update_task_stage_progress[] = {
|
||||
[UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0),
|
||||
|
||||
[UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5),
|
||||
[UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 15),
|
||||
[UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 45),
|
||||
[UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5),
|
||||
|
||||
[UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 15),
|
||||
[UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 60),
|
||||
[UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 80),
|
||||
[UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 60),
|
||||
[UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 80),
|
||||
[UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 35),
|
||||
[UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 60),
|
||||
[UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 30),
|
||||
[UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 5),
|
||||
|
||||
[UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 10),
|
||||
[UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 2),
|
||||
|
||||
[UpdateTaskStageValidateDFUImage] = STAGE_DEF(UpdateTaskStageGroupFirmware, 50),
|
||||
[UpdateTaskStageFlashWrite] = STAGE_DEF(UpdateTaskStageGroupFirmware, 200),
|
||||
[UpdateTaskStageFlashValidate] = STAGE_DEF(UpdateTaskStageGroupFirmware, 30),
|
||||
[UpdateTaskStageValidateDFUImage] = STAGE_DEF(UpdateTaskStageGroupFirmware, 30),
|
||||
[UpdateTaskStageFlashWrite] = STAGE_DEF(UpdateTaskStageGroupFirmware, 150),
|
||||
[UpdateTaskStageFlashValidate] = STAGE_DEF(UpdateTaskStageGroupFirmware, 15),
|
||||
|
||||
[UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 30),
|
||||
[UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 5),
|
||||
|
||||
[UpdateTaskStageResourcesUpdate] = STAGE_DEF(UpdateTaskStageGroupResources, 255),
|
||||
[UpdateTaskStageSplashscreenInstall] = STAGE_DEF(UpdateTaskStageGroupSplashscreen, 5),
|
||||
|
||||
@@ -41,6 +41,14 @@ static bool update_task_pre_update(UpdateTask* update_task) {
|
||||
return success;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
UpdateTaskResourcesWeightsFileCleanup = 20,
|
||||
UpdateTaskResourcesWeightsDirCleanup = 20,
|
||||
UpdateTaskResourcesWeightsFileUnpack = 60,
|
||||
} UpdateTaskResourcesWeights;
|
||||
|
||||
#define UPDATE_TASK_RESOURCES_FILE_TO_TOTAL_PERCENT 90
|
||||
|
||||
typedef struct {
|
||||
UpdateTask* update_task;
|
||||
int32_t total_files, processed_files;
|
||||
@@ -54,33 +62,36 @@ static bool update_task_resource_unpack_cb(const char* name, bool is_directory,
|
||||
update_task_set_progress(
|
||||
unpack_progress->update_task,
|
||||
UpdateTaskStageProgress,
|
||||
/* For this stage, last 70% of progress = extraction */
|
||||
30 + (unpack_progress->processed_files * 70) / (unpack_progress->total_files + 1));
|
||||
/* For this stage, last progress segment = extraction */
|
||||
(UpdateTaskResourcesWeightsFileCleanup + UpdateTaskResourcesWeightsDirCleanup) +
|
||||
(unpack_progress->processed_files * UpdateTaskResourcesWeightsFileUnpack) /
|
||||
(unpack_progress->total_files + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
update_task_cleanup_resources(UpdateTask* update_task, uint32_t n_approx_file_entries) {
|
||||
static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_t n_tar_entries) {
|
||||
ResourceManifestReader* manifest_reader = resource_manifest_reader_alloc(update_task->storage);
|
||||
do {
|
||||
FURI_LOG_I(TAG, "Cleaning up old manifest");
|
||||
FURI_LOG_D(TAG, "Cleaning up old manifest");
|
||||
if(!resource_manifest_reader_open(manifest_reader, EXT_PATH("Manifest"))) {
|
||||
FURI_LOG_W(TAG, "No existing manifest");
|
||||
break;
|
||||
}
|
||||
|
||||
/* We got # of entries in TAR file. Approx 1/4th is dir entries, we skip them */
|
||||
n_approx_file_entries = n_approx_file_entries * 3 / 4 + 1;
|
||||
uint32_t n_processed_files = 0;
|
||||
const uint32_t n_approx_file_entries =
|
||||
n_tar_entries * UPDATE_TASK_RESOURCES_FILE_TO_TOTAL_PERCENT / 100 + 1;
|
||||
uint32_t n_dir_entries = 1;
|
||||
|
||||
ResourceManifestEntry* entry_ptr = NULL;
|
||||
uint32_t n_processed_entries = 0;
|
||||
while((entry_ptr = resource_manifest_reader_next(manifest_reader))) {
|
||||
if(entry_ptr->type == ResourceManifestEntryTypeFile) {
|
||||
update_task_set_progress(
|
||||
update_task,
|
||||
UpdateTaskStageProgress,
|
||||
/* For this stage, first 20% of progress = cleanup files */
|
||||
(n_processed_files++ * 20) / (n_approx_file_entries + 1));
|
||||
/* For this stage, first pass = old manifest's file cleanup */
|
||||
(n_processed_entries++ * UpdateTaskResourcesWeightsFileCleanup) /
|
||||
n_approx_file_entries);
|
||||
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
path_concat(
|
||||
@@ -88,16 +99,21 @@ static void
|
||||
FURI_LOG_D(TAG, "Removing %s", furi_string_get_cstr(file_path));
|
||||
storage_simply_remove(update_task->storage, furi_string_get_cstr(file_path));
|
||||
furi_string_free(file_path);
|
||||
} else if(entry_ptr->type == ResourceManifestEntryTypeDirectory) {
|
||||
n_dir_entries++;
|
||||
}
|
||||
}
|
||||
|
||||
n_processed_entries = 0;
|
||||
while((entry_ptr = resource_manifest_reader_previous(manifest_reader))) {
|
||||
if(entry_ptr->type == ResourceManifestEntryTypeDirectory) {
|
||||
update_task_set_progress(
|
||||
update_task,
|
||||
UpdateTaskStageProgress,
|
||||
/* For this stage, second 10% of progress = cleanup directories */
|
||||
(n_processed_files++ * 10) / (n_approx_file_entries + 1));
|
||||
UpdateTaskResourcesWeightsFileCleanup +
|
||||
(n_processed_entries++ * UpdateTaskResourcesWeightsDirCleanup) /
|
||||
n_dir_entries);
|
||||
|
||||
FuriString* folder_path = furi_string_alloc();
|
||||
File* folder_file = storage_file_alloc(update_task->storage);
|
||||
|
||||
@@ -1146,23 +1146,13 @@ Function,+,furi_hal_i2c_tx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, const uin
|
||||
Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_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_ibutton_add_interrupt,void,"GpioExtiCallback, void*"
|
||||
Function,+,furi_hal_ibutton_emulate_set_next,void,uint32_t
|
||||
Function,+,furi_hal_ibutton_emulate_start,void,"uint32_t, FuriHalIbuttonEmulateCallback, void*"
|
||||
Function,+,furi_hal_ibutton_emulate_stop,void,
|
||||
Function,-,furi_hal_ibutton_init,void,
|
||||
Function,+,furi_hal_ibutton_pin_configure,void,
|
||||
Function,+,furi_hal_ibutton_pin_get_level,_Bool,
|
||||
Function,+,furi_hal_ibutton_pin_high,void,
|
||||
Function,+,furi_hal_ibutton_pin_low,void,
|
||||
Function,+,furi_hal_ibutton_pin_reset,void,
|
||||
Function,+,furi_hal_ibutton_pin_write,void,const _Bool
|
||||
Function,+,furi_hal_ibutton_remove_interrupt,void,
|
||||
Function,+,furi_hal_ibutton_start_drive,void,
|
||||
Function,+,furi_hal_ibutton_start_drive_in_isr,void,
|
||||
Function,+,furi_hal_ibutton_start_interrupt,void,
|
||||
Function,+,furi_hal_ibutton_start_interrupt_in_isr,void,
|
||||
Function,+,furi_hal_ibutton_stop,void,
|
||||
Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, 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
|
||||
|
||||
|
@@ -89,51 +89,6 @@ void furi_hal_ibutton_emulate_stop() {
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_start_drive() {
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_start_drive_in_isr() {
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_start_interrupt() {
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_start_interrupt_in_isr() {
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
|
||||
LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_stop() {
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context) {
|
||||
furi_hal_gpio_add_int_callback(&ibutton_gpio, cb, context);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_remove_interrupt() {
|
||||
furi_hal_gpio_remove_int_callback(&ibutton_gpio);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_pin_low() {
|
||||
furi_hal_gpio_write(&ibutton_gpio, false);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_pin_high() {
|
||||
furi_hal_gpio_write(&ibutton_gpio, true);
|
||||
}
|
||||
|
||||
bool furi_hal_ibutton_pin_get_level() {
|
||||
return furi_hal_gpio_read(&ibutton_gpio);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_pin_configure() {
|
||||
furi_hal_gpio_write(&ibutton_gpio, true);
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
@@ -146,4 +101,4 @@ void furi_hal_ibutton_pin_reset() {
|
||||
|
||||
void furi_hal_ibutton_pin_write(const bool state) {
|
||||
furi_hal_gpio_write(&ibutton_gpio, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <furi_hal_gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -18,71 +17,28 @@ typedef void (*FuriHalIbuttonEmulateCallback)(void* context);
|
||||
/** Initialize */
|
||||
void furi_hal_ibutton_init();
|
||||
|
||||
/**
|
||||
* Start emulation timer
|
||||
* @param period timer period
|
||||
* @param callback timer callback
|
||||
* @param context callback context
|
||||
*/
|
||||
void furi_hal_ibutton_emulate_start(
|
||||
uint32_t period,
|
||||
FuriHalIbuttonEmulateCallback callback,
|
||||
void* context);
|
||||
|
||||
/**
|
||||
* Update emulation timer period
|
||||
* @param period new timer period
|
||||
*/
|
||||
void furi_hal_ibutton_emulate_set_next(uint32_t period);
|
||||
|
||||
/**
|
||||
* Stop emulation timer
|
||||
*/
|
||||
void furi_hal_ibutton_emulate_stop();
|
||||
|
||||
/**
|
||||
* Sets the pin to normal mode (open collector), and sets it to float
|
||||
*/
|
||||
void furi_hal_ibutton_start_drive();
|
||||
|
||||
/**
|
||||
* Sets the pin to normal mode (open collector), and clears pin EXTI interrupt.
|
||||
* Used in EXTI interrupt context.
|
||||
*/
|
||||
void furi_hal_ibutton_start_drive_in_isr();
|
||||
|
||||
/**
|
||||
* Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and sets it to float
|
||||
*/
|
||||
void furi_hal_ibutton_start_interrupt();
|
||||
|
||||
/**
|
||||
* Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and clears pin EXTI interrupt.
|
||||
* Used in EXTI interrupt context.
|
||||
*/
|
||||
void furi_hal_ibutton_start_interrupt_in_isr();
|
||||
|
||||
/**
|
||||
* Sets the pin to analog mode, and sets it to float
|
||||
*/
|
||||
void furi_hal_ibutton_stop();
|
||||
|
||||
/**
|
||||
* Attach interrupt callback to iButton pin
|
||||
* @param cb callback
|
||||
* @param context context
|
||||
*/
|
||||
void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context);
|
||||
|
||||
/**
|
||||
* Remove interrupt callback from iButton pin
|
||||
*/
|
||||
void furi_hal_ibutton_remove_interrupt();
|
||||
|
||||
/**
|
||||
* Sets the pin to low
|
||||
*/
|
||||
void furi_hal_ibutton_pin_low();
|
||||
|
||||
/**
|
||||
* Sets the pin to high (float in iButton pin modes)
|
||||
*/
|
||||
void furi_hal_ibutton_pin_high();
|
||||
|
||||
/**
|
||||
* Get pin level
|
||||
* @return true if level is high
|
||||
* @return false if level is low
|
||||
*/
|
||||
bool furi_hal_ibutton_pin_get_level();
|
||||
|
||||
/**
|
||||
* Set the pin to normal mode (open collector), and sets it to float
|
||||
*/
|
||||
|
||||
@@ -77,7 +77,7 @@ void furi_hal_rfid_init() {
|
||||
|
||||
void furi_hal_rfid_pins_reset() {
|
||||
// ibutton bus disable
|
||||
furi_hal_ibutton_stop();
|
||||
furi_hal_ibutton_pin_reset();
|
||||
|
||||
// pulldown rfid antenna
|
||||
furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
@@ -94,8 +94,8 @@ void furi_hal_rfid_pins_reset() {
|
||||
|
||||
void furi_hal_rfid_pins_emulate() {
|
||||
// ibutton low
|
||||
furi_hal_ibutton_start_drive();
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_ibutton_pin_configure();
|
||||
furi_hal_ibutton_pin_write(false);
|
||||
|
||||
// pull pin to timer out
|
||||
furi_hal_gpio_init_ex(
|
||||
@@ -115,8 +115,8 @@ void furi_hal_rfid_pins_emulate() {
|
||||
|
||||
void furi_hal_rfid_pins_read() {
|
||||
// ibutton low
|
||||
furi_hal_ibutton_start_drive();
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_ibutton_pin_configure();
|
||||
furi_hal_ibutton_pin_write(false);
|
||||
|
||||
// dont pull rfid antenna
|
||||
furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
@@ -800,6 +800,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
GpioSpeedLow,
|
||||
GpioAltFn1TIM2);
|
||||
} else {
|
||||
//Signal generation with mem-to-mem DMA
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, true);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
@@ -863,24 +864,28 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
LL_TIM_SetCounter(TIM2, 0);
|
||||
LL_TIM_EnableCounter(TIM2);
|
||||
|
||||
//Signal generation for external module
|
||||
// Start debug
|
||||
if(furi_hal_subghz_start_debug() || furi_hal_subghz.radio_type == SubGhzRadioExternal) {
|
||||
const GpioPin* gpio = furi_hal_subghz.cc1101_g0_pin;
|
||||
//Preparing bit mask
|
||||
//Debug pin is may be only PORTB! (PB0, PB1, .., PB15)
|
||||
furi_hal_subghz_debug_gpio_buff[0] = 0;
|
||||
furi_hal_subghz_debug_gpio_buff[1] = 0;
|
||||
|
||||
// Start debug (and speaker)
|
||||
furi_hal_subghz_start_debug();
|
||||
//Mirror pin (for example, speaker)
|
||||
if(furi_hal_subghz.async_mirror_pin != NULL) {
|
||||
furi_hal_subghz_debug_gpio_buff[0] |= (uint32_t)furi_hal_subghz.async_mirror_pin->pin
|
||||
<< GPIO_NUMBER;
|
||||
furi_hal_subghz_debug_gpio_buff[1] |= furi_hal_subghz.async_mirror_pin->pin;
|
||||
gpio = furi_hal_subghz.async_mirror_pin;
|
||||
}
|
||||
|
||||
const GpioPin* gpio = furi_hal_subghz.cc1101_g0_pin;
|
||||
|
||||
if((furi_hal_subghz.async_mirror_pin != NULL) &&
|
||||
(furi_hal_subghz.radio_type == SubGhzRadioInternal)) {
|
||||
gpio = furi_hal_subghz.async_mirror_pin;
|
||||
}
|
||||
if(((furi_hal_subghz.async_mirror_pin != NULL) &&
|
||||
(furi_hal_subghz.radio_type == SubGhzRadioInternal)) ||
|
||||
(furi_hal_subghz.radio_type == SubGhzRadioExternal)) {
|
||||
furi_hal_subghz_debug_gpio_buff[0] =
|
||||
((uint32_t)gpio->pin << GPIO_NUMBER) |
|
||||
((uint32_t)furi_hal_subghz.async_mirror_pin->pin << GPIO_NUMBER);
|
||||
furi_hal_subghz_debug_gpio_buff[1] = gpio->pin | furi_hal_subghz.async_mirror_pin->pin;
|
||||
//G0 singnal generation for external radio
|
||||
if(furi_hal_subghz.radio_type == SubGhzRadioExternal) {
|
||||
furi_hal_subghz_debug_gpio_buff[0] |= (uint32_t)furi_hal_subghz.cc1101_g0_pin->pin
|
||||
<< GPIO_NUMBER;
|
||||
furi_hal_subghz_debug_gpio_buff[1] |= furi_hal_subghz.cc1101_g0_pin->pin;
|
||||
}
|
||||
|
||||
dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff;
|
||||
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR);
|
||||
|
||||
@@ -340,7 +340,7 @@ static void usb_process_mode_start(FuriHalUsbInterface* interface, void* context
|
||||
}
|
||||
|
||||
static void usb_process_mode_change(FuriHalUsbInterface* interface, void* context) {
|
||||
if(interface != usb.interface) {
|
||||
if((interface != usb.interface) || (context != usb.interface_context)) {
|
||||
if(usb.enabled) {
|
||||
// Disable current interface
|
||||
susp_evt(&udev, 0, 0);
|
||||
|
||||
@@ -234,16 +234,11 @@ void ibutton_worker_emulate_timer_cb(void* context) {
|
||||
furi_assert(context);
|
||||
iButtonWorker* worker = context;
|
||||
|
||||
LevelDuration level =
|
||||
const LevelDuration level_duration =
|
||||
protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode);
|
||||
|
||||
furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level));
|
||||
|
||||
if(level_duration_get_level(level)) {
|
||||
furi_hal_ibutton_pin_high();
|
||||
} else {
|
||||
furi_hal_ibutton_pin_low();
|
||||
}
|
||||
furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level_duration));
|
||||
furi_hal_ibutton_pin_write(level_duration_get_level(level_duration));
|
||||
}
|
||||
|
||||
void ibutton_worker_emulate_timer_start(iButtonWorker* worker) {
|
||||
@@ -266,7 +261,7 @@ void ibutton_worker_emulate_timer_start(iButtonWorker* worker) {
|
||||
protocol_dict_set_data(worker->protocols, worker->protocol_to_encode, key_id, key_size);
|
||||
protocol_dict_encoder_start(worker->protocols, worker->protocol_to_encode);
|
||||
|
||||
furi_hal_ibutton_start_drive();
|
||||
furi_hal_ibutton_pin_configure();
|
||||
furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include "one_wire_host.h"
|
||||
#include "one_wire_host_timing.h"
|
||||
|
||||
@@ -24,49 +24,47 @@ void onewire_host_free(OneWireHost* host) {
|
||||
}
|
||||
|
||||
bool onewire_host_reset(OneWireHost* host) {
|
||||
UNUSED(host);
|
||||
uint8_t r;
|
||||
uint8_t retries = 125;
|
||||
|
||||
// wait until the gpio is high
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(host->gpio_pin, true);
|
||||
do {
|
||||
if(--retries == 0) return 0;
|
||||
furi_delay_us(2);
|
||||
} while(!furi_hal_ibutton_pin_get_level());
|
||||
} while(!furi_hal_gpio_read(host->gpio_pin));
|
||||
|
||||
// pre delay
|
||||
furi_delay_us(OWH_RESET_DELAY_PRE);
|
||||
|
||||
// drive low
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_gpio_write(host->gpio_pin, false);
|
||||
furi_delay_us(OWH_RESET_DRIVE);
|
||||
|
||||
// release
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(host->gpio_pin, true);
|
||||
furi_delay_us(OWH_RESET_RELEASE);
|
||||
|
||||
// read and post delay
|
||||
r = !furi_hal_ibutton_pin_get_level();
|
||||
r = !furi_hal_gpio_read(host->gpio_pin);
|
||||
furi_delay_us(OWH_RESET_DELAY_POST);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool onewire_host_read_bit(OneWireHost* host) {
|
||||
UNUSED(host);
|
||||
bool result;
|
||||
|
||||
// drive low
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_gpio_write(host->gpio_pin, false);
|
||||
furi_delay_us(OWH_READ_DRIVE);
|
||||
|
||||
// release
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(host->gpio_pin, true);
|
||||
furi_delay_us(OWH_READ_RELEASE);
|
||||
|
||||
// read and post delay
|
||||
result = furi_hal_ibutton_pin_get_level();
|
||||
result = furi_hal_gpio_read(host->gpio_pin);
|
||||
furi_delay_us(OWH_READ_DELAY_POST);
|
||||
|
||||
return result;
|
||||
@@ -91,22 +89,21 @@ void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count)
|
||||
}
|
||||
|
||||
void onewire_host_write_bit(OneWireHost* host, bool value) {
|
||||
UNUSED(host);
|
||||
if(value) {
|
||||
// drive low
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_gpio_write(host->gpio_pin, false);
|
||||
furi_delay_us(OWH_WRITE_1_DRIVE);
|
||||
|
||||
// release
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(host->gpio_pin, true);
|
||||
furi_delay_us(OWH_WRITE_1_RELEASE);
|
||||
} else {
|
||||
// drive low
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_gpio_write(host->gpio_pin, false);
|
||||
furi_delay_us(OWH_WRITE_0_DRIVE);
|
||||
|
||||
// release
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(host->gpio_pin, true);
|
||||
furi_delay_us(OWH_WRITE_0_RELEASE);
|
||||
}
|
||||
}
|
||||
@@ -124,13 +121,13 @@ void onewire_host_skip(OneWireHost* host) {
|
||||
}
|
||||
|
||||
void onewire_host_start(OneWireHost* host) {
|
||||
UNUSED(host);
|
||||
furi_hal_ibutton_start_drive();
|
||||
furi_hal_gpio_write(host->gpio_pin, true);
|
||||
furi_hal_gpio_init(host->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void onewire_host_stop(OneWireHost* host) {
|
||||
UNUSED(host);
|
||||
furi_hal_ibutton_stop();
|
||||
furi_hal_gpio_write(host->gpio_pin, true);
|
||||
furi_hal_gpio_init(host->gpio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void onewire_host_reset_search(OneWireHost* host) {
|
||||
@@ -151,7 +148,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code) {
|
||||
host->last_device_flag = false;
|
||||
}
|
||||
|
||||
uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode) {
|
||||
uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode) {
|
||||
uint8_t id_bit_number;
|
||||
uint8_t last_zero, rom_byte_number, search_result;
|
||||
uint8_t id_bit, cmp_id_bit;
|
||||
@@ -260,7 +257,7 @@ uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSear
|
||||
host->last_family_discrepancy = 0;
|
||||
search_result = false;
|
||||
} else {
|
||||
for(int i = 0; i < 8; i++) newAddr[i] = host->saved_rom[i];
|
||||
for(int i = 0; i < 8; i++) new_addr[i] = host->saved_rom[i];
|
||||
}
|
||||
|
||||
return search_result;
|
||||
|
||||
@@ -22,7 +22,7 @@ typedef struct OneWireHost OneWireHost;
|
||||
|
||||
/**
|
||||
* Allocate onewire host bus
|
||||
* @param gpio
|
||||
* @param pin
|
||||
* @return OneWireHost*
|
||||
*/
|
||||
OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin);
|
||||
@@ -114,7 +114,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code);
|
||||
* @param mode
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode);
|
||||
uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -36,15 +36,15 @@ struct OneWireSlave {
|
||||
|
||||
/*********************** PRIVATE ***********************/
|
||||
|
||||
uint32_t onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) {
|
||||
UNUSED(bus);
|
||||
static uint32_t
|
||||
onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) {
|
||||
uint32_t start = DWT->CYCCNT;
|
||||
uint32_t time_ticks = time * furi_hal_cortex_instructions_per_microsecond();
|
||||
uint32_t time_captured;
|
||||
|
||||
do { //-V1044
|
||||
time_captured = DWT->CYCCNT;
|
||||
if(furi_hal_ibutton_pin_get_level() != pin_value) {
|
||||
if(furi_hal_gpio_read(bus->gpio_pin) != pin_value) {
|
||||
uint32_t remaining_time = time_ticks - (time_captured - start);
|
||||
remaining_time /= furi_hal_cortex_instructions_per_microsecond();
|
||||
return remaining_time;
|
||||
@@ -54,14 +54,14 @@ uint32_t onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool onewire_slave_show_presence(OneWireSlave* bus) {
|
||||
static bool onewire_slave_show_presence(OneWireSlave* bus) {
|
||||
// wait while master delay presence check
|
||||
onewire_slave_wait_while_gpio_is(bus, OWS_PRESENCE_TIMEOUT, true);
|
||||
|
||||
// show presence
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_gpio_write(bus->gpio_pin, false);
|
||||
furi_delay_us(OWS_PRESENCE_MIN);
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(bus->gpio_pin, true);
|
||||
|
||||
// somebody also can show presence
|
||||
const uint32_t wait_low_time = OWS_PRESENCE_MAX - OWS_PRESENCE_MIN;
|
||||
@@ -75,7 +75,7 @@ bool onewire_slave_show_presence(OneWireSlave* bus) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onewire_slave_receive_bit(OneWireSlave* bus) {
|
||||
static bool onewire_slave_receive_bit(OneWireSlave* bus) {
|
||||
// wait while bus is low
|
||||
uint32_t time = OWS_SLOT_MAX;
|
||||
time = onewire_slave_wait_while_gpio_is(bus, time, false);
|
||||
@@ -99,7 +99,7 @@ bool onewire_slave_receive_bit(OneWireSlave* bus) {
|
||||
return (time > 0);
|
||||
}
|
||||
|
||||
bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
|
||||
static bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
|
||||
const bool write_zero = !value;
|
||||
|
||||
// wait while bus is low
|
||||
@@ -120,7 +120,7 @@ bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
|
||||
|
||||
// choose write time
|
||||
if(write_zero) {
|
||||
furi_hal_ibutton_pin_low();
|
||||
furi_hal_gpio_write(bus->gpio_pin, false);
|
||||
time = OWS_WRITE_ZERO;
|
||||
} else {
|
||||
time = OWS_READ_MAX;
|
||||
@@ -128,12 +128,12 @@ bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
|
||||
|
||||
// hold line for ZERO or ONE time
|
||||
furi_delay_us(time);
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(bus->gpio_pin, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onewire_slave_cmd_search_rom(OneWireSlave* bus) {
|
||||
static void onewire_slave_cmd_search_rom(OneWireSlave* bus) {
|
||||
const uint8_t key_bytes = 8;
|
||||
uint8_t* key = onewire_device_get_id_p(bus->device);
|
||||
|
||||
@@ -152,7 +152,7 @@ void onewire_slave_cmd_search_rom(OneWireSlave* bus) {
|
||||
}
|
||||
}
|
||||
|
||||
bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) {
|
||||
static bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) {
|
||||
uint8_t cmd;
|
||||
onewire_slave_receive(bus, &cmd, 1);
|
||||
|
||||
@@ -179,14 +179,14 @@ bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) {
|
||||
}
|
||||
}
|
||||
|
||||
bool onewire_slave_bus_start(OneWireSlave* bus) {
|
||||
static bool onewire_slave_bus_start(OneWireSlave* bus) {
|
||||
bool result = true;
|
||||
|
||||
if(bus->device == NULL) {
|
||||
result = false;
|
||||
} else {
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_ibutton_start_drive_in_isr();
|
||||
furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
bus->error = NO_ERROR;
|
||||
|
||||
if(onewire_slave_show_presence(bus)) {
|
||||
@@ -198,7 +198,7 @@ bool onewire_slave_bus_start(OneWireSlave* bus) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
furi_hal_ibutton_start_interrupt_in_isr();
|
||||
furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ bool onewire_slave_bus_start(OneWireSlave* bus) {
|
||||
static void exti_cb(void* context) {
|
||||
OneWireSlave* bus = context;
|
||||
|
||||
volatile bool input_state = furi_hal_ibutton_pin_get_level();
|
||||
volatile bool input_state = furi_hal_gpio_read(bus->gpio_pin);
|
||||
static uint32_t pulse_start = 0;
|
||||
|
||||
if(input_state) {
|
||||
@@ -251,14 +251,15 @@ void onewire_slave_free(OneWireSlave* bus) {
|
||||
}
|
||||
|
||||
void onewire_slave_start(OneWireSlave* bus) {
|
||||
furi_hal_ibutton_add_interrupt(exti_cb, bus);
|
||||
furi_hal_ibutton_start_interrupt();
|
||||
furi_hal_gpio_add_int_callback(bus->gpio_pin, exti_cb, bus);
|
||||
furi_hal_gpio_write(bus->gpio_pin, true);
|
||||
furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void onewire_slave_stop(OneWireSlave* bus) {
|
||||
UNUSED(bus);
|
||||
furi_hal_ibutton_stop();
|
||||
furi_hal_ibutton_remove_interrupt();
|
||||
furi_hal_gpio_write(bus->gpio_pin, true);
|
||||
furi_hal_gpio_init(bus->gpio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_remove_int_callback(bus->gpio_pin);
|
||||
}
|
||||
|
||||
void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device) {
|
||||
@@ -284,7 +285,7 @@ void onewire_slave_set_result_callback(
|
||||
bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length) {
|
||||
uint8_t bytes_sent = 0;
|
||||
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(bus->gpio_pin, true);
|
||||
|
||||
// bytes loop
|
||||
for(; bytes_sent < data_length; ++bytes_sent) {
|
||||
@@ -306,7 +307,7 @@ bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t
|
||||
bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length) {
|
||||
uint8_t bytes_received = 0;
|
||||
|
||||
furi_hal_ibutton_pin_high();
|
||||
furi_hal_gpio_write(bus->gpio_pin, true);
|
||||
|
||||
for(; bytes_received < data_length; ++bytes_received) {
|
||||
uint8_t value = 0;
|
||||
|
||||
@@ -19,7 +19,7 @@ typedef void (*OneWireSlaveResultCallback)(void* context);
|
||||
|
||||
/**
|
||||
* Allocate onewire slave
|
||||
* @param pin
|
||||
* @param gpio_pin
|
||||
* @return OneWireSlave*
|
||||
*/
|
||||
OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin);
|
||||
|
||||
@@ -100,7 +100,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment)
|
||||
TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name);
|
||||
}
|
||||
instance->encoder.repeat = 10;
|
||||
instance->encoder.size_upload = 1728; //wrong!! upload 186*16 = 2976 - actual size about 1728
|
||||
instance->encoder.size_upload = 2400; //wrong!! upload 186*16 = 2976 - actual size about 1728
|
||||
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
|
||||
instance->encoder.is_running = false;
|
||||
return instance;
|
||||
@@ -113,6 +113,8 @@ void subghz_protocol_encoder_nice_flor_s_free(void* context) {
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, uint8_t hold_bit);
|
||||
|
||||
/**
|
||||
* Generating an upload from data.
|
||||
* @param instance Pointer to a SubGhzProtocolEncoderNiceFlorS instance
|
||||
@@ -160,8 +162,8 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload(
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_nice_flor_s_const.te_short * 3);
|
||||
|
||||
//Send key data
|
||||
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
|
||||
if(bit_read(instance->generic.data, i - 1)) {
|
||||
for(uint8_t j = 52; j > 0; j--) {
|
||||
if(bit_read(instance->generic.data, j - 1)) {
|
||||
//send bit 1
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_nice_flor_s_const.te_long);
|
||||
@@ -175,6 +177,35 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload(
|
||||
false, (uint32_t)subghz_protocol_nice_flor_s_const.te_long);
|
||||
}
|
||||
}
|
||||
if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) {
|
||||
uint8_t add_data[10] = {0};
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
add_data[i] = (instance->generic.data >> (48 - i * 8)) & 0xFF;
|
||||
}
|
||||
subghz_protocol_nice_one_get_data(add_data, loops[i], loops[i]);
|
||||
instance->generic.data_2 = 0;
|
||||
for(size_t j = 7; j < 10; j++) {
|
||||
instance->generic.data_2 <<= 8;
|
||||
instance->generic.data_2 += add_data[j];
|
||||
}
|
||||
|
||||
//Send key data
|
||||
for(uint8_t j = 24; j > 4; j--) {
|
||||
if(bit_read(instance->generic.data_2, j - 1)) {
|
||||
//send bit 1
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_nice_flor_s_const.te_long);
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_nice_flor_s_const.te_short);
|
||||
} else {
|
||||
//send bit 0
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
true, (uint32_t)subghz_protocol_nice_flor_s_const.te_short);
|
||||
instance->encoder.upload[index++] = level_duration_make(
|
||||
false, (uint32_t)subghz_protocol_nice_flor_s_const.te_long);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Send stop bit
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_nice_flor_s_const.te_short * 3);
|
||||
@@ -197,6 +228,8 @@ bool subghz_protocol_encoder_nice_flor_s_deserialize(void* context, FlipperForma
|
||||
//optional parameter parameter
|
||||
flipper_format_read_uint32(
|
||||
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
|
||||
// flipper_format_read_uint32(
|
||||
// flipper_format, "Data", (uint32_t*)&instance->generic.data_2, 1);
|
||||
|
||||
subghz_protocol_nice_flor_s_remote_controller(
|
||||
&instance->generic, instance->nice_flor_s_rainbow_table_file_name);
|
||||
@@ -216,6 +249,17 @@ bool subghz_protocol_encoder_nice_flor_s_deserialize(void* context, FlipperForma
|
||||
break;
|
||||
}
|
||||
|
||||
if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) {
|
||||
if(!flipper_format_rewind(flipper_format)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
break;
|
||||
}
|
||||
uint32_t temp = (instance->generic.data_2 >> 4) & 0xFFFFF;
|
||||
if(!flipper_format_update_uint32(flipper_format, "Data", &temp, 1)) {
|
||||
FURI_LOG_E(TAG, "Unable to add Data");
|
||||
}
|
||||
}
|
||||
|
||||
instance->encoder.is_running = true;
|
||||
|
||||
res = true;
|
||||
@@ -247,63 +291,63 @@ LevelDuration subghz_protocol_encoder_nice_flor_s_yield(void* context) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Read bytes from rainbow table
|
||||
// * @param p array[10] P0-P1|P2-P3-P4-P5-P6-P7-P8-P9-P10
|
||||
// * @return crc
|
||||
// */
|
||||
// static uint32_t subghz_protocol_nice_one_crc(uint8_t* p) {
|
||||
// uint8_t crc = 0;
|
||||
// uint8_t crc_data = 0xff;
|
||||
// for(uint8_t i = 4; i < 68; i++) {
|
||||
// if(subghz_protocol_blocks_get_bit_array(p, i)) {
|
||||
// crc = crc_data ^ 1;
|
||||
// } else {
|
||||
// crc = crc_data;
|
||||
// }
|
||||
// crc_data >>= 1;
|
||||
// if((crc & 0x01)) {
|
||||
// crc_data ^= 0x97;
|
||||
// }
|
||||
// }
|
||||
// crc = 0;
|
||||
// for(uint8_t i = 0; i < 8; i++) {
|
||||
// crc <<= 1;
|
||||
// if((crc_data >> i) & 0x01) crc = crc | 1;
|
||||
// }
|
||||
// return crc;
|
||||
// }
|
||||
/**
|
||||
* Read bytes from rainbow table
|
||||
* @param p array[10] P0-P1|P2-P3-P4-P5-P6-P7-P8-P9-P10
|
||||
* @return crc
|
||||
*/
|
||||
static uint32_t subghz_protocol_nice_one_crc(uint8_t* p) {
|
||||
uint8_t crc = 0;
|
||||
uint8_t crc_data = 0xff;
|
||||
for(uint8_t i = 4; i < 68; i++) {
|
||||
if(subghz_protocol_blocks_get_bit_array(p, i)) {
|
||||
crc = crc_data ^ 1;
|
||||
} else {
|
||||
crc = crc_data;
|
||||
}
|
||||
crc_data >>= 1;
|
||||
if((crc & 0x01)) {
|
||||
crc_data ^= 0x97;
|
||||
}
|
||||
}
|
||||
crc = 0;
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
crc <<= 1;
|
||||
if((crc_data >> i) & 0x01) crc = crc | 1;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Read bytes from rainbow table
|
||||
// * @param p array[10] P0-P1|P2-P3-P4-P5-P6-P7-XX-XX-XX
|
||||
// * @param num_parcel parcel number 0..15
|
||||
// * @param hold_bit 0 - the button was only pressed, 1 - the button was held down
|
||||
// */
|
||||
// static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, uint8_t hold_bit) {
|
||||
// uint8_t k = 0;
|
||||
// uint8_t crc = 0;
|
||||
// p[1] = (p[1] & 0x0f) | ((0x0f ^ (p[0] & 0x0F) ^ num_parcel) << 4);
|
||||
// if(num_parcel < 4) {
|
||||
// k = 0x8f;
|
||||
// } else {
|
||||
// k = 0x80;
|
||||
// }
|
||||
/**
|
||||
* Read bytes from rainbow table
|
||||
* @param p array[10] P0-P1|P2-P3-P4-P5-P6-P7-XX-XX-XX
|
||||
* @param num_parcel parcel number 0..15
|
||||
* @param hold_bit 0 - the button was only pressed, 1 - the button was held down
|
||||
*/
|
||||
static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, uint8_t hold_bit) {
|
||||
uint8_t k = 0;
|
||||
uint8_t crc = 0;
|
||||
p[1] = (p[1] & 0x0f) | ((0x0f ^ (p[0] & 0x0F) ^ num_parcel) << 4);
|
||||
if(num_parcel < 4) {
|
||||
k = 0x8f;
|
||||
} else {
|
||||
k = 0x80;
|
||||
}
|
||||
|
||||
// if(!hold_bit) {
|
||||
// hold_bit = 0;
|
||||
// } else {
|
||||
// hold_bit = 0x10;
|
||||
// }
|
||||
// k = num_parcel ^ k;
|
||||
// p[7] = k;
|
||||
// p[8] = hold_bit ^ (k << 4);
|
||||
if(!hold_bit) {
|
||||
hold_bit = 0;
|
||||
} else {
|
||||
hold_bit = 0x10;
|
||||
}
|
||||
k = num_parcel ^ k;
|
||||
p[7] = k;
|
||||
p[8] = hold_bit ^ (k << 4);
|
||||
|
||||
// crc = subghz_protocol_nice_one_crc(p);
|
||||
crc = subghz_protocol_nice_one_crc(p);
|
||||
|
||||
// p[8] |= crc >> 4;
|
||||
// p[9] = crc << 4;
|
||||
// }
|
||||
p[8] |= crc >> 4;
|
||||
p[9] = crc << 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read bytes from rainbow table
|
||||
|
||||
309
lib/subghz/protocols/revers.c
Normal file
309
lib/subghz/protocols/revers.c
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "revers.h"
|
||||
|
||||
#include "../blocks/const.h"
|
||||
#include "../blocks/decoder.h"
|
||||
#include "../blocks/encoder.h"
|
||||
#include "../blocks/generic.h"
|
||||
#include "../blocks/math.h"
|
||||
|
||||
#define TAG "SubGhzProtocolRevers"
|
||||
|
||||
static const SubGhzBlockConst subghz_protocol_revers_const = {
|
||||
.te_short = 200,
|
||||
.te_long = 430,
|
||||
.te_delta = 80,
|
||||
.min_count_bit_for_found = 8,
|
||||
};
|
||||
|
||||
struct SubGhzProtocolDecoderRevers {
|
||||
SubGhzProtocolDecoderBase base;
|
||||
|
||||
SubGhzBlockDecoder decoder;
|
||||
SubGhzBlockGeneric generic;
|
||||
|
||||
uint32_t last_data;
|
||||
uint16_t header_count;
|
||||
};
|
||||
|
||||
struct SubGhzProtocolEncoderRevers {
|
||||
SubGhzProtocolEncoderBase base;
|
||||
|
||||
SubGhzProtocolBlockEncoder encoder;
|
||||
SubGhzBlockGeneric generic;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
ReversDecoderStepReset = 0,
|
||||
ReversDecoderStepCheckPreambula,
|
||||
ReversDecoderStepSaveDuration,
|
||||
ReversDecoderStepCheckDuration,
|
||||
} ReversDecoderStep;
|
||||
|
||||
const SubGhzProtocolDecoder subghz_protocol_revers_decoder = {
|
||||
.alloc = subghz_protocol_decoder_revers_alloc,
|
||||
.free = subghz_protocol_decoder_revers_free,
|
||||
|
||||
.feed = subghz_protocol_decoder_revers_feed,
|
||||
.reset = subghz_protocol_decoder_revers_reset,
|
||||
|
||||
.get_hash_data = subghz_protocol_decoder_revers_get_hash_data,
|
||||
.serialize = subghz_protocol_decoder_revers_serialize,
|
||||
.deserialize = subghz_protocol_decoder_revers_deserialize,
|
||||
.get_string = subghz_protocol_decoder_revers_get_string,
|
||||
};
|
||||
|
||||
const SubGhzProtocolEncoder subghz_protocol_revers_encoder = {
|
||||
.alloc = subghz_protocol_encoder_revers_alloc,
|
||||
.free = subghz_protocol_encoder_revers_free,
|
||||
|
||||
.deserialize = subghz_protocol_encoder_revers_deserialize,
|
||||
.stop = subghz_protocol_encoder_revers_stop,
|
||||
.yield = subghz_protocol_encoder_revers_yield,
|
||||
};
|
||||
|
||||
const SubGhzProtocol subghz_protocol_revers = {
|
||||
.name = SUBGHZ_PROTOCOL_REVERS_NAME,
|
||||
.type = SubGhzProtocolTypeStatic,
|
||||
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
|
||||
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
|
||||
|
||||
.decoder = &subghz_protocol_revers_decoder,
|
||||
.encoder = &subghz_protocol_revers_encoder,
|
||||
};
|
||||
|
||||
void* subghz_protocol_encoder_revers_alloc(SubGhzEnvironment* environment) {
|
||||
UNUSED(environment);
|
||||
SubGhzProtocolEncoderRevers* instance = malloc(sizeof(SubGhzProtocolEncoderRevers));
|
||||
|
||||
instance->base.protocol = &subghz_protocol_revers;
|
||||
instance->generic.protocol_name = instance->base.protocol->name;
|
||||
|
||||
instance->encoder.repeat = 10;
|
||||
instance->encoder.size_upload = 512;
|
||||
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
|
||||
instance->encoder.is_running = false;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_protocol_encoder_revers_free(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderRevers* instance = context;
|
||||
free(instance->encoder.upload);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generating an upload from data.
|
||||
* @param instance Pointer to a SubGhzProtocolEncoderRevers instance
|
||||
* @return true On success
|
||||
*/
|
||||
static bool subghz_protocol_encoder_revers_get_upload(SubGhzProtocolEncoderRevers* instance) {
|
||||
furi_assert(instance);
|
||||
size_t index = 0;
|
||||
/*size_t size_upload = instance->generic.data_count_bit;
|
||||
if(size_upload > instance->encoder.size_upload) {
|
||||
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
|
||||
return false;
|
||||
} else {
|
||||
instance->encoder.size_upload = size_upload;
|
||||
}*/
|
||||
|
||||
//Send key data
|
||||
/*for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) {
|
||||
if(bit_read(instance->generic.data, i - 1)) {
|
||||
//send bit 1
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_revers_const.te_short);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_revers_const.te_short);
|
||||
} else {
|
||||
//send bit 0
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_revers_const.te_long);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_revers_const.te_long);
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subghz_protocol_encoder_revers_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderRevers* instance = context;
|
||||
bool res = false;
|
||||
do {
|
||||
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
|
||||
FURI_LOG_E(TAG, "Deserialize error");
|
||||
break;
|
||||
}
|
||||
if(instance->generic.data_count_bit !=
|
||||
subghz_protocol_revers_const.min_count_bit_for_found) {
|
||||
FURI_LOG_E(TAG, "Wrong number of bits in key");
|
||||
break;
|
||||
}
|
||||
//optional parameter parameter
|
||||
flipper_format_read_uint32(
|
||||
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
|
||||
|
||||
if(!subghz_protocol_encoder_revers_get_upload(instance)) break;
|
||||
instance->encoder.is_running = true;
|
||||
|
||||
res = true;
|
||||
} while(false);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void subghz_protocol_encoder_revers_stop(void* context) {
|
||||
SubGhzProtocolEncoderRevers* instance = context;
|
||||
instance->encoder.is_running = false;
|
||||
}
|
||||
|
||||
LevelDuration subghz_protocol_encoder_revers_yield(void* context) {
|
||||
SubGhzProtocolEncoderRevers* instance = context;
|
||||
|
||||
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
|
||||
instance->encoder.is_running = false;
|
||||
return level_duration_reset();
|
||||
}
|
||||
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* subghz_protocol_decoder_revers_alloc(SubGhzEnvironment* environment) {
|
||||
UNUSED(environment);
|
||||
SubGhzProtocolDecoderRevers* instance = malloc(sizeof(SubGhzProtocolDecoderRevers));
|
||||
instance->base.protocol = &subghz_protocol_revers;
|
||||
instance->generic.protocol_name = instance->base.protocol->name;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_revers_free(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderRevers* instance = context;
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_revers_reset(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderRevers* instance = context;
|
||||
instance->decoder.parser_step = ReversDecoderStepReset;
|
||||
instance->last_data = 0;
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_revers_feed(void* context, bool level, uint32_t duration) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderRevers* instance = context;
|
||||
switch(instance->decoder.parser_step) {
|
||||
case ReversDecoderStepReset:
|
||||
if((level) && DURATION_DIFF(duration, subghz_protocol_revers_const.te_short) <
|
||||
subghz_protocol_revers_const.te_delta) {
|
||||
instance->decoder.parser_step = ReversDecoderStepCheckPreambula;
|
||||
instance->header_count++;
|
||||
}
|
||||
break;
|
||||
case ReversDecoderStepCheckPreambula:
|
||||
if((!level) && (DURATION_DIFF(duration, subghz_protocol_revers_const.te_short) <
|
||||
subghz_protocol_revers_const.te_delta)) {
|
||||
instance->decoder.parser_step = ReversDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
if((instance->header_count > 2) &&
|
||||
(DURATION_DIFF(duration, subghz_protocol_revers_const.te_long) <
|
||||
subghz_protocol_revers_const.te_delta)) {
|
||||
// Preambula found
|
||||
instance->decoder.parser_step = ReversDecoderStepSaveDuration;
|
||||
} else {
|
||||
instance->decoder.parser_step = ReversDecoderStepReset;
|
||||
instance->header_count = 0;
|
||||
}
|
||||
case ReversDecoderStepSaveDuration:
|
||||
if(level) {
|
||||
instance->decoder.te_last = duration;
|
||||
instance->decoder.parser_step = ReversDecoderStepCheckDuration;
|
||||
} else {
|
||||
instance->decoder.parser_step = ReversDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case ReversDecoderStepCheckDuration:
|
||||
if(!level) {
|
||||
/*if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_revers_const.te_short) <
|
||||
subghz_protocol_revers_const.te_delta) &&
|
||||
(DURATION_DIFF(duration, subghz_protocol_revers_const.te_short * 7) <
|
||||
subghz_protocol_revers_const.te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||
instance->decoder.parser_step = ReversDecoderStepSaveDuration;
|
||||
} else if(
|
||||
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_revers_const.te_long) <
|
||||
subghz_protocol_revers_const.te_delta) &&
|
||||
(DURATION_DIFF(duration, subghz_protocol_revers_const.te_long) <
|
||||
subghz_protocol_revers_const.te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||
instance->decoder.parser_step = ReversDecoderStepSaveDuration;
|
||||
} else {
|
||||
instance->decoder.parser_step = ReversDecoderStepReset;
|
||||
}*/
|
||||
|
||||
} else {
|
||||
instance->decoder.parser_step = ReversDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_decoder_revers_get_hash_data(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderRevers* instance = context;
|
||||
return subghz_protocol_blocks_get_hash_data(
|
||||
&instance->decoder, (instance->decoder.decode_count_bit / 8));
|
||||
}
|
||||
|
||||
bool subghz_protocol_decoder_revers_serialize(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
SubGhzRadioPreset* preset) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderRevers* instance = context;
|
||||
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||
}
|
||||
|
||||
bool subghz_protocol_decoder_revers_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderRevers* instance = context;
|
||||
bool ret = false;
|
||||
do {
|
||||
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
|
||||
break;
|
||||
}
|
||||
if(instance->generic.data_count_bit !=
|
||||
subghz_protocol_revers_const.min_count_bit_for_found) {
|
||||
FURI_LOG_E(TAG, "Wrong number of bits in key");
|
||||
break;
|
||||
}
|
||||
ret = true;
|
||||
} while(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_revers_get_string(void* context, FuriString* output) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderRevers* instance = context;
|
||||
|
||||
uint32_t data = instance->generic.data & 0xFF;
|
||||
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"%s %dbit\r\n"
|
||||
"Key:0x%lX\r\n",
|
||||
instance->generic.protocol_name,
|
||||
instance->generic.data_count_bit,
|
||||
data);
|
||||
}
|
||||
107
lib/subghz/protocols/revers.h
Normal file
107
lib/subghz/protocols/revers.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
|
||||
#define SUBGHZ_PROTOCOL_REVERS_NAME "Revers"
|
||||
|
||||
typedef struct SubGhzProtocolDecoderRevers SubGhzProtocolDecoderRevers;
|
||||
typedef struct SubGhzProtocolEncoderRevers SubGhzProtocolEncoderRevers;
|
||||
|
||||
extern const SubGhzProtocolDecoder subghz_protocol_revers_decoder;
|
||||
extern const SubGhzProtocolEncoder subghz_protocol_revers_encoder;
|
||||
extern const SubGhzProtocol subghz_protocol_revers;
|
||||
|
||||
/**
|
||||
* Allocate SubGhzProtocolEncoderRevers.
|
||||
* @param environment Pointer to a SubGhzEnvironment instance
|
||||
* @return SubGhzProtocolEncoderRevers* pointer to a SubGhzProtocolEncoderRevers instance
|
||||
*/
|
||||
void* subghz_protocol_encoder_revers_alloc(SubGhzEnvironment* environment);
|
||||
|
||||
/**
|
||||
* Free SubGhzProtocolEncoderRevers.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderRevers instance
|
||||
*/
|
||||
void subghz_protocol_encoder_revers_free(void* context);
|
||||
|
||||
/**
|
||||
* Deserialize and generating an upload to send.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderRevers instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @return true On success
|
||||
*/
|
||||
bool subghz_protocol_encoder_revers_deserialize(void* context, FlipperFormat* flipper_format);
|
||||
|
||||
/**
|
||||
* Forced transmission stop.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderRevers instance
|
||||
*/
|
||||
void subghz_protocol_encoder_revers_stop(void* context);
|
||||
|
||||
/**
|
||||
* Getting the level and duration of the upload to be loaded into DMA.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderRevers instance
|
||||
* @return LevelDuration
|
||||
*/
|
||||
LevelDuration subghz_protocol_encoder_revers_yield(void* context);
|
||||
|
||||
/**
|
||||
* Allocate SubGhzProtocolDecoderRevers.
|
||||
* @param environment Pointer to a SubGhzEnvironment instance
|
||||
* @return SubGhzProtocolDecoderRevers* pointer to a SubGhzProtocolDecoderRevers instance
|
||||
*/
|
||||
void* subghz_protocol_decoder_revers_alloc(SubGhzEnvironment* environment);
|
||||
|
||||
/**
|
||||
* Free SubGhzProtocolDecoderRevers.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderRevers instance
|
||||
*/
|
||||
void subghz_protocol_decoder_revers_free(void* context);
|
||||
|
||||
/**
|
||||
* Reset decoder SubGhzProtocolDecoderRevers.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderRevers instance
|
||||
*/
|
||||
void subghz_protocol_decoder_revers_reset(void* context);
|
||||
|
||||
/**
|
||||
* Parse a raw sequence of levels and durations received from the air.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderRevers instance
|
||||
* @param level Signal level true-high false-low
|
||||
* @param duration Duration of this level in, us
|
||||
*/
|
||||
void subghz_protocol_decoder_revers_feed(void* context, bool level, uint32_t duration);
|
||||
|
||||
/**
|
||||
* Getting the hash sum of the last randomly received parcel.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderRevers instance
|
||||
* @return hash Hash sum
|
||||
*/
|
||||
uint8_t subghz_protocol_decoder_revers_get_hash_data(void* context);
|
||||
|
||||
/**
|
||||
* Serialize data SubGhzProtocolDecoderRevers.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderRevers instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
|
||||
* @return true On success
|
||||
*/
|
||||
bool subghz_protocol_decoder_revers_serialize(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
/**
|
||||
* Deserialize data SubGhzProtocolDecoderRevers.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderRevers instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @return true On success
|
||||
*/
|
||||
bool subghz_protocol_decoder_revers_deserialize(void* context, FlipperFormat* flipper_format);
|
||||
|
||||
/**
|
||||
* Getting a textual representation of the received data.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderRevers instance
|
||||
* @param output Resulting text
|
||||
*/
|
||||
void subghz_protocol_decoder_revers_get_string(void* context, FuriString* output);
|
||||
@@ -106,6 +106,7 @@ void tar_archive_set_file_callback(TarArchive* archive, tar_unpack_file_cb callb
|
||||
static int tar_archive_entry_counter(mtar_t* tar, const mtar_header_t* header, void* param) {
|
||||
UNUSED(tar);
|
||||
UNUSED(header);
|
||||
furi_assert(param);
|
||||
int32_t* counter = param;
|
||||
(*counter)++;
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from SCons.Builder import Builder
|
||||
from SCons.Action import Action
|
||||
from SCons.Script import Delete, Mkdir, GetBuildFailures
|
||||
from SCons.Script import Delete, Mkdir, GetBuildFailures, Flatten
|
||||
import multiprocessing
|
||||
import webbrowser
|
||||
import atexit
|
||||
@@ -30,13 +30,14 @@ def atexist_handler():
|
||||
return
|
||||
|
||||
for bf in GetBuildFailures():
|
||||
if bf.node.exists and bf.node.name.endswith(".html"):
|
||||
# macOS
|
||||
if sys.platform == "darwin":
|
||||
subprocess.run(["open", bf.node.abspath])
|
||||
else:
|
||||
webbrowser.open(bf.node.abspath)
|
||||
break
|
||||
for node in Flatten(bf.node):
|
||||
if node.exists and node.name.endswith(".html"):
|
||||
# macOS
|
||||
if sys.platform == "darwin":
|
||||
subprocess.run(["open", node.abspath])
|
||||
else:
|
||||
webbrowser.open(node.abspath)
|
||||
break
|
||||
|
||||
|
||||
def generate(env):
|
||||
|
||||
Reference in New Issue
Block a user