mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 09:58:36 -07:00
Merge remote-tracking branch 'mntm/dev' into ofw-3822-nestednonces
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include "ble_hid.h"
|
||||
#include <storage/storage.h>
|
||||
@@ -99,7 +100,7 @@ uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_c
|
||||
|
||||
bool ducky_get_number(const char* param, uint32_t* val) {
|
||||
uint32_t value = 0;
|
||||
if(sscanf(param, "%lu", &value) == 1) {
|
||||
if(strint_to_uint32(param, NULL, &value, 10) == StrintParseNoError) {
|
||||
*val = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
ID 1234:abcd Generic:USB Keyboard
|
||||
REM Declare ourselves as a generic usb keyboard
|
||||
|
||||
REM This will install qFlipper on Linux/Gnome, using the latest AppImage package
|
||||
|
||||
REM Open a terminal
|
||||
ALT F2
|
||||
DELAY 1000
|
||||
STRINGLN gnome-terminal --maximize
|
||||
DELAY 1000
|
||||
|
||||
REM Ensure we have a folder to run executables from
|
||||
STRINGLN mkdir -p $HOME/.local/bin
|
||||
|
||||
REM Download the latest AppImage
|
||||
STRINGLN curl -fsSL "https://update.flipperzero.one/qFlipper/release/linux-amd64/AppImage" -o "$HOME/.local/bin/qFlipper"
|
||||
DELAY 1000
|
||||
|
||||
REM Make it executable
|
||||
STRINGLN chmod +x $HOME/.local/bin/qFlipper
|
||||
|
||||
REM Extract the appimage in /tmp to install icon and .desktop file
|
||||
STRINGLN cd /tmp
|
||||
STRINGLN $HOME/.local/bin/qFlipper --appimage-extract > /dev/null
|
||||
STRINGLN sed "s@Exec=qFlipper@Exec=$HOME/.local/bin/qFlipper@" squashfs-root/usr/share/applications/qFlipper.desktop > $HOME/.local/share/applications/qFlipper.desktop
|
||||
STRINGLN mkdir -p $HOME/.local/share/icons/hicolor/512x512/apps
|
||||
STRINGLN cp squashfs-root/usr/share/icons/hicolor/512x512/apps/qFlipper.png $HOME/.local/share/icons/hicolor/512x512/apps/qFlipper.png
|
||||
STRINGLN rm -rf squashfs-root
|
||||
STRINGLN cd
|
||||
|
||||
REM Depending on the Linux distribution and display manager
|
||||
REM there might be several ways to update desktop entries
|
||||
REM try all
|
||||
STRINGLN xdg-desktop-menu forceupdate || true
|
||||
STRINGLN update-desktop-database ~/.local/share/applications || true
|
||||
|
||||
STRINGLN echo "
|
||||
ENTER
|
||||
REPEAT 60
|
||||
STRINGLN ==========================================================================================
|
||||
STRINGLN qFlipper has been installed to $HOME/.local/bin/
|
||||
STRINGLN It should appear in your Applications menu.
|
||||
STRINGLN If it does not, you might want to log out and log in again.
|
||||
ENTER
|
||||
STRINGLN If you prefer to run qFlipper from your terminal, either use the absolute path
|
||||
STRINGLN or make sure $HOME/.local/bin/ is included in your PATH environment variable.
|
||||
ENTER
|
||||
STRINGLN Additional configurations might be required by your Linux distribution such as
|
||||
STRINGLN group membership, udev rules or else.
|
||||
STRINGLN ==========================================================================================
|
||||
STRINGLN "
|
||||
@@ -0,0 +1,16 @@
|
||||
ID 05ac:021e Apple:Keyboard
|
||||
REM Keep these 3 lines IF (and only if) it's the first time you are performing a badKB attack against a specific macOS target.
|
||||
REM In fact, it helps Flipper Zero bypass the macOS keyboard setup assistant. Otherwise the attack will not start.
|
||||
REM Author: 47LeCoste
|
||||
REM Version 1.0 (Flipper Ducky)
|
||||
REM Target: macOS
|
||||
DELAY 3000
|
||||
F4
|
||||
DELAY 2500
|
||||
STRING Terminal
|
||||
DELAY 2500
|
||||
ENTER
|
||||
DELAY 1500
|
||||
STRING (cd /tmp && curl -L -o qFlipper.dmg https://update.flipperzero.one/qFlipper/release/macos-amd64/dmg && hdiutil attach qFlipper.dmg && app_volume=$(ls /Volumes | grep -i "qFlipper") && (test -e /Applications/qFlipper.app && rm -rf /Applications/qFlipper.app ); cp -R "/Volumes/$app_volume/qFlipper.app" /Applications/ && hdiutil detach "/Volumes/$app_volume" && rm qFlipper.dmg && open /Applications/qFlipper.app)
|
||||
DELAY 1000
|
||||
ENTER
|
||||
@@ -0,0 +1,42 @@
|
||||
REM Written by @dexv
|
||||
DELAY 2000
|
||||
GUI r
|
||||
DELAY 500
|
||||
STRING powershell
|
||||
ENTER
|
||||
DELAY 1000
|
||||
STRING $url = "https://update.flipperzero.one/qFlipper/release/windows-amd64/portable"
|
||||
ENTER
|
||||
STRING $output = "$env:USERPROFILE\Documents\qFlipper.zip"
|
||||
ENTER
|
||||
STRING $destination = "$env:USERPROFILE\Documents\qFlipper"
|
||||
ENTER
|
||||
STRING $shortcutPath = "$env:USERPROFILE\Desktop\qFlipper.lnk"
|
||||
ENTER
|
||||
STRING $scriptPath = "$env:USERPROFILE\Documents\qFlipperInstall.ps1"
|
||||
ENTER
|
||||
STRING $driverPath = "$destination\STM32 Driver"
|
||||
ENTER
|
||||
STRING $installBat = "$driverPath\install.bat"
|
||||
ENTER
|
||||
STRING (New-Object System.Net.WebClient).DownloadFile($url, $output)
|
||||
ENTER
|
||||
STRING Expand-Archive -Path $output -DestinationPath $destination -Force
|
||||
ENTER
|
||||
STRING Set-Location -Path $destination
|
||||
ENTER
|
||||
STRING Start-Process -FilePath ".\qFlipper.exe"
|
||||
ENTER
|
||||
STRING Start-Process -Wait -FilePath "cmd.exe" -ArgumentList "/c $installBat"
|
||||
ENTER
|
||||
STRING $shell = New-Object -ComObject WScript.Shell
|
||||
ENTER
|
||||
STRING $shortcut = $shell.CreateShortcut($shortcutPath)
|
||||
ENTER
|
||||
STRING $shortcut.TargetPath = "$destination\qFlipper.exe"
|
||||
ENTER
|
||||
STRING $shortcut.Save()
|
||||
ENTER
|
||||
DELAY 500
|
||||
STRING "powershell -ExecutionPolicy Bypass -File $scriptPath"
|
||||
ENTER
|
||||
@@ -0,0 +1,87 @@
|
||||
ID 1234:abcd Generic:USB Keyboard
|
||||
REM Declare ourselves as a generic usb keyboard
|
||||
REM You can override this to use something else
|
||||
REM Check the `lsusb` command to know your own devices IDs
|
||||
|
||||
REM This is BadUSB demo script for Linux/Gnome
|
||||
|
||||
REM Open terminal window
|
||||
DELAY 1000
|
||||
ALT F2
|
||||
DELAY 500
|
||||
STRING gnome-terminal --maximize
|
||||
DELAY 500
|
||||
ENTER
|
||||
DELAY 750
|
||||
|
||||
REM Clear the screen in case some banner was displayed
|
||||
STRING clear
|
||||
ENTER
|
||||
|
||||
REM Bigger shell script example
|
||||
STRING cat > /dev/null << EOF
|
||||
ENTER
|
||||
|
||||
STRING Hello World!
|
||||
ENTER
|
||||
|
||||
DEFAULT_DELAY 50
|
||||
|
||||
STRING =
|
||||
REPEAT 59
|
||||
ENTER
|
||||
ENTER
|
||||
|
||||
STRING _.-------.._ -,
|
||||
ENTER
|
||||
HOME
|
||||
STRING .-"'''"--..,,_/ /'-, -, \
|
||||
ENTER
|
||||
HOME
|
||||
STRING .:" /:/ /'\ \ ,_..., '. | |
|
||||
ENTER
|
||||
HOME
|
||||
STRING / ,----/:/ /'\ _\~'_-"' _;
|
||||
ENTER
|
||||
HOME
|
||||
STRING ' / /'"""'\ \ \.~'_-' ,-"'/
|
||||
ENTER
|
||||
HOME
|
||||
STRING | | | 0 | | .-' ,/' /
|
||||
ENTER
|
||||
HOME
|
||||
STRING | ,..\ \ ,.-"' ,/' /
|
||||
ENTER
|
||||
HOME
|
||||
STRING ; : '/'""\' ,/--==,/-----,
|
||||
ENTER
|
||||
HOME
|
||||
STRING | '-...| -.___-Z:_______J...---;
|
||||
ENTER
|
||||
HOME
|
||||
STRING : ' _-'
|
||||
ENTER
|
||||
HOME
|
||||
STRING _L_ _ ___ ___ ___ ___ ____--"'
|
||||
ENTER
|
||||
HOME
|
||||
STRING | __|| | |_ _|| _ \| _ \| __|| _ \
|
||||
ENTER
|
||||
HOME
|
||||
STRING | _| | |__ | | | _/| _/| _| | /
|
||||
ENTER
|
||||
HOME
|
||||
STRING |_| |____||___||_| |_| |___||_|_\
|
||||
ENTER
|
||||
HOME
|
||||
ENTER
|
||||
|
||||
STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format
|
||||
ENTER
|
||||
STRING More information about script syntax can be found here:
|
||||
ENTER
|
||||
STRING https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/file_formats/BadUsbScriptFormat.md
|
||||
ENTER
|
||||
|
||||
STRING EOF
|
||||
ENTER
|
||||
@@ -2,7 +2,7 @@ ID 1234:5678 Apple:Keyboard
|
||||
REM You can change these values to VID/PID of original Apple keyboard
|
||||
REM to bypass Keyboard Setup Assistant
|
||||
|
||||
REM This is BadKB demo script for macOS
|
||||
REM This is BadUSB demo script for macOS
|
||||
|
||||
REM Open terminal window
|
||||
DELAY 1000
|
||||
@@ -75,7 +75,7 @@ ENTER
|
||||
HOME
|
||||
ENTER
|
||||
|
||||
STRING Flipper Zero BadKB feature is compatible with USB Rubber Ducky script format
|
||||
STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format
|
||||
ENTER
|
||||
STRING More information about script syntax can be found here:
|
||||
ENTER
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
REM This is BadKB demo script for windows
|
||||
REM This is BadUSB demo script for windows
|
||||
|
||||
REM Open windows notepad
|
||||
DELAY 1000
|
||||
@@ -76,7 +76,7 @@ ENTER
|
||||
HOME
|
||||
ENTER
|
||||
|
||||
STRING Flipper Zero BadKB feature is compatible with USB Rubber Ducky script format
|
||||
STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format
|
||||
ENTER
|
||||
STRING More information about script syntax can be found here:
|
||||
ENTER
|
||||
|
||||
@@ -94,9 +94,9 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GpioStartEventOtgOn) {
|
||||
furi_hal_power_enable_otg();
|
||||
if(!furi_hal_power_is_otg_enabled()) furi_hal_power_enable_otg();
|
||||
} else if(event.event == GpioStartEventOtgOff) {
|
||||
furi_hal_power_disable_otg();
|
||||
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
|
||||
} else if(event.event == GpioStartEventManualControl) {
|
||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemTest);
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneTest);
|
||||
|
||||
@@ -185,7 +185,7 @@ bool ibutton_load_key(iButton* ibutton, bool show_error) {
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
path_extract_filename(ibutton->file_path, tmp, true);
|
||||
strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE);
|
||||
strlcpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE);
|
||||
|
||||
furi_string_free(tmp);
|
||||
} else if(show_error) {
|
||||
@@ -245,7 +245,7 @@ bool ibutton_delete_key(iButton* ibutton) {
|
||||
}
|
||||
|
||||
void ibutton_reset_key(iButton* ibutton) {
|
||||
memset(ibutton->key_name, 0, IBUTTON_KEY_NAME_SIZE + 1);
|
||||
ibutton->key_name[0] = '\0';
|
||||
furi_string_reset(ibutton->file_path);
|
||||
ibutton_key_reset(ibutton->key);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#define IBUTTON_APP_FILENAME_PREFIX "iBtn"
|
||||
#define IBUTTON_APP_FILENAME_EXTENSION ".ibtn"
|
||||
|
||||
#define IBUTTON_KEY_NAME_SIZE 29
|
||||
#define IBUTTON_KEY_NAME_SIZE 30
|
||||
|
||||
typedef enum {
|
||||
iButtonWriteModeInvalid,
|
||||
@@ -56,7 +56,7 @@ struct iButton {
|
||||
iButtonWriteMode write_mode;
|
||||
|
||||
FuriString* file_path;
|
||||
char key_name[IBUTTON_KEY_NAME_SIZE + 1];
|
||||
char key_name[IBUTTON_KEY_NAME_SIZE];
|
||||
|
||||
Submenu* submenu;
|
||||
ByteInput* byte_input;
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
#include "../ibutton_i.h"
|
||||
|
||||
void ibutton_scene_rpc_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
static void ibutton_rpc_start_emulation(iButton* ibutton) {
|
||||
Popup* popup = ibutton->popup;
|
||||
|
||||
popup_set_header(popup, "iButton", 82, 28, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
|
||||
|
||||
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 2, 14, &I_iButtonKey_49x44);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||
|
||||
ibutton_worker_emulate_start(ibutton->worker, ibutton->key);
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
notification_message(ibutton->notifications, &sequence_display_backlight_on);
|
||||
}
|
||||
|
||||
bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
@@ -27,17 +31,13 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
bool result = false;
|
||||
|
||||
if(ibutton_load_key(ibutton, false)) {
|
||||
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
ibutton_worker_emulate_start(ibutton->worker, ibutton->key);
|
||||
|
||||
ibutton_rpc_start_emulation(ibutton);
|
||||
result = true;
|
||||
} else {
|
||||
rpc_system_app_set_error_code(ibutton->rpc, RpcAppSystemErrorCodeParseFile);
|
||||
rpc_system_app_set_error_text(ibutton->rpc, "Cannot load key file");
|
||||
}
|
||||
|
||||
rpc_system_app_confirm(ibutton->rpc, result);
|
||||
|
||||
} else if(event.event == iButtonCustomEventRpcExit) {
|
||||
rpc_system_app_confirm(ibutton->rpc, true);
|
||||
scene_manager_stop(ibutton->scene_manager);
|
||||
|
||||
@@ -288,7 +288,7 @@ static void infrared_free(InfraredApp* infrared) {
|
||||
free(infrared);
|
||||
}
|
||||
|
||||
bool infrared_add_remote_with_button(
|
||||
InfraredErrorCode infrared_add_remote_with_button(
|
||||
const InfraredApp* infrared,
|
||||
const char* button_name,
|
||||
const InfraredSignal* signal) {
|
||||
@@ -301,21 +301,23 @@ bool infrared_add_remote_with_button(
|
||||
furi_string_cat_printf(
|
||||
new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION);
|
||||
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
do {
|
||||
if(!infrared_remote_create(remote, furi_string_get_cstr(new_path))) break;
|
||||
if(!infrared_remote_append_signal(remote, signal, button_name)) break;
|
||||
success = true;
|
||||
error = infrared_remote_create(remote, furi_string_get_cstr(new_path));
|
||||
if(INFRARED_ERROR_PRESENT(error)) break;
|
||||
|
||||
error = infrared_remote_append_signal(remote, signal, button_name);
|
||||
} while(false);
|
||||
|
||||
furi_string_free(new_name);
|
||||
furi_string_free(new_path);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_rename_current_remote(const InfraredApp* infrared, const char* new_name) {
|
||||
InfraredErrorCode
|
||||
infrared_rename_current_remote(const InfraredApp* infrared, const char* new_name) {
|
||||
InfraredRemote* remote = infrared->remote;
|
||||
const char* old_path = infrared_remote_get_path(remote);
|
||||
|
||||
@@ -335,12 +337,13 @@ bool infrared_rename_current_remote(const InfraredApp* infrared, const char* new
|
||||
path_append(new_path_fstr, furi_string_get_cstr(new_name_fstr));
|
||||
furi_string_cat(new_path_fstr, INFRARED_APP_EXTENSION);
|
||||
|
||||
const bool success = infrared_remote_rename(remote, furi_string_get_cstr(new_path_fstr));
|
||||
const InfraredErrorCode error =
|
||||
infrared_remote_rename(remote, furi_string_get_cstr(new_path_fstr));
|
||||
|
||||
furi_string_free(new_name_fstr);
|
||||
furi_string_free(new_path_fstr);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_tx_start(InfraredApp* infrared) {
|
||||
@@ -373,17 +376,16 @@ void infrared_tx_start(InfraredApp* infrared) {
|
||||
infrared->app_state.is_transmitting = true;
|
||||
}
|
||||
|
||||
void infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index) {
|
||||
InfraredErrorCode infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index) {
|
||||
furi_assert(button_index < infrared_remote_get_signal_count(infrared->remote));
|
||||
|
||||
if(infrared_remote_load_signal(infrared->remote, infrared->current_signal, button_index)) {
|
||||
InfraredErrorCode error =
|
||||
infrared_remote_load_signal(infrared->remote, infrared->current_signal, button_index);
|
||||
|
||||
if(!INFRARED_ERROR_PRESENT(error)) {
|
||||
infrared_tx_start(infrared);
|
||||
} else {
|
||||
infrared_show_error_message(
|
||||
infrared,
|
||||
"Failed to load\n\"%s\"",
|
||||
infrared_remote_get_signal_name(infrared->remote, button_index));
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_tx_stop(InfraredApp* infrared) {
|
||||
@@ -406,7 +408,7 @@ void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback call
|
||||
furi_thread_start(infrared->task_thread);
|
||||
}
|
||||
|
||||
bool infrared_blocking_task_finalize(InfraredApp* infrared) {
|
||||
InfraredErrorCode infrared_blocking_task_finalize(InfraredApp* infrared) {
|
||||
furi_thread_join(infrared->task_thread);
|
||||
return furi_thread_get_return_code(infrared->task_thread);
|
||||
}
|
||||
@@ -458,9 +460,9 @@ void infrared_set_tx_pin(InfraredApp* infrared, FuriHalInfraredTxPin tx_pin) {
|
||||
|
||||
void infrared_enable_otg(InfraredApp* infrared, bool enable) {
|
||||
if(enable) {
|
||||
furi_hal_power_enable_otg();
|
||||
if(!furi_hal_power_is_otg_enabled()) furi_hal_power_enable_otg();
|
||||
} else {
|
||||
furi_hal_power_disable_otg();
|
||||
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
|
||||
}
|
||||
infrared->app_state.is_otg_enabled = enable;
|
||||
}
|
||||
@@ -556,10 +558,18 @@ int32_t infrared_app(void* p) {
|
||||
is_rpc_mode = true;
|
||||
} else {
|
||||
const char* file_path = (const char*)p;
|
||||
is_remote_loaded = infrared_remote_load(infrared->remote, file_path);
|
||||
InfraredErrorCode error = infrared_remote_load(infrared->remote, file_path);
|
||||
|
||||
if(!is_remote_loaded) {
|
||||
infrared_show_error_message(infrared, "Failed to load\n\"%s\"", file_path);
|
||||
if(!INFRARED_ERROR_PRESENT(error)) {
|
||||
is_remote_loaded = true;
|
||||
} else {
|
||||
is_remote_loaded = false;
|
||||
bool wrong_file_type = INFRARED_ERROR_CHECK(error, InfraredErrorCodeWrongFileType);
|
||||
const char* format = wrong_file_type ?
|
||||
"Library file\n\"%s\" can't be openned as a remote" :
|
||||
"Failed to load\n\"%s\"";
|
||||
|
||||
infrared_show_error_message(infrared, format, file_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
#define INFRARED_TEXT_STORE_NUM 2
|
||||
#define INFRARED_TEXT_STORE_SIZE 128
|
||||
|
||||
#define INFRARED_MAX_BUTTON_NAME_LENGTH 22
|
||||
#define INFRARED_MAX_REMOTE_NAME_LENGTH 22
|
||||
#define INFRARED_MAX_BUTTON_NAME_LENGTH 23
|
||||
#define INFRARED_MAX_REMOTE_NAME_LENGTH 23
|
||||
|
||||
#define INFRARED_APP_FOLDER EXT_PATH("infrared")
|
||||
#define INFRARED_APP_EXTENSION ".ir"
|
||||
@@ -174,9 +174,9 @@ typedef enum {
|
||||
* @param[in] infrared pointer to the application instance.
|
||||
* @param[in] name pointer to a zero-terminated string containing the signal name.
|
||||
* @param[in] signal pointer to the signal to be added.
|
||||
* @return true if the remote was successfully created, false otherwise.
|
||||
* @return InfraredErrorCodeNone if the remote was successfully created, otherwise error code.
|
||||
*/
|
||||
bool infrared_add_remote_with_button(
|
||||
InfraredErrorCode infrared_add_remote_with_button(
|
||||
const InfraredApp* infrared,
|
||||
const char* name,
|
||||
const InfraredSignal* signal);
|
||||
@@ -186,9 +186,10 @@ bool infrared_add_remote_with_button(
|
||||
*
|
||||
* @param[in] infrared pointer to the application instance.
|
||||
* @param[in] new_name pointer to a zero-terminated string containing the new remote name.
|
||||
* @return true if the remote was successfully renamed, false otherwise.
|
||||
* @return InfraredErrorCodeNone if the remote was successfully renamed, otherwise error code.
|
||||
*/
|
||||
bool infrared_rename_current_remote(const InfraredApp* infrared, const char* new_name);
|
||||
InfraredErrorCode
|
||||
infrared_rename_current_remote(const InfraredApp* infrared, const char* new_name);
|
||||
|
||||
/**
|
||||
* @brief Begin transmission of the currently loaded signal.
|
||||
@@ -206,9 +207,9 @@ void infrared_tx_start(InfraredApp* infrared);
|
||||
*
|
||||
* @param[in,out] infrared pointer to the application instance.
|
||||
* @param[in] button_index index of the signal to be loaded.
|
||||
* @returns true if the signal could be loaded, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the signal could be loaded, otherwise error code.
|
||||
*/
|
||||
void infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index);
|
||||
InfraredErrorCode infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index);
|
||||
|
||||
/**
|
||||
* @brief Stop transmission of the currently loaded signal.
|
||||
@@ -236,9 +237,9 @@ void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback call
|
||||
* (e.g. to display the results), the caller code MUST set it explicitly.
|
||||
*
|
||||
* @param[in,out] infrared pointer to the application instance.
|
||||
* @return true if the blocking task finished successfully, false otherwise.
|
||||
* @return InfraredErrorCodeNone if the blocking task finished successfully, otherwise error code.
|
||||
*/
|
||||
bool infrared_blocking_task_finalize(InfraredApp* infrared);
|
||||
InfraredErrorCode infrared_blocking_task_finalize(InfraredApp* infrared);
|
||||
|
||||
/**
|
||||
* @brief Set the internal text store with formatted text.
|
||||
|
||||
@@ -50,10 +50,10 @@ void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const
|
||||
brute_force->db_filename = db_filename;
|
||||
}
|
||||
|
||||
bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
InfraredErrorCode infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
furi_assert(brute_force->db_filename);
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
|
||||
@@ -61,12 +61,15 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
|
||||
do {
|
||||
if(!flipper_format_buffered_file_open_existing(ff, brute_force->db_filename)) break;
|
||||
if(!flipper_format_buffered_file_open_existing(ff, brute_force->db_filename)) {
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
bool signals_valid = false;
|
||||
while(infrared_signal_read_name(ff, signal_name)) {
|
||||
signals_valid = infrared_signal_read_body(signal, ff) &&
|
||||
infrared_signal_is_valid(signal);
|
||||
while(infrared_signal_read_name(ff, signal_name) == InfraredErrorCodeNone) {
|
||||
error = infrared_signal_read_body(signal, ff);
|
||||
signals_valid = (!INFRARED_ERROR_PRESENT(error)) && infrared_signal_is_valid(signal);
|
||||
if(!signals_valid) break;
|
||||
|
||||
InfraredBruteForceRecord* record =
|
||||
@@ -75,9 +78,7 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
++(record->count);
|
||||
}
|
||||
}
|
||||
|
||||
if(!signals_valid) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
infrared_signal_free(signal);
|
||||
@@ -85,7 +86,7 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_brute_force_start(
|
||||
@@ -139,10 +140,12 @@ void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
|
||||
|
||||
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) {
|
||||
furi_assert(brute_force->is_started);
|
||||
|
||||
const bool success = infrared_signal_search_by_name_and_read(
|
||||
brute_force->current_signal,
|
||||
brute_force->ff,
|
||||
furi_string_get_cstr(brute_force->current_record_name));
|
||||
brute_force->current_signal,
|
||||
brute_force->ff,
|
||||
furi_string_get_cstr(brute_force->current_record_name)) ==
|
||||
InfraredErrorCodeNone;
|
||||
if(success) {
|
||||
infrared_signal_transmit(brute_force->current_signal);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "infrared_error_code.h"
|
||||
|
||||
/**
|
||||
* @brief InfraredBruteForce opaque type declaration.
|
||||
@@ -45,9 +46,9 @@ void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const
|
||||
* a infrared_brute_force_set_db_filename() call.
|
||||
*
|
||||
* @param[in,out] brute_force pointer to the instance to be updated.
|
||||
* @returns true on success, false otherwise.
|
||||
* @returns InfraredErrorCodeNone on success, otherwise error code.
|
||||
*/
|
||||
bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force);
|
||||
InfraredErrorCode infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force);
|
||||
|
||||
/**
|
||||
* @brief Start transmitting signals from a category stored in an InfraredBruteForce's instance dictionary.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <furi_hal_infrared.h>
|
||||
#include <flipper_format.h>
|
||||
#include <toolbox/args.h>
|
||||
#include <toolbox/strint.h>
|
||||
#include <m-dict.h>
|
||||
|
||||
#include "infrared_signal.h"
|
||||
@@ -176,25 +177,28 @@ static bool infrared_cli_parse_raw(const char* str, InfraredSignal* signal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT);
|
||||
uint32_t frequency = atoi(frequency_str);
|
||||
float duty_cycle = (float)atoi(duty_cycle_str) / 100;
|
||||
uint32_t frequency;
|
||||
uint32_t duty_cycle_u32;
|
||||
if(strint_to_uint32(frequency_str, NULL, &frequency, 10) != StrintParseNoError ||
|
||||
strint_to_uint32(duty_cycle_str, NULL, &duty_cycle_u32, 10) != StrintParseNoError)
|
||||
return false;
|
||||
float duty_cycle = duty_cycle_u32 / 100.0f;
|
||||
|
||||
str += strlen(frequency_str) + strlen(duty_cycle_str) + INFRARED_CLI_BUF_SIZE;
|
||||
|
||||
uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT);
|
||||
size_t timings_size = 0;
|
||||
while(1) {
|
||||
while(*str == ' ') {
|
||||
++str;
|
||||
}
|
||||
|
||||
char timing_str[INFRARED_CLI_BUF_SIZE];
|
||||
if(sscanf(str, "%9s", timing_str) != 1) {
|
||||
uint32_t timing;
|
||||
char* next_token;
|
||||
if(strint_to_uint32(str, &next_token, &timing, 10) != StrintParseNoError) {
|
||||
break;
|
||||
}
|
||||
|
||||
str += strlen(timing_str);
|
||||
uint32_t timing = atoi(timing_str);
|
||||
str = next_token;
|
||||
|
||||
if((timing <= 0) || (timings_size >= MAX_TIMINGS_AMOUNT)) {
|
||||
break;
|
||||
@@ -228,9 +232,15 @@ static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args) {
|
||||
|
||||
static bool
|
||||
infrared_cli_save_signal(InfraredSignal* signal, FlipperFormat* file, const char* name) {
|
||||
bool ret = infrared_signal_save(signal, file, name);
|
||||
if(!ret) {
|
||||
printf("Failed to save signal: \"%s\"\r\n", name);
|
||||
bool ret = true;
|
||||
InfraredErrorCode error = infrared_signal_save(signal, file, name);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
printf(
|
||||
"Failed to save signal: \"%s\" code: 0x%X index: 0x%02X\r\n",
|
||||
name,
|
||||
INFRARED_ERROR_GET_CODE(error),
|
||||
INFRARED_ERROR_GET_INDEX(error));
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -292,7 +302,7 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o
|
||||
FuriString* tmp;
|
||||
tmp = furi_string_alloc();
|
||||
|
||||
while(infrared_signal_read(signal, input_file, tmp)) {
|
||||
while(infrared_signal_read(signal, input_file, tmp) == InfraredErrorCodeNone) {
|
||||
ret = false;
|
||||
if(!infrared_signal_is_valid(signal)) {
|
||||
printf("Invalid signal\r\n");
|
||||
@@ -460,7 +470,7 @@ static void
|
||||
printf("Missing signal name.\r\n");
|
||||
break;
|
||||
}
|
||||
if(!infrared_brute_force_calculate_messages(brute_force)) {
|
||||
if(infrared_brute_force_calculate_messages(brute_force) != InfraredErrorCodeNone) {
|
||||
printf("Invalid remote name.\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
45
applications/main/infrared/infrared_error_code.h
Normal file
45
applications/main/infrared/infrared_error_code.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
InfraredErrorCodeNone = 0,
|
||||
InfraredErrorCodeFileOperationFailed = 0x800000,
|
||||
InfraredErrorCodeWrongFileType = 0x80000100,
|
||||
InfraredErrorCodeWrongFileVersion = 0x80000200,
|
||||
|
||||
//Common signal errors
|
||||
InfraredErrorCodeSignalTypeUnknown = 0x80000300,
|
||||
InfraredErrorCodeSignalNameNotFound = 0x80000400,
|
||||
InfraredErrorCodeSignalUnableToReadType = 0x80000500,
|
||||
InfraredErrorCodeSignalUnableToWriteType = 0x80000600,
|
||||
|
||||
//Raw signal errors
|
||||
InfraredErrorCodeSignalRawUnableToReadFrequency = 0x80000700,
|
||||
InfraredErrorCodeSignalRawUnableToReadDutyCycle = 0x80000800,
|
||||
InfraredErrorCodeSignalRawUnableToReadTimingsSize = 0x80000900,
|
||||
InfraredErrorCodeSignalRawUnableToReadTooLongData = 0x80000A00,
|
||||
InfraredErrorCodeSignalRawUnableToReadData = 0x80000B00,
|
||||
|
||||
InfraredErrorCodeSignalRawUnableToWriteFrequency = 0x80000C00,
|
||||
InfraredErrorCodeSignalRawUnableToWriteDutyCycle = 0x80000D00,
|
||||
InfraredErrorCodeSignalRawUnableToWriteData = 0x80000E00,
|
||||
|
||||
//Message signal errors
|
||||
InfraredErrorCodeSignalMessageUnableToReadProtocol = 0x80000F00,
|
||||
InfraredErrorCodeSignalMessageUnableToReadAddress = 0x80001000,
|
||||
InfraredErrorCodeSignalMessageUnableToReadCommand = 0x80001100,
|
||||
InfraredErrorCodeSignalMessageIsInvalid = 0x80001200,
|
||||
|
||||
InfraredErrorCodeSignalMessageUnableToWriteProtocol = 0x80001300,
|
||||
InfraredErrorCodeSignalMessageUnableToWriteAddress = 0x80001400,
|
||||
InfraredErrorCodeSignalMessageUnableToWriteCommand = 0x80001500,
|
||||
} InfraredErrorCode;
|
||||
|
||||
#define INFRARED_ERROR_CODE_MASK (0xFFFFFF00)
|
||||
#define INFRARED_ERROR_INDEX_MASK (0x000000FF)
|
||||
|
||||
#define INFRARED_ERROR_GET_CODE(error) ((error) & INFRARED_ERROR_CODE_MASK)
|
||||
#define INFRARED_ERROR_GET_INDEX(error) ((error) & INFRARED_ERROR_INDEX_MASK)
|
||||
#define INFRARED_ERROR_SET_INDEX(code, index) ((code) |= ((index) & INFRARED_ERROR_INDEX_MASK))
|
||||
|
||||
#define INFRARED_ERROR_PRESENT(error) (INFRARED_ERROR_GET_CODE(error) != InfraredErrorCodeNone)
|
||||
#define INFRARED_ERROR_CHECK(error, test_code) (INFRARED_ERROR_GET_CODE(error) == (test_code))
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
#define TAG "InfraredRemote"
|
||||
|
||||
#define INFRARED_FILE_HEADER "IR signals file"
|
||||
#define INFRARED_FILE_VERSION (1)
|
||||
#define INFRARED_FILE_HEADER "IR signals file"
|
||||
#define INFRARED_LIBRARY_HEADER "IR library file"
|
||||
#define INFRARED_FILE_VERSION (1)
|
||||
|
||||
ARRAY_DEF(StringArray, const char*, M_CSTR_DUP_OPLIST); //-V575
|
||||
|
||||
@@ -34,7 +35,7 @@ typedef struct {
|
||||
const InfraredSignal* signal;
|
||||
} InfraredBatchTarget;
|
||||
|
||||
typedef bool (
|
||||
typedef InfraredErrorCode (
|
||||
*InfraredBatchCallback)(const InfraredBatch* batch, const InfraredBatchTarget* target);
|
||||
|
||||
InfraredRemote* infrared_remote_alloc(void) {
|
||||
@@ -80,7 +81,7 @@ const char* infrared_remote_get_signal_name(const InfraredRemote* remote, size_t
|
||||
return *StringArray_cget(remote->signal_names, index);
|
||||
}
|
||||
|
||||
bool infrared_remote_load_signal(
|
||||
InfraredErrorCode infrared_remote_load_signal(
|
||||
const InfraredRemote* remote,
|
||||
InfraredSignal* signal,
|
||||
size_t index) {
|
||||
@@ -89,25 +90,27 @@ bool infrared_remote_load_signal(
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
|
||||
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
do {
|
||||
const char* path = furi_string_get_cstr(remote->path);
|
||||
if(!flipper_format_buffered_file_open_existing(ff, path)) break;
|
||||
if(!flipper_format_buffered_file_open_existing(ff, path)) {
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!infrared_signal_search_by_index_and_read(signal, ff, index)) {
|
||||
error = infrared_signal_search_by_index_and_read(signal, ff, index);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
const char* signal_name = infrared_remote_get_signal_name(remote, index);
|
||||
FURI_LOG_E(TAG, "Failed to load signal '%s' from file '%s'", signal_name, path);
|
||||
break;
|
||||
}
|
||||
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_remote_get_signal_index(
|
||||
@@ -128,31 +131,35 @@ bool infrared_remote_get_signal_index(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool infrared_remote_append_signal(
|
||||
InfraredErrorCode infrared_remote_append_signal(
|
||||
InfraredRemote* remote,
|
||||
const InfraredSignal* signal,
|
||||
const char* name) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_file_alloc(storage);
|
||||
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
const char* path = furi_string_get_cstr(remote->path);
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_append(ff, path)) break;
|
||||
if(!infrared_signal_save(signal, ff, name)) break;
|
||||
if(!flipper_format_file_open_append(ff, path)) {
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
error = infrared_signal_save(signal, ff, name);
|
||||
if(INFRARED_ERROR_PRESENT(error)) break;
|
||||
|
||||
StringArray_push_back(remote->signal_names, name);
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
static bool infrared_remote_batch_start(
|
||||
static InfraredErrorCode infrared_remote_batch_start(
|
||||
InfraredRemote* remote,
|
||||
InfraredBatchCallback batch_callback,
|
||||
const InfraredBatchTarget* target) {
|
||||
@@ -179,33 +186,59 @@ static bool infrared_remote_batch_start(
|
||||
status = storage_common_stat(storage, path_out, NULL);
|
||||
} while(status == FSE_OK || status == FSE_EXIST);
|
||||
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
StringArray_t buf_names;
|
||||
StringArray_init_set(buf_names, remote->signal_names);
|
||||
do {
|
||||
if(!flipper_format_buffered_file_open_existing(batch_context.ff_in, path_in)) break;
|
||||
if(!flipper_format_buffered_file_open_always(batch_context.ff_out, path_out)) break;
|
||||
if(!flipper_format_write_header_cstr(
|
||||
batch_context.ff_out, INFRARED_FILE_HEADER, INFRARED_FILE_VERSION))
|
||||
if(!flipper_format_buffered_file_open_existing(batch_context.ff_in, path_in) ||
|
||||
!flipper_format_buffered_file_open_always(batch_context.ff_out, path_out) ||
|
||||
!flipper_format_write_header_cstr(
|
||||
batch_context.ff_out, INFRARED_FILE_HEADER, INFRARED_FILE_VERSION)) {
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
break;
|
||||
|
||||
}
|
||||
const size_t signal_count = infrared_remote_get_signal_count(remote);
|
||||
|
||||
for(; batch_context.signal_index < signal_count; ++batch_context.signal_index) {
|
||||
if(!infrared_signal_read(
|
||||
batch_context.signal, batch_context.ff_in, batch_context.signal_name))
|
||||
error = infrared_signal_read(
|
||||
batch_context.signal, batch_context.ff_in, batch_context.signal_name);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
INFRARED_ERROR_SET_INDEX(error, batch_context.signal_index);
|
||||
break;
|
||||
if(!batch_callback(&batch_context, target)) break;
|
||||
}
|
||||
|
||||
error = batch_callback(&batch_context, target);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
INFRARED_ERROR_SET_INDEX(error, batch_context.signal_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(INFRARED_ERROR_PRESENT(error)) break;
|
||||
|
||||
if(!flipper_format_buffered_file_close(batch_context.ff_out) ||
|
||||
!flipper_format_buffered_file_close(batch_context.ff_in)) {
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if(batch_context.signal_index != signal_count) break;
|
||||
|
||||
if(!flipper_format_buffered_file_close(batch_context.ff_out)) break;
|
||||
if(!flipper_format_buffered_file_close(batch_context.ff_in)) break;
|
||||
|
||||
const FS_Error status = storage_common_rename(storage, path_out, path_in);
|
||||
success = (status == FSE_OK || status == FSE_EXIST);
|
||||
error = (status == FSE_OK || status == FSE_EXIST) ? InfraredErrorCodeNone :
|
||||
InfraredErrorCodeFileOperationFailed;
|
||||
} while(false);
|
||||
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
//Remove all temp data and rollback signal names
|
||||
flipper_format_buffered_file_close(batch_context.ff_out);
|
||||
flipper_format_buffered_file_close(batch_context.ff_in);
|
||||
status = storage_common_stat(storage, path_out, NULL);
|
||||
if(status == FSE_OK || status == FSE_EXIST) storage_common_remove(storage, path_out);
|
||||
|
||||
StringArray_reset(remote->signal_names);
|
||||
StringArray_set(remote->signal_names, buf_names);
|
||||
}
|
||||
|
||||
StringArray_clear(buf_names);
|
||||
infrared_signal_free(batch_context.signal);
|
||||
furi_string_free(batch_context.signal_name);
|
||||
flipper_format_free(batch_context.ff_out);
|
||||
@@ -214,15 +247,18 @@ static bool infrared_remote_batch_start(
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
static bool infrared_remote_insert_signal_callback(
|
||||
static InfraredErrorCode infrared_remote_insert_signal_callback(
|
||||
const InfraredBatch* batch,
|
||||
const InfraredBatchTarget* target) {
|
||||
// Insert a signal under the specified index
|
||||
if(batch->signal_index == target->signal_index) {
|
||||
if(!infrared_signal_save(target->signal, batch->ff_out, target->signal_name)) return false;
|
||||
InfraredErrorCode error =
|
||||
infrared_signal_save(target->signal, batch->ff_out, target->signal_name);
|
||||
if(INFRARED_ERROR_PRESENT(error)) return error;
|
||||
|
||||
StringArray_push_at(
|
||||
batch->remote->signal_names, target->signal_index, target->signal_name);
|
||||
}
|
||||
@@ -232,7 +268,7 @@ static bool infrared_remote_insert_signal_callback(
|
||||
batch->signal, batch->ff_out, furi_string_get_cstr(batch->signal_name));
|
||||
}
|
||||
|
||||
bool infrared_remote_insert_signal(
|
||||
InfraredErrorCode infrared_remote_insert_signal(
|
||||
InfraredRemote* remote,
|
||||
const InfraredSignal* signal,
|
||||
const char* name,
|
||||
@@ -251,7 +287,7 @@ bool infrared_remote_insert_signal(
|
||||
remote, infrared_remote_insert_signal_callback, &insert_target);
|
||||
}
|
||||
|
||||
static bool infrared_remote_rename_signal_callback(
|
||||
static InfraredErrorCode infrared_remote_rename_signal_callback(
|
||||
const InfraredBatch* batch,
|
||||
const InfraredBatchTarget* target) {
|
||||
const char* signal_name;
|
||||
@@ -268,7 +304,8 @@ static bool infrared_remote_rename_signal_callback(
|
||||
return infrared_signal_save(batch->signal, batch->ff_out, signal_name);
|
||||
}
|
||||
|
||||
bool infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const char* new_name) {
|
||||
InfraredErrorCode
|
||||
infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const char* new_name) {
|
||||
furi_assert(index < infrared_remote_get_signal_count(remote));
|
||||
|
||||
const InfraredBatchTarget rename_target = {
|
||||
@@ -281,7 +318,7 @@ bool infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const c
|
||||
remote, infrared_remote_rename_signal_callback, &rename_target);
|
||||
}
|
||||
|
||||
static bool infrared_remote_delete_signal_callback(
|
||||
static InfraredErrorCode infrared_remote_delete_signal_callback(
|
||||
const InfraredBatch* batch,
|
||||
const InfraredBatchTarget* target) {
|
||||
if(batch->signal_index == target->signal_index) {
|
||||
@@ -294,10 +331,10 @@ static bool infrared_remote_delete_signal_callback(
|
||||
batch->signal, batch->ff_out, furi_string_get_cstr(batch->signal_name));
|
||||
}
|
||||
|
||||
return true;
|
||||
return InfraredErrorCodeNone;
|
||||
}
|
||||
|
||||
bool infrared_remote_delete_signal(InfraredRemote* remote, size_t index) {
|
||||
InfraredErrorCode infrared_remote_delete_signal(InfraredRemote* remote, size_t index) {
|
||||
furi_assert(index < infrared_remote_get_signal_count(remote));
|
||||
|
||||
const InfraredBatchTarget delete_target = {
|
||||
@@ -310,33 +347,35 @@ bool infrared_remote_delete_signal(InfraredRemote* remote, size_t index) {
|
||||
remote, infrared_remote_delete_signal_callback, &delete_target);
|
||||
}
|
||||
|
||||
bool infrared_remote_move_signal(InfraredRemote* remote, size_t index, size_t new_index) {
|
||||
InfraredErrorCode
|
||||
infrared_remote_move_signal(InfraredRemote* remote, size_t index, size_t new_index) {
|
||||
const size_t signal_count = infrared_remote_get_signal_count(remote);
|
||||
furi_assert(index < signal_count);
|
||||
furi_assert(new_index < signal_count);
|
||||
|
||||
if(index == new_index) return true;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
if(index == new_index) return error;
|
||||
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
char* signal_name = strdup(infrared_remote_get_signal_name(remote, index));
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!infrared_remote_load_signal(remote, signal, index)) break;
|
||||
if(!infrared_remote_delete_signal(remote, index)) break;
|
||||
if(!infrared_remote_insert_signal(remote, signal, signal_name, new_index)) break;
|
||||
error = infrared_remote_load_signal(remote, signal, index);
|
||||
if(INFRARED_ERROR_PRESENT(error)) break;
|
||||
|
||||
success = true;
|
||||
error = infrared_remote_delete_signal(remote, index);
|
||||
if(INFRARED_ERROR_PRESENT(error)) break;
|
||||
|
||||
error = infrared_remote_insert_signal(remote, signal, signal_name, new_index);
|
||||
} while(false);
|
||||
|
||||
free(signal_name);
|
||||
infrared_signal_free(signal);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_remote_create(InfraredRemote* remote, const char* path) {
|
||||
InfraredErrorCode infrared_remote_create(InfraredRemote* remote, const char* path) {
|
||||
FURI_LOG_I(TAG, "Creating new file: '%s'", path);
|
||||
|
||||
infrared_remote_reset(remote);
|
||||
@@ -358,45 +397,64 @@ bool infrared_remote_create(InfraredRemote* remote, const char* path) {
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return success;
|
||||
return success ? InfraredErrorCodeNone : InfraredErrorCodeFileOperationFailed;
|
||||
}
|
||||
|
||||
bool infrared_remote_load(InfraredRemote* remote, const char* path) {
|
||||
InfraredErrorCode infrared_remote_load(InfraredRemote* remote, const char* path) {
|
||||
FURI_LOG_I(TAG, "Loading file: '%s'", path);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
|
||||
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
do {
|
||||
if(!flipper_format_buffered_file_open_existing(ff, path)) break;
|
||||
if(!flipper_format_buffered_file_open_existing(ff, path)) {
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t version;
|
||||
if(!flipper_format_read_header(ff, tmp, &version)) break;
|
||||
|
||||
if(!furi_string_equal(tmp, INFRARED_FILE_HEADER) || (version != INFRARED_FILE_VERSION))
|
||||
if(!flipper_format_read_header(ff, tmp, &version)) {
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if(furi_string_equal(tmp, INFRARED_LIBRARY_HEADER)) {
|
||||
FURI_LOG_E(TAG, "Library file can't be loaded in this context");
|
||||
error = InfraredErrorCodeWrongFileType;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!furi_string_equal(tmp, INFRARED_FILE_HEADER)) {
|
||||
error = InfraredErrorCodeWrongFileType;
|
||||
FURI_LOG_E(TAG, "Filetype unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
if(version != INFRARED_FILE_VERSION) {
|
||||
error = InfraredErrorCodeWrongFileVersion;
|
||||
FURI_LOG_E(TAG, "Wrong file version");
|
||||
break;
|
||||
}
|
||||
|
||||
infrared_remote_set_path(remote, path);
|
||||
StringArray_reset(remote->signal_names);
|
||||
|
||||
while(infrared_signal_read_name(ff, tmp)) {
|
||||
while(infrared_signal_read_name(ff, tmp) == InfraredErrorCodeNone) {
|
||||
StringArray_push_back(remote->signal_names, furi_string_get_cstr(tmp));
|
||||
}
|
||||
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
furi_string_free(tmp);
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_remote_rename(InfraredRemote* remote, const char* new_path) {
|
||||
InfraredErrorCode infrared_remote_rename(InfraredRemote* remote, const char* new_path) {
|
||||
const char* old_path = infrared_remote_get_path(remote);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
@@ -409,10 +467,10 @@ bool infrared_remote_rename(InfraredRemote* remote, const char* new_path) {
|
||||
infrared_remote_set_path(remote, new_path);
|
||||
}
|
||||
|
||||
return success;
|
||||
return success ? InfraredErrorCodeNone : InfraredErrorCodeFileOperationFailed;
|
||||
}
|
||||
|
||||
bool infrared_remote_remove(InfraredRemote* remote) {
|
||||
InfraredErrorCode infrared_remote_remove(InfraredRemote* remote) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
const FS_Error status = storage_common_remove(storage, infrared_remote_get_path(remote));
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
@@ -423,5 +481,5 @@ bool infrared_remote_remove(InfraredRemote* remote) {
|
||||
infrared_remote_reset(remote);
|
||||
}
|
||||
|
||||
return success;
|
||||
return success ? InfraredErrorCodeNone : InfraredErrorCodeFileOperationFailed;
|
||||
}
|
||||
|
||||
@@ -105,12 +105,10 @@ bool infrared_remote_get_signal_index(
|
||||
* @param[in] remote pointer to the instance to load from.
|
||||
* @param[out] signal pointer to the signal to load into. Must be allocated.
|
||||
* @param[in] index index of the signal to be loaded. Must be less than the total signal count.
|
||||
* @return true if the signal was successfully loaded, false otherwise.
|
||||
* @return InfraredErrorCodeNone if the signal was successfully loaded, otherwise error code.
|
||||
*/
|
||||
bool infrared_remote_load_signal(
|
||||
const InfraredRemote* remote,
|
||||
InfraredSignal* signal,
|
||||
size_t index);
|
||||
InfraredErrorCode
|
||||
infrared_remote_load_signal(const InfraredRemote* remote, InfraredSignal* signal, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Append a signal to the file associated with an InfraredRemote instance.
|
||||
@@ -121,9 +119,9 @@ bool infrared_remote_load_signal(
|
||||
* @param[in,out] remote pointer to the instance to append to.
|
||||
* @param[in] signal pointer to the signal to be appended.
|
||||
* @param[in] name pointer to a zero-terminated string containing the name of the signal.
|
||||
* @returns true if the signal was successfully appended, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the signal was successfully appended, otherwise error code.
|
||||
*/
|
||||
bool infrared_remote_append_signal(
|
||||
InfraredErrorCode infrared_remote_append_signal(
|
||||
InfraredRemote* remote,
|
||||
const InfraredSignal* signal,
|
||||
const char* name);
|
||||
@@ -141,9 +139,10 @@ bool infrared_remote_append_signal(
|
||||
* @param[in] signal pointer to the signal to be inserted.
|
||||
* @param[in] name pointer to a zero-terminated string containing the name of the signal.
|
||||
* @param[in] index the index under which the signal shall be inserted.
|
||||
* @returns true if the signal was successfully inserted, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the signal was successfully inserted, otherwise error
|
||||
* code describing what error happened ORed with index pointing which signal caused an error.
|
||||
*/
|
||||
bool infrared_remote_insert_signal(
|
||||
InfraredErrorCode infrared_remote_insert_signal(
|
||||
InfraredRemote* remote,
|
||||
const InfraredSignal* signal,
|
||||
const char* name,
|
||||
@@ -157,9 +156,10 @@ bool infrared_remote_insert_signal(
|
||||
* @param[in,out] remote pointer to the instance to be modified.
|
||||
* @param[in] index index of the signal to be renamed. Must be less than the total signal count.
|
||||
* @param[in] new_name pointer to a zero-terminated string containig the signal's new name.
|
||||
* @returns true if the signal was successfully renamed, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the signal was successfully renamed, otherwise error code.
|
||||
*/
|
||||
bool infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const char* new_name);
|
||||
InfraredErrorCode
|
||||
infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const char* new_name);
|
||||
|
||||
/**
|
||||
* @brief Change a signal's position in the file associated with an InfraredRemote instance.
|
||||
@@ -169,17 +169,21 @@ bool infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const c
|
||||
* @param[in,out] remote pointer to the instance to be modified.
|
||||
* @param[in] index index of the signal to be moved. Must be less than the total signal count.
|
||||
* @param[in] new_index index of the signal to be moved. Must be less than the total signal count.
|
||||
* @returns InfraredErrorCodeNone if the signal was moved successfully, otherwise error
|
||||
* code describing what error happened ORed with index pointing which signal caused an error.
|
||||
*/
|
||||
bool infrared_remote_move_signal(InfraredRemote* remote, size_t index, size_t new_index);
|
||||
InfraredErrorCode
|
||||
infrared_remote_move_signal(InfraredRemote* remote, size_t index, size_t new_index);
|
||||
|
||||
/**
|
||||
* @brief Delete a signal in the file associated with an InfraredRemote instance.
|
||||
*
|
||||
* @param[in,out] remote pointer to the instance to be modified.
|
||||
* @param[in] index index of the signal to be deleted. Must be less than the total signal count.
|
||||
* @returns true if the signal was successfully deleted, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the signal was successfully deleted, otherwise error
|
||||
* code describing what error happened ORed with index pointing which signal caused an error.
|
||||
*/
|
||||
bool infrared_remote_delete_signal(InfraredRemote* remote, size_t index);
|
||||
InfraredErrorCode infrared_remote_delete_signal(InfraredRemote* remote, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Create a new file and associate it with an InfraredRemote instance.
|
||||
@@ -188,9 +192,9 @@ bool infrared_remote_delete_signal(InfraredRemote* remote, size_t index);
|
||||
*
|
||||
* @param[in,out] remote pointer to the instance to be assigned with a new file.
|
||||
* @param[in] path pointer to a zero-terminated string containing the full file path.
|
||||
* @returns true if the file was successfully created, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the file was successfully created, otherwise error code.
|
||||
*/
|
||||
bool infrared_remote_create(InfraredRemote* remote, const char* path);
|
||||
InfraredErrorCode infrared_remote_create(InfraredRemote* remote, const char* path);
|
||||
|
||||
/**
|
||||
* @brief Associate an InfraredRemote instance with a file and load the signal names from it.
|
||||
@@ -200,9 +204,9 @@ bool infrared_remote_create(InfraredRemote* remote, const char* path);
|
||||
*
|
||||
* @param[in,out] remote pointer to the instance to be assigned with an existing file.
|
||||
* @param[in] path pointer to a zero-terminated string containing the full file path.
|
||||
* @returns true if the file was successfully loaded, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the file was successfully loaded, otherwise error code.
|
||||
*/
|
||||
bool infrared_remote_load(InfraredRemote* remote, const char* path);
|
||||
InfraredErrorCode infrared_remote_load(InfraredRemote* remote, const char* path);
|
||||
|
||||
/**
|
||||
* @brief Rename the file associated with an InfraredRemote instance.
|
||||
@@ -211,9 +215,9 @@ bool infrared_remote_load(InfraredRemote* remote, const char* path);
|
||||
*
|
||||
* @param[in,out] remote pointer to the instance to be modified.
|
||||
* @param[in] new_path pointer to a zero-terminated string containing the new full file path.
|
||||
* @returns true if the file was successfully renamed, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the file was successfully renamed, otherwise error code.
|
||||
*/
|
||||
bool infrared_remote_rename(InfraredRemote* remote, const char* new_path);
|
||||
InfraredErrorCode infrared_remote_rename(InfraredRemote* remote, const char* new_path);
|
||||
|
||||
/**
|
||||
* @brief Remove the file associated with an InfraredRemote instance.
|
||||
@@ -224,6 +228,6 @@ bool infrared_remote_rename(InfraredRemote* remote, const char* new_path);
|
||||
* infrared_remote_create() or infrared_remote_load() are successfully executed.
|
||||
*
|
||||
* @param[in,out] remote pointer to the instance to be modified.
|
||||
* @returns true if the file was successfully removed, false otherwise.
|
||||
* @returns InfraredErrorCodeNone if the file was successfully removed, otherwise error code.
|
||||
*/
|
||||
bool infrared_remote_remove(InfraredRemote* remote);
|
||||
InfraredErrorCode infrared_remote_remove(InfraredRemote* remote);
|
||||
|
||||
@@ -101,104 +101,177 @@ static bool infrared_signal_is_raw_valid(const InfraredRawSignal* raw) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static inline InfraredErrorCode
|
||||
infrared_signal_save_message(const InfraredMessage* message, FlipperFormat* ff) {
|
||||
const char* protocol_name = infrared_get_protocol_name(message->protocol);
|
||||
return flipper_format_write_string_cstr(
|
||||
ff, INFRARED_SIGNAL_TYPE_KEY, INFRARED_SIGNAL_TYPE_PARSED) &&
|
||||
flipper_format_write_string_cstr(ff, INFRARED_SIGNAL_PROTOCOL_KEY, protocol_name) &&
|
||||
flipper_format_write_hex(
|
||||
ff, INFRARED_SIGNAL_ADDRESS_KEY, (uint8_t*)&message->address, 4) &&
|
||||
flipper_format_write_hex(
|
||||
ff, INFRARED_SIGNAL_COMMAND_KEY, (uint8_t*)&message->command, 4);
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
do {
|
||||
if(!flipper_format_write_string_cstr(
|
||||
ff, INFRARED_SIGNAL_TYPE_KEY, INFRARED_SIGNAL_TYPE_PARSED)) {
|
||||
error = InfraredErrorCodeSignalUnableToWriteType;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_string_cstr(ff, INFRARED_SIGNAL_PROTOCOL_KEY, protocol_name)) {
|
||||
error = InfraredErrorCodeSignalMessageUnableToWriteProtocol;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_hex(
|
||||
ff, INFRARED_SIGNAL_ADDRESS_KEY, (uint8_t*)&message->address, 4)) {
|
||||
error = InfraredErrorCodeSignalMessageUnableToWriteAddress;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_hex(
|
||||
ff, INFRARED_SIGNAL_COMMAND_KEY, (uint8_t*)&message->command, 4)) {
|
||||
error = InfraredErrorCodeSignalMessageUnableToWriteCommand;
|
||||
break;
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static inline bool infrared_signal_save_raw(const InfraredRawSignal* raw, FlipperFormat* ff) {
|
||||
static inline InfraredErrorCode
|
||||
infrared_signal_save_raw(const InfraredRawSignal* raw, FlipperFormat* ff) {
|
||||
furi_assert(raw->timings_size <= MAX_TIMINGS_AMOUNT);
|
||||
return flipper_format_write_string_cstr(
|
||||
ff, INFRARED_SIGNAL_TYPE_KEY, INFRARED_SIGNAL_TYPE_RAW) &&
|
||||
flipper_format_write_uint32(ff, INFRARED_SIGNAL_FREQUENCY_KEY, &raw->frequency, 1) &&
|
||||
flipper_format_write_float(ff, INFRARED_SIGNAL_DUTY_CYCLE_KEY, &raw->duty_cycle, 1) &&
|
||||
flipper_format_write_uint32(
|
||||
ff, INFRARED_SIGNAL_DATA_KEY, raw->timings, raw->timings_size);
|
||||
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
do {
|
||||
if(!flipper_format_write_string_cstr(
|
||||
ff, INFRARED_SIGNAL_TYPE_KEY, INFRARED_SIGNAL_TYPE_RAW)) {
|
||||
error = InfraredErrorCodeSignalUnableToWriteType;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_uint32(ff, INFRARED_SIGNAL_FREQUENCY_KEY, &raw->frequency, 1)) {
|
||||
error = InfraredErrorCodeSignalRawUnableToWriteFrequency;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_float(ff, INFRARED_SIGNAL_DUTY_CYCLE_KEY, &raw->duty_cycle, 1)) {
|
||||
error = InfraredErrorCodeSignalRawUnableToWriteDutyCycle;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_uint32(
|
||||
ff, INFRARED_SIGNAL_DATA_KEY, raw->timings, raw->timings_size)) {
|
||||
error = InfraredErrorCodeSignalRawUnableToWriteData;
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
return error;
|
||||
}
|
||||
|
||||
static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
static inline InfraredErrorCode
|
||||
infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, INFRARED_SIGNAL_PROTOCOL_KEY, buf)) break;
|
||||
if(!flipper_format_read_string(ff, INFRARED_SIGNAL_PROTOCOL_KEY, buf)) {
|
||||
error = InfraredErrorCodeSignalMessageUnableToReadProtocol;
|
||||
break;
|
||||
}
|
||||
|
||||
InfraredMessage message;
|
||||
message.protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf));
|
||||
|
||||
if(!flipper_format_read_hex(ff, INFRARED_SIGNAL_ADDRESS_KEY, (uint8_t*)&message.address, 4))
|
||||
if(!flipper_format_read_hex(
|
||||
ff, INFRARED_SIGNAL_ADDRESS_KEY, (uint8_t*)&message.address, 4)) {
|
||||
error = InfraredErrorCodeSignalMessageUnableToReadAddress;
|
||||
break;
|
||||
if(!flipper_format_read_hex(ff, INFRARED_SIGNAL_COMMAND_KEY, (uint8_t*)&message.command, 4))
|
||||
}
|
||||
if(!flipper_format_read_hex(
|
||||
ff, INFRARED_SIGNAL_COMMAND_KEY, (uint8_t*)&message.command, 4)) {
|
||||
error = InfraredErrorCodeSignalMessageUnableToReadCommand;
|
||||
break;
|
||||
if(!infrared_signal_is_message_valid(&message)) break;
|
||||
}
|
||||
|
||||
if(!infrared_signal_is_message_valid(&message)) {
|
||||
error = InfraredErrorCodeSignalMessageIsInvalid;
|
||||
break;
|
||||
}
|
||||
|
||||
infrared_signal_set_message(signal, &message);
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
furi_string_free(buf);
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
bool success = false;
|
||||
static inline InfraredErrorCode
|
||||
infrared_signal_read_raw(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
do {
|
||||
uint32_t frequency;
|
||||
if(!flipper_format_read_uint32(ff, INFRARED_SIGNAL_FREQUENCY_KEY, &frequency, 1)) break;
|
||||
if(!flipper_format_read_uint32(ff, INFRARED_SIGNAL_FREQUENCY_KEY, &frequency, 1)) {
|
||||
error = InfraredErrorCodeSignalRawUnableToReadFrequency;
|
||||
break;
|
||||
}
|
||||
|
||||
float duty_cycle;
|
||||
if(!flipper_format_read_float(ff, INFRARED_SIGNAL_DUTY_CYCLE_KEY, &duty_cycle, 1)) break;
|
||||
if(!flipper_format_read_float(ff, INFRARED_SIGNAL_DUTY_CYCLE_KEY, &duty_cycle, 1)) {
|
||||
error = InfraredErrorCodeSignalRawUnableToReadDutyCycle;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t timings_size;
|
||||
if(!flipper_format_get_value_count(ff, INFRARED_SIGNAL_DATA_KEY, &timings_size)) break;
|
||||
if(!flipper_format_get_value_count(ff, INFRARED_SIGNAL_DATA_KEY, &timings_size)) {
|
||||
error = InfraredErrorCodeSignalRawUnableToReadTimingsSize;
|
||||
break;
|
||||
}
|
||||
|
||||
if(timings_size > MAX_TIMINGS_AMOUNT) break;
|
||||
if(timings_size > MAX_TIMINGS_AMOUNT) {
|
||||
error = InfraredErrorCodeSignalRawUnableToReadTooLongData;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t* timings = malloc(sizeof(uint32_t) * timings_size);
|
||||
if(!flipper_format_read_uint32(ff, INFRARED_SIGNAL_DATA_KEY, timings, timings_size)) {
|
||||
error = InfraredErrorCodeSignalRawUnableToReadData;
|
||||
free(timings);
|
||||
break;
|
||||
}
|
||||
|
||||
infrared_signal_set_raw_signal(signal, timings, timings_size, frequency, duty_cycle);
|
||||
free(timings);
|
||||
|
||||
success = true;
|
||||
error = InfraredErrorCodeNone;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
InfraredErrorCode infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, INFRARED_SIGNAL_TYPE_KEY, tmp)) break;
|
||||
|
||||
if(furi_string_equal(tmp, INFRARED_SIGNAL_TYPE_RAW)) {
|
||||
if(!infrared_signal_read_raw(signal, ff)) break;
|
||||
} else if(furi_string_equal(tmp, INFRARED_SIGNAL_TYPE_PARSED)) {
|
||||
if(!infrared_signal_read_message(signal, ff)) break;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown signal type: %s", furi_string_get_cstr(tmp));
|
||||
if(!flipper_format_read_string(ff, INFRARED_SIGNAL_TYPE_KEY, tmp)) {
|
||||
error = InfraredErrorCodeSignalUnableToReadType;
|
||||
break;
|
||||
}
|
||||
|
||||
success = true;
|
||||
if(furi_string_equal(tmp, INFRARED_SIGNAL_TYPE_RAW)) {
|
||||
error = infrared_signal_read_raw(signal, ff);
|
||||
} else if(furi_string_equal(tmp, INFRARED_SIGNAL_TYPE_PARSED)) {
|
||||
error = infrared_signal_read_message(signal, ff);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown signal type: %s", furi_string_get_cstr(tmp));
|
||||
error = InfraredErrorCodeSignalTypeUnknown;
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
furi_string_free(tmp);
|
||||
return success;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
InfraredSignal* infrared_signal_alloc(void) {
|
||||
@@ -285,68 +358,88 @@ const InfraredMessage* infrared_signal_get_message(const InfraredSignal* signal)
|
||||
return &signal->payload.message;
|
||||
}
|
||||
|
||||
bool infrared_signal_save(const InfraredSignal* signal, FlipperFormat* ff, const char* name) {
|
||||
InfraredErrorCode
|
||||
infrared_signal_save(const InfraredSignal* signal, FlipperFormat* ff, const char* name) {
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
if(!flipper_format_write_comment_cstr(ff, "") ||
|
||||
!flipper_format_write_string_cstr(ff, INFRARED_SIGNAL_NAME_KEY, name)) {
|
||||
return false;
|
||||
error = InfraredErrorCodeFileOperationFailed;
|
||||
} else if(signal->is_raw) {
|
||||
return infrared_signal_save_raw(&signal->payload.raw, ff);
|
||||
error = infrared_signal_save_raw(&signal->payload.raw, ff);
|
||||
} else {
|
||||
return infrared_signal_save_message(&signal->payload.message, ff);
|
||||
error = infrared_signal_save_message(&signal->payload.message, ff);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) {
|
||||
bool success = false;
|
||||
InfraredErrorCode
|
||||
infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) {
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
|
||||
do {
|
||||
if(!infrared_signal_read_name(ff, name)) break;
|
||||
if(!infrared_signal_read_body(signal, ff)) break;
|
||||
error = infrared_signal_read_name(ff, name);
|
||||
if(INFRARED_ERROR_PRESENT(error)) break;
|
||||
|
||||
success = true; //-V779
|
||||
error = infrared_signal_read_body(signal, ff);
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_signal_read_name(FlipperFormat* ff, FuriString* name) {
|
||||
return flipper_format_read_string(ff, INFRARED_SIGNAL_NAME_KEY, name);
|
||||
InfraredErrorCode infrared_signal_read_name(FlipperFormat* ff, FuriString* name) {
|
||||
return flipper_format_read_string(ff, INFRARED_SIGNAL_NAME_KEY, name) ?
|
||||
InfraredErrorCodeNone :
|
||||
InfraredErrorCodeSignalNameNotFound;
|
||||
}
|
||||
|
||||
bool infrared_signal_search_by_name_and_read(
|
||||
InfraredErrorCode infrared_signal_search_by_name_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
const char* name) {
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
while(infrared_signal_read_name(ff, tmp)) {
|
||||
do {
|
||||
error = infrared_signal_read_name(ff, tmp);
|
||||
if(INFRARED_ERROR_PRESENT(error)) break;
|
||||
|
||||
if(furi_string_equal(tmp, name)) {
|
||||
success = infrared_signal_read_body(signal, ff);
|
||||
error = infrared_signal_read_body(signal, ff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(true);
|
||||
|
||||
furi_string_free(tmp);
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool infrared_signal_search_by_index_and_read(
|
||||
InfraredErrorCode infrared_signal_search_by_index_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
size_t index) {
|
||||
bool success = false;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
for(uint32_t i = 0; infrared_signal_read_name(ff, tmp); ++i) {
|
||||
for(uint32_t i = 0;; ++i) {
|
||||
error = infrared_signal_read_name(ff, tmp);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
INFRARED_ERROR_SET_INDEX(error, i);
|
||||
break;
|
||||
}
|
||||
|
||||
if(i == index) {
|
||||
success = infrared_signal_read_body(signal, ff);
|
||||
error = infrared_signal_read_body(signal, ff);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
INFRARED_ERROR_SET_INDEX(error, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_free(tmp);
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_signal_transmit(const InfraredSignal* signal) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "infrared_error_code.h"
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <infrared/encoder_decoder/infrared.h>
|
||||
|
||||
@@ -136,9 +137,10 @@ const InfraredMessage* infrared_signal_get_message(const InfraredSignal* signal)
|
||||
* @param[in,out] signal pointer to the instance to be read into.
|
||||
* @param[in,out] ff pointer to the FlipperFormat file instance to read from.
|
||||
* @param[out] name pointer to the string to hold the signal name. Must be properly allocated.
|
||||
* @returns true if a signal was successfully read, false otherwise (e.g. no more signals to read).
|
||||
* @returns InfraredErrorCodeNone if a signal was successfully read, otherwise error code
|
||||
*/
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name);
|
||||
InfraredErrorCode
|
||||
infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name);
|
||||
|
||||
/**
|
||||
* @brief Read a signal name from a FlipperFormat file.
|
||||
@@ -147,9 +149,9 @@ bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString*
|
||||
*
|
||||
* @param[in,out] ff pointer to the FlipperFormat file instance to read from.
|
||||
* @param[out] name pointer to the string to hold the signal name. Must be properly allocated.
|
||||
* @returns true if a signal name was successfully read, false otherwise (e.g. no more signals to read).
|
||||
* @returns InfraredErrorCodeNone if a signal name was successfully read, otherwise error code
|
||||
*/
|
||||
bool infrared_signal_read_name(FlipperFormat* ff, FuriString* name);
|
||||
InfraredErrorCode infrared_signal_read_name(FlipperFormat* ff, FuriString* name);
|
||||
|
||||
/**
|
||||
* @brief Read a signal from a FlipperFormat file.
|
||||
@@ -158,9 +160,9 @@ bool infrared_signal_read_name(FlipperFormat* ff, FuriString* name);
|
||||
*
|
||||
* @param[in,out] ff pointer to the FlipperFormat file instance to read from.
|
||||
* @param[out] body pointer to the InfraredSignal instance to hold the signal body. Must be properly allocated.
|
||||
* @returns true if a signal body was successfully read, false otherwise (e.g. syntax error).
|
||||
* @returns InfraredErrorCodeNone if a signal body was successfully read, otherwise error code.
|
||||
*/
|
||||
bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff);
|
||||
InfraredErrorCode infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff);
|
||||
|
||||
/**
|
||||
* @brief Read a signal with a particular name from a FlipperFormat file into an InfraredSignal instance.
|
||||
@@ -171,9 +173,9 @@ bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff);
|
||||
* @param[in,out] signal pointer to the instance to be read into.
|
||||
* @param[in,out] ff pointer to the FlipperFormat file instance to read from.
|
||||
* @param[in] name pointer to a zero-terminated string containing the requested signal name.
|
||||
* @returns true if a signal was found and successfully read, false otherwise (e.g. the signal was not found).
|
||||
* @returns InfraredErrorCodeNone if a signal was found and successfully read, otherwise error code.
|
||||
*/
|
||||
bool infrared_signal_search_by_name_and_read(
|
||||
InfraredErrorCode infrared_signal_search_by_name_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
const char* name);
|
||||
@@ -187,9 +189,9 @@ bool infrared_signal_search_by_name_and_read(
|
||||
* @param[in,out] signal pointer to the instance to be read into.
|
||||
* @param[in,out] ff pointer to the FlipperFormat file instance to read from.
|
||||
* @param[in] index the requested signal index.
|
||||
* @returns true if a signal was found and successfully read, false otherwise (e.g. the signal was not found).
|
||||
* @returns InfraredErrorCodeNone if a signal was found and successfully read, otherwise error code.
|
||||
*/
|
||||
bool infrared_signal_search_by_index_and_read(
|
||||
InfraredErrorCode infrared_signal_search_by_index_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
size_t index);
|
||||
@@ -203,8 +205,10 @@ bool infrared_signal_search_by_index_and_read(
|
||||
* @param[in] signal pointer to the instance holding the signal to be saved.
|
||||
* @param[in,out] ff pointer to the FlipperFormat file instance to write to.
|
||||
* @param[in] name pointer to a zero-terminated string contating the name of the signal.
|
||||
* @returns InfraredErrorCodeNone if a signal was successfully saved, otherwise error code
|
||||
*/
|
||||
bool infrared_signal_save(const InfraredSignal* signal, FlipperFormat* ff, const char* name);
|
||||
InfraredErrorCode
|
||||
infrared_signal_save(const InfraredSignal* signal, FlipperFormat* ff, const char* name);
|
||||
|
||||
/**
|
||||
* @brief Transmit a signal contained in an InfraredSignal instance.
|
||||
|
||||
@@ -1091,3 +1091,41 @@ type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4348 4439 520 1646 520 1646 520 1646 519 1646 520 561 520 561 520 1646 519 561 520 561 520 562 519 562 519 561 520 1646 520 1647 518 563 518 1646 519 562 519 561 520 561 520 562 519 562 519 561 520 1648 517 1647 519 1646 519 1647 519 1646 520 1646 520 1645 520 1647 519 561 520 561 520 562 519 562 519 562 519 562 519 561 520 562 519 561 520 1646 520 562 519 1647 518 1646 520 562 519 560 521 561 520 561 520 561 520 562 519 562 519 560 521 562 519 562 519 560 521 1646 520 1646 520 561 520 562 519 561 520 562 519 561 520 561 520 561 520 561 520 561 520 1647 518 1646 520 562 519 562 519 561 520 1646 520 561 520 5409 4348 4440 519 1645 521 1646 519 1645 521 1645 521 561 520 561 520 1644 522 561 520 561 520 561 520 560 521 562 519 1646 520 1646 520 562 519 1644 522 561 520 561 520 561 520 561 520 561 520 561 520 1646 520 1645 520 1646 520 1645 521 1646 520 1646 520 1644 522 1645 521 560 521 560 521 561 520 561 520 560 521 560 521 561 520 561 520 561 520 1645 521 562 519 1645 521 1645 520 561 520 562 519 561 520 561 520 561 520 560 521 560 521 560 521 560 521 561 520 560 521 1646 520 1646 520 561 520 560 521 559 522 560 521 561 520 561 520 560 521 560 521 560 521 1646 520 1645 520 561 520 560 521 560 521 1645 521 561 520
|
||||
#
|
||||
# Model: Airwell AW-HKD012-N91
|
||||
#
|
||||
name: Dh
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4387 4398 547 1609 547 530 547 1610 547 1611 545 530 547 530 547 1608 547 530 548 530 547 1611 545 532 546 532 547 1609 547 1610 547 531 547 1608 548 530 547 530 548 530 547 1610 546 1609 547 1610 547 1609 547 1609 547 1611 545 1609 548 1610 546 530 547 530 548 529 549 531 547 531 546 531 547 1608 548 1610 547 1608 548 533 545 1608 548 532 546 532 546 1611 545 532 547 532 545 530 548 1608 547 530 549 1608 547 1609 548 5203 4386 4398 547 1609 546 530 547 1609 546 1607 548 531 547 531 547 1609 547 530 548 531 547 1609 547 531 547 531 547 1608 547 1613 544 531 546 1609 547 531 547 531 547 532 546 1609 547 1609 546 1609 547 1609 547 1608 547 1608 548 1608 548 1609 547 530 547 530 547 530 547 532 546 530 547 530 548 1610 546 1608 547 1609 547 530 547 1609 547 530 547 530 548 1609 546 530 548 530 547 532 546 1610 546 531 546 1608 548 1608 548
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4388 4398 547 1608 548 531 546 1610 546 1609 547 530 547 529 548 1608 548 532 547 530 548 1612 544 529 549 530 548 1608 547 1609 547 531 546 1608 548 1607 549 529 549 1608 549 1609 548 1608 548 1608 548 1611 545 1608 548 530 548 1609 547 531 547 530 548 530 548 531 547 529 549 530 548 530 547 531 547 530 548 530 547 529 549 530 548 532 547 530 548 1609 547 1610 547 1608 548 1609 547 1608 548 1608 548 1608 548 1608 548 5203 4388 4396 549 1609 547 529 549 1610 546 1608 548 529 549 530 547 1609 547 530 548 529 549 1608 548 531 547 532 546 1609 547 1609 547 530 548 1609 548 1609 548 529 548 1608 548 1609 548 1609 547 1609 547 1608 548 1609 547 532 546 1608 548 531 548 531 548 530 548 530 548 531 547 530 548 531 548 531 547 530 548 530 548 530 548 531 547 529 549 529 549 1609 548 1608 548 1609 547 1608 548 1608 548 1608 548 1607 549 1607 549
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4384 4400 572 1585 571 505 572 1583 573 1584 572 508 570 503 575 1584 572 505 572 506 572 1583 573 504 573 506 571 1586 570 1585 572 532 546 1586 570 1585 571 506 571 1585 571 1583 573 1586 570 1583 573 1584 572 1589 569 505 572 1585 571 506 571 506 573 506 572 505 573 532 545 504 574 509 570 1611 545 506 572 1582 574 506 572 507 571 507 571 507 570 1584 572 507 571 1587 569 506 572 1584 572 1585 571 1583 573 1612 544 5179 4386 4400 570 1584 572 507 571 1583 572 1585 571 506 572 506 572 1584 572 505 572 504 574 1584 572 507 571 504 574 1583 573 1585 572 507 571 1584 572 1610 545 508 571 1587 569 1583 573 1583 573 1585 571 1585 572 1585 572 505 572 1584 572 505 573 507 572 506 571 504 574 505 573 505 574 508 571 1585 571 507 571 1585 571 506 571 506 572 504 574 505 572 1586 570 507 571 1586 570 505 573 1584 572 1585 571 1587 569 1584 573
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4386 4398 575 1582 574 503 575 1583 573 1582 574 505 573 504 574 1582 574 506 572 508 570 1583 573 504 574 505 573 1583 573 1584 573 505 573 1582 575 1583 574 504 574 1582 574 1583 573 1583 573 1583 573 1585 571 1586 572 504 573 1584 572 504 573 505 573 505 573 505 573 504 573 506 571 1583 574 505 573 1583 573 1583 573 1584 572 1583 573 505 572 505 573 504 574 1583 574 505 573 505 573 504 574 505 572 1584 572 1584 573 5178 4387 4400 571 1583 573 504 574 1584 572 1584 572 507 572 504 574 1582 574 505 572 505 573 1583 573 504 574 504 574 1582 574 1584 573 503 574 1583 573 1582 574 505 573 1583 573 1582 575 1583 573 1610 546 1584 572 1583 573 505 573 1610 546 506 572 505 573 504 574 504 574 505 573 505 573 1584 573 505 573 1582 574 1584 572 1583 573 1583 573 504 574 503 575 504 574 1585 571 507 571 504 573 506 572 505 572 1584 572 1585 571
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4388 4399 547 1608 548 530 548 1610 547 1610 547 529 549 529 548 1608 548 530 548 530 548 1607 549 533 545 531 548 1608 548 1610 546 531 547 1609 547 1608 548 529 549 1609 547 1609 547 1609 547 1609 547 1609 547 1608 548 529 548 1638 519 530 548 530 548 530 548 529 550 528 549 530 548 530 548 1608 548 530 548 1609 548 1610 547 1609 547 531 546 529 549 1608 548 530 548 1609 548 530 548 529 548 530 548 1609 548 1609 548 5205 4387 4398 547 1609 548 531 546 1609 547 1609 547 530 548 531 546 1609 547 531 548 530 573 1583 573 507 571 506 572 1583 573 1582 574 504 574 1581 575 1582 574 506 572 1583 574 1583 573 1583 573 1585 571 1584 572 1585 570 507 571 1582 574 505 574 532 545 505 573 505 572 506 571 505 573 505 573 1584 572 506 572 1583 573 1584 572 1583 573 505 572 504 573 1583 573 505 573 1586 571 506 572 505 573 507 572 1583 573 1584 572
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4388 4399 572 1583 573 532 546 1585 571 1583 574 503 575 505 573 1584 572 504 574 505 573 1584 573 506 572 504 573 1584 573 1584 572 505 574 1611 545 506 573 1583 573 1585 571 1586 545 1609 547 531 547 1611 545 1608 548 1607 549 530 548 529 548 531 548 532 546 1610 546 533 545 530 547 1609 547 1610 547 1609 547 533 545 529 548 530 548 530 547 531 546 530 547 530 548 533 544 1608 548 1608 548 1610 546 1606 550 1609 547 5203 4388 4397 548 1609 547 531 547 1608 548 1608 548 530 548 530 548 1608 548 531 547 531 547 1610 546 531 547 530 548 1609 547 1611 546 532 547 1609 547 531 547 1608 548 1610 546 1609 547 1608 548 530 547 1609 547 1608 548 1609 547 531 546 530 548 530 547 530 547 1608 548 532 547 534 545 1608 548 1608 548 1609 547 530 548 531 547 531 547 532 546 531 546 531 547 532 546 530 548 1608 547 1608 548 1610 546 1608 548 1608 548
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,12 +34,12 @@ static void infrared_scene_universal_common_hide_popup(InfraredApp* infrared) {
|
||||
|
||||
static int32_t infrared_scene_universal_common_task_callback(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
const bool success = infrared_brute_force_calculate_messages(infrared->brute_force);
|
||||
const InfraredErrorCode error = infrared_brute_force_calculate_messages(infrared->brute_force);
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher,
|
||||
infrared_custom_event_pack(InfraredCustomEventTypeTaskFinished, 0));
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_scene_universal_common_on_enter(void* context) {
|
||||
@@ -93,9 +93,9 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases);
|
||||
}
|
||||
} else if(event_type == InfraredCustomEventTypeTaskFinished) {
|
||||
const bool task_success = infrared_blocking_task_finalize(infrared);
|
||||
const InfraredErrorCode task_error = infrared_blocking_task_finalize(infrared);
|
||||
|
||||
if(!task_success) {
|
||||
if(INFRARED_ERROR_PRESENT(task_error)) {
|
||||
scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases);
|
||||
} else {
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||
|
||||
@@ -11,12 +11,12 @@ static int32_t infrared_scene_edit_delete_task_callback(void* context) {
|
||||
InfraredAppState* app_state = &infrared->app_state;
|
||||
const InfraredEditTarget edit_target = app_state->edit_target;
|
||||
|
||||
bool success;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
if(edit_target == InfraredEditTargetButton) {
|
||||
furi_assert(app_state->current_button_index != InfraredButtonIndexNone);
|
||||
success = infrared_remote_delete_signal(infrared->remote, app_state->current_button_index);
|
||||
error = infrared_remote_delete_signal(infrared->remote, app_state->current_button_index);
|
||||
} else if(edit_target == InfraredEditTargetRemote) {
|
||||
success = infrared_remote_remove(infrared->remote);
|
||||
error = infrared_remote_remove(infrared->remote);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
@@ -24,7 +24,7 @@ static int32_t infrared_scene_edit_delete_task_callback(void* context) {
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeTaskFinished);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_scene_edit_delete_on_enter(void* context) {
|
||||
@@ -39,11 +39,15 @@ void infrared_scene_edit_delete_on_enter(void* context) {
|
||||
const int32_t current_button_index = infrared->app_state.current_button_index;
|
||||
furi_check(current_button_index != InfraredButtonIndexNone);
|
||||
|
||||
if(!infrared_remote_load_signal(remote, infrared->current_signal, current_button_index)) {
|
||||
InfraredErrorCode error =
|
||||
infrared_remote_load_signal(remote, infrared->current_signal, current_button_index);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
const char* format =
|
||||
(INFRARED_ERROR_CHECK(error, InfraredErrorCodeSignalRawUnableToReadTooLongData)) ?
|
||||
"Failed to delete\n\"%s\" is too long.\nTry to edit file from pc" :
|
||||
"Failed to load\n\"%s\"";
|
||||
infrared_show_error_message(
|
||||
infrared,
|
||||
"Failed to load\n\"%s\"",
|
||||
infrared_remote_get_signal_name(remote, current_button_index));
|
||||
infrared, format, infrared_remote_get_signal_name(remote, current_button_index));
|
||||
scene_manager_previous_scene(infrared->scene_manager);
|
||||
return;
|
||||
}
|
||||
@@ -107,18 +111,30 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event)
|
||||
infrared_blocking_task_start(infrared, infrared_scene_edit_delete_task_callback);
|
||||
|
||||
} else if(event.event == InfraredCustomEventTypeTaskFinished) {
|
||||
const bool task_success = infrared_blocking_task_finalize(infrared);
|
||||
const InfraredErrorCode task_error = infrared_blocking_task_finalize(infrared);
|
||||
|
||||
InfraredAppState* app_state = &infrared->app_state;
|
||||
|
||||
if(task_success) {
|
||||
if(!INFRARED_ERROR_PRESENT(task_error)) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneEditDeleteDone);
|
||||
} else {
|
||||
const char* edit_target_text =
|
||||
app_state->edit_target == InfraredEditTargetButton ? "button" : "file";
|
||||
infrared_show_error_message(infrared, "Failed to\ndelete %s", edit_target_text);
|
||||
if(INFRARED_ERROR_CHECK(
|
||||
task_error, InfraredErrorCodeSignalRawUnableToReadTooLongData)) {
|
||||
const uint8_t index = INFRARED_ERROR_GET_INDEX(task_error);
|
||||
const char* format =
|
||||
"Failed to delete\n\"%s\" is too long.\nTry to edit file from pc";
|
||||
infrared_show_error_message(
|
||||
infrared,
|
||||
format,
|
||||
infrared_remote_get_signal_name(infrared->remote, index));
|
||||
} else {
|
||||
const char* edit_target_text =
|
||||
app_state->edit_target == InfraredEditTargetButton ? "button" : "file";
|
||||
infrared_show_error_message(
|
||||
infrared, "Failed to\ndelete %s", edit_target_text);
|
||||
}
|
||||
|
||||
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
|
||||
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneRemote};
|
||||
scene_manager_search_and_switch_to_previous_scene_one_of(
|
||||
scene_manager, possible_scenes, COUNT_OF(possible_scenes));
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
static int32_t infrared_scene_edit_move_task_callback(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
const bool success = infrared_remote_move_signal(
|
||||
const InfraredErrorCode error = infrared_remote_move_signal(
|
||||
infrared->remote,
|
||||
infrared->app_state.prev_button_index,
|
||||
infrared->app_state.current_button_index);
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeTaskFinished);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
static void infrared_scene_edit_move_button_callback(
|
||||
@@ -51,14 +51,26 @@ bool infrared_scene_edit_move_on_event(void* context, SceneManagerEvent event) {
|
||||
infrared_blocking_task_start(infrared, infrared_scene_edit_move_task_callback);
|
||||
|
||||
} else if(event.event == InfraredCustomEventTypeTaskFinished) {
|
||||
const bool task_success = infrared_blocking_task_finalize(infrared);
|
||||
const InfraredErrorCode task_error = infrared_blocking_task_finalize(infrared);
|
||||
|
||||
if(!task_success) {
|
||||
const char* signal_name = infrared_remote_get_signal_name(
|
||||
infrared->remote, infrared->app_state.current_button_index);
|
||||
infrared_show_error_message(infrared, "Failed to move\n\"%s\"", signal_name);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
infrared->scene_manager, InfraredSceneRemoteList);
|
||||
if(INFRARED_ERROR_PRESENT(task_error)) {
|
||||
const char* format = "Failed to move\n\"%s\"";
|
||||
uint8_t signal_index = infrared->app_state.prev_button_index;
|
||||
|
||||
if(INFRARED_ERROR_CHECK(
|
||||
task_error, InfraredErrorCodeSignalRawUnableToReadTooLongData)) {
|
||||
signal_index = INFRARED_ERROR_GET_INDEX(task_error);
|
||||
format = "Failed to move\n\"%s\" is too long.\nTry to edit file from pc";
|
||||
}
|
||||
furi_assert(format);
|
||||
|
||||
const char* signal_name =
|
||||
infrared_remote_get_signal_name(infrared->remote, signal_index);
|
||||
infrared_show_error_message(infrared, format, signal_name);
|
||||
|
||||
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneRemote};
|
||||
scene_manager_search_and_switch_to_previous_scene_one_of(
|
||||
infrared->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
|
||||
} else {
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewMove);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ static int32_t infrared_scene_edit_rename_task_callback(void* context) {
|
||||
InfraredAppState* app_state = &infrared->app_state;
|
||||
const InfraredEditTarget edit_target = app_state->edit_target;
|
||||
|
||||
bool success;
|
||||
InfraredErrorCode error = InfraredErrorCodeNone;
|
||||
if(edit_target == InfraredEditTargetButton) {
|
||||
furi_assert(app_state->current_button_index != InfraredButtonIndexNone);
|
||||
success = infrared_remote_rename_signal(
|
||||
error = infrared_remote_rename_signal(
|
||||
infrared->remote, app_state->current_button_index, infrared->text_store[0]);
|
||||
} else if(edit_target == InfraredEditTargetRemote) {
|
||||
success = infrared_rename_current_remote(infrared, infrared->text_store[0]);
|
||||
error = infrared_rename_current_remote(infrared, infrared->text_store[0]);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
@@ -22,7 +22,7 @@ static int32_t infrared_scene_edit_rename_task_callback(void* context) {
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeTaskFinished);
|
||||
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_scene_edit_rename_on_enter(void* context) {
|
||||
@@ -39,7 +39,7 @@ void infrared_scene_edit_rename_on_enter(void* context) {
|
||||
furi_check(current_button_index != InfraredButtonIndexNone);
|
||||
|
||||
enter_name_length = INFRARED_MAX_BUTTON_NAME_LENGTH;
|
||||
strncpy(
|
||||
strlcpy(
|
||||
infrared->text_store[0],
|
||||
infrared_remote_get_signal_name(remote, current_button_index),
|
||||
enter_name_length);
|
||||
@@ -47,7 +47,7 @@ void infrared_scene_edit_rename_on_enter(void* context) {
|
||||
} else if(edit_target == InfraredEditTargetRemote) {
|
||||
text_input_set_header_text(text_input, "Name the remote");
|
||||
enter_name_length = INFRARED_MAX_REMOTE_NAME_LENGTH;
|
||||
strncpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length);
|
||||
strlcpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length);
|
||||
|
||||
FuriString* folder_path;
|
||||
folder_path = furi_string_alloc();
|
||||
@@ -89,17 +89,30 @@ bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event)
|
||||
infrared_blocking_task_start(infrared, infrared_scene_edit_rename_task_callback);
|
||||
|
||||
} else if(event.event == InfraredCustomEventTypeTaskFinished) {
|
||||
const bool task_success = infrared_blocking_task_finalize(infrared);
|
||||
const InfraredErrorCode task_error = infrared_blocking_task_finalize(infrared);
|
||||
InfraredAppState* app_state = &infrared->app_state;
|
||||
|
||||
if(task_success) {
|
||||
if(!INFRARED_ERROR_PRESENT(task_error)) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneEditRenameDone);
|
||||
} else {
|
||||
const char* edit_target_text =
|
||||
app_state->edit_target == InfraredEditTargetButton ? "button" : "file";
|
||||
infrared_show_error_message(infrared, "Failed to\nrename %s", edit_target_text);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
scene_manager, InfraredSceneRemoteList);
|
||||
bool long_signal = INFRARED_ERROR_CHECK(
|
||||
task_error, InfraredErrorCodeSignalRawUnableToReadTooLongData);
|
||||
|
||||
const char* format = "Failed to rename\n%s";
|
||||
const char* target = infrared->app_state.edit_target == InfraredEditTargetButton ?
|
||||
"button" :
|
||||
"file";
|
||||
if(long_signal) {
|
||||
format = "Failed to rename\n\"%s\" is too long.\nTry to edit file from pc";
|
||||
target = infrared_remote_get_signal_name(
|
||||
infrared->remote, INFRARED_ERROR_GET_INDEX(task_error));
|
||||
}
|
||||
|
||||
infrared_show_error_message(infrared, format, target);
|
||||
|
||||
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneRemote};
|
||||
scene_manager_search_and_switch_to_previous_scene_one_of(
|
||||
scene_manager, possible_scenes, COUNT_OF(possible_scenes));
|
||||
}
|
||||
|
||||
app_state->current_button_index = InfraredButtonIndexNone;
|
||||
|
||||
@@ -41,12 +41,12 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == InfraredCustomEventTypeTextEditDone) {
|
||||
const char* signal_name = infrared->text_store[0];
|
||||
const bool success =
|
||||
const InfraredErrorCode error =
|
||||
infrared->app_state.is_learning_new_remote ?
|
||||
infrared_add_remote_with_button(infrared, signal_name, signal) :
|
||||
infrared_remote_append_signal(infrared->remote, signal, signal_name);
|
||||
|
||||
if(success) {
|
||||
if(!INFRARED_ERROR_PRESENT(error)) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneLearnDone);
|
||||
dolphin_deed(DolphinDeedIrSave);
|
||||
} else {
|
||||
|
||||
@@ -85,7 +85,13 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(custom_type == InfraredCustomEventTypeTransmitStarted) {
|
||||
furi_assert(button_index >= 0);
|
||||
infrared_tx_start_button_index(infrared, button_index);
|
||||
InfraredErrorCode error = infrared_tx_start_button_index(infrared, button_index);
|
||||
if(INFRARED_ERROR_PRESENT(error)) {
|
||||
infrared_show_error_message(
|
||||
infrared,
|
||||
"Failed to load\n\"%s\"",
|
||||
infrared_remote_get_signal_name(infrared->remote, button_index));
|
||||
}
|
||||
consumed = true;
|
||||
} else if(custom_type == InfraredCustomEventTypeTransmitStopped) {
|
||||
infrared_tx_stop(infrared);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
static int32_t infrared_scene_remote_list_task_callback(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
const bool success =
|
||||
const InfraredErrorCode error =
|
||||
infrared_remote_load(infrared->remote, furi_string_get_cstr(infrared->file_path));
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeTaskFinished);
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
static void infrared_scene_remote_list_select_and_load(InfraredApp* infrared) {
|
||||
@@ -38,13 +38,19 @@ bool infrared_scene_remote_list_on_event(void* context, SceneManagerEvent event)
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == InfraredCustomEventTypeTaskFinished) {
|
||||
const bool task_success = infrared_blocking_task_finalize(infrared);
|
||||
const InfraredErrorCode task_error = infrared_blocking_task_finalize(infrared);
|
||||
|
||||
if(task_success) {
|
||||
if(!INFRARED_ERROR_PRESENT(task_error)) {
|
||||
scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
|
||||
} else {
|
||||
bool wrong_file_type =
|
||||
INFRARED_ERROR_CHECK(task_error, InfraredErrorCodeWrongFileType);
|
||||
const char* format = wrong_file_type ?
|
||||
"Library file\n\"%s\" can't be openned as a remote" :
|
||||
"Failed to load\n\"%s\"";
|
||||
|
||||
infrared_show_error_message(
|
||||
infrared, "Failed to load\n\"%s\"", furi_string_get_cstr(infrared->file_path));
|
||||
infrared, format, furi_string_get_cstr(infrared->file_path));
|
||||
infrared_scene_remote_list_select_and_load(infrared);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,27 +11,33 @@ typedef enum {
|
||||
|
||||
static int32_t infrared_scene_rpc_task_callback(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
const bool success =
|
||||
const InfraredErrorCode error =
|
||||
infrared_remote_load(infrared->remote, furi_string_get_cstr(infrared->file_path));
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher, InfraredCustomEventTypeTaskFinished);
|
||||
return success;
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_scene_rpc_on_enter(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
scene_manager_set_scene_state(infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateIdle);
|
||||
}
|
||||
|
||||
static void infrared_scene_rpc_show(InfraredApp* infrared) {
|
||||
Popup* popup = infrared->popup;
|
||||
|
||||
popup_set_header(popup, "Infrared", 89, 42, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
|
||||
popup_set_text(popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop);
|
||||
|
||||
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
|
||||
|
||||
popup_set_context(popup, context);
|
||||
popup_set_context(popup, infrared);
|
||||
popup_set_callback(popup, infrared_popup_closed_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup);
|
||||
scene_manager_set_scene_state(infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateIdle);
|
||||
scene_manager_set_scene_state(
|
||||
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateSending);
|
||||
notification_message(infrared->notifications, &sequence_display_backlight_on);
|
||||
}
|
||||
|
||||
@@ -51,25 +57,24 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
|
||||
} else if(event.event == InfraredCustomEventTypeTaskFinished) {
|
||||
const bool task_success = infrared_blocking_task_finalize(infrared);
|
||||
const InfraredErrorCode task_error = infrared_blocking_task_finalize(infrared);
|
||||
|
||||
if(task_success) {
|
||||
if(!INFRARED_ERROR_PRESENT(task_error)) {
|
||||
const char* remote_name = infrared_remote_get_name(infrared->remote);
|
||||
infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name);
|
||||
scene_manager_set_scene_state(
|
||||
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded);
|
||||
|
||||
} else {
|
||||
infrared_text_store_set(
|
||||
infrared, 0, "failed to load\n%s", furi_string_get_cstr(infrared->file_path));
|
||||
FuriString* str = furi_string_alloc();
|
||||
furi_string_printf(
|
||||
str, "Failed to load\n%s", furi_string_get_cstr(infrared->file_path));
|
||||
|
||||
rpc_system_app_set_error_code(infrared->rpc_ctx, RpcAppSystemErrorCodeParseFile);
|
||||
rpc_system_app_set_error_text(infrared->rpc_ctx, furi_string_get_cstr(str));
|
||||
|
||||
furi_string_free(str);
|
||||
}
|
||||
|
||||
popup_set_text(
|
||||
infrared->popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop);
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup);
|
||||
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, task_success);
|
||||
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, !INFRARED_ERROR_PRESENT(task_error));
|
||||
} else if(
|
||||
event.event == InfraredCustomEventTypeRpcButtonPressName ||
|
||||
event.event == InfraredCustomEventTypeRpcButtonPressIndex) {
|
||||
@@ -88,10 +93,21 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
TAG, "Sending signal with index \"%ld\"", app_state->current_button_index);
|
||||
}
|
||||
if(infrared->app_state.current_button_index != InfraredButtonIndexNone) {
|
||||
infrared_tx_start_button_index(infrared, app_state->current_button_index);
|
||||
scene_manager_set_scene_state(
|
||||
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateSending);
|
||||
result = true;
|
||||
InfraredErrorCode error =
|
||||
infrared_tx_start_button_index(infrared, app_state->current_button_index);
|
||||
if(!INFRARED_ERROR_PRESENT(error)) {
|
||||
const char* remote_name = infrared_remote_get_name(infrared->remote);
|
||||
infrared_text_store_set(infrared, 0, "emulating\n%s", remote_name);
|
||||
|
||||
infrared_scene_rpc_show(infrared);
|
||||
result = true;
|
||||
} else {
|
||||
rpc_system_app_set_error_code(
|
||||
infrared->rpc_ctx, RpcAppSystemErrorCodeInternalParse);
|
||||
rpc_system_app_set_error_text(
|
||||
infrared->rpc_ctx, "Cannot load button data");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
rpc_system_app_confirm(infrared->rpc_ctx, result);
|
||||
|
||||
@@ -2,23 +2,30 @@
|
||||
|
||||
void lfrfid_scene_rpc_on_enter(void* context) {
|
||||
LfRfid* app = context;
|
||||
app->rpc_state = LfRfidRpcStateIdle;
|
||||
}
|
||||
|
||||
static void lfrfid_rpc_start_emulation(LfRfid* app) {
|
||||
Popup* popup = app->popup;
|
||||
|
||||
lfrfid_text_store_set(app, "emulating\n%s", furi_string_get_cstr(app->file_name));
|
||||
|
||||
popup_set_header(popup, "LF RFID", 89, 42, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
|
||||
popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
|
||||
|
||||
notification_message(app->notifications, &sequence_display_backlight_on);
|
||||
lfrfid_worker_start_thread(app->lfworker);
|
||||
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
|
||||
|
||||
app->rpc_state = LfRfidRpcStateIdle;
|
||||
notification_message(app->notifications, &sequence_display_backlight_on);
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
app->rpc_state = LfRfidRpcStateEmulating;
|
||||
}
|
||||
|
||||
bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
LfRfid* app = context;
|
||||
Popup* popup = app->popup;
|
||||
UNUSED(event);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
@@ -34,16 +41,11 @@ bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
bool result = false;
|
||||
if(app->rpc_state == LfRfidRpcStateIdle) {
|
||||
if(lfrfid_load_key_data(app, app->file_path, false)) {
|
||||
lfrfid_worker_start_thread(app->lfworker);
|
||||
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
|
||||
app->rpc_state = LfRfidRpcStateEmulating;
|
||||
|
||||
lfrfid_text_store_set(
|
||||
app, "emulating\n%s", furi_string_get_cstr(app->file_name));
|
||||
popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
lfrfid_rpc_start_emulation(app);
|
||||
result = true;
|
||||
} else {
|
||||
rpc_system_app_set_error_code(app->rpc_ctx, RpcAppSystemErrorCodeParseFile);
|
||||
rpc_system_app_set_error_text(app->rpc_ctx, "Cannot load key file");
|
||||
}
|
||||
}
|
||||
rpc_system_app_confirm(app->rpc_ctx, result);
|
||||
|
||||
@@ -114,6 +114,8 @@ void momentum_app_scene_misc_dolphin_on_enter(void* context) {
|
||||
VariableItemList* var_item_list = app->var_item_list;
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
DolphinSettings settings;
|
||||
dolphin_get_settings(app->dolphin, &settings);
|
||||
|
||||
uint8_t level = dolphin_get_level(app->dolphin_xp);
|
||||
char level_str[4];
|
||||
@@ -150,6 +152,13 @@ void momentum_app_scene_misc_dolphin_on_enter(void* context) {
|
||||
app);
|
||||
variable_item_set_current_value_index(item, app->dolphin_angry);
|
||||
variable_item_set_current_value_text(item, angry_str);
|
||||
variable_item_set_locked(
|
||||
item,
|
||||
settings.happy_mode,
|
||||
"Settings >\n"
|
||||
"Desktop >\n"
|
||||
"Happy Mode\n"
|
||||
"is enabled!");
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
@@ -161,6 +170,13 @@ void momentum_app_scene_misc_dolphin_on_enter(void* context) {
|
||||
momentum_settings.butthurt_timer, butthurt_timer_values, COUNT_OF(butthurt_timer_values));
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, butthurt_timer_names[value_index]);
|
||||
variable_item_set_locked(
|
||||
item,
|
||||
settings.happy_mode,
|
||||
"Settings >\n"
|
||||
"Desktop >\n"
|
||||
"Happy Mode\n"
|
||||
"is enabled!");
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, momentum_app_scene_misc_dolphin_var_item_list_callback, app);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "iso14443_3a_render.h"
|
||||
|
||||
void nfc_render_iso14443_3a_format_bytes(FuriString* str, const uint8_t* const data, size_t size) {
|
||||
void nfc_render_iso14443_3a_format_bytes(FuriString* str, const uint8_t* data, size_t size) {
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
furi_string_cat_printf(str, " %02X", data[i]);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ void nfc_render_iso14443_3a_info(
|
||||
|
||||
void nfc_render_iso14443_tech_type(const Iso14443_3aData* data, FuriString* str);
|
||||
|
||||
void nfc_render_iso14443_3a_format_bytes(FuriString* str, const uint8_t* const data, size_t size);
|
||||
void nfc_render_iso14443_3a_format_bytes(FuriString* str, const uint8_t* data, size_t size);
|
||||
|
||||
void nfc_render_iso14443_3a_brief(const Iso14443_3aData* data, FuriString* str);
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ static void nfc_scene_read_menu_on_enter_mf_classic(NfcApp* instance) {
|
||||
if(!mf_classic_is_card_read(data)) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Detect Reader",
|
||||
"Extract MF Keys",
|
||||
SubmenuIndexDetectReader,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
@@ -155,7 +155,7 @@ static void nfc_scene_saved_menu_on_enter_mf_classic(NfcApp* instance) {
|
||||
if(!mf_classic_is_card_read(data)) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Detect Reader",
|
||||
"Extract MF Keys",
|
||||
SubmenuIndexDetectReader,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
|
||||
@@ -10,22 +10,29 @@ static void nfc_render_mf_ultralight_pages_count(const MfUltralightData* data, F
|
||||
}
|
||||
|
||||
void nfc_render_mf_ultralight_pwd_pack(const MfUltralightData* data, FuriString* str) {
|
||||
MfUltralightConfigPages* config;
|
||||
|
||||
bool all_pages = mf_ultralight_is_all_data_read(data);
|
||||
if(all_pages) {
|
||||
bool has_config = mf_ultralight_get_config_page(data, &config);
|
||||
|
||||
if(!has_config) {
|
||||
furi_string_cat_printf(str, "\e#Already Unlocked!");
|
||||
} else if(all_pages) {
|
||||
furi_string_cat_printf(str, "\e#All Pages Are Unlocked!");
|
||||
} else {
|
||||
furi_string_cat_printf(str, "\e#Some Pages Are Locked!");
|
||||
}
|
||||
|
||||
MfUltralightConfigPages* config;
|
||||
mf_ultralight_get_config_page(data, &config);
|
||||
if(has_config) {
|
||||
furi_string_cat_printf(str, "\nPassword: ");
|
||||
nfc_render_iso14443_3a_format_bytes(
|
||||
str, config->password.data, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE);
|
||||
|
||||
furi_string_cat_printf(str, "\nPassword: ");
|
||||
nfc_render_iso14443_3a_format_bytes(
|
||||
str, config->password.data, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE);
|
||||
|
||||
furi_string_cat_printf(str, "\nPACK: ");
|
||||
nfc_render_iso14443_3a_format_bytes(str, config->pack.data, MF_ULTRALIGHT_AUTH_PACK_SIZE);
|
||||
furi_string_cat_printf(str, "\nPACK: ");
|
||||
nfc_render_iso14443_3a_format_bytes(str, config->pack.data, MF_ULTRALIGHT_AUTH_PACK_SIZE);
|
||||
} else {
|
||||
furi_string_cat_printf(str, "\nThis card does not support\npassword protection!");
|
||||
}
|
||||
|
||||
nfc_render_mf_ultralight_pages_count(data, str);
|
||||
}
|
||||
|
||||
@@ -731,6 +731,10 @@ static bool nfc_protocol_support_scene_rpc_on_event(NfcApp* instance, SceneManag
|
||||
if(nfc_load_file(instance, instance->file_path, false)) {
|
||||
nfc_protocol_support_scene_rpc_setup_ui_and_emulate(instance);
|
||||
success = true;
|
||||
} else {
|
||||
rpc_system_app_set_error_code(
|
||||
instance->rpc_ctx, RpcAppSystemErrorCodeParseFile);
|
||||
rpc_system_app_set_error_text(instance->rpc_ctx, "Cannot load key file");
|
||||
}
|
||||
}
|
||||
rpc_system_app_confirm(instance->rpc_ctx, success);
|
||||
|
||||
@@ -496,7 +496,7 @@ int32_t nfc_app(void* p) {
|
||||
nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
furi_string_set(nfc->file_path, args);
|
||||
if(nfc_load_file(nfc, nfc->file_path, false)) {
|
||||
if(nfc_load_file(nfc, nfc->file_path, true)) {
|
||||
nfc->fav_timeout = is_favorite;
|
||||
nfc_show_initial_scene_for_device(nfc);
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <flipper_application.h>
|
||||
|
||||
#include <lib/nfc/protocols/mf_desfire/mf_desfire.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
#include <applications/services/locale/locale.h>
|
||||
#include <datetime.h>
|
||||
@@ -72,7 +73,10 @@ static bool itso_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||
dateBuff[17] = '\0';
|
||||
|
||||
// DateStamp is defined in BS EN 1545 - Days passed since 01/01/1997
|
||||
uint32_t dateStamp = (int)strtol(datep, NULL, 16);
|
||||
uint32_t dateStamp;
|
||||
if(strint_to_uint32(datep, NULL, &dateStamp, 16) != StrintParseNoError) {
|
||||
return false;
|
||||
}
|
||||
uint32_t unixTimestamp = dateStamp * 24 * 60 * 60 + 852076800U;
|
||||
|
||||
furi_string_set(parsed_data, "\e#ITSO Card\n");
|
||||
|
||||
@@ -29,7 +29,11 @@ void nfc_scene_start_on_enter(void* context) {
|
||||
|
||||
submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Detect Reader", SubmenuIndexDetectReader, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu,
|
||||
"Extract MF Keys",
|
||||
SubmenuIndexDetectReader,
|
||||
nfc_scene_start_submenu_callback,
|
||||
nfc);
|
||||
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc);
|
||||
|
||||
@@ -20,7 +20,7 @@ static void onewire_cli_search(Cli* cli) {
|
||||
printf("Search started\r\n");
|
||||
|
||||
onewire_host_start(onewire);
|
||||
furi_hal_power_enable_otg();
|
||||
if(!furi_hal_power_is_otg_enabled()) furi_hal_power_enable_otg();
|
||||
|
||||
while(!done) {
|
||||
if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) {
|
||||
@@ -37,7 +37,7 @@ static void onewire_cli_search(Cli* cli) {
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
|
||||
furi_hal_power_disable_otg();
|
||||
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
|
||||
onewire_host_free(onewire);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,9 @@ typedef enum {
|
||||
SetTypePricenton315,
|
||||
SetTypePricenton433,
|
||||
SetTypeBETT_433,
|
||||
SetTypeGangQi_433,
|
||||
SetTypeHollarm_433,
|
||||
SetTypeMarantec24_868,
|
||||
SetTypeLinear_300_00,
|
||||
// SetTypeNeroSketch, //Deleted in OFW
|
||||
// SetTypeNeroRadio, //Deleted in OFW
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
/** SubGhzErrorType */
|
||||
typedef enum {
|
||||
SubGhzErrorTypeNoError = 0, /** There are no errors */
|
||||
SubGhzErrorTypeParseFile =
|
||||
1, /** File parsing error, or wrong file structure, or missing required parameters. more accurate data can be obtained through the debug port */
|
||||
SubGhzErrorTypeOnlyRX =
|
||||
2, /** Transmission on this frequency is blocked by regional settings */
|
||||
SubGhzErrorTypeParserOthers = 3, /** Error in protocol parameters description */
|
||||
} SubGhzErrorType;
|
||||
@@ -382,3 +382,35 @@ bool subghz_txrx_gen_secplus_v1_protocol(
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subghz_txrx_gen_serial_gangqi(uint64_t* result_key) {
|
||||
uint64_t randkey;
|
||||
uint64_t only_required_bytes;
|
||||
uint16_t sum_of_3bytes;
|
||||
uint8_t xorbytes;
|
||||
|
||||
do {
|
||||
randkey = (uint64_t)rand();
|
||||
only_required_bytes = (randkey & 0x0FFFF0000) | 0x200000000;
|
||||
sum_of_3bytes = ((only_required_bytes >> 32) & 0xFF) +
|
||||
((only_required_bytes >> 24) & 0xFF) +
|
||||
((only_required_bytes >> 16) & 0xFF);
|
||||
xorbytes = ((only_required_bytes >> 32) & 0xFF) ^ ((only_required_bytes >> 24) & 0xFF) ^
|
||||
((only_required_bytes >> 16) & 0xFF);
|
||||
} while(
|
||||
!((((!(sum_of_3bytes & 0x3)) && ((0xB < sum_of_3bytes) && (sum_of_3bytes < 0x141))) &&
|
||||
((((only_required_bytes >> 32) & 0xFF) == 0x2) ||
|
||||
(((only_required_bytes >> 32) & 0xFF) == 0x3))) &&
|
||||
((((xorbytes == 0xBA) || (xorbytes == 0xE2)) ||
|
||||
((xorbytes == 0x3A) || (xorbytes == 0xF2))) ||
|
||||
(xorbytes == 0xB2))));
|
||||
|
||||
// Serial 01 button 01
|
||||
uint64_t new_key = only_required_bytes | (0b01 << 14) | (0xD << 10) | (0b01 << 8);
|
||||
|
||||
uint8_t crc = -0xD7 - ((new_key >> 32) & 0xFF) - ((new_key >> 24) & 0xFF) -
|
||||
((new_key >> 16) & 0xFF) - ((new_key >> 8) & 0xFF);
|
||||
|
||||
// Add crc sum to the end
|
||||
*result_key = (new_key | crc);
|
||||
}
|
||||
|
||||
@@ -146,3 +146,10 @@ bool subghz_txrx_gen_secplus_v1_protocol(
|
||||
SubGhzTxRx* instance,
|
||||
const char* name_preset,
|
||||
uint32_t frequency);
|
||||
|
||||
/**
|
||||
* Generate valid serial number for GangQi protocol
|
||||
*
|
||||
* @return uint64_t if success
|
||||
*/
|
||||
void subghz_txrx_gen_serial_gangqi(uint64_t* result_key);
|
||||
|
||||
@@ -10,23 +10,33 @@ typedef enum {
|
||||
|
||||
void subghz_scene_rpc_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
|
||||
}
|
||||
|
||||
static void subghz_format_file_name_tmp(SubGhz* subghz) {
|
||||
FuriString* file_name;
|
||||
file_name = furi_string_alloc();
|
||||
path_extract_filename(subghz->file_path, file_name, true);
|
||||
snprintf(
|
||||
subghz->file_name_tmp, SUBGHZ_MAX_LEN_NAME, "loaded\n%s", furi_string_get_cstr(file_name));
|
||||
furi_string_free(file_name);
|
||||
}
|
||||
|
||||
static void subghz_scene_rpc_emulation_show(SubGhz* subghz) {
|
||||
Popup* popup = subghz->popup;
|
||||
|
||||
subghz_format_file_name_tmp(subghz);
|
||||
popup_set_header(popup, "Sub-GHz", 89, 42, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
|
||||
|
||||
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
|
||||
popup_set_text(popup, subghz->file_name_tmp, 89, 44, AlignCenter, AlignTop);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
|
||||
|
||||
scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
|
||||
|
||||
notification_message(subghz->notifications, &sequence_display_backlight_on);
|
||||
}
|
||||
|
||||
bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
Popup* popup = subghz->popup;
|
||||
bool consumed = false;
|
||||
SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc);
|
||||
|
||||
@@ -45,13 +55,15 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
switch(
|
||||
subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) {
|
||||
case SubGhzTxRxStartTxStateErrorOnlyRx:
|
||||
rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeOnlyRX);
|
||||
rpc_system_app_set_error_code(
|
||||
subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock);
|
||||
rpc_system_app_set_error_text(
|
||||
subghz->rpc_ctx,
|
||||
"Transmission on this frequency is restricted in your settings");
|
||||
break;
|
||||
case SubGhzTxRxStartTxStateErrorParserOthers:
|
||||
rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeParserOthers);
|
||||
rpc_system_app_set_error_code(
|
||||
subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse);
|
||||
rpc_system_app_set_error_text(
|
||||
subghz->rpc_ctx, "Error in protocol parameters description");
|
||||
break;
|
||||
@@ -79,22 +91,12 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
bool result = false;
|
||||
if(state == SubGhzRpcStateIdle) {
|
||||
if(subghz_key_load(subghz, furi_string_get_cstr(subghz->file_path), false)) {
|
||||
subghz_scene_rpc_emulation_show(subghz);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded);
|
||||
result = true;
|
||||
FuriString* file_name = furi_string_alloc();
|
||||
path_extract_filename(subghz->file_path, file_name, true);
|
||||
|
||||
snprintf(
|
||||
subghz->file_name_tmp,
|
||||
SUBGHZ_MAX_LEN_NAME,
|
||||
"loaded\n%s",
|
||||
furi_string_get_cstr(file_name));
|
||||
popup_set_text(popup, subghz->file_name_tmp, 89, 44, AlignCenter, AlignTop);
|
||||
|
||||
furi_string_free(file_name);
|
||||
} else {
|
||||
rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeParseFile);
|
||||
rpc_system_app_set_error_code(subghz->rpc_ctx, RpcAppSystemErrorCodeParseFile);
|
||||
rpc_system_app_set_error_text(subghz->rpc_ctx, "Cannot parse file");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
furi_string_set(subghz->file_path, dir_name);
|
||||
}
|
||||
|
||||
strncpy(subghz->file_name_tmp, furi_string_get_cstr(file_name), SUBGHZ_MAX_LEN_NAME);
|
||||
strlcpy(subghz->file_name_tmp, furi_string_get_cstr(file_name), SUBGHZ_MAX_LEN_NAME);
|
||||
text_input_set_header_text(text_input, "Name signal");
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
|
||||
@@ -63,6 +63,9 @@ static const char* submenu_names[SetTypeMAX] = {
|
||||
[SetTypeCAMESpace] = "KL: CAME Space 433MHz",
|
||||
[SetTypePricenton315] = "Princeton 315MHz",
|
||||
[SetTypePricenton433] = "Princeton 433MHz",
|
||||
[SetTypeGangQi_433] = "GangQi 433MHz",
|
||||
[SetTypeHollarm_433] = "Hollarm 433MHz",
|
||||
[SetTypeMarantec24_868] = "Marantec24 868MHz",
|
||||
[SetTypeBETT_433] = "BETT 433MHz",
|
||||
[SetTypeLinear_300_00] = "Linear 300MHz",
|
||||
// [SetTypeNeroSketch] = "Nero Sketch", // Deleted in OFW
|
||||
@@ -111,7 +114,7 @@ typedef struct {
|
||||
union {
|
||||
struct {
|
||||
const char* name;
|
||||
uint32_t key;
|
||||
uint64_t key;
|
||||
uint8_t bits;
|
||||
uint16_t te;
|
||||
} data;
|
||||
@@ -179,7 +182,11 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t key = (uint32_t)rand();
|
||||
uint64_t key = (uint64_t)rand();
|
||||
|
||||
uint64_t gangqi_key;
|
||||
subghz_txrx_gen_serial_gangqi(&gangqi_key);
|
||||
|
||||
GenInfo gen_info = {0};
|
||||
switch(event.event) {
|
||||
case SetTypePricenton433:
|
||||
@@ -302,6 +309,42 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
.data.bits = 24,
|
||||
.data.te = 0};
|
||||
break;
|
||||
case SetTypeGangQi_433:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenData,
|
||||
.mod = "AM650",
|
||||
.freq = 433920000,
|
||||
.data.name =
|
||||
SUBGHZ_PROTOCOL_GANGQI_NAME, // Add button 0xD arm and crc sum to the end
|
||||
.data.key = gangqi_key,
|
||||
.data.bits = 34,
|
||||
.data.te = 0};
|
||||
break;
|
||||
case SetTypeHollarm_433:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenData,
|
||||
.mod = "AM650",
|
||||
.freq = 433920000,
|
||||
.data.name = SUBGHZ_PROTOCOL_HOLLARM_NAME, // Add button 0x2 and crc sum to the end
|
||||
.data.key = (key & 0x000FFF0000) | 0xF0B0002200 |
|
||||
((((((key & 0x000FFF0000) | 0xF0B0002200) >> 32) & 0xFF) +
|
||||
((((key & 0x000FFF0000) | 0xF0B0002200) >> 24) & 0xFF) +
|
||||
((((key & 0x000FFF0000) | 0xF0B0002200) >> 16) & 0xFF) +
|
||||
((((key & 0x000FFF0000) | 0xF0B0002200) >> 8) & 0xFF)) &
|
||||
0xFF),
|
||||
.data.bits = 42,
|
||||
.data.te = 0};
|
||||
break;
|
||||
case SetTypeMarantec24_868:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenData,
|
||||
.mod = "AM650",
|
||||
.freq = 868350000,
|
||||
.data.name = SUBGHZ_PROTOCOL_MARANTEC24_NAME, // Add button code 0x8 to the end
|
||||
.data.key = (key & 0xFFFFF0) | 0x000008,
|
||||
.data.bits = 24,
|
||||
.data.te = 0};
|
||||
break;
|
||||
case SetTypeFaacSLH_433:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenFaacSLH,
|
||||
@@ -321,7 +364,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
.faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4,
|
||||
.faac_slh.btn = 0x06,
|
||||
.faac_slh.cnt = 0x02,
|
||||
.faac_slh.seed = key,
|
||||
.faac_slh.seed = (key & 0x0FFFFFFF),
|
||||
.faac_slh.manuf = "FAAC_SLH"};
|
||||
break;
|
||||
case SetTypeBeninca433:
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/subghz/subghz_keystore.h>
|
||||
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||
|
||||
#include <lib/subghz/subghz_keystore.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
#include <lib/subghz/subghz_file_encoder_worker.h>
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
|
||||
#include <lib/subghz/devices/devices.h>
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
#include "helpers/subghz_chat.h"
|
||||
|
||||
#include <notification/notification_messages.h>
|
||||
@@ -76,9 +78,8 @@ void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t frequency = 433920000;
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency);
|
||||
if(ret != 1) {
|
||||
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &frequency, 10) !=
|
||||
StrintParseNoError) {
|
||||
cli_print_usage("subghz tx_carrier", "<Frequency: in Hz>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
@@ -120,9 +121,8 @@ void subghz_cli_command_rx_carrier(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t frequency = 433920000;
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency);
|
||||
if(ret != 1) {
|
||||
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &frequency, 10) !=
|
||||
StrintParseNoError) {
|
||||
cli_print_usage("subghz rx_carrier", "<Frequency: in Hz>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
@@ -186,23 +186,14 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(
|
||||
furi_string_get_cstr(args),
|
||||
"%lx %lu %lu %lu %lu",
|
||||
&key,
|
||||
&frequency,
|
||||
&te,
|
||||
&repeat,
|
||||
&device_ind);
|
||||
if(ret != 5) {
|
||||
printf(
|
||||
"sscanf returned %d, key: %lx, frequency: %lu, te: %lu, repeat: %lu, device: %lu\r\n ",
|
||||
ret,
|
||||
key,
|
||||
frequency,
|
||||
te,
|
||||
repeat,
|
||||
device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &key, 16);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &te, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &repeat, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz tx",
|
||||
"<3 Byte Key: in hex> <Frequency: in Hz> <Te us> <Repeat count> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
@@ -318,10 +309,11 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind);
|
||||
if(ret != 2) {
|
||||
printf(
|
||||
"sscanf returned %d, frequency: %lu device: %lu\r\n", ret, frequency, device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz rx",
|
||||
"<Frequency: in Hz> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
@@ -405,9 +397,8 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t frequency = 433920000;
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency);
|
||||
if(ret != 1) {
|
||||
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &frequency, 10) !=
|
||||
StrintParseNoError) {
|
||||
cli_print_usage("subghz rx", "<Frequency: in Hz>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
@@ -624,9 +615,11 @@ void subghz_cli_command_tx_from_file(Cli* cli, FuriString* args, void* context)
|
||||
}
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &repeat, &device_ind);
|
||||
if(ret != 2) {
|
||||
printf("sscanf returned %d, repeat: %lu device: %lu\r\n", ret, repeat, device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz tx_from_file:",
|
||||
"<file_name: path_file> <Repeat count> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
@@ -939,10 +932,11 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) {
|
||||
uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind);
|
||||
if(ret != 2) {
|
||||
printf("sscanf returned %d, Frequency: %lu\r\n", ret, frequency);
|
||||
printf("sscanf returned %d, Device: %lu\r\n", ret, device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz chat",
|
||||
"<Frequency: in Hz> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/subghz_types.h"
|
||||
#include "helpers/subghz_error_type.h"
|
||||
#include <lib/subghz/types.h>
|
||||
#include "subghz.h"
|
||||
#include "views/receiver.h"
|
||||
|
||||
Reference in New Issue
Block a user