Merge branch 'release-candidate' into release
This commit is contained in:
commit
d294b5e256
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -25,6 +25,7 @@ applications/sd-filesystem/** @skotopes @DrZlo13
|
||||
applications/subghz/** @skotopes @DrZlo13
|
||||
applications/template/** @skotopes @DrZlo13
|
||||
applications/tests/** @skotopes @DrZlo13
|
||||
applications/updater/** @skotopes @DrZlo13 @hedger
|
||||
|
||||
# Assets and asset generator
|
||||
assets/** @skotopes @DrZlo13
|
||||
|
||||
28
.github/workflows/build.yml
vendored
28
.github/workflows/build.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
run: |
|
||||
test -d artifacts && rm -rf artifacts || true
|
||||
mkdir artifacts
|
||||
|
||||
|
||||
- name: 'Generate suffix and folder name'
|
||||
id: names
|
||||
run: |
|
||||
@ -52,13 +52,13 @@ jobs:
|
||||
fi
|
||||
BRANCH_OR_TAG=${REF#refs/*/}
|
||||
SHA=$(git rev-parse --short HEAD)
|
||||
|
||||
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
SUFFIX=${BRANCH_OR_TAG//\//_}
|
||||
else
|
||||
SUFFIX=${BRANCH_OR_TAG//\//_}-$(date +'%d%m%Y')-${SHA}
|
||||
fi
|
||||
|
||||
|
||||
echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV
|
||||
echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV
|
||||
echo "::set-output name=artifacts-path::${BRANCH_OR_TAG}"
|
||||
@ -86,7 +86,7 @@ jobs:
|
||||
set -e
|
||||
for TARGET in ${TARGETS}
|
||||
do
|
||||
make TARGET=${TARGET} ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
||||
make updater_package TARGET=${TARGET} ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
||||
done
|
||||
|
||||
- name: 'Move upload files'
|
||||
@ -100,6 +100,20 @@ jobs:
|
||||
mv dist/${TARGET}/* artifacts/
|
||||
done
|
||||
|
||||
- name: 'Bundle self-update package'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
uses: ./.github/actions/docker
|
||||
with:
|
||||
run: |
|
||||
set -e
|
||||
for UPDATEBUNDLE in artifacts/*/
|
||||
do
|
||||
BUNDLE_NAME=`echo $UPDATEBUNDLE | cut -d'/' -f2`
|
||||
echo Packaging ${BUNDLE_NAME}
|
||||
tar czpf artifacts/flipper-z-${BUNDLE_NAME}.tgz -C artifacts ${BUNDLE_NAME}
|
||||
rm -rf artifacts/${BUNDLE_NAME}
|
||||
done
|
||||
|
||||
- name: 'Bundle resources'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
run: |
|
||||
@ -175,7 +189,7 @@ jobs:
|
||||
|
||||
- name: 'Build docker image'
|
||||
uses: ./.github/actions/docker
|
||||
|
||||
|
||||
- name: 'Generate suffix and folder name'
|
||||
id: names
|
||||
run: |
|
||||
@ -185,13 +199,13 @@ jobs:
|
||||
fi
|
||||
BRANCH_OR_TAG=${REF#refs/*/}
|
||||
SHA=$(git rev-parse --short HEAD)
|
||||
|
||||
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
SUFFIX=${BRANCH_OR_TAG//\//_}
|
||||
else
|
||||
SUFFIX=${BRANCH_OR_TAG//\//_}-$(date +'%d%m%Y')-${SHA}
|
||||
fi
|
||||
|
||||
|
||||
echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV
|
||||
echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV
|
||||
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -36,3 +36,6 @@ CMakeLists.txt
|
||||
|
||||
# bundle output
|
||||
dist
|
||||
|
||||
# kde
|
||||
.directory
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -19,3 +19,6 @@
|
||||
[submodule "lib/FreeRTOS-Kernel"]
|
||||
path = lib/FreeRTOS-Kernel
|
||||
url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git
|
||||
[submodule "lib/microtar"]
|
||||
path = lib/microtar
|
||||
url = https://github.com/amachronic/microtar.git
|
||||
|
||||
52
Makefile
52
Makefile
@ -1,16 +1,16 @@
|
||||
PROJECT_ROOT := $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
|
||||
|
||||
include $(PROJECT_ROOT)/make/git.mk
|
||||
|
||||
COPRO_DIR := $(PROJECT_ROOT)/lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
|
||||
|
||||
PROJECT_SOURCE_DIRECTORIES := \
|
||||
$(PROJECT_ROOT)/applications \
|
||||
$(PROJECT_ROOT)/bootloader/src \
|
||||
$(PROJECT_ROOT)/bootloader/targets \
|
||||
$(PROJECT_ROOT)/core \
|
||||
$(PROJECT_ROOT)/firmware/targets \
|
||||
$(PROJECT_ROOT)/lib/app-template \
|
||||
$(PROJECT_ROOT)/lib/app-scened-template \
|
||||
$(PROJECT_ROOT)/lib/common-api \
|
||||
$(PROJECT_ROOT)/lib/cyfral \
|
||||
$(PROJECT_ROOT)/lib/drivers \
|
||||
$(PROJECT_ROOT)/lib/flipper_file \
|
||||
$(PROJECT_ROOT)/lib/infrared \
|
||||
@ -34,18 +34,18 @@ endif
|
||||
include $(PROJECT_ROOT)/make/defaults.mk
|
||||
|
||||
.PHONY: all
|
||||
all: bootloader_all firmware_all
|
||||
@$(PROJECT_ROOT)/scripts/dist.sh
|
||||
all: firmware_all
|
||||
@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware -s $(DIST_SUFFIX)
|
||||
|
||||
.PHONY: whole
|
||||
whole: flash_radio bootloader_flash firmware_flash
|
||||
whole: flash_radio firmware_flash
|
||||
|
||||
.PHONY: clean
|
||||
clean: bootloader_clean firmware_clean
|
||||
clean: firmware_clean updater_clean
|
||||
@rm -rf $(PROJECT_ROOT)/dist/$(TARGET)
|
||||
|
||||
.PHONY: flash
|
||||
flash: bootloader_flash firmware_flash
|
||||
flash: firmware_flash
|
||||
|
||||
.PHONY: debug
|
||||
debug:
|
||||
@ -60,36 +60,38 @@ wipe:
|
||||
@$(PROJECT_ROOT)/scripts/flash.py wipe
|
||||
@$(PROJECT_ROOT)/scripts/ob.py set
|
||||
|
||||
.PHONY: bootloader_all
|
||||
bootloader_all:
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) all
|
||||
|
||||
.PHONY: firmware_all
|
||||
firmware_all:
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) all
|
||||
|
||||
.PHONY: bootloader_clean
|
||||
bootloader_clean:
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) clean
|
||||
|
||||
.PHONY: firmware_clean
|
||||
firmware_clean:
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) clean
|
||||
|
||||
.PHONY: bootloader_flash
|
||||
bootloader_flash:
|
||||
ifeq ($(FORCE), 1)
|
||||
@rm $(PROJECT_ROOT)/bootloader/.obj/f*/flash || true
|
||||
endif
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) flash
|
||||
|
||||
.PHONY: firmware_flash
|
||||
firmware_flash:
|
||||
ifeq ($(FORCE), 1)
|
||||
@rm $(PROJECT_ROOT)/firmware/.obj/f*/flash || true
|
||||
@rm $(PROJECT_ROOT)/firmware/.obj/f*-firmware/flash || true
|
||||
endif
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash
|
||||
|
||||
|
||||
.PHONY: updater
|
||||
updater:
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all
|
||||
|
||||
.PHONY: updater_clean
|
||||
updater_clean:
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 clean
|
||||
|
||||
.PHONY: updater_debug
|
||||
updater_debug:
|
||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 debug
|
||||
|
||||
.PHONY: updater_package
|
||||
updater_package: firmware_all updater
|
||||
@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)"
|
||||
|
||||
.PHONY: flash_radio
|
||||
flash_radio:
|
||||
@$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080D7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_light_fw.bin
|
||||
@ -100,7 +102,7 @@ flash_radio_fus:
|
||||
@echo
|
||||
@echo "================ DON'T DO IT ================"
|
||||
@echo "= Flashing FUS is going to erase secure enclave ="
|
||||
@echo "= You will loose ability to use encrypted assets ="
|
||||
@echo "= You will lose ability to use encrypted assets ="
|
||||
@echo "= type 'find / -exec rm -rf {} \;' ="
|
||||
@echo "= In case if you still want to continue ="
|
||||
@echo "================ JUST DON'T ================"
|
||||
|
||||
@ -11,17 +11,16 @@ Our goal is to create nice and clean code with good documentation, to make it a
|
||||
|
||||
[Get Latest Firmware from Update Server](https://update.flipperzero.one/)
|
||||
|
||||
Flipper Zero's firmware consists of three components:
|
||||
Flipper Zero's firmware consists of two components:
|
||||
|
||||
- Core2 firmware set - proprietary components by ST: FUS + radio stack. FUS is flashed at factory and you should never update it.
|
||||
- Core1 Bootloader - controls basic hardware initialization and loads firmware.
|
||||
- Core1 Firmware - HAL + OS + Drivers + Applications.
|
||||
|
||||
All 3 of them must be flashed in order described.
|
||||
They both must be flashed in order described.
|
||||
|
||||
## With STLink
|
||||
|
||||
### Core1 Bootloader + Firmware
|
||||
### Core1 Firmware
|
||||
|
||||
Prerequisites:
|
||||
|
||||
@ -144,7 +143,6 @@ make whole
|
||||
|
||||
- `applications` - Applications and services used in firmware
|
||||
- `assets` - Assets used by applications and services
|
||||
- `bootloader` - Bootloader source code
|
||||
- `core` - Furi Core: os level primitives and helpers
|
||||
- `debug` - Debug tool: GDB-plugins, SVD-file and etc
|
||||
- `docker` - Docker image sources (used for firmware build automation)
|
||||
|
||||
@ -35,7 +35,6 @@ Main goal for 1.0.0 is to provide first stable version for both Users and Develo
|
||||
|
||||
## What we're planning to implement in 1.0.0
|
||||
|
||||
- Updating firmware from SD (work in progress, almost done)
|
||||
- Loading applications from SD (tested as PoC, work scheduled for Q2)
|
||||
- More protocols (gathering feedback)
|
||||
- User documentation (work in progress)
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
- `system` - System settings, tools and API
|
||||
- `tests` - Unit tests and etc
|
||||
- `u2f` - U2F Application
|
||||
- `updater` - Update service & application
|
||||
|
||||
- `application.c` - Firmware application list source
|
||||
- `application.h` - Firmware application list header
|
||||
|
||||
@ -82,11 +82,12 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage*
|
||||
|
||||
string_cat_printf(
|
||||
buffer,
|
||||
"%d.F%dB%dC%d %s\n",
|
||||
"%d.F%dB%dC%d %s %s\n",
|
||||
furi_hal_version_get_hw_version(),
|
||||
furi_hal_version_get_hw_target(),
|
||||
furi_hal_version_get_hw_body(),
|
||||
furi_hal_version_get_hw_connect(),
|
||||
furi_hal_version_get_hw_region_name(),
|
||||
my_name ? my_name : "Unknown");
|
||||
|
||||
string_cat_printf(buffer, "Serial number:\n");
|
||||
@ -116,9 +117,10 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage*
|
||||
} else {
|
||||
string_cat_printf(
|
||||
buffer,
|
||||
"%s [%s]\n%s [%s]\n[%d] %s",
|
||||
"%s [%s]\n%s%s [%s]\n[%d] %s",
|
||||
version_get_version(ver),
|
||||
version_get_builddate(ver),
|
||||
version_get_dirty_flag(ver) ? "[!] " : "",
|
||||
version_get_githash(ver),
|
||||
version_get_gitbranchnum(ver),
|
||||
version_get_target(ver),
|
||||
@ -135,36 +137,6 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage*
|
||||
return result;
|
||||
}
|
||||
|
||||
static DialogMessageButton bootloader_version_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
const Version* ver = furi_hal_version_get_bootloader_version();
|
||||
|
||||
if(!ver) {
|
||||
string_cat_printf(buffer, "No info\n");
|
||||
} else {
|
||||
string_cat_printf(
|
||||
buffer,
|
||||
"%s [%s]\n%s [%s]\n[%d] %s",
|
||||
version_get_version(ver),
|
||||
version_get_builddate(ver),
|
||||
version_get_githash(ver),
|
||||
version_get_gitbranchnum(ver),
|
||||
version_get_target(ver),
|
||||
version_get_gitbranch(ver));
|
||||
}
|
||||
|
||||
dialog_message_set_header(message, "Boot Version info:", 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
string_clear(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const AboutDialogScreen about_screens[] = {
|
||||
product_screen,
|
||||
compliance_screen,
|
||||
@ -172,8 +144,7 @@ const AboutDialogScreen about_screens[] = {
|
||||
icon1_screen,
|
||||
icon2_screen,
|
||||
hw_version_screen,
|
||||
fw_version_screen,
|
||||
bootloader_version_screen};
|
||||
fw_version_screen};
|
||||
|
||||
const size_t about_screens_count = sizeof(about_screens) / sizeof(AboutDialogScreen);
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ extern int32_t notification_srv(void* p);
|
||||
extern int32_t power_srv(void* p);
|
||||
extern int32_t storage_srv(void* p);
|
||||
extern int32_t desktop_srv(void* p);
|
||||
extern int32_t updater_srv(void* p);
|
||||
|
||||
// Apps
|
||||
extern int32_t accessor_app(void* p);
|
||||
@ -58,6 +59,7 @@ extern void storage_on_system_start();
|
||||
extern void subghz_on_system_start();
|
||||
extern void power_on_system_start();
|
||||
extern void unit_tests_on_system_start();
|
||||
extern void updater_on_system_start();
|
||||
|
||||
// Settings
|
||||
extern int32_t notification_settings_app(void* p);
|
||||
@ -91,6 +93,9 @@ const FlipperApplication FLIPPER_SERVICES[] = {
|
||||
#endif
|
||||
|
||||
#ifdef SRV_DESKTOP
|
||||
#ifdef SRV_UPDATER
|
||||
#error SRV_UPDATER and SRV_DESKTOP are mutually exclusive!
|
||||
#endif
|
||||
{.app = desktop_srv, .name = "DesktopSrv", .stack_size = 2048, .icon = NULL},
|
||||
#endif
|
||||
|
||||
@ -117,9 +122,27 @@ const FlipperApplication FLIPPER_SERVICES[] = {
|
||||
#ifdef SRV_STORAGE
|
||||
{.app = storage_srv, .name = "StorageSrv", .stack_size = 3072, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef SRV_UPDATER
|
||||
#ifdef SRV_DESKTOP
|
||||
#error SRV_UPDATER and SRV_DESKTOP are mutually exclusive!
|
||||
#endif
|
||||
{.app = updater_srv, .name = "UpdaterSrv", .stack_size = 2048, .icon = NULL},
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(FlipperApplication);
|
||||
const size_t FLIPPER_SERVICES_COUNT = COUNT_OF(FLIPPER_SERVICES);
|
||||
|
||||
const FlipperApplication FLIPPER_SYSTEM_APPS[] = {
|
||||
#ifdef APP_UPDATER
|
||||
#ifdef SRV_UPDATER
|
||||
#error APP_UPDATER and SRV_UPDATER are mutually exclusive!
|
||||
#endif
|
||||
{.app = updater_srv, .name = "UpdaterApp", .stack_size = 2048, .icon = NULL},
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_SYSTEM_APPS_COUNT = COUNT_OF(FLIPPER_SYSTEM_APPS);
|
||||
|
||||
// Main menu APP
|
||||
const FlipperApplication FLIPPER_APPS[] = {
|
||||
@ -158,7 +181,7 @@ const FlipperApplication FLIPPER_APPS[] = {
|
||||
|
||||
};
|
||||
|
||||
const size_t FLIPPER_APPS_COUNT = sizeof(FLIPPER_APPS) / sizeof(FlipperApplication);
|
||||
const size_t FLIPPER_APPS_COUNT = COUNT_OF(FLIPPER_APPS);
|
||||
|
||||
// On system start hooks
|
||||
const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = {
|
||||
@ -199,15 +222,18 @@ const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = {
|
||||
#ifdef APP_UNIT_TESTS
|
||||
unit_tests_on_system_start,
|
||||
#endif
|
||||
|
||||
#ifdef APP_UPDATER
|
||||
updater_on_system_start,
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_ON_SYSTEM_START_COUNT =
|
||||
sizeof(FLIPPER_ON_SYSTEM_START) / sizeof(FlipperOnStartHook);
|
||||
const size_t FLIPPER_ON_SYSTEM_START_COUNT = COUNT_OF(FLIPPER_ON_SYSTEM_START);
|
||||
|
||||
// Plugin menu
|
||||
const FlipperApplication FLIPPER_PLUGINS[] = {
|
||||
#ifdef APP_BLE_HID
|
||||
{.app = bt_hid_app, .name = "Bluetooth remote", .stack_size = 1024, .icon = NULL},
|
||||
{.app = bt_hid_app, .name = "Bluetooth Remote", .stack_size = 1024, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef APP_MUSIC_PLAYER
|
||||
@ -219,7 +245,7 @@ const FlipperApplication FLIPPER_PLUGINS[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_PLUGINS_COUNT = sizeof(FLIPPER_PLUGINS) / sizeof(FlipperApplication);
|
||||
const size_t FLIPPER_PLUGINS_COUNT = COUNT_OF(FLIPPER_PLUGINS);
|
||||
|
||||
// Plugin menu
|
||||
const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
||||
@ -244,7 +270,7 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
||||
#endif
|
||||
|
||||
#ifdef APP_USB_MOUSE
|
||||
{.app = usb_mouse_app, .name = "USB Mouse demo", .stack_size = 1024, .icon = NULL},
|
||||
{.app = usb_mouse_app, .name = "USB Mouse Demo", .stack_size = 1024, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef APP_UART_ECHO
|
||||
@ -280,7 +306,7 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication);
|
||||
const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS);
|
||||
|
||||
#ifdef APP_ARCHIVE
|
||||
const FlipperApplication FLIPPER_ARCHIVE =
|
||||
@ -295,7 +321,7 @@ const FlipperApplication FLIPPER_SETTINGS_APPS[] = {
|
||||
|
||||
#ifdef SRV_NOTIFICATION
|
||||
{.app = notification_settings_app,
|
||||
.name = "LCD and notifications",
|
||||
.name = "LCD and Notifications",
|
||||
.stack_size = 1024,
|
||||
.icon = NULL},
|
||||
#endif
|
||||
@ -325,5 +351,4 @@ const FlipperApplication FLIPPER_SETTINGS_APPS[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_SETTINGS_APPS_COUNT =
|
||||
sizeof(FLIPPER_SETTINGS_APPS) / sizeof(FlipperApplication);
|
||||
const size_t FLIPPER_SETTINGS_APPS_COUNT = COUNT_OF(FLIPPER_SETTINGS_APPS);
|
||||
|
||||
@ -42,6 +42,12 @@ extern const size_t FLIPPER_PLUGINS_COUNT;
|
||||
extern const FlipperApplication FLIPPER_DEBUG_APPS[];
|
||||
extern const size_t FLIPPER_DEBUG_APPS_COUNT;
|
||||
|
||||
/* System apps
|
||||
* Can only be spawned by loader by name
|
||||
*/
|
||||
extern const FlipperApplication FLIPPER_SYSTEM_APPS[];
|
||||
extern const size_t FLIPPER_SYSTEM_APPS_COUNT;
|
||||
|
||||
/* Seperate scene app holder
|
||||
* Spawned by loader
|
||||
*/
|
||||
@ -55,4 +61,4 @@ extern const FlipperApplication FLIPPER_ARCHIVE;
|
||||
* Spawned by loader
|
||||
*/
|
||||
extern const FlipperApplication FLIPPER_SETTINGS_APPS[];
|
||||
extern const size_t FLIPPER_SETTINGS_APPS_COUNT;
|
||||
extern const size_t FLIPPER_SETTINGS_APPS_COUNT;
|
||||
|
||||
@ -5,6 +5,16 @@ CFLAGS += -I$(APP_DIR)
|
||||
C_SOURCES += $(shell find $(APP_DIR) -name "*.c")
|
||||
CPP_SOURCES += $(shell find $(APP_DIR) -name "*.cpp")
|
||||
|
||||
RAM_EXEC ?= 0
|
||||
ifeq ($(RAM_EXEC), 1)
|
||||
APP_RELEASE = 0
|
||||
SRV_GUI = 1
|
||||
SRV_INPUT = 1
|
||||
SRV_NOTIFICATION = 1
|
||||
SRV_STORAGE = 1
|
||||
SRV_UPDATER = 1
|
||||
APP_UPDATER = 0
|
||||
endif
|
||||
|
||||
APP_RELEASE ?= 1
|
||||
ifeq ($(APP_RELEASE), 1)
|
||||
@ -18,13 +28,13 @@ SRV_INPUT = 1
|
||||
SRV_LOADER = 1
|
||||
SRV_NOTIFICATION = 1
|
||||
SRV_POWER = 1
|
||||
SRV_RPC = 1
|
||||
SRV_RPC = 1
|
||||
SRV_STORAGE = 1
|
||||
|
||||
# Apps
|
||||
SRV_DESKTOP = 1
|
||||
APP_ARCHIVE = 1
|
||||
APP_GPIO = 1
|
||||
APP_GPIO = 1
|
||||
APP_IBUTTON = 1
|
||||
APP_INFRARED = 1
|
||||
APP_LF_RFID = 1
|
||||
@ -32,6 +42,7 @@ APP_NFC = 1
|
||||
APP_SUBGHZ = 1
|
||||
APP_ABOUT = 1
|
||||
APP_PASSPORT = 1
|
||||
APP_UPDATER = 1
|
||||
|
||||
# Plugins
|
||||
APP_MUSIC_PLAYER = 1
|
||||
@ -223,6 +234,14 @@ CFLAGS += -DAPP_IBUTTON
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_UPDATER ?= 0
|
||||
ifeq ($(APP_UPDATER), 1)
|
||||
CFLAGS += -DAPP_UPDATER
|
||||
SRV_GUI = 1
|
||||
SRV_STORAGE = 1
|
||||
SRV_NOTIFICATION = 1
|
||||
SRV_INPUT = 1
|
||||
endif
|
||||
|
||||
# Services
|
||||
# that will start with OS
|
||||
@ -245,6 +264,14 @@ SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
||||
SRV_UPDATER ?= 0
|
||||
ifeq ($(SRV_UPDATER), 1)
|
||||
CFLAGS += -DSRV_UPDATER
|
||||
SRV_STORAGE = 1
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
||||
SRV_DOLPHIN ?= 0
|
||||
ifeq ($(SRV_DOLPHIN), 1)
|
||||
CFLAGS += -DSRV_DOLPHIN
|
||||
|
||||
@ -21,13 +21,23 @@ bool archive_app_is_available(void* context, const char* path) {
|
||||
ArchiveAppTypeEnum app = archive_get_app_type(path);
|
||||
|
||||
if(app == ArchiveAppTypeU2f) {
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, "/any/u2f/key.u2f", &file_exists);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
file_exists = storage_file_open(file, "/any/u2f/key.u2f", FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(file_exists) {
|
||||
file_worker_is_file_exist(file_worker, "/any/u2f/cnt.u2f", &file_exists);
|
||||
storage_file_close(file);
|
||||
file_exists =
|
||||
storage_file_open(file, "/any/u2f/cnt.u2f", FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(file_exists) {
|
||||
storage_file_close(file);
|
||||
}
|
||||
}
|
||||
file_worker_free(file_worker);
|
||||
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return file_exists;
|
||||
} else {
|
||||
return false;
|
||||
@ -60,10 +70,10 @@ void archive_app_delete_file(void* context, const char* path) {
|
||||
bool res = false;
|
||||
|
||||
if(app == ArchiveAppTypeU2f) {
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
res = file_worker_remove(file_worker, "/any/u2f/key.u2f");
|
||||
res |= file_worker_remove(file_worker, "/any/u2f/cnt.u2f");
|
||||
file_worker_free(file_worker);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
res = (storage_common_remove(fs_api, "/any/u2f/key.u2f") == FSE_OK);
|
||||
res |= (storage_common_remove(fs_api, "/any/u2f/cnt.u2f") == FSE_OK);
|
||||
furi_record_close("storage");
|
||||
|
||||
if(archive_is_favorite("/app:u2f/U2F Token")) {
|
||||
archive_favorites_delete("/app:u2f/U2F Token");
|
||||
|
||||
@ -120,13 +120,12 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) {
|
||||
ArchiveFile_t_clear(&temp);
|
||||
} else if(model->item_idx == array_size && dir > 0) {
|
||||
ArchiveFile_t_init(&temp);
|
||||
files_array_pop_at(&temp, model->files, model->item_idx);
|
||||
files_array_pop_at(&temp, model->files, 0);
|
||||
files_array_push_at(model->files, array_size, temp);
|
||||
ArchiveFile_t_clear(&temp);
|
||||
} else {
|
||||
files_array_swap_at(model->files, model->item_idx, swap_idx);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
@ -392,6 +391,17 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) {
|
||||
furi_assert(browser);
|
||||
furi_assert(name);
|
||||
|
||||
uint8_t browser_depth = 0;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser_depth = idx_last_array_size(model->idx_last);
|
||||
return false;
|
||||
});
|
||||
|
||||
if(browser_depth > BROWSER_DEPTH_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
archive_dir_count_items(browser, string_get_cstr(name));
|
||||
|
||||
with_view_model(
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#define TAB_RIGHT InputKeyRight //default tab swith direction
|
||||
#define FILE_LIST_BUF_LEN 100
|
||||
#define BROWSER_DEPTH_MAX 8
|
||||
|
||||
static const char* tab_default_paths[] = {
|
||||
[ArchiveTabFavorites] = "/any/favorites",
|
||||
@ -25,6 +26,7 @@ static const char* known_ext[] = {
|
||||
[ArchiveFileTypeInfrared] = ".ir",
|
||||
[ArchiveFileTypeBadUsb] = ".txt",
|
||||
[ArchiveFileTypeU2f] = "?",
|
||||
[ArchiveFileTypeUpdateManifest] = ".fuf",
|
||||
[ArchiveFileTypeFolder] = "?",
|
||||
[ArchiveFileTypeUnknown] = "*",
|
||||
};
|
||||
|
||||
@ -4,20 +4,63 @@
|
||||
#include "archive_apps.h"
|
||||
#include "archive_browser.h"
|
||||
|
||||
#define ARCHIVE_FAV_FILE_BUF_LEN 32
|
||||
|
||||
static bool archive_favorites_read_line(File* file, string_t str_result) {
|
||||
string_reset(str_result);
|
||||
uint8_t buffer[ARCHIVE_FAV_FILE_BUF_LEN];
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
uint16_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN);
|
||||
if(storage_file_get_error(file) != FSE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < read_count; i++) {
|
||||
if(buffer[i] == '\n') {
|
||||
uint32_t position = storage_file_tell(file);
|
||||
if(storage_file_get_error(file) != FSE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
position = position - read_count + i + 1;
|
||||
|
||||
storage_file_seek(file, position, true);
|
||||
if(storage_file_get_error(file) != FSE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
result = true;
|
||||
break;
|
||||
} else {
|
||||
string_push_back(str_result, buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(result || read_count == 0) {
|
||||
break;
|
||||
}
|
||||
} while(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t archive_favorites_count(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
uint16_t lines = 0;
|
||||
|
||||
if(result) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@ -27,21 +70,26 @@ uint16_t archive_favorites_count(void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
storage_file_close(file);
|
||||
|
||||
string_clear(buffer);
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
static bool archive_favourites_rescan() {
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
File* fav_item_file = storage_file_alloc(fs_api);
|
||||
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(result) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@ -53,10 +101,13 @@ static bool archive_favourites_rescan() {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
}
|
||||
} else {
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
bool file_exists = storage_file_open(
|
||||
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(file_exists) {
|
||||
storage_file_close(fav_item_file);
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
} else {
|
||||
storage_file_close(fav_item_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,11 +115,14 @@ static bool archive_favourites_rescan() {
|
||||
|
||||
string_clear(buffer);
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
||||
storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
|
||||
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
storage_file_free(fav_item_file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -77,7 +131,9 @@ bool archive_favorites_read(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
ArchiveBrowserView* browser = context;
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
File* fav_item_file = storage_file_alloc(fs_api);
|
||||
|
||||
string_t buffer;
|
||||
FileInfo file_info;
|
||||
@ -88,11 +144,11 @@ bool archive_favorites_read(void* context) {
|
||||
|
||||
archive_file_array_rm_all(browser);
|
||||
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
|
||||
if(result) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@ -107,13 +163,15 @@ bool archive_favorites_read(void* context) {
|
||||
need_refresh = true;
|
||||
}
|
||||
} else {
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
|
||||
bool file_exists = storage_file_open(
|
||||
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(file_exists) {
|
||||
storage_common_stat(fs_api, string_get_cstr(buffer), &file_info);
|
||||
storage_file_close(fav_item_file);
|
||||
archive_add_file_item(browser, &file_info, string_get_cstr(buffer));
|
||||
file_count++;
|
||||
} else {
|
||||
storage_file_close(fav_item_file);
|
||||
need_refresh = true;
|
||||
}
|
||||
}
|
||||
@ -121,9 +179,11 @@ bool archive_favorites_read(void* context) {
|
||||
string_reset(buffer);
|
||||
}
|
||||
}
|
||||
storage_file_close(file);
|
||||
string_clear(buffer);
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
storage_file_free(fav_item_file);
|
||||
furi_record_close("storage");
|
||||
|
||||
archive_set_item_count(browser, file_count);
|
||||
|
||||
@ -143,12 +203,14 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
va_end(args);
|
||||
|
||||
string_init(buffer);
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(result) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@ -164,11 +226,13 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
||||
storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
|
||||
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -182,14 +246,15 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
va_end(args);
|
||||
|
||||
string_init(buffer);
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
bool found = false;
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
|
||||
if(result) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@ -202,10 +267,11 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
storage_file_close(file);
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return found;
|
||||
}
|
||||
@ -214,7 +280,8 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
furi_assert(src);
|
||||
furi_assert(dst);
|
||||
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
string_t path;
|
||||
string_t buffer;
|
||||
@ -223,11 +290,11 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
string_init(path);
|
||||
|
||||
string_printf(path, "%s", src);
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
|
||||
if(result) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@ -244,11 +311,13 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
string_clear(buffer);
|
||||
string_clear(path);
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
||||
storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
|
||||
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -263,15 +332,18 @@ void archive_favorites_save(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
ArchiveBrowserView* browser = context;
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
for(size_t i = 0; i < archive_file_get_array_size(browser); i++) {
|
||||
ArchiveFile_t* item = archive_get_file_at(browser, i);
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->name));
|
||||
}
|
||||
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
||||
storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
|
||||
|
||||
file_worker_free(file_worker);
|
||||
}
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "file_worker.h"
|
||||
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define ARCHIVE_FAV_PATH "/any/favorites.txt"
|
||||
#define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp"
|
||||
|
||||
@ -201,18 +201,18 @@ void archive_file_append(const char* path, const char* format, ...) {
|
||||
string_init_vprintf(string, format, args);
|
||||
va_end(args);
|
||||
|
||||
FileWorker* file_worker = file_worker_alloc(false);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) {
|
||||
FURI_LOG_E(TAG, "Append open error");
|
||||
bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND);
|
||||
|
||||
if(res) {
|
||||
storage_file_write(file, string_get_cstr(string), string_size(string));
|
||||
}
|
||||
|
||||
if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) {
|
||||
FURI_LOG_E(TAG, "Append write error");
|
||||
}
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
void archive_delete_file(void* context, const char* format, ...) {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "file_worker.h"
|
||||
|
||||
#include <m-array.h>
|
||||
#include <m-string.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
typedef enum {
|
||||
ArchiveFileTypeIButton,
|
||||
@ -10,6 +12,7 @@ typedef enum {
|
||||
ArchiveFileTypeInfrared,
|
||||
ArchiveFileTypeBadUsb,
|
||||
ArchiveFileTypeU2f,
|
||||
ArchiveFileTypeUpdateManifest,
|
||||
ArchiveFileTypeFolder,
|
||||
ArchiveFileTypeUnknown,
|
||||
ArchiveFileTypeLoading,
|
||||
|
||||
@ -15,6 +15,7 @@ static const char* flipper_app_name[] = {
|
||||
[ArchiveFileTypeInfrared] = "Infrared",
|
||||
[ArchiveFileTypeBadUsb] = "Bad USB",
|
||||
[ArchiveFileTypeU2f] = "U2F",
|
||||
[ArchiveFileTypeUpdateManifest] = "UpdaterApp",
|
||||
};
|
||||
|
||||
static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected) {
|
||||
|
||||
@ -12,7 +12,8 @@ static const char* ArchiveTabNames[] = {
|
||||
[ArchiveTabInfrared] = "Infrared",
|
||||
[ArchiveTabBadUsb] = "Bad USB",
|
||||
[ArchiveTabU2f] = "U2F",
|
||||
[ArchiveTabBrowser] = "Browser"};
|
||||
[ArchiveTabBrowser] = "Browser",
|
||||
};
|
||||
|
||||
static const Icon* ArchiveItemIcons[] = {
|
||||
[ArchiveFileTypeIButton] = &I_ibutt_10px,
|
||||
@ -22,6 +23,7 @@ static const Icon* ArchiveItemIcons[] = {
|
||||
[ArchiveFileTypeInfrared] = &I_ir_10px,
|
||||
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
|
||||
[ArchiveFileTypeU2f] = &I_u2f_10px,
|
||||
[ArchiveFileTypeUpdateManifest] = &I_update_10px,
|
||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
||||
[ArchiveFileTypeLoading] = &I_unknown_10px, // TODO loading icon
|
||||
@ -52,6 +54,10 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
|
||||
ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset);
|
||||
|
||||
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
}
|
||||
|
||||
if(!archive_is_known_app(selected->type)) {
|
||||
string_set_str(menu[0], "---");
|
||||
string_set_str(menu[1], "---");
|
||||
@ -65,10 +71,6 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
}
|
||||
}
|
||||
|
||||
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < MENU_ITEMS; i++) {
|
||||
canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i]));
|
||||
string_clear(menu[i]);
|
||||
@ -374,4 +376,4 @@ void browser_free(ArchiveBrowserView* browser) {
|
||||
|
||||
view_free(browser->view);
|
||||
free(browser);
|
||||
}
|
||||
}
|
||||
@ -244,5 +244,7 @@ void bt_on_system_start() {
|
||||
cli_add_command(cli, "bt", CliCommandFlagDefault, bt_cli, NULL);
|
||||
furi_record_close("bt");
|
||||
furi_record_close("cli");
|
||||
#else
|
||||
UNUSED(bt_cli);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -54,7 +54,7 @@ void bt_settings_scene_start_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, BtSettingOff);
|
||||
variable_item_set_current_value_text(item, bt_settings_text[BtSettingOff]);
|
||||
}
|
||||
variable_item_list_add(var_item_list, "Forget all paired devices", 1, NULL, NULL);
|
||||
variable_item_list_add(var_item_list, "Forget All Paired Devices", 1, NULL, NULL);
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, bt_settings_scene_start_var_list_enter_callback, app);
|
||||
} else {
|
||||
|
||||
@ -95,10 +95,11 @@ void cli_motd() {
|
||||
const Version* firmware_version = furi_hal_version_get_firmware_version();
|
||||
if(firmware_version) {
|
||||
printf(
|
||||
"Firmware version: %s %s (%s built on %s)\r\n",
|
||||
"Firmware version: %s %s (%s%s built on %s)\r\n",
|
||||
version_get_gitbranch(firmware_version),
|
||||
version_get_version(firmware_version),
|
||||
version_get_githash(firmware_version),
|
||||
version_get_dirty_flag(firmware_version) ? "-dirty" : "",
|
||||
version_get_builddate(firmware_version));
|
||||
}
|
||||
}
|
||||
@ -400,6 +401,8 @@ void cli_delete_command(Cli* cli, const char* name) {
|
||||
int32_t cli_srv(void* p) {
|
||||
Cli* cli = cli_alloc();
|
||||
|
||||
furi_hal_vcp_init();
|
||||
|
||||
// Init basic cli commands
|
||||
cli_commands_init(cli);
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <time.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <loader/loader.h>
|
||||
#include <stream_buffer.h>
|
||||
|
||||
// Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'`
|
||||
#define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d"
|
||||
@ -126,11 +127,28 @@ void cli_command_date(Cli* cli, string_t args, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
#define CLI_COMMAND_LOG_RING_SIZE 2048
|
||||
#define CLI_COMMAND_LOG_BUFFER_SIZE 64
|
||||
|
||||
void cli_command_log_tx_callback(const uint8_t* buffer, size_t size, void* context) {
|
||||
xStreamBufferSend(context, buffer, size, 0);
|
||||
}
|
||||
|
||||
void cli_command_log(Cli* cli, string_t args, void* context) {
|
||||
furi_stdglue_set_global_stdout_callback(cli_stdout_callback);
|
||||
printf("Press any key to stop...\r\n");
|
||||
cli_getc(cli);
|
||||
furi_stdglue_set_global_stdout_callback(NULL);
|
||||
StreamBufferHandle_t ring = xStreamBufferCreate(CLI_COMMAND_LOG_RING_SIZE, 1);
|
||||
uint8_t buffer[CLI_COMMAND_LOG_BUFFER_SIZE];
|
||||
|
||||
furi_hal_console_set_tx_callback(cli_command_log_tx_callback, ring);
|
||||
|
||||
printf("Press CTRL+C to stop...\r\n");
|
||||
while(!cli_cmd_interrupt_received(cli)) {
|
||||
size_t ret = xStreamBufferReceive(ring, buffer, CLI_COMMAND_LOG_BUFFER_SIZE, 50);
|
||||
cli_write(cli, buffer, ret);
|
||||
}
|
||||
|
||||
furi_hal_console_set_tx_callback(NULL, NULL);
|
||||
|
||||
vStreamBufferDelete(ring);
|
||||
}
|
||||
|
||||
void cli_command_vibro(Cli* cli, string_t args, void* context) {
|
||||
@ -327,6 +345,7 @@ void cli_command_ps(Cli* cli, string_t args, void* context) {
|
||||
|
||||
void cli_command_free(Cli* cli, string_t args, void* context) {
|
||||
printf("Free heap size: %d\r\n", memmgr_get_free_heap());
|
||||
printf("Total heap size: %d\r\n", memmgr_get_total_heap());
|
||||
printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap());
|
||||
printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block());
|
||||
}
|
||||
|
||||
@ -276,7 +276,7 @@ void crypto_cli_store_key(Cli* cli, string_t args) {
|
||||
string_clear(key_type);
|
||||
}
|
||||
|
||||
void crypto_cli(Cli* cli, string_t args, void* context) {
|
||||
static void crypto_cli(Cli* cli, string_t args, void* context) {
|
||||
string_t cmd;
|
||||
string_init(cmd);
|
||||
|
||||
@ -317,5 +317,7 @@ void crypto_on_system_start() {
|
||||
Cli* cli = furi_record_open("cli");
|
||||
cli_add_command(cli, "crypto", CliCommandFlagDefault, crypto_cli, NULL);
|
||||
furi_record_close("cli");
|
||||
#else
|
||||
UNUSED(crypto_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ static void usb_mouse_render_callback(Canvas* canvas, void* ctx) {
|
||||
canvas_clear(canvas);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 10, "USB Mouse demo");
|
||||
canvas_draw_str(canvas, 0, 10, "USB Mouse Demo");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 63, "Hold [back] to exit");
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
#include <storage/storage.h>
|
||||
#include <assets_icons.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
@ -13,6 +16,10 @@
|
||||
#include "desktop_i.h"
|
||||
#include "desktop_helpers.h"
|
||||
|
||||
static void desktop_auto_lock_arm(Desktop*);
|
||||
static void desktop_auto_lock_inhibit(Desktop*);
|
||||
static void desktop_start_auto_lock_timer(Desktop*);
|
||||
|
||||
static void desktop_loader_callback(const void* message, void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = context;
|
||||
@ -37,9 +44,19 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
||||
switch(event) {
|
||||
case DesktopGlobalBeforeAppStarted:
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
desktop_auto_lock_inhibit(desktop);
|
||||
return true;
|
||||
case DesktopGlobalAfterAppFinished:
|
||||
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
||||
// TODO: Implement a message mechanism for loading settings and (optionally)
|
||||
// locking and unlocking
|
||||
LOAD_DESKTOP_SETTINGS(&desktop->settings);
|
||||
desktop_auto_lock_arm(desktop);
|
||||
return true;
|
||||
case DesktopGlobalAutoLock:
|
||||
if(!loader_is_locked(desktop->loader)) {
|
||||
desktop_lock(desktop);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -58,6 +75,63 @@ static void desktop_tick_event_callback(void* context) {
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void desktop_input_event_callback(const void* value, void* context) {
|
||||
furi_assert(value);
|
||||
furi_assert(context);
|
||||
const InputEvent* event = value;
|
||||
Desktop* desktop = context;
|
||||
if(event->type == InputTypePress) {
|
||||
desktop_start_auto_lock_timer(desktop);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_auto_lock_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoLock);
|
||||
}
|
||||
|
||||
static void desktop_start_auto_lock_timer(Desktop* desktop) {
|
||||
osTimerStart(
|
||||
desktop->auto_lock_timer, furi_hal_ms_to_ticks(desktop->settings.auto_lock_delay_ms));
|
||||
}
|
||||
|
||||
static void desktop_stop_auto_lock_timer(Desktop* desktop) {
|
||||
osTimerStop(desktop->auto_lock_timer);
|
||||
}
|
||||
|
||||
static void desktop_auto_lock_arm(Desktop* desktop) {
|
||||
if(desktop->settings.auto_lock_delay_ms) {
|
||||
desktop->input_events_subscription = furi_pubsub_subscribe(
|
||||
desktop->input_events_pubsub, desktop_input_event_callback, desktop);
|
||||
desktop_start_auto_lock_timer(desktop);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_auto_lock_inhibit(Desktop* desktop) {
|
||||
desktop_stop_auto_lock_timer(desktop);
|
||||
if(desktop->input_events_subscription) {
|
||||
furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription);
|
||||
desktop->input_events_subscription = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void desktop_lock(Desktop* desktop) {
|
||||
desktop_auto_lock_inhibit(desktop);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
notification_message(desktop->notification, &sequence_display_off_delay_1000);
|
||||
}
|
||||
|
||||
void desktop_unlock(Desktop* desktop) {
|
||||
furi_hal_rtc_set_pin_fails(0);
|
||||
desktop_helpers_unlock_system(desktop);
|
||||
desktop_view_locked_unlock(desktop->locked_view);
|
||||
scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
desktop_auto_lock_arm(desktop);
|
||||
}
|
||||
|
||||
Desktop* desktop_alloc() {
|
||||
Desktop* desktop = malloc(sizeof(Desktop));
|
||||
|
||||
@ -146,9 +220,17 @@ Desktop* desktop_alloc() {
|
||||
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
}
|
||||
|
||||
desktop->notification = furi_record_open("notification");
|
||||
desktop->app_start_stop_subscription = furi_pubsub_subscribe(
|
||||
loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop);
|
||||
|
||||
desktop->input_events_pubsub = furi_record_open("input_events");
|
||||
desktop->input_events_subscription = NULL;
|
||||
|
||||
desktop->auto_lock_timer =
|
||||
osTimerNew(desktop_auto_lock_timer_callback, osTimerOnce, desktop, NULL);
|
||||
|
||||
return desktop;
|
||||
}
|
||||
|
||||
@ -157,8 +239,17 @@ void desktop_free(Desktop* desktop) {
|
||||
|
||||
furi_pubsub_unsubscribe(
|
||||
loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription);
|
||||
|
||||
if(desktop->input_events_subscription) {
|
||||
furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription);
|
||||
desktop->input_events_subscription = NULL;
|
||||
}
|
||||
|
||||
desktop->loader = NULL;
|
||||
desktop->input_events_pubsub = NULL;
|
||||
furi_record_close("loader");
|
||||
furi_record_close("notification");
|
||||
furi_record_close("input_events");
|
||||
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
|
||||
@ -191,6 +282,8 @@ void desktop_free(Desktop* desktop) {
|
||||
|
||||
furi_record_close("menu");
|
||||
|
||||
osTimerDelete(desktop->auto_lock_timer);
|
||||
|
||||
free(desktop);
|
||||
}
|
||||
|
||||
@ -214,14 +307,16 @@ int32_t desktop_srv(void* p) {
|
||||
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
if(desktop->settings.pin_code.length > 0) {
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
} else {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock) && !desktop->settings.pin_code.length) {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||
}
|
||||
|
||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
if(!loader_is_locked(desktop->loader)) {
|
||||
desktop_auto_lock_arm(desktop);
|
||||
}
|
||||
} else {
|
||||
desktop_lock(desktop);
|
||||
}
|
||||
|
||||
if(desktop_is_first_start()) {
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include <loader/loader.h>
|
||||
#include <notification/notification_app.h>
|
||||
|
||||
#define STATUS_BAR_Y_SHIFT 13
|
||||
|
||||
@ -59,10 +60,18 @@ struct Desktop {
|
||||
ViewPort* lock_viewport;
|
||||
|
||||
AnimationManager* animation_manager;
|
||||
|
||||
Loader* loader;
|
||||
NotificationApp* notification;
|
||||
|
||||
FuriPubSubSubscription* app_start_stop_subscription;
|
||||
FuriPubSub* input_events_pubsub;
|
||||
FuriPubSubSubscription* input_events_subscription;
|
||||
osTimerId_t auto_lock_timer;
|
||||
};
|
||||
|
||||
Desktop* desktop_alloc();
|
||||
|
||||
void desktop_free(Desktop* desktop);
|
||||
void desktop_lock(Desktop* desktop);
|
||||
void desktop_unlock(Desktop* desktop);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <toolbox/saved_struct.h>
|
||||
|
||||
#define DESKTOP_SETTINGS_VER (1)
|
||||
#define DESKTOP_SETTINGS_VER (2)
|
||||
#define DESKTOP_SETTINGS_PATH "/int/desktop.settings"
|
||||
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
||||
#define PIN_MAX_LENGTH 12
|
||||
@ -39,6 +39,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
uint16_t favorite;
|
||||
PinCode pin_code;
|
||||
uint32_t auto_lock_delay_ms;
|
||||
} DesktopSettings;
|
||||
|
||||
static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) {
|
||||
|
||||
@ -36,12 +36,17 @@ DesktopSettingsApp* desktop_settings_app_alloc() {
|
||||
|
||||
app->popup = popup_alloc();
|
||||
app->submenu = submenu_alloc();
|
||||
app->variable_item_list = variable_item_list_alloc();
|
||||
app->pin_input_view = desktop_view_pin_input_alloc();
|
||||
app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc();
|
||||
app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc();
|
||||
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewVarItemList,
|
||||
variable_item_list_get_view(app->variable_item_list));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup));
|
||||
view_dispatcher_add_view(
|
||||
@ -63,10 +68,12 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
|
||||
furi_assert(app);
|
||||
// Variable item list
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
||||
variable_item_list_free(app->variable_item_list);
|
||||
submenu_free(app->submenu);
|
||||
popup_free(app->popup);
|
||||
desktop_view_pin_input_free(app->pin_input_view);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
|
||||
#include "desktop_settings.h"
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
@ -13,6 +14,7 @@
|
||||
|
||||
typedef enum {
|
||||
DesktopSettingsAppViewMenu,
|
||||
DesktopSettingsAppViewVarItemList,
|
||||
DesktopSettingsAppViewIdPopup,
|
||||
DesktopSettingsAppViewIdPinInput,
|
||||
DesktopSettingsAppViewIdPinSetupHowto,
|
||||
@ -25,6 +27,7 @@ typedef struct {
|
||||
Gui* gui;
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
VariableItemList* variable_item_list;
|
||||
Submenu* submenu;
|
||||
Popup* popup;
|
||||
DesktopViewPinInput* pin_input_view;
|
||||
|
||||
@ -1,35 +1,65 @@
|
||||
#include <applications.h>
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EVENT_SELECT_FAVORITE 0
|
||||
#define SCENE_EVENT_SELECT_PIN_SETUP 1
|
||||
#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 2
|
||||
|
||||
static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
#define AUTO_LOCK_DELAY_COUNT 6
|
||||
const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
|
||||
"OFF",
|
||||
"30s",
|
||||
"60s",
|
||||
"2min",
|
||||
"5min",
|
||||
"10min",
|
||||
};
|
||||
|
||||
const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] =
|
||||
{0, 30000, 60000, 120000, 300000, 600000};
|
||||
|
||||
static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) {
|
||||
DesktopSettingsApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, auto_lock_delay_text[index]);
|
||||
app->settings.auto_lock_delay_ms = auto_lock_delay_value[index];
|
||||
}
|
||||
|
||||
void desktop_settings_scene_start_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
VariableItemList* variable_item_list = app->variable_item_list;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Favorite App",
|
||||
SCENE_EVENT_SELECT_FAVORITE,
|
||||
desktop_settings_scene_start_submenu_callback,
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
|
||||
variable_item_list_add(variable_item_list, "Favorite App", 1, NULL, NULL);
|
||||
|
||||
variable_item_list_add(variable_item_list, "PIN Setup", 1, NULL, NULL);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Auto Lock Time",
|
||||
AUTO_LOCK_DELAY_COUNT,
|
||||
desktop_settings_scene_start_auto_lock_delay_changed,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"PIN Setup",
|
||||
SCENE_EVENT_SELECT_PIN_SETUP,
|
||||
desktop_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list, desktop_settings_scene_start_var_list_enter_callback, app);
|
||||
value_index = value_index_uint32(
|
||||
app->settings.auto_lock_delay_ms, auto_lock_delay_value, AUTO_LOCK_DELAY_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
@ -46,6 +76,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
@ -53,5 +86,6 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
|
||||
|
||||
void desktop_settings_scene_start_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
variable_item_list_reset(app->variable_item_list);
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
}
|
||||
|
||||
@ -34,13 +34,13 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
|
||||
case DesktopDebugEventDeed:
|
||||
dolphin_deed(dolphin, DolphinDeedIbuttonEmulate);
|
||||
dolphin_deed(dolphin, DolphinDeedTestRight);
|
||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopDebugEventWrongDeed:
|
||||
dolphin_deed(dolphin, DolphinDeedIbuttonRead);
|
||||
dolphin_deed(dolphin, DolphinDeedTestLeft);
|
||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@ -48,17 +48,13 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
switch(event.event) {
|
||||
case DesktopLockMenuEventLock:
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
desktop_lock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockMenuEventPinLock:
|
||||
if(desktop->settings.pin_code.length > 0) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
desktop_lock(desktop);
|
||||
} else {
|
||||
LoaderStatus status =
|
||||
loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
|
||||
|
||||
@ -81,13 +81,13 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopLockedEventUnlocked:
|
||||
furi_hal_rtc_set_pin_fails(0);
|
||||
desktop_helpers_unlock_system(desktop);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneMain);
|
||||
desktop_unlock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockedEventUpdate:
|
||||
if(desktop_view_locked_is_locked_hint_visible(desktop->locked_view)) {
|
||||
notification_message(desktop->notification, &sequence_display_off);
|
||||
}
|
||||
desktop_view_locked_update(desktop->locked_view);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@ -129,16 +129,13 @@ bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopPinInputEventUnlocked:
|
||||
desktop_view_locked_unlock(desktop->locked_view);
|
||||
furi_hal_rtc_set_pin_fails(0);
|
||||
desktop_helpers_unlock_system(desktop);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneMain);
|
||||
desktop_unlock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopPinInputEventBack:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneLocked);
|
||||
notification_message(desktop->notification, &sequence_display_off);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -38,4 +38,5 @@ typedef enum {
|
||||
// Global events
|
||||
DesktopGlobalBeforeAppStarted,
|
||||
DesktopGlobalAfterAppFinished,
|
||||
DesktopGlobalAutoLock,
|
||||
} DesktopEvent;
|
||||
|
||||
@ -23,7 +23,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
const Version* ver;
|
||||
char buffer[64];
|
||||
|
||||
static const char* headers[] = {"FW Version info:", "Boot Version info:", "Dolphin info:"};
|
||||
static const char* headers[] = {"FW Version info:", "Dolphin info:"};
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
@ -36,16 +36,16 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"HW: %d.F%dB%dC%d %s",
|
||||
"%d.F%dB%dC%d %s %s",
|
||||
furi_hal_version_get_hw_version(),
|
||||
furi_hal_version_get_hw_target(),
|
||||
furi_hal_version_get_hw_body(),
|
||||
furi_hal_version_get_hw_connect(),
|
||||
furi_hal_version_get_hw_region_name(),
|
||||
my_name ? my_name : "Unknown");
|
||||
canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
ver = m->screen == DesktopViewStatsBoot ? furi_hal_version_get_bootloader_version() :
|
||||
furi_hal_version_get_firmware_version();
|
||||
ver = furi_hal_version_get_firmware_version();
|
||||
|
||||
if(!ver) {
|
||||
canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, "No info");
|
||||
@ -63,7 +63,8 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%s [%s]",
|
||||
"%s%s [%s]",
|
||||
version_get_dirty_flag(ver) ? "[!] " : "",
|
||||
version_get_githash(ver),
|
||||
version_get_gitbranchnum(ver));
|
||||
canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
@ -110,18 +111,15 @@ bool desktop_debug_input(InputEvent* event, void* context) {
|
||||
|
||||
DesktopDebugView* debug_view = context;
|
||||
|
||||
if(event->type != InputTypeShort) return false;
|
||||
if(event->type != InputTypeShort && event->type != InputTypeRepeat) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DesktopViewStatsScreens current = 0;
|
||||
with_view_model(
|
||||
debug_view->view, (DesktopDebugViewModel * model) {
|
||||
#if SRV_DOLPHIN_STATE_DEBUG == 1
|
||||
if(event->key == InputKeyDown) {
|
||||
model->screen = (model->screen + 1) % DesktopViewStatsTotalCount;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
model->screen = ((model->screen - 1) + DesktopViewStatsTotalCount) %
|
||||
DesktopViewStatsTotalCount;
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef SRV_DOLPHIN_STATE_DEBUG
|
||||
if((event->key == InputKeyDown) || (event->key == InputKeyUp)) {
|
||||
model->screen = !model->screen;
|
||||
}
|
||||
@ -130,11 +128,16 @@ bool desktop_debug_input(InputEvent* event, void* context) {
|
||||
return true;
|
||||
});
|
||||
|
||||
size_t count = (event->type == InputTypeRepeat) ? 10 : 1;
|
||||
if(current == DesktopViewStatsMeta) {
|
||||
if(event->key == InputKeyLeft) {
|
||||
debug_view->callback(DesktopDebugEventWrongDeed, debug_view->context);
|
||||
while(count-- > 0) {
|
||||
debug_view->callback(DesktopDebugEventWrongDeed, debug_view->context);
|
||||
}
|
||||
} else if(event->key == InputKeyRight) {
|
||||
debug_view->callback(DesktopDebugEventDeed, debug_view->context);
|
||||
while(count-- > 0) {
|
||||
debug_view->callback(DesktopDebugEventDeed, debug_view->context);
|
||||
}
|
||||
} else if(event->key == InputKeyOk) {
|
||||
debug_view->callback(DesktopDebugEventSaveState, debug_view->context);
|
||||
} else {
|
||||
|
||||
@ -11,7 +11,6 @@ typedef void (*DesktopDebugViewCallback)(DesktopEvent event, void* context);
|
||||
// Debug info
|
||||
typedef enum {
|
||||
DesktopViewStatsFw,
|
||||
DesktopViewStatsBoot,
|
||||
DesktopViewStatsMeta,
|
||||
DesktopViewStatsTotalCount,
|
||||
} DesktopViewStatsScreens;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "desktop_view_locked.h"
|
||||
|
||||
#define DOOR_MOVING_INTERVAL_MS (1000 / 16)
|
||||
#define LOCKED_HINT_TIMEOUT_MS (1000)
|
||||
#define UNLOCKED_HINT_TIMEOUT_MS (2000)
|
||||
|
||||
#define DOOR_OFFSET_START -55
|
||||
@ -32,14 +33,18 @@ struct DesktopViewLocked {
|
||||
uint32_t lock_lastpress;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t hint_icon_expire_at;
|
||||
bool unlocked_hint;
|
||||
bool locked;
|
||||
bool pin_locked;
|
||||
typedef enum {
|
||||
DesktopViewLockedStateUnlocked,
|
||||
DesktopViewLockedStateLocked,
|
||||
DesktopViewLockedStateDoorsClosing,
|
||||
DesktopViewLockedStateLockedHintShown,
|
||||
DesktopViewLockedStateUnlockedHintShown
|
||||
} DesktopViewLockedState;
|
||||
|
||||
typedef struct {
|
||||
bool pin_locked;
|
||||
int8_t door_offset;
|
||||
bool doors_closing;
|
||||
DesktopViewLockedState view_state;
|
||||
} DesktopViewLockedModel;
|
||||
|
||||
void desktop_view_locked_set_callback(
|
||||
@ -78,51 +83,54 @@ static bool desktop_view_locked_doors_move(DesktopViewLockedModel* model) {
|
||||
|
||||
static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* locked_view) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
|
||||
view_commit_model(locked_view->view, true);
|
||||
const bool change_state = (model->view_state == DesktopViewLockedStateLocked) &&
|
||||
!model->pin_locked;
|
||||
if(change_state) {
|
||||
model->view_state = DesktopViewLockedStateLockedHintShown;
|
||||
}
|
||||
view_commit_model(locked_view->view, change_state);
|
||||
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(LOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
|
||||
}
|
||||
|
||||
void desktop_view_locked_update(DesktopViewLocked* locked_view) {
|
||||
bool stop_timer = false;
|
||||
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
if(model->locked) {
|
||||
model->doors_closing = desktop_view_locked_doors_move(model);
|
||||
stop_timer = !model->doors_closing;
|
||||
} else {
|
||||
model->unlocked_hint = false;
|
||||
stop_timer = true;
|
||||
DesktopViewLockedState view_state = model->view_state;
|
||||
|
||||
if(view_state == DesktopViewLockedStateDoorsClosing &&
|
||||
!desktop_view_locked_doors_move(model)) {
|
||||
model->view_state = DesktopViewLockedStateLocked;
|
||||
} else if(view_state == DesktopViewLockedStateLockedHintShown) {
|
||||
model->view_state = DesktopViewLockedStateLocked;
|
||||
} else if(view_state == DesktopViewLockedStateUnlockedHintShown) {
|
||||
model->view_state = DesktopViewLockedStateUnlocked;
|
||||
}
|
||||
|
||||
view_commit_model(locked_view->view, true);
|
||||
|
||||
if(stop_timer) {
|
||||
if(view_state != DesktopViewLockedStateDoorsClosing) {
|
||||
xTimerStop(locked_view->timer, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_view_locked_draw(Canvas* canvas, void* model) {
|
||||
DesktopViewLockedModel* m = model;
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
DesktopViewLockedState view_state = m->view_state;
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(m->locked) {
|
||||
if(m->doors_closing) {
|
||||
desktop_view_locked_doors_draw(canvas, m);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
||||
} else if((now < m->hint_icon_expire_at) && !m->pin_locked) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48);
|
||||
elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
|
||||
canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8);
|
||||
canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42);
|
||||
canvas_draw_dot(canvas, 17, 61);
|
||||
}
|
||||
} else {
|
||||
if(m->unlocked_hint) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
|
||||
}
|
||||
if(view_state == DesktopViewLockedStateDoorsClosing) {
|
||||
desktop_view_locked_doors_draw(canvas, m);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
||||
} else if(view_state == DesktopViewLockedStateLockedHintShown) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48);
|
||||
elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
|
||||
canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8);
|
||||
canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42);
|
||||
canvas_draw_dot(canvas, 17, 61);
|
||||
} else if(view_state == DesktopViewLockedStateUnlockedHintShown) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,43 +142,38 @@ View* desktop_view_locked_get_view(DesktopViewLocked* locked_view) {
|
||||
static bool desktop_view_locked_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
bool is_changed = false;
|
||||
const uint32_t press_time = xTaskGetTickCount();
|
||||
DesktopViewLocked* locked_view = context;
|
||||
bool locked = false;
|
||||
bool locked_with_pin = false;
|
||||
bool doors_closing = false;
|
||||
uint32_t press_time = xTaskGetTickCount();
|
||||
|
||||
{
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
bool changed = false;
|
||||
locked = model->locked;
|
||||
locked_with_pin = model->pin_locked;
|
||||
doors_closing = model->doors_closing;
|
||||
if(!locked && model->unlocked_hint && event->type == InputTypePress) {
|
||||
model->unlocked_hint = false;
|
||||
changed = true;
|
||||
}
|
||||
view_commit_model(locked_view->view, changed);
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
if(model->view_state == DesktopViewLockedStateUnlockedHintShown &&
|
||||
event->type == InputTypePress) {
|
||||
model->view_state = DesktopViewLockedStateUnlocked;
|
||||
is_changed = true;
|
||||
}
|
||||
const DesktopViewLockedState view_state = model->view_state;
|
||||
const bool pin_locked = model->pin_locked;
|
||||
view_commit_model(locked_view->view, is_changed);
|
||||
|
||||
if(!locked || doors_closing || (event->type != InputTypeShort)) {
|
||||
return locked;
|
||||
}
|
||||
|
||||
if(locked_with_pin) {
|
||||
if(view_state == DesktopViewLockedStateUnlocked || event->type != InputTypeShort) {
|
||||
return view_state != DesktopViewLockedStateUnlocked;
|
||||
} else if(view_state == DesktopViewLockedStateLocked && pin_locked) {
|
||||
locked_view->callback(DesktopLockedEventShowPinInput, locked_view->context);
|
||||
} else {
|
||||
} else if(
|
||||
view_state == DesktopViewLockedStateLocked ||
|
||||
view_state == DesktopViewLockedStateLockedHintShown) {
|
||||
if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count = 0;
|
||||
}
|
||||
|
||||
desktop_view_locked_update_hint_icon_timeout(locked_view);
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count++;
|
||||
if(locked_view->lock_count == UNLOCK_CNT) {
|
||||
desktop_view_locked_unlock(locked_view);
|
||||
locked_view->callback(DesktopLockedEventUnlocked, locked_view->context);
|
||||
}
|
||||
} else {
|
||||
@ -180,7 +183,7 @@ static bool desktop_view_locked_input(InputEvent* event, void* context) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
}
|
||||
|
||||
return locked;
|
||||
return true;
|
||||
}
|
||||
|
||||
DesktopViewLocked* desktop_view_locked_alloc() {
|
||||
@ -189,7 +192,6 @@ DesktopViewLocked* desktop_view_locked_alloc() {
|
||||
locked_view->timer =
|
||||
xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback);
|
||||
|
||||
locked_view->view = view_alloc();
|
||||
view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel));
|
||||
view_set_context(locked_view->view, locked_view);
|
||||
view_set_draw_callback(locked_view->view, desktop_view_locked_draw);
|
||||
@ -207,7 +209,8 @@ void desktop_view_locked_free(DesktopViewLocked* locked_view) {
|
||||
|
||||
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->doors_closing = true;
|
||||
furi_assert(model->view_state == DesktopViewLockedStateLocked);
|
||||
model->view_state = DesktopViewLockedStateDoorsClosing;
|
||||
model->door_offset = DOOR_OFFSET_START;
|
||||
view_commit_model(locked_view->view, true);
|
||||
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY);
|
||||
@ -215,19 +218,24 @@ void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
|
||||
|
||||
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->locked = true;
|
||||
furi_assert(model->view_state == DesktopViewLockedStateUnlocked);
|
||||
model->view_state = DesktopViewLockedStateLocked;
|
||||
model->pin_locked = pin_locked;
|
||||
view_commit_model(locked_view->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_locked_unlock(DesktopViewLocked* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
|
||||
locked_view->lock_count = 0;
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->locked = false;
|
||||
model->view_state = DesktopViewLockedStateUnlockedHintShown;
|
||||
model->pin_locked = false;
|
||||
model->unlocked_hint = true;
|
||||
view_commit_model(locked_view->view, true);
|
||||
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
|
||||
}
|
||||
|
||||
bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
const DesktopViewLockedState view_state = model->view_state;
|
||||
view_commit_model(locked_view->view, false);
|
||||
return view_state == DesktopViewLockedStateLockedHintShown;
|
||||
}
|
||||
|
||||
@ -19,3 +19,4 @@ void desktop_view_locked_free(DesktopViewLocked* locked_view);
|
||||
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked);
|
||||
void desktop_view_locked_unlock(DesktopViewLocked* locked_view);
|
||||
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view);
|
||||
bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view);
|
||||
|
||||
@ -52,7 +52,10 @@ typedef enum {
|
||||
|
||||
DolphinDeedU2fAuthorized,
|
||||
|
||||
DolphinDeedMAX
|
||||
DolphinDeedMAX,
|
||||
|
||||
DolphinDeedTestLeft,
|
||||
DolphinDeedTestRight,
|
||||
} DolphinDeed;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -126,6 +126,23 @@ uint32_t dolphin_state_xp_to_levelup(uint32_t icounter) {
|
||||
}
|
||||
|
||||
void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) {
|
||||
// Special case for testing
|
||||
if(deed > DolphinDeedMAX) {
|
||||
if(deed == DolphinDeedTestLeft) {
|
||||
dolphin_state->data.butthurt =
|
||||
CLAMP(dolphin_state->data.butthurt + 1, BUTTHURT_MAX, BUTTHURT_MIN);
|
||||
if(dolphin_state->data.icounter > 0) dolphin_state->data.icounter--;
|
||||
dolphin_state->data.timestamp = dolphin_state_timestamp();
|
||||
dolphin_state->dirty = true;
|
||||
} else if(deed == DolphinDeedTestRight) {
|
||||
dolphin_state->data.butthurt = BUTTHURT_MIN;
|
||||
if(dolphin_state->data.icounter < UINT32_MAX) dolphin_state->data.icounter++;
|
||||
dolphin_state->data.timestamp = dolphin_state_timestamp();
|
||||
dolphin_state->dirty = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
DolphinApp app = dolphin_deed_get_app(deed);
|
||||
int8_t weight_limit =
|
||||
dolphin_deed_get_app_limit(app) - dolphin_state->data.icounter_daily_limit[app];
|
||||
|
||||
@ -49,9 +49,9 @@ void gpio_scene_start_on_enter(void* context) {
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, gpio_scene_start_var_list_enter_callback, app);
|
||||
|
||||
variable_item_list_add(var_item_list, "USB-UART bridge", 0, NULL, NULL);
|
||||
variable_item_list_add(var_item_list, "USB-UART Bridge", 0, NULL, NULL);
|
||||
|
||||
variable_item_list_add(var_item_list, "GPIO manual control", 0, NULL, NULL);
|
||||
variable_item_list_add(var_item_list, "GPIO Manual Control", 0, NULL, NULL);
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
|
||||
@ -739,4 +739,4 @@ void elements_text_box(
|
||||
}
|
||||
}
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,9 @@
|
||||
#include "scene/ibutton_scene_read_crc_error.h"
|
||||
#include "scene/ibutton_scene_read_not_key_error.h"
|
||||
#include "scene/ibutton_scene_read_success.h"
|
||||
#include "scene/ibutton_scene_readed_key_menu.h"
|
||||
#include "scene/ibutton_scene_retry_confirm.h"
|
||||
#include "scene/ibutton_scene_exit_confirm.h"
|
||||
#include "scene/ibutton_scene_read_key_menu.h"
|
||||
#include "scene/ibutton_scene_write.h"
|
||||
#include "scene/ibutton_scene_write_success.h"
|
||||
#include "scene/ibutton_scene_saved_key_menu.h"
|
||||
@ -42,7 +44,9 @@ public:
|
||||
SceneReadNotKeyError,
|
||||
SceneReadCRCError,
|
||||
SceneReadSuccess,
|
||||
SceneReadedKeyMenu,
|
||||
SceneRetryConfirm,
|
||||
SceneExitConfirm,
|
||||
SceneReadKeyMenu,
|
||||
SceneWrite,
|
||||
SceneWriteSuccess,
|
||||
SceneEmulate,
|
||||
@ -105,7 +109,9 @@ private:
|
||||
{Scene::SceneReadCRCError, new iButtonSceneReadCRCError()},
|
||||
{Scene::SceneReadNotKeyError, new iButtonSceneReadNotKeyError()},
|
||||
{Scene::SceneReadSuccess, new iButtonSceneReadSuccess()},
|
||||
{Scene::SceneReadedKeyMenu, new iButtonSceneReadedKeyMenu()},
|
||||
{Scene::SceneRetryConfirm, new iButtonSceneRetryConfirm()},
|
||||
{Scene::SceneExitConfirm, new iButtonSceneExitConfirm()},
|
||||
{Scene::SceneReadKeyMenu, new iButtonSceneReadKeyMenu()},
|
||||
{Scene::SceneWrite, new iButtonSceneWrite()},
|
||||
{Scene::SceneWriteSuccess, new iButtonSceneWriteSuccess()},
|
||||
{Scene::SceneEmulate, new iButtonSceneEmulate()},
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
#include <one_wire/ibutton/ibutton_worker.h>
|
||||
#include <one_wire/one_wire_host.h>
|
||||
|
||||
void ibutton_cli(Cli* cli, string_t args, void* context);
|
||||
void onewire_cli(Cli* cli, string_t args, void* context);
|
||||
static void ibutton_cli(Cli* cli, string_t args, void* context);
|
||||
static void onewire_cli(Cli* cli, string_t args, void* context);
|
||||
|
||||
// app cli function
|
||||
void ibutton_on_system_start() {
|
||||
@ -16,6 +16,9 @@ void ibutton_on_system_start() {
|
||||
cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli, cli);
|
||||
cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli);
|
||||
furi_record_close("cli");
|
||||
#else
|
||||
UNUSED(ibutton_cli);
|
||||
UNUSED(onewire_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -236,7 +239,7 @@ void ibutton_cli_emulate(Cli* cli, string_t args) {
|
||||
ibutton_key_free(key);
|
||||
};
|
||||
|
||||
void ibutton_cli(Cli* cli, string_t args, void* context) {
|
||||
static void ibutton_cli(Cli* cli, string_t args, void* context) {
|
||||
string_t cmd;
|
||||
string_init(cmd);
|
||||
|
||||
@ -264,7 +267,7 @@ void onewire_cli_print_usage() {
|
||||
printf("onewire search\r\n");
|
||||
};
|
||||
|
||||
void onewire_cli_search(Cli* cli) {
|
||||
static void onewire_cli_search(Cli* cli) {
|
||||
OneWireHost* onewire = onewire_host_alloc();
|
||||
uint8_t address[8];
|
||||
bool done = false;
|
||||
@ -308,4 +311,4 @@ void onewire_cli(Cli* cli, string_t args, void* context) {
|
||||
}
|
||||
|
||||
string_clear(cmd);
|
||||
}
|
||||
}
|
||||
@ -22,7 +22,7 @@ void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) {
|
||||
app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key));
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store());
|
||||
widget_add_button_element(widget, GuiButtonTypeLeft, "Back", widget_callback, app);
|
||||
widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app);
|
||||
widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app);
|
||||
|
||||
switch(ibutton_key_get_type(key)) {
|
||||
|
||||
@ -14,7 +14,7 @@ void iButtonSceneDeleteSuccess::on_enter(iButtonApp* app) {
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_text(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
|
||||
popup_set_callback(popup, popup_callback);
|
||||
popup_set_context(popup, app);
|
||||
|
||||
51
applications/ibutton/scene/ibutton_scene_exit_confirm.cpp
Normal file
51
applications/ibutton/scene/ibutton_scene_exit_confirm.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "ibutton_scene_exit_confirm.h"
|
||||
#include "../ibutton_app.h"
|
||||
|
||||
static void widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
iButtonApp* app = static_cast<iButtonApp*>(context);
|
||||
iButtonEvent event;
|
||||
|
||||
if(type == InputTypeShort) {
|
||||
event.type = iButtonEvent::Type::EventTypeWidgetButtonResult;
|
||||
event.payload.widget_button_result = result;
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
}
|
||||
|
||||
void iButtonSceneExitConfirm::on_enter(iButtonApp* app) {
|
||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||
Widget* widget = view_manager->get_widget();
|
||||
|
||||
widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", widget_callback, app);
|
||||
widget_add_button_element(widget, GuiButtonTypeRight, "Stay", widget_callback, app);
|
||||
widget_add_string_element(
|
||||
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu");
|
||||
widget_add_string_element(
|
||||
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost");
|
||||
|
||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget);
|
||||
}
|
||||
|
||||
bool iButtonSceneExitConfirm::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) {
|
||||
if(event->payload.widget_button_result == GuiButtonTypeLeft) {
|
||||
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneStart});
|
||||
} else if(event->payload.widget_button_result == GuiButtonTypeRight) {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void iButtonSceneExitConfirm::on_exit(iButtonApp* app) {
|
||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||
Widget* widget = view_manager->get_widget();
|
||||
widget_reset(widget);
|
||||
}
|
||||
9
applications/ibutton/scene/ibutton_scene_exit_confirm.h
Normal file
9
applications/ibutton/scene/ibutton_scene_exit_confirm.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "ibutton_scene_generic.h"
|
||||
|
||||
class iButtonSceneExitConfirm : public iButtonScene {
|
||||
public:
|
||||
void on_enter(iButtonApp* app) final;
|
||||
bool on_event(iButtonApp* app, iButtonEvent* event) final;
|
||||
void on_exit(iButtonApp* app) final;
|
||||
};
|
||||
@ -1,18 +1,6 @@
|
||||
#include "ibutton_scene_info.h"
|
||||
#include "../ibutton_app.h"
|
||||
|
||||
static void widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
iButtonApp* app = static_cast<iButtonApp*>(context);
|
||||
iButtonEvent event;
|
||||
|
||||
if(type == InputTypeShort) {
|
||||
event.type = iButtonEvent::Type::EventTypeWidgetButtonResult;
|
||||
event.payload.widget_button_result = result;
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
}
|
||||
|
||||
void iButtonSceneInfo::on_enter(iButtonApp* app) {
|
||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||
Widget* widget = view_manager->get_widget();
|
||||
@ -21,8 +9,7 @@ void iButtonSceneInfo::on_enter(iButtonApp* app) {
|
||||
|
||||
app->set_text_store("%s", ibutton_key_get_name_p(key));
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store());
|
||||
widget_add_button_element(widget, GuiButtonTypeLeft, "Back", widget_callback, app);
|
||||
widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store());
|
||||
|
||||
switch(ibutton_key_get_type(key)) {
|
||||
case iButtonKeyDS1990:
|
||||
@ -37,36 +24,28 @@ void iButtonSceneInfo::on_enter(iButtonApp* app) {
|
||||
key_data[6],
|
||||
key_data[7]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Dallas");
|
||||
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Dallas");
|
||||
break;
|
||||
case iButtonKeyMetakom:
|
||||
app->set_text_store(
|
||||
"%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Metakom");
|
||||
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Metakom");
|
||||
break;
|
||||
case iButtonKeyCyfral:
|
||||
app->set_text_store("%02X %02X", key_data[0], key_data[1]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
|
||||
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
|
||||
break;
|
||||
}
|
||||
widget_add_string_element(
|
||||
widget, 64, 33, AlignCenter, AlignBottom, FontPrimary, app->get_text_store());
|
||||
widget, 64, 35, AlignCenter, AlignBottom, FontPrimary, app->get_text_store());
|
||||
|
||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget);
|
||||
}
|
||||
|
||||
bool iButtonSceneInfo::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) {
|
||||
if(event->payload.widget_button_result == GuiButtonTypeLeft) {
|
||||
app->switch_to_previous_scene();
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
|
||||
@ -34,15 +34,22 @@ bool iButtonSceneRead::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
consumed = true;
|
||||
|
||||
iButtonKey* key = app->get_key();
|
||||
bool success = false;
|
||||
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
|
||||
if(!ibutton_key_dallas_crc_is_valid(key)) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError);
|
||||
} else if(!ibutton_key_dallas_is_1990_key(key)) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError);
|
||||
} else {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess);
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
if(success) {
|
||||
app->notify_success();
|
||||
app->notify_green_on();
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess);
|
||||
}
|
||||
} else if(event->type == iButtonEvent::Type::EventTypeTick) {
|
||||
|
||||
@ -47,7 +47,7 @@ bool iButtonSceneReadCRCError::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
|
||||
if(event->payload.dialog_result == DialogExResultRight) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
#include "ibutton_scene_readed_key_menu.h"
|
||||
#include "ibutton_scene_read_key_menu.h"
|
||||
#include "../ibutton_app.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexWrite,
|
||||
SubmenuIndexEmulate,
|
||||
SubmenuIndexSave,
|
||||
SubmenuIndexReadNewKey,
|
||||
} SubmenuIndex;
|
||||
|
||||
static void submenu_callback(void* context, uint32_t index) {
|
||||
@ -19,7 +18,7 @@ static void submenu_callback(void* context, uint32_t index) {
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void iButtonSceneReadedKeyMenu::on_enter(iButtonApp* app) {
|
||||
void iButtonSceneReadKeyMenu::on_enter(iButtonApp* app) {
|
||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
@ -28,13 +27,12 @@ void iButtonSceneReadedKeyMenu::on_enter(iButtonApp* app) {
|
||||
}
|
||||
submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Read new key", SubmenuIndexReadNewKey, submenu_callback, app);
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
|
||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
|
||||
}
|
||||
|
||||
bool iButtonSceneReadedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
bool iButtonSceneReadKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
|
||||
@ -49,20 +47,17 @@ bool iButtonSceneReadedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
case SubmenuIndexSave:
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName);
|
||||
break;
|
||||
case SubmenuIndexReadNewKey:
|
||||
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneRead});
|
||||
break;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneStart});
|
||||
app->switch_to_previous_scene();
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void iButtonSceneReadedKeyMenu::on_exit(iButtonApp* app) {
|
||||
void iButtonSceneReadKeyMenu::on_exit(iButtonApp* app) {
|
||||
iButtonAppViewManager* view = app->get_view_manager();
|
||||
Submenu* submenu = view->get_submenu();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "ibutton_scene_generic.h"
|
||||
|
||||
class iButtonSceneReadedKeyMenu : public iButtonScene {
|
||||
class iButtonSceneReadKeyMenu : public iButtonScene {
|
||||
public:
|
||||
void on_enter(iButtonApp* app) final;
|
||||
bool on_event(iButtonApp* app, iButtonEvent* event) final;
|
||||
@ -47,7 +47,7 @@ bool iButtonSceneReadNotKeyError::on_event(iButtonApp* app, iButtonEvent* event)
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
|
||||
if(event->payload.dialog_result == DialogExResultRight) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
|
||||
@ -18,7 +18,6 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) {
|
||||
DialogEx* dialog_ex = view_manager->get_dialog_ex();
|
||||
iButtonKey* key = app->get_key();
|
||||
const uint8_t* key_data = ibutton_key_get_data_p(key);
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
|
||||
|
||||
switch(ibutton_key_get_type(key)) {
|
||||
case iButtonKeyDS1990:
|
||||
@ -45,14 +44,11 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) {
|
||||
dialog_ex_set_text(dialog_ex, app->get_text_store(), 95, 30, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "More");
|
||||
dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinExcited_64x63);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63);
|
||||
dialog_ex_set_result_callback(dialog_ex, dialog_ex_callback);
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
|
||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx);
|
||||
|
||||
app->notify_success();
|
||||
app->notify_green_on();
|
||||
}
|
||||
|
||||
bool iButtonSceneReadSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
@ -60,11 +56,13 @@ bool iButtonSceneReadSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
|
||||
if(event->payload.dialog_result == DialogExResultRight) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneRetryConfirm);
|
||||
}
|
||||
|
||||
consumed = true;
|
||||
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneExitConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
|
||||
51
applications/ibutton/scene/ibutton_scene_retry_confirm.cpp
Normal file
51
applications/ibutton/scene/ibutton_scene_retry_confirm.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "ibutton_scene_retry_confirm.h"
|
||||
#include "../ibutton_app.h"
|
||||
|
||||
static void widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
iButtonApp* app = static_cast<iButtonApp*>(context);
|
||||
iButtonEvent event;
|
||||
|
||||
if(type == InputTypeShort) {
|
||||
event.type = iButtonEvent::Type::EventTypeWidgetButtonResult;
|
||||
event.payload.widget_button_result = result;
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
}
|
||||
|
||||
void iButtonSceneRetryConfirm::on_enter(iButtonApp* app) {
|
||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||
Widget* widget = view_manager->get_widget();
|
||||
|
||||
widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", widget_callback, app);
|
||||
widget_add_button_element(widget, GuiButtonTypeRight, "Stay", widget_callback, app);
|
||||
widget_add_string_element(
|
||||
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?");
|
||||
widget_add_string_element(
|
||||
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost");
|
||||
|
||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget);
|
||||
}
|
||||
|
||||
bool iButtonSceneRetryConfirm::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) {
|
||||
if(event->payload.widget_button_result == GuiButtonTypeLeft) {
|
||||
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneRead});
|
||||
} else if(event->payload.widget_button_result == GuiButtonTypeRight) {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void iButtonSceneRetryConfirm::on_exit(iButtonApp* app) {
|
||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||
Widget* widget = view_manager->get_widget();
|
||||
widget_reset(widget);
|
||||
}
|
||||
9
applications/ibutton/scene/ibutton_scene_retry_confirm.h
Normal file
9
applications/ibutton/scene/ibutton_scene_retry_confirm.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "ibutton_scene_generic.h"
|
||||
|
||||
class iButtonSceneRetryConfirm : public iButtonScene {
|
||||
public:
|
||||
void on_enter(iButtonApp* app) final;
|
||||
bool on_event(iButtonApp* app, iButtonEvent* event) final;
|
||||
void on_exit(iButtonApp* app) final;
|
||||
};
|
||||
@ -49,7 +49,7 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess);
|
||||
} else {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{iButtonApp::Scene::SceneReadedKeyMenu,
|
||||
{iButtonApp::Scene::SceneReadKeyMenu,
|
||||
iButtonApp::Scene::SceneSavedKeyMenu,
|
||||
iButtonApp::Scene::SceneAddType});
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ void iButtonSceneSaveSuccess::on_enter(iButtonApp* app) {
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonSave);
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_text(popup, "Saved!", 13, 22, AlignLeft, AlignBottom);
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_callback(popup, popup_callback);
|
||||
popup_set_context(popup, app);
|
||||
@ -31,7 +31,7 @@ bool iButtonSceneSaveSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{iButtonApp::Scene::SceneReadedKeyMenu,
|
||||
{iButtonApp::Scene::SceneReadKeyMenu,
|
||||
iButtonApp::Scene::SceneSavedKeyMenu,
|
||||
iButtonApp::Scene::SceneAddType});
|
||||
consumed = true;
|
||||
|
||||
@ -24,7 +24,7 @@ void iButtonSceneStart::on_enter(iButtonApp* app) {
|
||||
|
||||
submenu_add_item(submenu, "Read", SubmenuIndexRead, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Add manually", SubmenuIndexAdd, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Add Manually", SubmenuIndexAdd, submenu_callback, app);
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
|
||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
|
||||
|
||||
@ -33,7 +33,7 @@ bool iButtonSceneWriteSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{iButtonApp::Scene::SceneReadedKeyMenu, iButtonApp::Scene::SceneStart});
|
||||
{iButtonApp::Scene::SceneReadKeyMenu, iButtonApp::Scene::SceneStart});
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
|
||||
@ -192,5 +192,7 @@ extern "C" void infrared_on_system_start() {
|
||||
Cli* cli = (Cli*)furi_record_open("cli");
|
||||
cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir, NULL);
|
||||
furi_record_close("cli");
|
||||
#else
|
||||
UNUSED(infrared_cli_start_ir);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include <storage/storage.h>
|
||||
#include "infrared_app.h"
|
||||
|
||||
static const std::string default_remote_name = "remote";
|
||||
static const char* default_remote_name = "remote";
|
||||
|
||||
std::string InfraredAppRemoteManager::make_full_name(
|
||||
const std::string& path,
|
||||
|
||||
@ -23,11 +23,11 @@ void InfraredAppSceneEdit::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_add_item(submenu, "Add key", SubmenuIndexAddKey, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Rename key", SubmenuIndexRenameKey, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Delete key", SubmenuIndexDeleteKey, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Rename remote", SubmenuIndexRenameRemote, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Delete remote", SubmenuIndexDeleteRemote, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Add Key", SubmenuIndexAddKey, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Rename Key", SubmenuIndexRenameKey, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Delete Key", SubmenuIndexDeleteKey, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app);
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
submenu_item_selected = 0;
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ void InfraredAppSceneEditRenameDone::on_enter(InfraredApp* app) {
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_callback(popup, InfraredApp::popup_callback);
|
||||
|
||||
@ -21,10 +21,10 @@ void InfraredAppSceneStart::on_enter(InfraredApp* app) {
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Universal library", SubmenuIndexUniversalLibrary, submenu_callback, app);
|
||||
submenu, "Universal Library", SubmenuIndexUniversalLibrary, submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu, "Learn new remote", SubmenuIndexLearnNewRemote, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Saved remotes", SubmenuIndexSavedRemotes, submenu_callback, app);
|
||||
submenu, "Learn New Remote", SubmenuIndexLearnNewRemote, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Saved Remotes", SubmenuIndexSavedRemotes, submenu_callback, app);
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
submenu_item_selected = 0;
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ static void input_cli_send_print_usage() {
|
||||
printf("\t\t <type>\t - one of 'press', 'release', 'short', 'long'\r\n");
|
||||
}
|
||||
|
||||
void input_cli_send(Cli* cli, string_t args, Input* input) {
|
||||
static void input_cli_send(Cli* cli, string_t args, Input* input) {
|
||||
InputEvent event;
|
||||
string_t key_str;
|
||||
string_init(key_str);
|
||||
|
||||
@ -15,7 +15,7 @@ constexpr uint32_t long_time_high = long_time + jitter_time;
|
||||
|
||||
void DecoderEMMarin::reset_state() {
|
||||
ready = false;
|
||||
readed_data = 0;
|
||||
read_data = 0;
|
||||
manchester_advance(
|
||||
manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr);
|
||||
}
|
||||
@ -26,7 +26,7 @@ bool DecoderEMMarin::read(uint8_t* data, uint8_t data_size) {
|
||||
if(ready) {
|
||||
result = true;
|
||||
em_marin.decode(
|
||||
reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t), data, data_size);
|
||||
reinterpret_cast<const uint8_t*>(&read_data), sizeof(uint64_t), data, data_size);
|
||||
ready = false;
|
||||
}
|
||||
|
||||
@ -59,10 +59,10 @@ void DecoderEMMarin::process_front(bool polarity, uint32_t time) {
|
||||
manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
|
||||
|
||||
if(data_ok) {
|
||||
readed_data = (readed_data << 1) | data;
|
||||
read_data = (read_data << 1) | data;
|
||||
|
||||
ready = em_marin.can_be_decoded(
|
||||
reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t));
|
||||
reinterpret_cast<const uint8_t*>(&read_data), sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ public:
|
||||
private:
|
||||
void reset_state();
|
||||
|
||||
uint64_t readed_data = 0;
|
||||
uint64_t read_data = 0;
|
||||
std::atomic<bool> ready;
|
||||
|
||||
ManchesterState manchester_saved_state;
|
||||
|
||||
@ -78,7 +78,7 @@ void RfidReader::start() {
|
||||
start_comparator();
|
||||
|
||||
switch_timer_reset();
|
||||
last_readed_count = 0;
|
||||
last_read_count = 0;
|
||||
}
|
||||
|
||||
void RfidReader::start_forced(RfidReader::Type _type) {
|
||||
@ -97,45 +97,45 @@ void RfidReader::stop() {
|
||||
|
||||
bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable) {
|
||||
bool result = false;
|
||||
bool something_readed = false;
|
||||
bool something_read = false;
|
||||
|
||||
// reading
|
||||
if(decoder_em.read(data, data_size)) {
|
||||
*_type = LfrfidKeyType::KeyEM4100;
|
||||
something_readed = true;
|
||||
something_read = true;
|
||||
}
|
||||
|
||||
if(decoder_hid26.read(data, data_size)) {
|
||||
*_type = LfrfidKeyType::KeyH10301;
|
||||
something_readed = true;
|
||||
something_read = true;
|
||||
}
|
||||
|
||||
if(decoder_indala.read(data, data_size)) {
|
||||
*_type = LfrfidKeyType::KeyI40134;
|
||||
something_readed = true;
|
||||
something_read = true;
|
||||
}
|
||||
|
||||
// validation
|
||||
if(something_readed) {
|
||||
if(something_read) {
|
||||
switch_timer_reset();
|
||||
|
||||
if(last_readed_type == *_type && memcmp(last_readed_data, data, data_size) == 0) {
|
||||
last_readed_count = last_readed_count + 1;
|
||||
if(last_read_type == *_type && memcmp(last_read_data, data, data_size) == 0) {
|
||||
last_read_count = last_read_count + 1;
|
||||
|
||||
if(last_readed_count > 2) {
|
||||
if(last_read_count > 2) {
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
last_readed_type = *_type;
|
||||
memcpy(last_readed_data, data, data_size);
|
||||
last_readed_count = 0;
|
||||
last_read_type = *_type;
|
||||
memcpy(last_read_data, data, data_size);
|
||||
last_read_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// mode switching
|
||||
if(switch_enable && switch_timer_elapsed()) {
|
||||
switch_mode();
|
||||
last_readed_count = 0;
|
||||
last_read_count = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -152,7 +152,7 @@ bool RfidReader::detect() {
|
||||
}
|
||||
|
||||
bool RfidReader::any_read() {
|
||||
return last_readed_count > 0;
|
||||
return last_read_count > 0;
|
||||
}
|
||||
|
||||
void RfidReader::start_comparator(void) {
|
||||
|
||||
@ -49,9 +49,9 @@ private:
|
||||
void switch_timer_reset();
|
||||
void switch_mode();
|
||||
|
||||
LfrfidKeyType last_readed_type;
|
||||
uint8_t last_readed_data[LFRFID_KEY_SIZE];
|
||||
uint8_t last_readed_count;
|
||||
LfrfidKeyType last_read_type;
|
||||
uint8_t last_read_data[LFRFID_KEY_SIZE];
|
||||
uint8_t last_read_count;
|
||||
|
||||
Type type = Type::Normal;
|
||||
};
|
||||
|
||||
@ -2,7 +2,9 @@
|
||||
#include "scene/lfrfid_app_scene_start.h"
|
||||
#include "scene/lfrfid_app_scene_read.h"
|
||||
#include "scene/lfrfid_app_scene_read_success.h"
|
||||
#include "scene/lfrfid_app_scene_readed_menu.h"
|
||||
#include "scene/lfrfid_app_scene_retry_confirm.h"
|
||||
#include "scene/lfrfid_app_scene_exit_confirm.h"
|
||||
#include "scene/lfrfid_app_scene_read_menu.h"
|
||||
#include "scene/lfrfid_app_scene_write.h"
|
||||
#include "scene/lfrfid_app_scene_write_success.h"
|
||||
#include "scene/lfrfid_app_scene_emulate.h"
|
||||
@ -48,8 +50,10 @@ void LfRfidApp::run(void* _args) {
|
||||
} else {
|
||||
scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart());
|
||||
scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead());
|
||||
scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm());
|
||||
scene_controller.add_scene(SceneType::ExitConfirm, new LfRfidAppSceneExitConfirm());
|
||||
scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess());
|
||||
scene_controller.add_scene(SceneType::ReadedMenu, new LfRfidAppSceneReadedMenu());
|
||||
scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu());
|
||||
scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite());
|
||||
scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess());
|
||||
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
|
||||
|
||||
@ -27,13 +27,17 @@ public:
|
||||
GENERIC_EVENT_ENUM_VALUES,
|
||||
Next,
|
||||
MenuSelected,
|
||||
Stay,
|
||||
Retry,
|
||||
};
|
||||
|
||||
enum class SceneType : uint8_t {
|
||||
GENERIC_SCENE_ENUM_VALUES,
|
||||
Read,
|
||||
ReadSuccess,
|
||||
ReadedMenu,
|
||||
RetryConfirm,
|
||||
ExitConfirm,
|
||||
ReadKeyMenu,
|
||||
Write,
|
||||
WriteSuccess,
|
||||
Emulate,
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include "helpers/rfid_reader.h"
|
||||
#include "helpers/rfid_timer_emulator.h"
|
||||
|
||||
void lfrfid_cli(Cli* cli, string_t args, void* context);
|
||||
static void lfrfid_cli(Cli* cli, string_t args, void* context);
|
||||
|
||||
// app cli function
|
||||
extern "C" void lfrfid_on_system_start() {
|
||||
@ -15,6 +15,8 @@ extern "C" void lfrfid_on_system_start() {
|
||||
Cli* cli = static_cast<Cli*>(furi_record_open("cli"));
|
||||
cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli, NULL);
|
||||
furi_record_close("cli");
|
||||
#else
|
||||
UNUSED(lfrfid_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -29,7 +31,7 @@ void lfrfid_cli_print_usage() {
|
||||
printf("\t<key_data> are hex-formatted\r\n");
|
||||
};
|
||||
|
||||
bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) {
|
||||
static bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) {
|
||||
bool result = false;
|
||||
|
||||
if(string_cmp_str(data, "EM4100") == 0 || string_cmp_str(data, "EM-Marin") == 0) {
|
||||
@ -46,7 +48,7 @@ bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void lfrfid_cli_read(Cli* cli, string_t args) {
|
||||
static void lfrfid_cli_read(Cli* cli, string_t args) {
|
||||
RfidReader reader;
|
||||
string_t type_string;
|
||||
string_init(type_string);
|
||||
@ -97,12 +99,12 @@ void lfrfid_cli_read(Cli* cli, string_t args) {
|
||||
string_clear(type_string);
|
||||
}
|
||||
|
||||
void lfrfid_cli_write(Cli* cli, string_t args) {
|
||||
static void lfrfid_cli_write(Cli* cli, string_t args) {
|
||||
// TODO implement rfid write
|
||||
printf("Not implemented :(\r\n");
|
||||
}
|
||||
|
||||
void lfrfid_cli_emulate(Cli* cli, string_t args) {
|
||||
static void lfrfid_cli_emulate(Cli* cli, string_t args) {
|
||||
string_t data;
|
||||
string_init(data);
|
||||
RfidTimerEmulator emulator;
|
||||
@ -144,7 +146,7 @@ void lfrfid_cli_emulate(Cli* cli, string_t args) {
|
||||
string_clear(data);
|
||||
}
|
||||
|
||||
void lfrfid_cli(Cli* cli, string_t args, void* context) {
|
||||
static void lfrfid_cli(Cli* cli, string_t args, void* context) {
|
||||
string_t cmd;
|
||||
string_init(cmd);
|
||||
|
||||
|
||||
@ -73,6 +73,11 @@ bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* eve
|
||||
app->delete_key(&app->worker.key);
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess);
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Stay) {
|
||||
app->scene_controller.switch_to_previous_scene();
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
@ -88,7 +93,7 @@ void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) {
|
||||
void LfRfidAppSceneDeleteConfirm::back_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Back;
|
||||
event.type = LfRfidApp::EventType::Stay;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
|
||||
popup->set_icon(0, 2, &I_DolphinMafia_115x62);
|
||||
popup->set_text("Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
popup->set_header("Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
popup->set_context(app);
|
||||
popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback);
|
||||
popup->set_timeout(1500);
|
||||
|
||||
59
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp
Normal file
59
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "lfrfid_app_scene_exit_confirm.h"
|
||||
#include "../view/elements/button_element.h"
|
||||
#include "../view/elements/icon_element.h"
|
||||
#include "../view/elements/string_element.h"
|
||||
|
||||
void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
auto container = app->view_controller.get<ContainerVM>();
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Left, "Exit");
|
||||
button->set_callback(app, LfRfidAppSceneExitConfirm::exit_callback);
|
||||
|
||||
button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Right, "Stay");
|
||||
button->set_callback(app, LfRfidAppSceneExitConfirm::stay_callback);
|
||||
|
||||
auto line_1 = container->add<StringElement>();
|
||||
auto line_2 = container->add<StringElement>();
|
||||
|
||||
line_1->set_text("Exit to RFID menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
|
||||
line_2->set_text(
|
||||
"All unsaved data will be lost", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneExitConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start});
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Stay) {
|
||||
app->scene_controller.switch_to_previous_scene();
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExitConfirm::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<ContainerVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExitConfirm::exit_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExitConfirm::stay_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Stay;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
13
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h
Normal file
13
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneExitConfirm : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void exit_callback(void* context);
|
||||
static void stay_callback(void* context);
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
#include "lfrfid_app_scene_readed_menu.h"
|
||||
#include "lfrfid_app_scene_read_menu.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuWrite,
|
||||
@ -6,7 +6,7 @@ typedef enum {
|
||||
SubmenuEmulate,
|
||||
} SubmenuIndex;
|
||||
|
||||
void LfRfidAppSceneReadedMenu::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
auto submenu = app->view_controller.get<SubmenuVM>();
|
||||
|
||||
submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
|
||||
@ -20,7 +20,7 @@ void LfRfidAppSceneReadedMenu::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
app->view_controller.switch_to<SubmenuVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneReadedMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::MenuSelected) {
|
||||
@ -38,18 +38,18 @@ bool LfRfidAppSceneReadedMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event)
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start});
|
||||
app->scene_controller.switch_to_previous_scene();
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadedMenu::on_exit(LfRfidApp* app) {
|
||||
void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<SubmenuVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadedMenu::submenu_callback(void* context, uint32_t index) {
|
||||
void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneReadedMenu : public GenericScene<LfRfidApp> {
|
||||
class LfRfidAppSceneReadKeyMenu : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
@ -85,7 +85,13 @@ bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadedMenu);
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadKeyMenu);
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Retry) {
|
||||
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::RetryConfirm});
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::ExitConfirm});
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
@ -103,7 +109,7 @@ void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) {
|
||||
void LfRfidAppSceneReadSuccess::back_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Back;
|
||||
event.type = LfRfidApp::EventType::Retry;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
|
||||
59
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp
Normal file
59
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "lfrfid_app_scene_retry_confirm.h"
|
||||
#include "../view/elements/button_element.h"
|
||||
#include "../view/elements/icon_element.h"
|
||||
#include "../view/elements/string_element.h"
|
||||
|
||||
void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
auto container = app->view_controller.get<ContainerVM>();
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Left, "Exit");
|
||||
button->set_callback(app, LfRfidAppSceneRetryConfirm::exit_callback);
|
||||
|
||||
button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Right, "Stay");
|
||||
button->set_callback(app, LfRfidAppSceneRetryConfirm::stay_callback);
|
||||
|
||||
auto line_1 = container->add<StringElement>();
|
||||
auto line_2 = container->add<StringElement>();
|
||||
|
||||
line_1->set_text("Return to reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
|
||||
line_2->set_text(
|
||||
"All unsaved data will be lost", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneRetryConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Read});
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Stay) {
|
||||
app->scene_controller.switch_to_previous_scene();
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRetryConfirm::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<ContainerVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRetryConfirm::exit_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRetryConfirm::stay_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Stay;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
13
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h
Normal file
13
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneRetryConfirm : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void exit_callback(void* context);
|
||||
static void stay_callback(void* context);
|
||||
};
|
||||
@ -42,7 +42,7 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess);
|
||||
} else {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedRfidSave);
|
||||
popup->set_icon(32, 5, &I_DolphinNice_96x59);
|
||||
popup->set_text("Saved!", 13, 22, AlignLeft, AlignBottom);
|
||||
popup->set_header("Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
popup->set_context(app);
|
||||
popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback);
|
||||
popup->set_timeout(1500);
|
||||
@ -22,11 +22,11 @@ bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Back) {
|
||||
bool result = app->scene_controller.has_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
|
||||
|
||||
if(result) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
|
||||
} else {
|
||||
app->scene_controller.search_and_switch_to_another_scene(
|
||||
{LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey);
|
||||
|
||||
@ -11,7 +11,7 @@ void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
|
||||
submenu->add_item("Read", SubmenuRead, submenu_callback, app);
|
||||
submenu->add_item("Saved", SubmenuSaved, submenu_callback, app);
|
||||
submenu->add_item("Add manually", SubmenuAddManually, submenu_callback, app);
|
||||
submenu->add_item("Add Manually", SubmenuAddManually, submenu_callback, app);
|
||||
|
||||
if(need_restore) {
|
||||
submenu->set_selected_item(submenu_item_selected);
|
||||
|
||||
@ -18,7 +18,7 @@ bool LfRfidAppSceneWriteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* even
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
|
||||
@ -65,39 +65,47 @@ static void loader_cli_print_usage() {
|
||||
printf("\topen <Application Name:string>\t - Open application by name\r\n");
|
||||
}
|
||||
|
||||
static FlipperApplication const* loader_find_application_by_name_in_list(
|
||||
const char* name,
|
||||
const FlipperApplication* list,
|
||||
const uint32_t n_apps) {
|
||||
for(size_t i = 0; i < n_apps; i++) {
|
||||
if(strcmp(name, list[i].name) == 0) {
|
||||
return &list[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const FlipperApplication* loader_find_application_by_name(const char* name) {
|
||||
const FlipperApplication* application = NULL;
|
||||
|
||||
for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
||||
if(strcmp(name, FLIPPER_APPS[i].name) == 0) {
|
||||
application = &FLIPPER_APPS[i];
|
||||
}
|
||||
application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT);
|
||||
if(!application) {
|
||||
application =
|
||||
loader_find_application_by_name_in_list(name, FLIPPER_PLUGINS, FLIPPER_PLUGINS_COUNT);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < FLIPPER_PLUGINS_COUNT; i++) {
|
||||
if(strcmp(name, FLIPPER_PLUGINS[i].name) == 0) {
|
||||
application = &FLIPPER_PLUGINS[i];
|
||||
}
|
||||
if(!application) {
|
||||
application = loader_find_application_by_name_in_list(
|
||||
name, FLIPPER_SETTINGS_APPS, FLIPPER_SETTINGS_APPS_COUNT);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
|
||||
if(strcmp(name, FLIPPER_SETTINGS_APPS[i].name) == 0) {
|
||||
application = &FLIPPER_SETTINGS_APPS[i];
|
||||
}
|
||||
if(!application) {
|
||||
application = loader_find_application_by_name_in_list(
|
||||
name, FLIPPER_SYSTEM_APPS, FLIPPER_SYSTEM_APPS_COUNT);
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) {
|
||||
if(strcmp(name, FLIPPER_DEBUG_APPS[i].name) == 0) {
|
||||
application = &FLIPPER_DEBUG_APPS[i];
|
||||
}
|
||||
}
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && !application) {
|
||||
application = loader_find_application_by_name_in_list(
|
||||
name, FLIPPER_DEBUG_APPS, FLIPPER_DEBUG_APPS_COUNT);
|
||||
}
|
||||
|
||||
return application;
|
||||
}
|
||||
|
||||
void loader_cli_open(Cli* cli, string_t args, Loader* instance) {
|
||||
if(loader_is_locked(instance)) {
|
||||
printf("Can't start, furi application is running");
|
||||
return;
|
||||
}
|
||||
|
||||
string_t application_name;
|
||||
string_init(application_name);
|
||||
|
||||
@ -149,7 +157,7 @@ void loader_cli_list(Cli* cli, string_t args, Loader* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
void loader_cli(Cli* cli, string_t args, void* _ctx) {
|
||||
static void loader_cli(Cli* cli, string_t args, void* _ctx) {
|
||||
furi_assert(_ctx);
|
||||
Loader* instance = _ctx;
|
||||
|
||||
@ -289,7 +297,9 @@ static Loader* loader_alloc() {
|
||||
|
||||
#ifdef SRV_CLI
|
||||
instance->cli = furi_record_open("cli");
|
||||
cli_add_command(instance->cli, "loader", CliCommandFlagDefault, loader_cli, instance);
|
||||
cli_add_command(instance->cli, "loader", CliCommandFlagParallelSafe, loader_cli, instance);
|
||||
#else
|
||||
UNUSED(loader_cli);
|
||||
#endif
|
||||
|
||||
instance->loader_thread = osThreadGetId();
|
||||
@ -386,7 +396,7 @@ static void loader_build_menu() {
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
menu_add_item(
|
||||
loader_instance->primary_menu,
|
||||
"Debug tools",
|
||||
"Debug Tools",
|
||||
&A_Debug_14,
|
||||
i++,
|
||||
loader_submenu_callback,
|
||||
|
||||
@ -136,5 +136,7 @@ void nfc_on_system_start() {
|
||||
Cli* cli = furi_record_open("cli");
|
||||
cli_add_command(cli, "nfc", CliCommandFlagDefault, nfc_cli, NULL);
|
||||
furi_record_close("cli");
|
||||
#else
|
||||
UNUSED(nfc_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
|
||||
if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Run compatible app",
|
||||
"Run Compatible App",
|
||||
SubmenuIndexRunApp,
|
||||
nfc_scene_card_menu_submenu_callback,
|
||||
nfc);
|
||||
@ -34,7 +34,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
|
||||
submenu_add_item(
|
||||
submenu, "Emulate UID", SubmenuIndexEmulate, nfc_scene_card_menu_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Name and save UID", SubmenuIndexSave, nfc_scene_card_menu_submenu_callback, nfc);
|
||||
submenu, "Save UID", SubmenuIndexSave, nfc_scene_card_menu_submenu_callback, nfc);
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneCardMenu));
|
||||
|
||||
|
||||
@ -15,11 +15,7 @@ void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Name and save",
|
||||
SubmenuIndexSave,
|
||||
nfc_scene_mifare_desfire_menu_submenu_callback,
|
||||
nfc);
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_desfire_menu_submenu_callback, nfc);
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu,
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireMenu));
|
||||
|
||||
@ -16,7 +16,7 @@ void nfc_scene_mifare_ul_menu_on_enter(void* context) {
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Name and save", SubmenuIndexSave, nfc_scene_mifare_ul_menu_submenu_callback, nfc);
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_ul_menu_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mifare_ul_menu_submenu_callback, nfc);
|
||||
submenu_set_selected_item(
|
||||
|
||||
@ -36,7 +36,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
|
||||
nfc);
|
||||
}
|
||||
submenu_add_item(
|
||||
submenu, "Edit UID and name", SubmenuIndexEdit, nfc_scene_saved_menu_submenu_callback, nfc);
|
||||
submenu, "Edit UID and Name", SubmenuIndexEdit, nfc_scene_saved_menu_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
|
||||
@ -18,7 +18,7 @@ void nfc_scene_scripts_menu_on_enter(void* context) {
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Read bank card",
|
||||
"Read Bank Card",
|
||||
SubmenuIndexBankCard,
|
||||
nfc_scene_scripts_menu_submenu_callback,
|
||||
nfc);
|
||||
|
||||
@ -19,17 +19,16 @@ void nfc_scene_start_on_enter(void* context) {
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Read card", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu, "Read Card", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Run special action",
|
||||
"Run Special Action",
|
||||
SubmenuIndexRunScript,
|
||||
nfc_scene_start_submenu_callback,
|
||||
nfc);
|
||||
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Saved cards", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Add manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu, "Add Manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
submenu_add_item(
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <storage/storage.h>
|
||||
#include <input/input.h>
|
||||
#include "notification.h"
|
||||
#include "notification_messages.h"
|
||||
#include "notification_app.h"
|
||||
@ -163,7 +164,6 @@ void notification_process_notification_message(
|
||||
notification_message = (*message->sequence)[notification_message_index];
|
||||
|
||||
bool led_active = false;
|
||||
uint8_t display_led_lock = 0;
|
||||
uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
|
||||
bool reset_notifications = true;
|
||||
float speaker_volume_setting = app->settings.speaker_volume;
|
||||
@ -191,18 +191,18 @@ void notification_process_notification_message(
|
||||
reset_mask |= reset_display_mask;
|
||||
break;
|
||||
case NotificationMessageTypeLedDisplayLock:
|
||||
furi_assert(display_led_lock < UINT8_MAX);
|
||||
display_led_lock++;
|
||||
if(display_led_lock == 1) {
|
||||
furi_assert(app->display_led_lock < UINT8_MAX);
|
||||
app->display_led_lock++;
|
||||
if(app->display_led_lock == 1) {
|
||||
notification_apply_internal_led_layer(
|
||||
&app->display,
|
||||
notification_message->data.led.value * display_brightness_setting);
|
||||
}
|
||||
break;
|
||||
case NotificationMessageTypeLedDisplayUnlock:
|
||||
furi_assert(display_led_lock > 0);
|
||||
display_led_lock--;
|
||||
if(display_led_lock == 0) {
|
||||
furi_assert(app->display_led_lock > 0);
|
||||
app->display_led_lock--;
|
||||
if(app->display_led_lock == 0) {
|
||||
notification_apply_internal_led_layer(
|
||||
&app->display,
|
||||
notification_message->data.led.value * display_brightness_setting);
|
||||
@ -416,6 +416,8 @@ static bool notification_save_settings(NotificationApp* app) {
|
||||
};
|
||||
|
||||
static void input_event_callback(const void* value, void* context) {
|
||||
furi_assert(value);
|
||||
furi_assert(context);
|
||||
NotificationApp* app = context;
|
||||
notification_message(app, &sequence_display_on);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user