1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Compare commits

...

38 Commits

Author SHA1 Message Date
MX
fc6adcbeb1 WIP - Implement header(preambula) lookup
Bits = unknown
0 = unknown
1 = unknown
2023-02-15 00:42:28 +03:00
MX
842b497829 Show RSSI in weather station app and in pocsag pager app 2023-02-14 01:44:02 +03:00
MX
928d57b050 Small fixes and updates 2023-02-13 22:06:01 +03:00
MX
641934f8dd Update readme & changelog 2023-02-13 21:39:21 +03:00
MX
de07313173 Merge pull request #335 from assasinfil/nice-one
Nice one encoder
2023-02-13 21:11:03 +03:00
assasinfil
921db0bb22 Bugfix 2023-02-13 21:04:11 +03:00
MX
f93462667c 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
2023-02-13 20:54:03 +03:00
assasinfil
c56eaae89d Data save fix 2023-02-13 20:49:39 +03:00
assasinfil
185bb3277a Test fix 2023-02-13 19:58:07 +03:00
MX
b5a60dc10b Merge branch 'fz-dev' into dev 2023-02-13 19:30:36 +03:00
MX
f4af57d15a Revert "Temp fix of broken ibutton emulation"
This reverts commit 1831902fbd.
2023-02-13 19:29:48 +03:00
MX
0abb88842a Merge pull request #334 from Willy-JL/last-filebrowser-fixes
(Hopefully) last filebrowser fixes
2023-02-13 19:18:47 +03:00
Nikolay Minaylov
bc06d407f3 [FL-3113] BadUSB: disable CDC mode, USB mode switch fix (#2394) 2023-02-14 00:43:29 +09:00
Willy-JL
cb89bb9628 Fix archive sorting (skip on big folders) 2023-02-13 14:54:23 +00:00
Willy-JL
fbf99d6cb3 Skip browser inputs while loading / sorting 2023-02-13 14:54:15 +00:00
hedger
d0c6c3402c Updater visual fixes (#2391)
* updater: removed unused code; fbt: fixed build error processing in certain cases
* updater: simplified internal pre-update state
* updater: rebalanced stage weights; fixed progress hiccups
2023-02-13 23:07:53 +09:00
Georgii Surkov
5a730e3adc [FL-3107] Fix Cyfral & Metakom emulation (#2392)
* Fix Cyfral & Metakom emulation

Co-authored-by: あく <alleteam@gmail.com>
2023-02-13 20:33:15 +09:00
WillyJL
628f089c42 Mark debug app as debug not external (#2387) 2023-02-13 13:10:36 +09:00
MX
3accc005e7 Fix message 2023-02-13 03:31:16 +03:00
MX
e08b10fa3c Send default build and extra pack in the end in case of tg faults 2023-02-13 02:54:12 +03:00
MX
9007f0e360 Send extra pack builds instead of default one to telegram 2023-02-13 02:31:04 +03:00
MX
8608ba01aa Update changelog 2023-02-13 00:53:40 +03:00
MX
3747f95d5a Fix external cc1101 module issues
SubGHz HAL fixes, by @Quen0n
2023-02-13 00:43:58 +03:00
MX
6c4334e7cb Rename functions and cleanup a bit 2023-02-13 00:41:50 +03:00
MX
d247eb43de Fbt format 2023-02-12 23:58:16 +03:00
MX
ca12057426 Fix large folders parsing 2023-02-12 23:55:39 +03:00
MX
8b22952dac Merge pull request #333 from ClaraCrazy/fix-filebrowser
Fix file browser update issues
2023-02-12 20:09:06 +03:00
MX
70af1e3bfb Merge branch 'dev' into fix-filebrowser 2023-02-12 20:04:00 +03:00
MX
896a78c645 Use 17 (1W) pin for subghz debug mode 2023-02-12 20:02:27 +03:00
Willy-JL
37b84a9dbb Remove unnecessary sarcastic comment 2023-02-12 12:28:40 +00:00
Willy-JL
5a2f693551 File browser load speed improvements (skip redraw) 2023-02-12 11:22:52 +00:00
Willy-JL
82f77edc70 Fix file browser back history 2023-02-12 11:22:37 +00:00
Willy-JL
80b8a0dddb Fix file browser clownage comment 2023-02-12 11:22:23 +00:00
assasinfil
d179199a42 Need fix 2023-02-12 00:01:43 +03:00
assasinfil
f388a7ecab Bit fix 2023-02-11 20:26:18 +03:00
assasinfil
92d55ec90f Fix 2023-02-11 20:09:36 +03:00
assasinfil
f86582b99e Fix 2023-02-11 20:09:01 +03:00
assasinfil
c2545a2f7b Encoder fix 2023-02-11 19:18:42 +03:00
47 changed files with 981 additions and 381 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
1 entry status name type params
1146 Function + furi_hal_i2c_write_mem _Bool FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t
1147 Function + furi_hal_i2c_write_reg_16 _Bool FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t
1148 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*
1149 Function + furi_hal_ibutton_emulate_set_next void uint32_t
1150 Function + furi_hal_ibutton_emulate_start void uint32_t, FuriHalIbuttonEmulateCallback, void*
1151 Function + furi_hal_ibutton_emulate_stop void
1152 Function - furi_hal_ibutton_init void
1153 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
1154 Function + furi_hal_ibutton_pin_reset void
1155 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
1156 Function + furi_hal_info_get void PropertyValueCallback, char, void*
1157 Function + furi_hal_infrared_async_rx_set_capture_isr_callback void FuriHalInfraredRxCaptureCallback, void*
1158 Function + furi_hal_infrared_async_rx_set_timeout void uint32_t

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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