Merge remote-tracking branch 'origin/dev' into release-candidate
75
.github/workflows/build.yml
vendored
@ -9,7 +9,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
TARGETS: f7
|
TARGETS: f7 f18
|
||||||
DEFAULT_TARGET: f7
|
DEFAULT_TARGET: f7
|
||||||
FBT_TOOLCHAIN_PATH: /runner/_work
|
FBT_TOOLCHAIN_PATH: /runner/_work
|
||||||
|
|
||||||
@ -52,10 +52,8 @@ jobs:
|
|||||||
|
|
||||||
- name: 'Make artifacts directory'
|
- name: 'Make artifacts directory'
|
||||||
run: |
|
run: |
|
||||||
rm -rf artifacts
|
rm -rf artifacts map_analyser_files
|
||||||
rm -rf map_analyser_files
|
mkdir artifacts map_analyser_files
|
||||||
mkdir artifacts
|
|
||||||
mkdir map_analyser_files
|
|
||||||
|
|
||||||
- name: 'Bundle scripts'
|
- name: 'Bundle scripts'
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
@ -66,28 +64,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
for TARGET in ${TARGETS}; do
|
for TARGET in ${TARGETS}; do
|
||||||
TARGET="$(echo "${TARGET}" | sed 's/f//')"; \
|
TARGET_HW="$(echo "${TARGET}" | sed 's/f//')"; \
|
||||||
./fbt TARGET_HW=$TARGET copro_dist updater_package \
|
./fbt TARGET_HW=$TARGET_HW copro_dist updater_package \
|
||||||
${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
|
||||||
done
|
|
||||||
|
|
||||||
- name: 'Move upload files'
|
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
|
||||||
run: |
|
|
||||||
set -e
|
|
||||||
for TARGET in ${TARGETS}; do
|
|
||||||
mv dist/${TARGET}-*/* artifacts/
|
mv dist/${TARGET}-*/* artifacts/
|
||||||
|
tar czpf "artifacts/flipper-z-${TARGET}-resources-${SUFFIX}.tgz" \
|
||||||
|
-C assets resources
|
||||||
|
./fbt TARGET_HW=$TARGET_HW fap_dist
|
||||||
|
tar czpf "artifacts/flipper-z-${TARGET}-debugapps-${SUFFIX}.tgz" \
|
||||||
|
-C dist/${TARGET}-*/apps/Debug .
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: "Check for uncommitted changes"
|
- name: "Check for uncommitted changes"
|
||||||
run: |
|
run: |
|
||||||
git diff --exit-code
|
git diff --exit-code
|
||||||
|
|
||||||
- name: 'Bundle resources'
|
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
|
||||||
run: |
|
|
||||||
tar czpf "artifacts/flipper-z-any-resources-${SUFFIX}.tgz" -C assets resources
|
|
||||||
|
|
||||||
- name: 'Bundle core2 firmware'
|
- name: 'Bundle core2 firmware'
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
run: |
|
run: |
|
||||||
@ -96,29 +87,35 @@ jobs:
|
|||||||
- name: 'Copy map analyser files'
|
- name: 'Copy map analyser files'
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
run: |
|
run: |
|
||||||
cp build/f7-firmware-*/firmware.elf.map map_analyser_files/firmware.elf.map
|
cp build/${DEFAULT_TARGET}-firmware-*/firmware.elf.map map_analyser_files/firmware.elf.map
|
||||||
cp build/f7-firmware-*/firmware.elf map_analyser_files/firmware.elf
|
cp build/${DEFAULT_TARGET}-firmware-*/firmware.elf map_analyser_files/firmware.elf
|
||||||
cp ${{ github.event_path }} map_analyser_files/event.json
|
cp ${{ github.event_path }} map_analyser_files/event.json
|
||||||
|
|
||||||
- name: 'Upload map analyser files to storage'
|
- name: 'Analyse map file'
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
uses: prewk/s3-cp-action@v2
|
run: |
|
||||||
with:
|
source scripts/toolchain/fbtenv.sh
|
||||||
aws_s3_endpoint: "${{ secrets.MAP_REPORT_AWS_ENDPOINT }}"
|
get_size()
|
||||||
aws_access_key_id: "${{ secrets.MAP_REPORT_AWS_ACCESS_KEY }}"
|
{
|
||||||
aws_secret_access_key: "${{ secrets.MAP_REPORT_AWS_SECRET_KEY }}"
|
SECTION="$1";
|
||||||
source: "./map_analyser_files/"
|
arm-none-eabi-size \
|
||||||
dest: "s3://${{ secrets.MAP_REPORT_AWS_BUCKET }}/${{steps.names.outputs.random_hash}}"
|
-A map_analyser_files/firmware.elf \
|
||||||
flags: "--recursive --acl public-read"
|
| grep "^$SECTION" | awk '{print $2}'
|
||||||
|
}
|
||||||
- name: 'Trigger map file reporter'
|
export BSS_SIZE="$(get_size ".bss")"
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
export TEXT_SIZE="$(get_size ".text")"
|
||||||
uses: peter-evans/repository-dispatch@v2
|
export RODATA_SIZE="$(get_size ".rodata")"
|
||||||
with:
|
export DATA_SIZE="$(get_size ".data")"
|
||||||
repository: flipperdevices/flipper-map-reporter
|
export FREE_FLASH_SIZE="$(get_size ".free_flash")"
|
||||||
token: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }}
|
python3 -m pip install mariadb==1.1.6 cxxfilt==0.3.0
|
||||||
event-type: map-file-analyse
|
python3 scripts/map_parser.py map_analyser_files/firmware.elf.map map_analyser_files/firmware.elf.map.all
|
||||||
client-payload: '{"random_hash": "${{steps.names.outputs.random_hash}}", "event_type": "${{steps.names.outputs.event_type}}"}'
|
python3 scripts/map_mariadb_insert.py \
|
||||||
|
${{ secrets.AMAP_MARIADB_USER }} \
|
||||||
|
${{ secrets.AMAP_MARIADB_PASSWORD }} \
|
||||||
|
${{ secrets.AMAP_MARIADB_HOST }} \
|
||||||
|
${{ secrets.AMAP_MARIADB_PORT }} \
|
||||||
|
${{ secrets.AMAP_MARIADB_DATABASE }} \
|
||||||
|
map_analyser_files/firmware.elf.map.all
|
||||||
|
|
||||||
- name: 'Upload artifacts to update server'
|
- name: 'Upload artifacts to update server'
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
|
|||||||
@ -171,7 +171,7 @@ distenv.Depends(firmware_env["FW_RESOURCES"], external_apps_artifacts.resources_
|
|||||||
|
|
||||||
fap_deploy = distenv.PhonyTarget(
|
fap_deploy = distenv.PhonyTarget(
|
||||||
"fap_deploy",
|
"fap_deploy",
|
||||||
"${PYTHON3} ${ROOT_DIR}/scripts/storage.py send ${SOURCE} /ext/apps",
|
"${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send ${SOURCE} /ext/apps",
|
||||||
source=Dir("#/assets/resources/apps"),
|
source=Dir("#/assets/resources/apps"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -323,7 +323,9 @@ distenv.PhonyTarget(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Start Flipper CLI via PySerial's miniterm
|
# Start Flipper CLI via PySerial's miniterm
|
||||||
distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py")
|
distenv.PhonyTarget(
|
||||||
|
"cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Find blackmagic probe
|
# Find blackmagic probe
|
||||||
|
|||||||
4
applications/external/hid_app/hid.c
vendored
@ -377,7 +377,7 @@ int32_t hid_usb_app(void* p) {
|
|||||||
|
|
||||||
bt_hid_connection_status_changed_callback(BtStatusConnected, app);
|
bt_hid_connection_status_changed_callback(BtStatusConnected, app);
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedPluginStart);
|
dolphin_deed(DolphinDeedPluginStart);
|
||||||
|
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
|
|
||||||
@ -417,7 +417,7 @@ int32_t hid_ble_app(void* p) {
|
|||||||
furi_hal_bt_start_advertising();
|
furi_hal_bt_start_advertising();
|
||||||
bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app);
|
bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app);
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedPluginStart);
|
dolphin_deed(DolphinDeedPluginStart);
|
||||||
|
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
|
|
||||||
|
|||||||
2
applications/external/mfkey32/mfkey32.c
vendored
@ -1112,7 +1112,7 @@ void mfkey32(ProgramState* program_state) {
|
|||||||
}
|
}
|
||||||
if(keyarray_size > 0) {
|
if(keyarray_size > 0) {
|
||||||
// TODO: Should we use DolphinDeedNfcMfcAdd?
|
// TODO: Should we use DolphinDeedNfcMfcAdd?
|
||||||
DOLPHIN_DEED(DolphinDeedNfcMfcAdd);
|
dolphin_deed(DolphinDeedNfcMfcAdd);
|
||||||
}
|
}
|
||||||
napi_mf_classic_nonce_array_free(nonce_arr);
|
napi_mf_classic_nonce_array_free(nonce_arr);
|
||||||
napi_mf_classic_dict_free(user_dict);
|
napi_mf_classic_dict_free(user_dict);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ void picopass_scene_device_info_on_enter(void* context) {
|
|||||||
FuriString* wiegand_str = furi_string_alloc();
|
FuriString* wiegand_str = furi_string_alloc();
|
||||||
FuriString* sio_str = furi_string_alloc();
|
FuriString* sio_str = furi_string_alloc();
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
PicopassBlock* AA1 = picopass->dev->dev_data.AA1;
|
PicopassBlock* AA1 = picopass->dev->dev_data.AA1;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context
|
|||||||
|
|
||||||
void picopass_scene_read_card_on_enter(void* context) {
|
void picopass_scene_read_card_on_enter(void* context) {
|
||||||
Picopass* picopass = context;
|
Picopass* picopass = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = picopass->popup;
|
Popup* popup = picopass->popup;
|
||||||
|
|||||||
@ -21,7 +21,7 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|||||||
FuriString* wiegand_str = furi_string_alloc();
|
FuriString* wiegand_str = furi_string_alloc();
|
||||||
FuriString* sio_str = furi_string_alloc();
|
FuriString* sio_str = furi_string_alloc();
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Send notification
|
// Send notification
|
||||||
notification_message(picopass->notifications, &sequence_success);
|
notification_message(picopass->notifications, &sequence_success);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ void picopass_scene_read_factory_success_on_enter(void* context) {
|
|||||||
FuriString* title = furi_string_alloc_set("Factory Default");
|
FuriString* title = furi_string_alloc_set("Factory Default");
|
||||||
FuriString* subtitle = furi_string_alloc_set("");
|
FuriString* subtitle = furi_string_alloc_set("");
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Send notification
|
// Send notification
|
||||||
notification_message(picopass->notifications, &sequence_success);
|
notification_message(picopass->notifications, &sequence_success);
|
||||||
|
|||||||
@ -8,7 +8,7 @@ void picopass_scene_save_success_popup_callback(void* context) {
|
|||||||
|
|
||||||
void picopass_scene_save_success_on_enter(void* context) {
|
void picopass_scene_save_success_on_enter(void* context) {
|
||||||
Picopass* picopass = context;
|
Picopass* picopass = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = picopass->popup;
|
Popup* popup = picopass->popup;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ void picopass_write_card_worker_callback(PicopassWorkerEvent event, void* contex
|
|||||||
|
|
||||||
void picopass_scene_write_card_on_enter(void* context) {
|
void picopass_scene_write_card_on_enter(void* context) {
|
||||||
Picopass* picopass = context;
|
Picopass* picopass = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = picopass->popup;
|
Popup* popup = picopass->popup;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ void picopass_scene_write_card_success_on_enter(void* context) {
|
|||||||
Widget* widget = picopass->widget;
|
Widget* widget = picopass->widget;
|
||||||
FuriString* str = furi_string_alloc_set("Write Success!");
|
FuriString* str = furi_string_alloc_set("Write Success!");
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Send notification
|
// Send notification
|
||||||
notification_message(picopass->notifications, &sequence_success);
|
notification_message(picopass->notifications, &sequence_success);
|
||||||
|
|||||||
@ -9,7 +9,7 @@ void picopass_write_key_worker_callback(PicopassWorkerEvent event, void* context
|
|||||||
|
|
||||||
void picopass_scene_write_key_on_enter(void* context) {
|
void picopass_scene_write_key_on_enter(void* context) {
|
||||||
Picopass* picopass = context;
|
Picopass* picopass = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = picopass->popup;
|
Popup* popup = picopass->popup;
|
||||||
|
|||||||
@ -346,7 +346,7 @@ int32_t snake_game_app(void* p) {
|
|||||||
|
|
||||||
notification_message_block(notification, &sequence_display_backlight_enforce_on);
|
notification_message_block(notification, &sequence_display_backlight_enforce_on);
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
dolphin_deed(DolphinDeedPluginGameStart);
|
||||||
|
|
||||||
SnakeEvent event;
|
SnakeEvent event;
|
||||||
for(bool processing = true; processing;) {
|
for(bool processing = true; processing;) {
|
||||||
|
|||||||
365
applications/external/weather_station/protocols/oregon3.c
vendored
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
#include "oregon3.h"
|
||||||
|
|
||||||
|
#include <lib/subghz/blocks/const.h>
|
||||||
|
#include <lib/subghz/blocks/decoder.h>
|
||||||
|
#include <lib/subghz/blocks/encoder.h>
|
||||||
|
#include <lib/subghz/blocks/math.h>
|
||||||
|
#include "ws_generic.h"
|
||||||
|
|
||||||
|
#include <lib/toolbox/manchester_decoder.h>
|
||||||
|
#include <lib/flipper_format/flipper_format_i.h>
|
||||||
|
|
||||||
|
#define TAG "WSProtocolOregon3"
|
||||||
|
|
||||||
|
static const SubGhzBlockConst ws_oregon3_const = {
|
||||||
|
.te_long = 1100,
|
||||||
|
.te_short = 500,
|
||||||
|
.te_delta = 300,
|
||||||
|
.min_count_bit_for_found = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OREGON3_PREAMBLE_BITS 28
|
||||||
|
#define OREGON3_PREAMBLE_MASK 0b1111111111111111111111111111
|
||||||
|
// 24 ones + 0101 (inverted A)
|
||||||
|
#define OREGON3_PREAMBLE 0b1111111111111111111111110101
|
||||||
|
|
||||||
|
// Fixed part contains:
|
||||||
|
// - Sensor type: 16 bits
|
||||||
|
// - Channel: 4 bits
|
||||||
|
// - ID (changes when batteries are changed): 8 bits
|
||||||
|
// - Battery status: 4 bits
|
||||||
|
#define OREGON3_FIXED_PART_BITS (16 + 4 + 8 + 4)
|
||||||
|
#define OREGON3_SENSOR_ID(d) (((d) >> 16) & 0xFFFF)
|
||||||
|
#define OREGON3_CHECKSUM_BITS 8
|
||||||
|
|
||||||
|
// bit indicating the low battery
|
||||||
|
#define OREGON3_FLAG_BAT_LOW 0x4
|
||||||
|
|
||||||
|
/// Documentation for Oregon Scientific protocols can be found here:
|
||||||
|
/// https://www.osengr.org/Articles/OS-RF-Protocols-IV.pdf
|
||||||
|
// Sensors ID
|
||||||
|
#define ID_THGR221 0xf824
|
||||||
|
|
||||||
|
struct WSProtocolDecoderOregon3 {
|
||||||
|
SubGhzProtocolDecoderBase base;
|
||||||
|
|
||||||
|
SubGhzBlockDecoder decoder;
|
||||||
|
WSBlockGeneric generic;
|
||||||
|
ManchesterState manchester_state;
|
||||||
|
bool prev_bit;
|
||||||
|
|
||||||
|
uint8_t var_bits;
|
||||||
|
uint64_t var_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct WSProtocolDecoderOregon3 WSProtocolDecoderOregon3;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Oregon3DecoderStepReset = 0,
|
||||||
|
Oregon3DecoderStepFoundPreamble,
|
||||||
|
Oregon3DecoderStepVarData,
|
||||||
|
} Oregon3DecoderStep;
|
||||||
|
|
||||||
|
void* ws_protocol_decoder_oregon3_alloc(SubGhzEnvironment* environment) {
|
||||||
|
UNUSED(environment);
|
||||||
|
WSProtocolDecoderOregon3* instance = malloc(sizeof(WSProtocolDecoderOregon3));
|
||||||
|
instance->base.protocol = &ws_protocol_oregon3;
|
||||||
|
instance->generic.protocol_name = instance->base.protocol->name;
|
||||||
|
instance->generic.humidity = WS_NO_HUMIDITY;
|
||||||
|
instance->generic.temp = WS_NO_TEMPERATURE;
|
||||||
|
instance->generic.btn = WS_NO_BTN;
|
||||||
|
instance->generic.channel = WS_NO_CHANNEL;
|
||||||
|
instance->generic.battery_low = WS_NO_BATT;
|
||||||
|
instance->generic.id = WS_NO_ID;
|
||||||
|
instance->prev_bit = false;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_oregon3_free(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderOregon3* instance = context;
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_oregon3_reset(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderOregon3* instance = context;
|
||||||
|
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||||
|
instance->decoder.decode_data = 0UL;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
manchester_advance(
|
||||||
|
instance->manchester_state, ManchesterEventReset, &instance->manchester_state, NULL);
|
||||||
|
instance->prev_bit = false;
|
||||||
|
instance->var_data = 0;
|
||||||
|
instance->var_bits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) {
|
||||||
|
bool is_long = false;
|
||||||
|
|
||||||
|
if(DURATION_DIFF(duration, ws_oregon3_const.te_long) < ws_oregon3_const.te_delta) {
|
||||||
|
is_long = true;
|
||||||
|
} else if(DURATION_DIFF(duration, ws_oregon3_const.te_short) < ws_oregon3_const.te_delta) {
|
||||||
|
is_long = false;
|
||||||
|
} else {
|
||||||
|
return ManchesterEventReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(level)
|
||||||
|
return is_long ? ManchesterEventLongHigh : ManchesterEventShortHigh;
|
||||||
|
else
|
||||||
|
return is_long ? ManchesterEventLongLow : ManchesterEventShortLow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From sensor id code return amount of bits in variable section
|
||||||
|
// https://temofeev.ru/info/articles/o-dekodirovanii-protokola-pogodnykh-datchikov-oregon-scientific
|
||||||
|
static uint8_t oregon3_sensor_id_var_bits(uint16_t sensor_id) {
|
||||||
|
switch(sensor_id) {
|
||||||
|
case ID_THGR221:
|
||||||
|
default:
|
||||||
|
// nibbles: temp + hum + '0'
|
||||||
|
return (4 + 2 + 1) * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ws_oregon3_decode_const_data(WSBlockGeneric* ws_block) {
|
||||||
|
ws_block->id = OREGON3_SENSOR_ID(ws_block->data);
|
||||||
|
ws_block->channel = (ws_block->data >> 12) & 0xF;
|
||||||
|
ws_block->battery_low = (ws_block->data & OREGON3_FLAG_BAT_LOW) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t ws_oregon3_bcd_decode_short(uint32_t data) {
|
||||||
|
return (data & 0xF) * 10 + ((data >> 4) & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float ws_oregon3_decode_temp(uint32_t data) {
|
||||||
|
int32_t temp_val;
|
||||||
|
temp_val = ws_oregon3_bcd_decode_short(data >> 4);
|
||||||
|
temp_val *= 10;
|
||||||
|
temp_val += (data >> 12) & 0xF;
|
||||||
|
if(data & 0xF) temp_val = -temp_val;
|
||||||
|
return (float)temp_val / 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ws_oregon3_decode_var_data(WSBlockGeneric* ws_b, uint16_t sensor_id, uint32_t data) {
|
||||||
|
switch(sensor_id) {
|
||||||
|
case ID_THGR221:
|
||||||
|
default:
|
||||||
|
ws_b->humidity = ws_oregon3_bcd_decode_short(data >> 4);
|
||||||
|
ws_b->temp = ws_oregon3_decode_temp(data >> 12);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_oregon3_feed(void* context, bool level, uint32_t duration) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderOregon3* instance = context;
|
||||||
|
// Oregon v3.0 protocol is inverted
|
||||||
|
ManchesterEvent event = level_and_duration_to_event(!level, duration);
|
||||||
|
|
||||||
|
// low-level bit sequence decoding
|
||||||
|
if(event == ManchesterEventReset) {
|
||||||
|
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||||
|
instance->prev_bit = false;
|
||||||
|
instance->decoder.decode_data = 0UL;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
}
|
||||||
|
if(manchester_advance(
|
||||||
|
instance->manchester_state, event, &instance->manchester_state, &instance->prev_bit)) {
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, instance->prev_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(instance->decoder.parser_step) {
|
||||||
|
case Oregon3DecoderStepReset:
|
||||||
|
// waiting for fixed oregon3 preamble
|
||||||
|
if(instance->decoder.decode_count_bit >= OREGON3_PREAMBLE_BITS &&
|
||||||
|
((instance->decoder.decode_data & OREGON3_PREAMBLE_MASK) == OREGON3_PREAMBLE)) {
|
||||||
|
instance->decoder.parser_step = Oregon3DecoderStepFoundPreamble;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
instance->decoder.decode_data = 0UL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Oregon3DecoderStepFoundPreamble:
|
||||||
|
// waiting for fixed oregon3 data
|
||||||
|
if(instance->decoder.decode_count_bit == OREGON3_FIXED_PART_BITS) {
|
||||||
|
instance->generic.data = instance->decoder.decode_data;
|
||||||
|
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
|
||||||
|
instance->decoder.decode_data = 0UL;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
|
||||||
|
// reverse nibbles in decoded data as oregon v3.0 is LSB first
|
||||||
|
instance->generic.data = (instance->generic.data & 0x55555555) << 1 |
|
||||||
|
(instance->generic.data & 0xAAAAAAAA) >> 1;
|
||||||
|
instance->generic.data = (instance->generic.data & 0x33333333) << 2 |
|
||||||
|
(instance->generic.data & 0xCCCCCCCC) >> 2;
|
||||||
|
|
||||||
|
ws_oregon3_decode_const_data(&instance->generic);
|
||||||
|
instance->var_bits =
|
||||||
|
oregon3_sensor_id_var_bits(OREGON3_SENSOR_ID(instance->generic.data));
|
||||||
|
|
||||||
|
if(!instance->var_bits) {
|
||||||
|
// sensor is not supported, stop decoding, but showing the decoded fixed part
|
||||||
|
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||||
|
if(instance->base.callback)
|
||||||
|
instance->base.callback(&instance->base, instance->base.context);
|
||||||
|
} else {
|
||||||
|
instance->decoder.parser_step = Oregon3DecoderStepVarData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Oregon3DecoderStepVarData:
|
||||||
|
// waiting for variable (sensor-specific data)
|
||||||
|
if(instance->decoder.decode_count_bit == instance->var_bits + OREGON3_CHECKSUM_BITS) {
|
||||||
|
instance->var_data = instance->decoder.decode_data & 0xFFFFFFFFFFFFFFFF;
|
||||||
|
|
||||||
|
// reverse nibbles in var data
|
||||||
|
instance->var_data = (instance->var_data & 0x5555555555555555) << 1 |
|
||||||
|
(instance->var_data & 0xAAAAAAAAAAAAAAAA) >> 1;
|
||||||
|
instance->var_data = (instance->var_data & 0x3333333333333333) << 2 |
|
||||||
|
(instance->var_data & 0xCCCCCCCCCCCCCCCC) >> 2;
|
||||||
|
|
||||||
|
ws_oregon3_decode_var_data(
|
||||||
|
&instance->generic,
|
||||||
|
OREGON3_SENSOR_ID(instance->generic.data),
|
||||||
|
instance->var_data >> OREGON3_CHECKSUM_BITS);
|
||||||
|
|
||||||
|
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||||
|
if(instance->base.callback)
|
||||||
|
instance->base.callback(&instance->base, instance->base.context);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ws_protocol_decoder_oregon3_get_hash_data(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderOregon3* instance = context;
|
||||||
|
return subghz_protocol_blocks_get_hash_data(
|
||||||
|
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus ws_protocol_decoder_oregon3_serialize(
|
||||||
|
void* context,
|
||||||
|
FlipperFormat* flipper_format,
|
||||||
|
SubGhzRadioPreset* preset) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderOregon3* instance = context;
|
||||||
|
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
|
||||||
|
ret = ws_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||||
|
if(ret != SubGhzProtocolStatusOk) return ret;
|
||||||
|
uint32_t temp = instance->var_bits;
|
||||||
|
if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) {
|
||||||
|
FURI_LOG_E(TAG, "Error adding VarBits");
|
||||||
|
return SubGhzProtocolStatusErrorParserOthers;
|
||||||
|
}
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
flipper_format,
|
||||||
|
"VarData",
|
||||||
|
(const uint8_t*)&instance->var_data,
|
||||||
|
sizeof(instance->var_data))) {
|
||||||
|
FURI_LOG_E(TAG, "Error adding VarData");
|
||||||
|
return SubGhzProtocolStatusErrorParserOthers;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
ws_protocol_decoder_oregon3_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderOregon3* instance = context;
|
||||||
|
uint32_t temp_data;
|
||||||
|
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
|
||||||
|
do {
|
||||||
|
ret = ws_block_generic_deserialize(&instance->generic, flipper_format);
|
||||||
|
if(ret != SubGhzProtocolStatusOk) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) {
|
||||||
|
FURI_LOG_E(TAG, "Missing VarLen");
|
||||||
|
ret = SubGhzProtocolStatusErrorParserOthers;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
instance->var_bits = (uint8_t)temp_data;
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
flipper_format,
|
||||||
|
"VarData",
|
||||||
|
(uint8_t*)&instance->var_data,
|
||||||
|
sizeof(instance->var_data))) { //-V1051
|
||||||
|
FURI_LOG_E(TAG, "Missing VarData");
|
||||||
|
ret = SubGhzProtocolStatusErrorParserOthers;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(instance->generic.data_count_bit != ws_oregon3_const.min_count_bit_for_found) {
|
||||||
|
FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit);
|
||||||
|
ret = SubGhzProtocolStatusErrorValueBitCount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oregon3_append_check_sum(uint32_t fix_data, uint64_t var_data, FuriString* output) {
|
||||||
|
uint8_t sum = fix_data & 0xF;
|
||||||
|
uint8_t ref_sum = var_data & 0xFF;
|
||||||
|
var_data >>= 4;
|
||||||
|
|
||||||
|
for(uint8_t i = 1; i < 8; i++) {
|
||||||
|
fix_data >>= 4;
|
||||||
|
var_data >>= 4;
|
||||||
|
sum += (fix_data & 0xF) + (var_data & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap calculated sum nibbles
|
||||||
|
sum = (((sum >> 4) & 0xF) | (sum << 4)) & 0xFF;
|
||||||
|
if(sum == ref_sum)
|
||||||
|
furi_string_cat_printf(output, "Sum ok: 0x%hhX", ref_sum);
|
||||||
|
else
|
||||||
|
furi_string_cat_printf(output, "Sum err: 0x%hhX vs 0x%hhX", ref_sum, sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_protocol_decoder_oregon3_get_string(void* context, FuriString* output) {
|
||||||
|
furi_assert(context);
|
||||||
|
WSProtocolDecoderOregon3* instance = context;
|
||||||
|
furi_string_cat_printf(
|
||||||
|
output,
|
||||||
|
"%s\r\n"
|
||||||
|
"ID: 0x%04lX, ch: %d, bat: %d, rc: 0x%02lX\r\n",
|
||||||
|
instance->generic.protocol_name,
|
||||||
|
instance->generic.id,
|
||||||
|
instance->generic.channel,
|
||||||
|
instance->generic.battery_low,
|
||||||
|
(uint32_t)(instance->generic.data >> 4) & 0xFF);
|
||||||
|
|
||||||
|
if(instance->var_bits > 0) {
|
||||||
|
furi_string_cat_printf(
|
||||||
|
output,
|
||||||
|
"Temp:%d.%d C Hum:%d%%",
|
||||||
|
(int16_t)instance->generic.temp,
|
||||||
|
abs(
|
||||||
|
((int16_t)(instance->generic.temp * 10) -
|
||||||
|
(((int16_t)instance->generic.temp) * 10))),
|
||||||
|
instance->generic.humidity);
|
||||||
|
oregon3_append_check_sum((uint32_t)instance->generic.data, instance->var_data, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubGhzProtocolDecoder ws_protocol_oregon3_decoder = {
|
||||||
|
.alloc = ws_protocol_decoder_oregon3_alloc,
|
||||||
|
.free = ws_protocol_decoder_oregon3_free,
|
||||||
|
|
||||||
|
.feed = ws_protocol_decoder_oregon3_feed,
|
||||||
|
.reset = ws_protocol_decoder_oregon3_reset,
|
||||||
|
|
||||||
|
.get_hash_data = ws_protocol_decoder_oregon3_get_hash_data,
|
||||||
|
.serialize = ws_protocol_decoder_oregon3_serialize,
|
||||||
|
.deserialize = ws_protocol_decoder_oregon3_deserialize,
|
||||||
|
.get_string = ws_protocol_decoder_oregon3_get_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubGhzProtocol ws_protocol_oregon3 = {
|
||||||
|
.name = WS_PROTOCOL_OREGON3_NAME,
|
||||||
|
.type = SubGhzProtocolWeatherStation,
|
||||||
|
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
|
||||||
|
|
||||||
|
.decoder = &ws_protocol_oregon3_decoder,
|
||||||
|
};
|
||||||
6
applications/external/weather_station/protocols/oregon3.h
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lib/subghz/protocols/base.h>
|
||||||
|
|
||||||
|
#define WS_PROTOCOL_OREGON3_NAME "Oregon3"
|
||||||
|
extern const SubGhzProtocol ws_protocol_oregon3;
|
||||||
@ -11,6 +11,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = {
|
|||||||
&ws_protocol_lacrosse_tx,
|
&ws_protocol_lacrosse_tx,
|
||||||
&ws_protocol_lacrosse_tx141thbv2,
|
&ws_protocol_lacrosse_tx141thbv2,
|
||||||
&ws_protocol_oregon2,
|
&ws_protocol_oregon2,
|
||||||
|
&ws_protocol_oregon3,
|
||||||
&ws_protocol_acurite_592txr,
|
&ws_protocol_acurite_592txr,
|
||||||
&ws_protocol_ambient_weather,
|
&ws_protocol_ambient_weather,
|
||||||
&ws_protocol_auriol_th,
|
&ws_protocol_auriol_th,
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "lacrosse_tx.h"
|
#include "lacrosse_tx.h"
|
||||||
#include "lacrosse_tx141thbv2.h"
|
#include "lacrosse_tx141thbv2.h"
|
||||||
#include "oregon2.h"
|
#include "oregon2.h"
|
||||||
|
#include "oregon3.h"
|
||||||
#include "acurite_592txr.h"
|
#include "acurite_592txr.h"
|
||||||
#include "ambient_weather.h"
|
#include "ambient_weather.h"
|
||||||
#include "auriol_hg0601a.h"
|
#include "auriol_hg0601a.h"
|
||||||
|
|||||||
@ -426,7 +426,7 @@ static int32_t bad_usb_worker(void* context) {
|
|||||||
if(flags & WorkerEvtEnd) {
|
if(flags & WorkerEvtEnd) {
|
||||||
break;
|
break;
|
||||||
} else if(flags & WorkerEvtStartStop) { // Start executing script
|
} else if(flags & WorkerEvtStartStop) { // Start executing script
|
||||||
DOLPHIN_DEED(DolphinDeedBadUsbPlayScript);
|
dolphin_deed(DolphinDeedBadUsbPlayScript);
|
||||||
delay_val = 0;
|
delay_val = 0;
|
||||||
bad_usb->buf_len = 0;
|
bad_usb->buf_len = 0;
|
||||||
bad_usb->st.line_cur = 0;
|
bad_usb->st.line_cur = 0;
|
||||||
@ -449,7 +449,7 @@ static int32_t bad_usb_worker(void* context) {
|
|||||||
if(flags & WorkerEvtEnd) {
|
if(flags & WorkerEvtEnd) {
|
||||||
break;
|
break;
|
||||||
} else if(flags & WorkerEvtConnect) { // Start executing script
|
} else if(flags & WorkerEvtConnect) { // Start executing script
|
||||||
DOLPHIN_DEED(DolphinDeedBadUsbPlayScript);
|
dolphin_deed(DolphinDeedBadUsbPlayScript);
|
||||||
delay_val = 0;
|
delay_val = 0;
|
||||||
bad_usb->buf_len = 0;
|
bad_usb->buf_len = 0;
|
||||||
bad_usb->st.line_cur = 0;
|
bad_usb->st.line_cur = 0;
|
||||||
|
|||||||
@ -89,7 +89,7 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(event.event == GpioStartEventUsbUart) {
|
} else if(event.event == GpioStartEventUsbUart) {
|
||||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart);
|
scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart);
|
||||||
if(!furi_hal_usb_is_locked()) {
|
if(!furi_hal_usb_is_locked()) {
|
||||||
DOLPHIN_DEED(DolphinDeedGpioUartBridge);
|
dolphin_deed(DolphinDeedGpioUartBridge);
|
||||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart);
|
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc);
|
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc);
|
||||||
|
|||||||
@ -282,14 +282,14 @@ int32_t ibutton_app(void* arg) {
|
|||||||
view_dispatcher_attach_to_gui(
|
view_dispatcher_attach_to_gui(
|
||||||
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop);
|
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop);
|
||||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc);
|
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc);
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
|
dolphin_deed(DolphinDeedIbuttonEmulate);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
view_dispatcher_attach_to_gui(
|
view_dispatcher_attach_to_gui(
|
||||||
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
|
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
|
||||||
if(key_loaded) { //-V547
|
if(key_loaded) { //-V547
|
||||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
|
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
|
dolphin_deed(DolphinDeedIbuttonEmulate);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart);
|
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) {
|
|||||||
ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess);
|
ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess);
|
||||||
scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess);
|
scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess);
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
|
dolphin_deed(DolphinDeedIbuttonReadSuccess);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(scene_manager, iButtonSceneReadError);
|
scene_manager_next_scene(scene_manager, iButtonSceneReadError);
|
||||||
|
|||||||
@ -75,7 +75,7 @@ bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event
|
|||||||
scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
|
scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
|
||||||
} else if(event.event == SubmenuIndexEmulate) {
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
|
scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
|
dolphin_deed(DolphinDeedIbuttonEmulate);
|
||||||
} else if(event.event == SubmenuIndexViewData) {
|
} else if(event.event == SubmenuIndexViewData) {
|
||||||
scene_manager_next_scene(scene_manager, iButtonSceneViewData);
|
scene_manager_next_scene(scene_manager, iButtonSceneViewData);
|
||||||
} else if(event.event == SubmenuIndexWriteBlank) {
|
} else if(event.event == SubmenuIndexWriteBlank) {
|
||||||
|
|||||||
@ -58,9 +58,9 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
// Nothing, do not count editing as saving
|
// Nothing, do not count editing as saving
|
||||||
} else if(scene_manager_has_previous_scene(
|
} else if(scene_manager_has_previous_scene(
|
||||||
ibutton->scene_manager, iButtonSceneAddType)) {
|
ibutton->scene_manager, iButtonSceneAddType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonAdd);
|
dolphin_deed(DolphinDeedIbuttonAdd);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonSave);
|
dolphin_deed(DolphinDeedIbuttonSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -48,7 +48,7 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
if(event.event == SubmenuIndexEmulate) {
|
if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
|
scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
|
dolphin_deed(DolphinDeedIbuttonEmulate);
|
||||||
} else if(event.event == SubmenuIndexWriteBlank) {
|
} else if(event.event == SubmenuIndexWriteBlank) {
|
||||||
ibutton->write_mode = iButtonWriteModeBlank;
|
ibutton->write_mode = iButtonWriteModeBlank;
|
||||||
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
|
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
|
||||||
|
|||||||
@ -33,7 +33,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
if(event.event == SubmenuIndexRead) {
|
if(event.event == SubmenuIndexRead) {
|
||||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
|
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
|
||||||
DOLPHIN_DEED(DolphinDeedIbuttonRead);
|
dolphin_deed(DolphinDeedIbuttonRead);
|
||||||
} else if(event.event == SubmenuIndexSaved) {
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
|
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
|
||||||
} else if(event.event == SubmenuIndexAdd) {
|
} else if(event.event == SubmenuIndexAdd) {
|
||||||
|
|||||||
@ -319,7 +319,7 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
|
|||||||
infrared_worker_set_decoded_signal(infrared->worker, message);
|
infrared_worker_set_decoded_signal(infrared->worker, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedIrSend);
|
dolphin_deed(DolphinDeedIrSend);
|
||||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
|
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
|
||||||
|
|
||||||
infrared_worker_tx_set_get_signal_callback(
|
infrared_worker_tx_set_get_signal_callback(
|
||||||
|
|||||||
@ -70,7 +70,7 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
|
|||||||
uint32_t record_count;
|
uint32_t record_count;
|
||||||
if(infrared_brute_force_start(
|
if(infrared_brute_force_start(
|
||||||
brute_force, infrared_custom_event_get_value(event.event), &record_count)) {
|
brute_force, infrared_custom_event_get_value(event.event), &record_count)) {
|
||||||
DOLPHIN_DEED(DolphinDeedIrSend);
|
dolphin_deed(DolphinDeedIrSend);
|
||||||
infrared_scene_universal_common_show_popup(infrared, record_count);
|
infrared_scene_universal_common_show_popup(infrared, record_count);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases);
|
scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases);
|
||||||
|
|||||||
@ -28,7 +28,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == InfraredCustomEventTypeSignalReceived) {
|
if(event.event == InfraredCustomEventTypeSignalReceived) {
|
||||||
infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess);
|
infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess);
|
||||||
scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess);
|
scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedIrLearnSuccess);
|
dolphin_deed(DolphinDeedIrLearnSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,7 +50,7 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e
|
|||||||
|
|
||||||
if(success) {
|
if(success) {
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneLearnDone);
|
scene_manager_next_scene(scene_manager, InfraredSceneLearnDone);
|
||||||
DOLPHIN_DEED(DolphinDeedIrSave);
|
dolphin_deed(DolphinDeedIrSave);
|
||||||
} else {
|
} else {
|
||||||
dialog_message_show_storage_error(infrared->dialogs, "Failed to save file");
|
dialog_message_show_storage_error(infrared->dialogs, "Failed to save file");
|
||||||
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
|
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
|
||||||
|
|||||||
@ -183,14 +183,14 @@ int32_t lfrfid_app(void* p) {
|
|||||||
view_dispatcher_attach_to_gui(
|
view_dispatcher_attach_to_gui(
|
||||||
app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop);
|
app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
dolphin_deed(DolphinDeedRfidEmulate);
|
||||||
} else {
|
} else {
|
||||||
furi_string_set(app->file_path, args);
|
furi_string_set(app->file_path, args);
|
||||||
lfrfid_load_key_data(app, app->file_path, true);
|
lfrfid_load_key_data(app, app->file_path, true);
|
||||||
view_dispatcher_attach_to_gui(
|
view_dispatcher_attach_to_gui(
|
||||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
dolphin_deed(DolphinDeedRfidEmulate);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -58,12 +58,12 @@ bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event)
|
|||||||
if(event.event == SubmenuIndexASK) {
|
if(event.event == SubmenuIndexASK) {
|
||||||
app->read_type = LFRFIDWorkerReadTypeASKOnly;
|
app->read_type = LFRFIDWorkerReadTypeASKOnly;
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidRead);
|
dolphin_deed(DolphinDeedRfidRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexPSK) {
|
} else if(event.event == SubmenuIndexPSK) {
|
||||||
app->read_type = LFRFIDWorkerReadTypePSKOnly;
|
app->read_type = LFRFIDWorkerReadTypePSKOnly;
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidRead);
|
dolphin_deed(DolphinDeedRfidRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexRAW) {
|
} else if(event.event == SubmenuIndexRAW) {
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName);
|
||||||
|
|||||||
@ -81,7 +81,7 @@ bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) {
|
|||||||
notification_message(app->notifications, &sequence_success);
|
notification_message(app->notifications, &sequence_success);
|
||||||
furi_string_reset(app->file_name);
|
furi_string_reset(app->file_name);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidReadSuccess);
|
dolphin_deed(DolphinDeedRfidReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == LfRfidEventReadStartPSK) {
|
} else if(event.event == LfRfidEventReadStartPSK) {
|
||||||
if(app->read_type == LFRFIDWorkerReadTypeAuto) {
|
if(app->read_type == LFRFIDWorkerReadTypeAuto) {
|
||||||
|
|||||||
@ -44,7 +44,7 @@ bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event)
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexEmulate) {
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
dolphin_deed(DolphinDeedRfidEmulate);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event);
|
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event);
|
||||||
|
|||||||
@ -59,9 +59,9 @@ bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSavedKeyMenu)) {
|
if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSavedKeyMenu)) {
|
||||||
// Nothing, do not count editing as saving
|
// Nothing, do not count editing as saving
|
||||||
} else if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSaveType)) {
|
} else if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSaveType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedRfidAdd);
|
dolphin_deed(DolphinDeedRfidAdd);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedRfidSave);
|
dolphin_deed(DolphinDeedRfidSave);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
|||||||
@ -43,7 +43,7 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexEmulate) {
|
if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
dolphin_deed(DolphinDeedRfidEmulate);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexWrite) {
|
} else if(event.event == SubmenuIndexWrite) {
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
|
||||||
|
|||||||
@ -49,7 +49,7 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == SubmenuIndexRead) {
|
if(event.event == SubmenuIndexRead) {
|
||||||
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexRead);
|
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexRead);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidRead);
|
dolphin_deed(DolphinDeedRfidRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexSaved) {
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
// Like in the other apps, explicitly save the scene state
|
// Like in the other apps, explicitly save the scene state
|
||||||
|
|||||||
@ -12,4 +12,6 @@ enum NfcCustomEvent {
|
|||||||
NfcCustomEventDictAttackSkip,
|
NfcCustomEventDictAttackSkip,
|
||||||
NfcCustomEventRpcLoad,
|
NfcCustomEventRpcLoad,
|
||||||
NfcCustomEventRpcSessionClose,
|
NfcCustomEventRpcSessionClose,
|
||||||
|
NfcCustomEventUpdateLog,
|
||||||
|
NfcCustomEventSaveShadow,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -286,15 +286,18 @@ int32_t nfc_app(void* p) {
|
|||||||
if(nfc_device_load(nfc->dev, p, true)) {
|
if(nfc_device_load(nfc->dev, p, true)) {
|
||||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
|
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Exit app
|
// Exit app
|
||||||
|
|||||||
@ -14,6 +14,13 @@ ADD_SCENE(nfc, file_select, FileSelect)
|
|||||||
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
||||||
ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess)
|
ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess)
|
||||||
ADD_SCENE(nfc, nfca_menu, NfcaMenu)
|
ADD_SCENE(nfc, nfca_menu, NfcaMenu)
|
||||||
|
ADD_SCENE(nfc, nfcv_menu, NfcVMenu)
|
||||||
|
ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu)
|
||||||
|
ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput)
|
||||||
|
ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock)
|
||||||
|
ADD_SCENE(nfc, nfcv_emulate, NfcVEmulate)
|
||||||
|
ADD_SCENE(nfc, nfcv_sniff, NfcVSniff)
|
||||||
|
ADD_SCENE(nfc, nfcv_read_success, NfcVReadSuccess)
|
||||||
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
|
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
|
||||||
ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData)
|
ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData)
|
||||||
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
|
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
|
||||||
|
|||||||
@ -31,6 +31,8 @@ void nfc_scene_delete_on_enter(void* context) {
|
|||||||
nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
||||||
|
|
||||||
NfcProtocol protocol = nfc->dev->dev_data.protocol;
|
NfcProtocol protocol = nfc->dev->dev_data.protocol;
|
||||||
|
const char* nfc_type = "NFC-A";
|
||||||
|
|
||||||
if(protocol == NfcDeviceProtocolEMV) {
|
if(protocol == NfcDeviceProtocolEMV) {
|
||||||
furi_string_set(temp_str, "EMV bank card");
|
furi_string_set(temp_str, "EMV bank card");
|
||||||
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
||||||
@ -39,12 +41,15 @@ void nfc_scene_delete_on_enter(void* context) {
|
|||||||
furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type));
|
furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type));
|
||||||
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
furi_string_set(temp_str, "MIFARE DESFire");
|
furi_string_set(temp_str, "MIFARE DESFire");
|
||||||
|
} else if(protocol == NfcDeviceProtocolNfcV) {
|
||||||
|
furi_string_set(temp_str, "ISO15693 tag");
|
||||||
|
nfc_type = "NFC-V";
|
||||||
} else {
|
} else {
|
||||||
furi_string_set(temp_str, "Unknown ISO tag");
|
furi_string_set(temp_str, "Unknown ISO tag");
|
||||||
}
|
}
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
||||||
widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A");
|
widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, nfc_type);
|
||||||
furi_string_free(temp_str);
|
furi_string_free(temp_str);
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
|||||||
@ -4,6 +4,8 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexReadCardType,
|
SubmenuIndexReadCardType,
|
||||||
SubmenuIndexMfClassicKeys,
|
SubmenuIndexMfClassicKeys,
|
||||||
SubmenuIndexMfUltralightUnlock,
|
SubmenuIndexMfUltralightUnlock,
|
||||||
|
SubmenuIndexNfcVUnlock,
|
||||||
|
SubmenuIndexNfcVSniff,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
||||||
@ -34,6 +36,18 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
|||||||
SubmenuIndexMfUltralightUnlock,
|
SubmenuIndexMfUltralightUnlock,
|
||||||
nfc_scene_extra_actions_submenu_callback,
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
nfc);
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Unlock SLIX-L",
|
||||||
|
SubmenuIndexNfcVUnlock,
|
||||||
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Listen NfcV Reader",
|
||||||
|
SubmenuIndexNfcVSniff,
|
||||||
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
|
nfc);
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions));
|
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions));
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
@ -58,6 +72,12 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexNfcVUnlock) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexNfcVSniff) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVSniff);
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,7 +111,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
|||||||
} else {
|
} else {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.event == NfcWorkerEventAborted) {
|
} else if(event.event == NfcWorkerEventAborted) {
|
||||||
@ -123,7 +123,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
|||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||||
// Counting failed attempts too
|
// Counting failed attempts too
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.event == NfcWorkerEventCardDetected) {
|
} else if(event.event == NfcWorkerEventCardDetected) {
|
||||||
|
|||||||
@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
|
|||||||
nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
|
nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
|
||||||
} else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) {
|
} else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcMfcAdd);
|
dolphin_deed(DolphinDeedNfcMfcAdd);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,14 +54,14 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event)
|
|||||||
} else if(event.event == SubmenuIndexEmulate) {
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcAddEmulate);
|
dolphin_deed(DolphinDeedNfcAddEmulate);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexDetectReader) {
|
} else if(event.event == SubmenuIndexDetectReader) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcDetectReader);
|
dolphin_deed(DolphinDeedNfcDetectReader);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexInfo) {
|
} else if(event.event == SubmenuIndexInfo) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
|
||||||
|
|||||||
@ -34,7 +34,7 @@ static void nfc_scene_mf_classic_update_setup_view(Nfc* nfc) {
|
|||||||
|
|
||||||
void nfc_scene_mf_classic_update_on_enter(void* context) {
|
void nfc_scene_mf_classic_update_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch);
|
nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch);
|
||||||
|
|||||||
@ -8,7 +8,7 @@ void nfc_scene_mf_classic_update_success_popup_callback(void* context) {
|
|||||||
|
|
||||||
void nfc_scene_mf_classic_update_success_on_enter(void* context) {
|
void nfc_scene_mf_classic_update_success_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@ static void nfc_scene_mf_classic_write_setup_view(Nfc* nfc) {
|
|||||||
|
|
||||||
void nfc_scene_mf_classic_write_on_enter(void* context) {
|
void nfc_scene_mf_classic_write_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch);
|
nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch);
|
||||||
|
|||||||
@ -8,7 +8,7 @@ void nfc_scene_mf_classic_write_success_popup_callback(void* context) {
|
|||||||
|
|
||||||
void nfc_scene_mf_classic_write_success_on_enter(void* context) {
|
void nfc_scene_mf_classic_write_success_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
|
||||||
|
|||||||
@ -50,9 +50,9 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event)
|
|||||||
} else if(event.event == SubmenuIndexEmulateUid) {
|
} else if(event.event == SubmenuIndexEmulateUid) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcAddEmulate);
|
dolphin_deed(DolphinDeedNfcAddEmulate);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexInfo) {
|
} else if(event.event == SubmenuIndexInfo) {
|
||||||
|
|||||||
@ -60,9 +60,9 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even
|
|||||||
} else if(event.event == SubmenuIndexEmulate) {
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcAddEmulate);
|
dolphin_deed(DolphinDeedNfcAddEmulate);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexUnlock) {
|
} else if(event.event == SubmenuIndexUnlock) {
|
||||||
|
|||||||
@ -61,7 +61,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == DialogExResultRight) {
|
if(event.event == DialogExResultRight) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == DialogExResultLeft) {
|
} else if(event.event == DialogExResultLeft) {
|
||||||
if(auth_method == MfUltralightAuthMethodAuto) {
|
if(auth_method == MfUltralightAuthMethodAuto) {
|
||||||
@ -79,7 +79,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == DialogExResultCenter) {
|
if(event.event == DialogExResultCenter) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,19 +41,165 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
|||||||
temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type));
|
temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type));
|
||||||
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
furi_string_cat_printf(temp_str, "\e#MIFARE DESFire\n");
|
furi_string_cat_printf(temp_str, "\e#MIFARE DESFire\n");
|
||||||
|
} else if(protocol == NfcDeviceProtocolNfcV) {
|
||||||
|
switch(dev_data->nfcv_data.sub_type) {
|
||||||
|
case NfcVTypePlain:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixS:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-S\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixL:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix2:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX2\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n");
|
furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set tag iso data
|
// Set tag iso data
|
||||||
|
if(protocol == NfcDeviceProtocolNfcV) {
|
||||||
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
|
|
||||||
|
furi_string_cat_printf(temp_str, "UID:\n");
|
||||||
|
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
||||||
|
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "\n");
|
||||||
|
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
"DSFID: %02X %s\n",
|
||||||
|
nfcv_data->dsfid,
|
||||||
|
(nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : "");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
"AFI: %02X %s\n",
|
||||||
|
nfcv_data->afi,
|
||||||
|
(nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : "");
|
||||||
|
furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref);
|
||||||
|
furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num);
|
||||||
|
furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size);
|
||||||
|
|
||||||
|
switch(dev_data->nfcv_data.sub_type) {
|
||||||
|
case NfcVTypePlain:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: Plain\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixS:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX-S\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Read %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Write %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Privacy %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Destroy %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixL:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX-L\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Privacy %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Destroy %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix2:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX2\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Read %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Write %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Privacy %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Destroy %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08llX\n",
|
||||||
|
nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str, "Data (%d byte)\n", nfcv_data->block_num * nfcv_data->block_size);
|
||||||
|
|
||||||
|
int maxBlocks = nfcv_data->block_num;
|
||||||
|
if(maxBlocks > 32) {
|
||||||
|
maxBlocks = 32;
|
||||||
|
furi_string_cat_printf(temp_str, "(truncated to %d blocks)\n", maxBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int block = 0; block < maxBlocks; block++) {
|
||||||
|
const char* status = (nfcv_data->security_status[block] & 0x01) ? "(lck)" : "";
|
||||||
|
for(int pos = 0; pos < nfcv_data->block_size; pos++) {
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str, " %02X", nfcv_data->data[block * nfcv_data->block_size + pos]);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, " %s\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3';
|
char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3';
|
||||||
furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
|
furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
|
||||||
furi_string_cat_printf(temp_str, "UID:");
|
furi_string_cat_printf(temp_str, "UID:");
|
||||||
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
||||||
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
||||||
}
|
}
|
||||||
furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]);
|
furi_string_cat_printf(
|
||||||
|
temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]);
|
||||||
furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak);
|
furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak);
|
||||||
|
}
|
||||||
|
|
||||||
// Set application specific data
|
// Set application specific data
|
||||||
if(protocol == NfcDeviceProtocolMifareDesfire) {
|
if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
@ -139,6 +285,8 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(protocol == NfcDeviceProtocolMifareClassic) {
|
} else if(protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData);
|
||||||
|
} else if(protocol == NfcDeviceProtocolNfcV) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,9 +43,9 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(event.event == SubmenuIndexEmulateUid) {
|
} else if(event.event == SubmenuIndexEmulateUid) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcAddEmulate);
|
dolphin_deed(DolphinDeedNfcAddEmulate);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexInfo) {
|
} else if(event.event == SubmenuIndexInfo) {
|
||||||
|
|||||||
169
applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (200)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NfcSceneNfcVEmulateStateWidget,
|
||||||
|
NfcSceneNfcVEmulateStateTextBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_emulate_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
switch(event) {
|
||||||
|
case NfcWorkerEventNfcVCommandExecuted:
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NfcWorkerEventNfcVContentChanged:
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_textbox_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfc_scene_nfcv_emulate_widget_config(Nfc* nfc, bool data_received) {
|
||||||
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
|
Widget* widget = nfc->widget;
|
||||||
|
widget_reset(widget);
|
||||||
|
FuriString* info_str;
|
||||||
|
info_str = furi_string_alloc();
|
||||||
|
|
||||||
|
widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61);
|
||||||
|
widget_add_string_multiline_element(
|
||||||
|
widget, 87, 13, AlignCenter, AlignTop, FontPrimary, "Emulating\nNFC V");
|
||||||
|
if(strcmp(nfc->dev->dev_name, "") != 0) {
|
||||||
|
furi_string_printf(info_str, "%s", nfc->dev->dev_name);
|
||||||
|
} else {
|
||||||
|
for(uint8_t i = 0; i < data->uid_len; i++) {
|
||||||
|
furi_string_cat_printf(info_str, "%02X ", data->uid[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
furi_string_trim(info_str);
|
||||||
|
widget_add_text_box_element(
|
||||||
|
widget, 52, 40, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
|
||||||
|
furi_string_free(info_str);
|
||||||
|
if(data_received) {
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_emulate_widget_callback, nfc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Setup Widget
|
||||||
|
nfc_scene_nfcv_emulate_widget_config(nfc, false);
|
||||||
|
// Setup TextBox
|
||||||
|
TextBox* text_box = nfc->text_box;
|
||||||
|
text_box_set_font(text_box, TextBoxFontHex);
|
||||||
|
text_box_set_focus(text_box, TextBoxFocusEnd);
|
||||||
|
text_box_set_text(text_box, "");
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
// Set Widget state and view
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
// Start worker
|
||||||
|
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVEmulate,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_nfcv_emulate_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_emulate_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventUpdateLog) {
|
||||||
|
// Add data button to widget if data is received for the first time
|
||||||
|
if(strlen(nfcv_data->last_command) > 0) {
|
||||||
|
if(!furi_string_size(nfc->text_box_store)) {
|
||||||
|
nfc_scene_nfcv_emulate_widget_config(nfc, true);
|
||||||
|
}
|
||||||
|
/* use the last n bytes from the log so there's enough space for the new log entry */
|
||||||
|
size_t maxSize =
|
||||||
|
NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1);
|
||||||
|
if(furi_string_size(nfc->text_box_store) >= maxSize) {
|
||||||
|
furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1));
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command);
|
||||||
|
furi_string_push_back(nfc->text_box_store, '\n');
|
||||||
|
text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store));
|
||||||
|
|
||||||
|
/* clear previously logged command */
|
||||||
|
strcpy(nfcv_data->last_command, "");
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventSaveShadow) {
|
||||||
|
if(furi_string_size(nfc->dev->load_path)) {
|
||||||
|
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVEmulateStateWidget) {
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateTextBox);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVEmulateStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
if(state == NfcSceneNfcVEmulateStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
text_box_reset(nfc->text_box);
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
}
|
||||||
48
applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_key_input_byte_input_callback(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
memcpy(data->key_privacy, nfc->byte_input_store, 4);
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_key_input_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
ByteInput* byte_input = nfc->byte_input;
|
||||||
|
byte_input_set_header_text(byte_input, "Enter The Password In Hex");
|
||||||
|
byte_input_set_result_callback(
|
||||||
|
byte_input,
|
||||||
|
nfc_scene_nfcv_key_input_byte_input_callback,
|
||||||
|
NULL,
|
||||||
|
nfc,
|
||||||
|
nfc->byte_input_store,
|
||||||
|
4);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_key_input_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventByteInputDone) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock);
|
||||||
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_key_input_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||||
|
byte_input_set_header_text(nfc->byte_input, "");
|
||||||
|
}
|
||||||
68
applications/main/nfc/scenes/nfc_scene_nfcv_menu.c
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexSave,
|
||||||
|
SubmenuIndexEmulate,
|
||||||
|
SubmenuIndexInfo,
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_menu_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_nfcv_menu_submenu_callback, nfc);
|
||||||
|
submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_nfcv_menu_submenu_callback, nfc);
|
||||||
|
submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfcv_menu_submenu_callback, nfc);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVMenu));
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexSave) {
|
||||||
|
nfc->dev->format = NfcDeviceSaveFormatNfcV;
|
||||||
|
// Clear device name
|
||||||
|
nfc_device_set_name(nfc->dev, "");
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
|
dolphin_deed(DolphinDeedNfcAddEmulate);
|
||||||
|
} else {
|
||||||
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexInfo) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVMenu, event.event);
|
||||||
|
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_menu_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
submenu_reset(nfc->submenu);
|
||||||
|
}
|
||||||
94
applications/main/nfc/scenes/nfc_scene_nfcv_read_success.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_read_success_widget_callback(
|
||||||
|
GuiButtonType result,
|
||||||
|
InputType type,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_read_success_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcDeviceData* dev_data = &nfc->dev->dev_data;
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
||||||
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
|
// Setup view
|
||||||
|
Widget* widget = nfc->widget;
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfcv_read_success_widget_callback, nfc);
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeRight, "More", nfc_scene_nfcv_read_success_widget_callback, nfc);
|
||||||
|
|
||||||
|
FuriString* temp_str = furi_string_alloc();
|
||||||
|
|
||||||
|
switch(dev_data->nfcv_data.sub_type) {
|
||||||
|
case NfcVTypePlain:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixS:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-S\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixL:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix2:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX2\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "UID:");
|
||||||
|
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
||||||
|
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num);
|
||||||
|
furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size);
|
||||||
|
|
||||||
|
widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
|
||||||
|
notification_message_block(nfc->notifications, &sequence_set_green_255);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_read_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
|
// Clear device name
|
||||||
|
nfc_device_set_name(nfc->dev, "");
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_read_success_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
notification_message_block(nfc->notifications, &sequence_reset_green);
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
}
|
||||||
155
applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (800)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NfcSceneNfcVSniffStateWidget,
|
||||||
|
NfcSceneNfcVSniffStateTextBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_sniff_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
UNUSED(event);
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
switch(event) {
|
||||||
|
case NfcWorkerEventNfcVCommandExecuted:
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog);
|
||||||
|
break;
|
||||||
|
case NfcWorkerEventNfcVContentChanged:
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_textbox_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfc_scene_nfcv_sniff_widget_config(Nfc* nfc, bool data_received) {
|
||||||
|
Widget* widget = nfc->widget;
|
||||||
|
widget_reset(widget);
|
||||||
|
FuriString* info_str;
|
||||||
|
info_str = furi_string_alloc();
|
||||||
|
|
||||||
|
widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||||
|
widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Listen NfcV");
|
||||||
|
furi_string_trim(info_str);
|
||||||
|
widget_add_text_box_element(
|
||||||
|
widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
|
||||||
|
furi_string_free(info_str);
|
||||||
|
if(data_received) {
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_sniff_widget_callback, nfc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Setup Widget
|
||||||
|
nfc_scene_nfcv_sniff_widget_config(nfc, false);
|
||||||
|
// Setup TextBox
|
||||||
|
TextBox* text_box = nfc->text_box;
|
||||||
|
text_box_set_font(text_box, TextBoxFontHex);
|
||||||
|
text_box_set_focus(text_box, TextBoxFocusEnd);
|
||||||
|
text_box_set_text(text_box, "");
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
// Set Widget state and view
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
// Start worker
|
||||||
|
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVSniff,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_nfcv_sniff_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_emulate_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_sniff_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVSniff);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventUpdateLog) {
|
||||||
|
// Add data button to widget if data is received for the first time
|
||||||
|
if(strlen(nfcv_data->last_command) > 0) {
|
||||||
|
if(!furi_string_size(nfc->text_box_store)) {
|
||||||
|
nfc_scene_nfcv_sniff_widget_config(nfc, true);
|
||||||
|
}
|
||||||
|
/* use the last n bytes from the log so there's enough space for the new log entry */
|
||||||
|
size_t maxSize =
|
||||||
|
NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1);
|
||||||
|
if(furi_string_size(nfc->text_box_store) >= maxSize) {
|
||||||
|
furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1));
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command);
|
||||||
|
furi_string_push_back(nfc->text_box_store, '\n');
|
||||||
|
text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store));
|
||||||
|
|
||||||
|
/* clear previously logged command */
|
||||||
|
strcpy(nfcv_data->last_command, "");
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventSaveShadow) {
|
||||||
|
if(furi_string_size(nfc->dev->load_path)) {
|
||||||
|
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVSniffStateWidget) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateTextBox);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVSniffStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
if(state == NfcSceneNfcVSniffStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
text_box_reset(nfc->text_box);
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
}
|
||||||
154
applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcSceneNfcVUnlockStateIdle,
|
||||||
|
NfcSceneNfcVUnlockStateDetecting,
|
||||||
|
NfcSceneNfcVUnlockStateUnlocked,
|
||||||
|
NfcSceneNfcVUnlockStateAlreadyUnlocked,
|
||||||
|
NfcSceneNfcVUnlockStateNotSupportedCard,
|
||||||
|
} NfcSceneNfcVUnlockState;
|
||||||
|
|
||||||
|
static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
if(event == NfcWorkerEventNfcVPassKey) {
|
||||||
|
memcpy(data->key_privacy, nfc->byte_input_store, 4);
|
||||||
|
} else {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_popup_callback(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) {
|
||||||
|
FuriHalNfcDevData* nfc_data = &(nfc->dev->dev_data.nfc_data);
|
||||||
|
NfcVData* nfcv_data = &(nfc->dev->dev_data.nfcv_data);
|
||||||
|
|
||||||
|
uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock);
|
||||||
|
if(curr_state != state) {
|
||||||
|
Popup* popup = nfc->popup;
|
||||||
|
if(state == NfcSceneNfcVUnlockStateDetecting) {
|
||||||
|
popup_reset(popup);
|
||||||
|
popup_set_text(
|
||||||
|
popup, "Put figurine on\nFlipper's back", 97, 24, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 8, &I_NFC_manual_60x50);
|
||||||
|
} else if(state == NfcSceneNfcVUnlockStateUnlocked) {
|
||||||
|
popup_reset(popup);
|
||||||
|
|
||||||
|
if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) {
|
||||||
|
snprintf(
|
||||||
|
nfc->dev->dev_name,
|
||||||
|
sizeof(nfc->dev->dev_name),
|
||||||
|
"SLIX_%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||||
|
nfc_data->uid[0],
|
||||||
|
nfc_data->uid[1],
|
||||||
|
nfc_data->uid[2],
|
||||||
|
nfc_data->uid[3],
|
||||||
|
nfc_data->uid[4],
|
||||||
|
nfc_data->uid[5],
|
||||||
|
nfc_data->uid[6],
|
||||||
|
nfc_data->uid[7]);
|
||||||
|
|
||||||
|
nfc->dev->format = NfcDeviceSaveFormatNfcV;
|
||||||
|
|
||||||
|
if(nfc_save_file(nfc)) {
|
||||||
|
popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop);
|
||||||
|
} else {
|
||||||
|
popup_set_header(
|
||||||
|
popup, "Unlocked but\nsave failed!", 94, 3, AlignCenter, AlignTop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
popup_set_header(popup, "Successfully\nunlocked", 94, 3, AlignCenter, AlignTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
notification_message(nfc->notifications, &sequence_single_vibro);
|
||||||
|
//notification_message(nfc->notifications, &sequence_success);
|
||||||
|
|
||||||
|
popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
|
||||||
|
popup_set_context(popup, nfc);
|
||||||
|
popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
|
} else if(state == NfcSceneNfcVUnlockStateAlreadyUnlocked) {
|
||||||
|
popup_reset(popup);
|
||||||
|
|
||||||
|
popup_set_header(popup, "Already\nUnlocked!", 94, 3, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
|
||||||
|
popup_set_context(popup, nfc);
|
||||||
|
popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
} else if(state == NfcSceneNfcVUnlockStateNotSupportedCard) {
|
||||||
|
popup_reset(popup);
|
||||||
|
popup_set_header(popup, "Wrong Type Of Card!", 64, 3, AlignCenter, AlignTop);
|
||||||
|
popup_set_text(popup, nfcv_data->error, 4, 22, AlignLeft, AlignTop);
|
||||||
|
popup_set_icon(popup, 73, 20, &I_DolphinCommon_56x48);
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
nfc_device_clear(nfc->dev);
|
||||||
|
// Setup view
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
|
||||||
|
// Start worker
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVUnlockAndSave,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_nfcv_unlock_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_read_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_unlock_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcWorkerEventCardDetected) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateUnlocked);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventAborted) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateAlreadyUnlocked);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventWrongCardDetected) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateNotSupportedCard);
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(nfc->popup);
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVUnlock, NfcSceneNfcVUnlockStateIdle);
|
||||||
|
}
|
||||||
60
applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexNfcVUnlockMenuManual,
|
||||||
|
SubmenuIndexNfcVUnlockMenuTonieBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_menu_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Enter PWD Manually",
|
||||||
|
SubmenuIndexNfcVUnlockMenuManual,
|
||||||
|
nfc_scene_nfcv_unlock_menu_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Auth As TonieBox",
|
||||||
|
SubmenuIndexNfcVUnlockMenuTonieBox,
|
||||||
|
nfc_scene_nfcv_unlock_menu_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_set_selected_item(submenu, state);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_unlock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexNfcVUnlockMenuManual) {
|
||||||
|
nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodManual;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVKeyInput);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexNfcVUnlockMenuTonieBox) {
|
||||||
|
nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodTonieBox;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock);
|
||||||
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu, event.event);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_menu_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
submenu_reset(nfc->submenu);
|
||||||
|
}
|
||||||
@ -61,29 +61,34 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
|
|||||||
(event.event == NfcWorkerEventReadUidNfcV)) {
|
(event.event == NfcWorkerEventReadUidNfcV)) {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == NfcWorkerEventReadUidNfcA) {
|
} else if(event.event == NfcWorkerEventReadUidNfcA) {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventReadNfcV) {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVReadSuccess);
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == NfcWorkerEventReadMfUltralight) {
|
} else if(event.event == NfcWorkerEventReadMfUltralight) {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
// Set unlock password input to 0xFFFFFFFF only on fresh read
|
// Set unlock password input to 0xFFFFFFFF only on fresh read
|
||||||
memset(nfc->byte_input_store, 0xFF, sizeof(nfc->byte_input_store));
|
memset(nfc->byte_input_store, 0xFF, sizeof(nfc->byte_input_store));
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == NfcWorkerEventReadMfClassicDone) {
|
} else if(event.event == NfcWorkerEventReadMfClassicDone) {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == NfcWorkerEventReadMfDesfire) {
|
} else if(event.event == NfcWorkerEventReadMfDesfire) {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) {
|
} else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) {
|
||||||
if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) {
|
if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) {
|
|||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||||
|
|
||||||
dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop);
|
dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop);
|
||||||
dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring_38x32);
|
dialog_ex_set_icon(dialog_ex, 5, 11, &I_ArrowC_1_36x36);
|
||||||
dialog_ex_set_text(
|
dialog_ex_set_text(
|
||||||
dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop);
|
dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop);
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||||
|
|||||||
@ -55,6 +55,13 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_scene_rpc_emulate_callback,
|
nfc_scene_rpc_emulate_callback,
|
||||||
nfc);
|
nfc);
|
||||||
|
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVEmulate,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_rpc_emulate_callback,
|
||||||
|
nfc);
|
||||||
} else {
|
} else {
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
||||||
|
|||||||
@ -67,9 +67,9 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
||||||
// Nothing, do not count editing as saving
|
// Nothing, do not count editing as saving
|
||||||
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcAddSave);
|
dolphin_deed(DolphinDeedNfcAddSave);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -44,6 +44,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
|
|||||||
} else if(
|
} else if(
|
||||||
(nfc->dev->format == NfcDeviceSaveFormatMifareUl &&
|
(nfc->dev->format == NfcDeviceSaveFormatMifareUl &&
|
||||||
mf_ul_emulation_supported(&nfc->dev->dev_data.mf_ul_data)) ||
|
mf_ul_emulation_supported(&nfc->dev->dev_data.mf_ul_data)) ||
|
||||||
|
nfc->dev->format == NfcDeviceSaveFormatNfcV ||
|
||||||
nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc);
|
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc);
|
||||||
@ -118,14 +119,16 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
|
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
}
|
}
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
dolphin_deed(DolphinDeedNfcEmulate);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexDetectReader) {
|
} else if(event.event == SubmenuIndexDetectReader) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcDetectReader);
|
dolphin_deed(DolphinDeedNfcDetectReader);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexWrite) {
|
} else if(event.event == SubmenuIndexWrite) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite);
|
||||||
|
|||||||
@ -51,7 +51,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead);
|
||||||
nfc->dev->dev_data.read_mode = NfcReadModeAuto;
|
nfc->dev->dev_data.read_mode = NfcReadModeAuto;
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexDetectReader) {
|
} else if(event.event == SubmenuIndexDetectReader) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
@ -60,7 +60,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(sd_exist) {
|
if(sd_exist) {
|
||||||
nfc_device_data_clear(&nfc->dev->dev_data);
|
nfc_device_data_clear(&nfc->dev->dev_data);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcDetectReader);
|
dolphin_deed(DolphinDeedNfcDetectReader);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -204,7 +204,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else {
|
} else {
|
||||||
if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) ||
|
if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) ||
|
||||||
!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) {
|
!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
dolphin_deed(DolphinDeedSubGhzSend);
|
||||||
}
|
}
|
||||||
// set callback end tx
|
// set callback end tx
|
||||||
subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||||
@ -259,7 +259,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else {
|
} else {
|
||||||
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||||
if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) {
|
if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) {
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
|
dolphin_deed(DolphinDeedSubGhzRawRec);
|
||||||
subghz_txrx_rx_start(subghz->txrx);
|
subghz_txrx_rx_start(subghz->txrx);
|
||||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||||
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
|
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
|
||||||
|
|||||||
@ -163,7 +163,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubGhzCustomEventViewReceiverOK:
|
case SubGhzCustomEventViewReceiverOK:
|
||||||
subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
|
dolphin_deed(DolphinDeedSubGhzReceiverInfo);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case SubGhzCustomEventViewReceiverConfig:
|
case SubGhzCustomEventViewReceiverConfig:
|
||||||
|
|||||||
@ -137,9 +137,9 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
// Ditto, for RAW signals
|
// Ditto, for RAW signals
|
||||||
} else if(scene_manager_has_previous_scene(
|
} else if(scene_manager_has_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneSetType)) {
|
subghz->scene_manager, SubGhzSceneSetType)) {
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzAddManually);
|
dolphin_deed(DolphinDeedSubGhzAddManually);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzSave);
|
dolphin_deed(DolphinDeedSubGhzSave);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -92,7 +92,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer);
|
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer);
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer);
|
dolphin_deed(DolphinDeedSubGhzFrequencyAnalyzer);
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubmenuIndexTest) {
|
} else if(event.event == SubmenuIndexTest) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
|
|||||||
@ -61,7 +61,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
|
if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
|
||||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||||
subghz_scene_transmitter_update_data_show(subghz);
|
subghz_scene_transmitter_update_data_show(subghz);
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
dolphin_deed(DolphinDeedSubGhzSend);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
|
} else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
|
||||||
|
|||||||
@ -68,7 +68,7 @@ bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) {
|
|||||||
notification_message(app->notifications, &sequence_blink_magenta_10);
|
notification_message(app->notifications, &sequence_blink_magenta_10);
|
||||||
} else if(event.event == U2fCustomEventAuthSuccess) {
|
} else if(event.event == U2fCustomEventAuthSuccess) {
|
||||||
notification_message_block(app->notifications, &sequence_set_green_255);
|
notification_message_block(app->notifications, &sequence_set_green_255);
|
||||||
DOLPHIN_DEED(DolphinDeedU2fAuthorized);
|
dolphin_deed(DolphinDeedU2fAuthorized);
|
||||||
furi_timer_start(app->timer, U2F_SUCCESS_TIMEOUT);
|
furi_timer_start(app->timer, U2F_SUCCESS_TIMEOUT);
|
||||||
app->event_cur = U2fCustomEventNone;
|
app->event_cur = U2fCustomEventNone;
|
||||||
u2f_view_set_state(app->u2f_view, U2fMsgSuccess);
|
u2f_view_set_state(app->u2f_view, U2fMsgSuccess);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "bt_i.h"
|
#include "bt_i.h"
|
||||||
#include "battery_service.h"
|
|
||||||
#include "bt_keys_storage.h"
|
#include "bt_keys_storage.h"
|
||||||
|
|
||||||
|
#include <services/battery_service.h>
|
||||||
#include <notification/notification_messages.h>
|
#include <notification/notification_messages.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
|
|||||||
@ -34,13 +34,13 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DesktopDebugEventDeed:
|
case DesktopDebugEventDeed:
|
||||||
dolphin_deed(dolphin, DolphinDeedTestRight);
|
dolphin_deed(DolphinDeedTestRight);
|
||||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DesktopDebugEventWrongDeed:
|
case DesktopDebugEventWrongDeed:
|
||||||
dolphin_deed(dolphin, DolphinDeedTestLeft);
|
dolphin_deed(DolphinDeedTestLeft);
|
||||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -13,12 +13,13 @@
|
|||||||
|
|
||||||
static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin);
|
static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin);
|
||||||
|
|
||||||
void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) {
|
void dolphin_deed(DolphinDeed deed) {
|
||||||
furi_assert(dolphin);
|
Dolphin* dolphin = (Dolphin*)furi_record_open(RECORD_DOLPHIN);
|
||||||
DolphinEvent event;
|
DolphinEvent event;
|
||||||
event.type = DolphinEventTypeDeed;
|
event.type = DolphinEventTypeDeed;
|
||||||
event.deed = deed;
|
event.deed = deed;
|
||||||
dolphin_event_send_async(dolphin, &event);
|
dolphin_event_send_async(dolphin, &event);
|
||||||
|
furi_record_close(RECORD_DOLPHIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
DolphinStats dolphin_stats(Dolphin* dolphin) {
|
DolphinStats dolphin_stats(Dolphin* dolphin) {
|
||||||
|
|||||||
@ -26,18 +26,11 @@ typedef enum {
|
|||||||
DolphinPubsubEventUpdate,
|
DolphinPubsubEventUpdate,
|
||||||
} DolphinPubsubEvent;
|
} DolphinPubsubEvent;
|
||||||
|
|
||||||
#define DOLPHIN_DEED(deed) \
|
|
||||||
do { \
|
|
||||||
Dolphin* dolphin = (Dolphin*)furi_record_open("dolphin"); \
|
|
||||||
dolphin_deed(dolphin, deed); \
|
|
||||||
furi_record_close("dolphin"); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
/** Deed complete notification. Call it on deed completion.
|
/** Deed complete notification. Call it on deed completion.
|
||||||
* See dolphin_deed.h for available deeds. In futures it will become part of assets.
|
* See dolphin_deed.h for available deeds. In futures it will become part of assets.
|
||||||
* Thread safe, async
|
* Thread safe, async
|
||||||
*/
|
*/
|
||||||
void dolphin_deed(Dolphin* dolphin, DolphinDeed deed);
|
void dolphin_deed(DolphinDeed deed);
|
||||||
|
|
||||||
/** Retrieve dolphin stats
|
/** Retrieve dolphin stats
|
||||||
* Thread safe, blocking
|
* Thread safe, blocking
|
||||||
|
|||||||
@ -75,6 +75,8 @@ typedef enum {
|
|||||||
NotificationMessageTypeForceDisplayBrightnessSetting,
|
NotificationMessageTypeForceDisplayBrightnessSetting,
|
||||||
|
|
||||||
NotificationMessageTypeLedBrightnessSettingApply,
|
NotificationMessageTypeLedBrightnessSettingApply,
|
||||||
|
|
||||||
|
NotificationMessageTypeLcdContrastUpdate,
|
||||||
} NotificationMessageType;
|
} NotificationMessageType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@ -3,6 +3,9 @@
|
|||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
|
#include <gui/gui_i.h>
|
||||||
|
#include <u8g2_glue.h>
|
||||||
|
|
||||||
#include "notification.h"
|
#include "notification.h"
|
||||||
#include "notification_messages.h"
|
#include "notification_messages.h"
|
||||||
#include "notification_app.h"
|
#include "notification_app.h"
|
||||||
@ -20,14 +23,14 @@ static const uint8_t reset_sound_mask = 1 << 4;
|
|||||||
static const uint8_t reset_display_mask = 1 << 5;
|
static const uint8_t reset_display_mask = 1 << 5;
|
||||||
static const uint8_t reset_blink_mask = 1 << 6;
|
static const uint8_t reset_blink_mask = 1 << 6;
|
||||||
|
|
||||||
void notification_vibro_on(bool force);
|
static void notification_vibro_on(bool force);
|
||||||
void notification_vibro_off();
|
static void notification_vibro_off();
|
||||||
void notification_sound_on(float freq, float volume, bool force);
|
static void notification_sound_on(float freq, float volume, bool force);
|
||||||
void notification_sound_off();
|
static void notification_sound_off();
|
||||||
|
|
||||||
uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value);
|
static uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value);
|
||||||
uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value);
|
static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value);
|
||||||
uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app);
|
static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app);
|
||||||
|
|
||||||
void notification_message_save_settings(NotificationApp* app) {
|
void notification_message_save_settings(NotificationApp* app) {
|
||||||
NotificationAppMessage m = {
|
NotificationAppMessage m = {
|
||||||
@ -39,7 +42,8 @@ void notification_message_save_settings(NotificationApp* app) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// internal layer
|
// internal layer
|
||||||
void notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) {
|
static void
|
||||||
|
notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) {
|
||||||
furi_assert(layer);
|
furi_assert(layer);
|
||||||
furi_assert(layer->index < LayerMAX);
|
furi_assert(layer->index < LayerMAX);
|
||||||
|
|
||||||
@ -52,7 +56,13 @@ void notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) {
|
static void notification_apply_lcd_contrast(NotificationApp* app) {
|
||||||
|
Gui* gui = furi_record_open(RECORD_GUI);
|
||||||
|
u8x8_d_st756x_set_contrast(&gui->canvas->fb.u8x8, app->settings.contrast);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) ||
|
if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) ||
|
||||||
(app->led[2].index == LayerInternal)) {
|
(app->led[2].index == LayerInternal)) {
|
||||||
@ -67,7 +77,7 @@ bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// notification layer
|
// notification layer
|
||||||
void notification_apply_notification_led_layer(
|
static void notification_apply_notification_led_layer(
|
||||||
NotificationLedLayer* layer,
|
NotificationLedLayer* layer,
|
||||||
const uint8_t layer_value) {
|
const uint8_t layer_value) {
|
||||||
furi_assert(layer);
|
furi_assert(layer);
|
||||||
@ -81,7 +91,7 @@ void notification_apply_notification_led_layer(
|
|||||||
furi_hal_light_set(layer->light, layer->value[LayerNotification]);
|
furi_hal_light_set(layer->light, layer->value[LayerNotification]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification_reset_notification_led_layer(NotificationLedLayer* layer) {
|
static void notification_reset_notification_led_layer(NotificationLedLayer* layer) {
|
||||||
furi_assert(layer);
|
furi_assert(layer);
|
||||||
furi_assert(layer->index < LayerMAX);
|
furi_assert(layer->index < LayerMAX);
|
||||||
|
|
||||||
@ -94,7 +104,7 @@ void notification_reset_notification_led_layer(NotificationLedLayer* layer) {
|
|||||||
furi_hal_light_set(layer->light, layer->value[LayerInternal]);
|
furi_hal_light_set(layer->light, layer->value[LayerInternal]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification_reset_notification_layer(NotificationApp* app, uint8_t reset_mask) {
|
static void notification_reset_notification_layer(NotificationApp* app, uint8_t reset_mask) {
|
||||||
if(reset_mask & reset_blink_mask) {
|
if(reset_mask & reset_blink_mask) {
|
||||||
furi_hal_light_blink_stop();
|
furi_hal_light_blink_stop();
|
||||||
}
|
}
|
||||||
@ -130,28 +140,28 @@ uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8
|
|||||||
return (value * app->settings.display_brightness);
|
return (value * app->settings.display_brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) {
|
static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) {
|
||||||
return (value * app->settings.led_brightness);
|
return (value * app->settings.led_brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) {
|
static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) {
|
||||||
return (
|
return (
|
||||||
(float)(app->settings.display_off_delay_ms) /
|
(float)(app->settings.display_off_delay_ms) /
|
||||||
(1000.0f / furi_kernel_get_tick_frequency()));
|
(1000.0f / furi_kernel_get_tick_frequency()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// generics
|
// generics
|
||||||
void notification_vibro_on(bool force) {
|
static void notification_vibro_on(bool force) {
|
||||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) {
|
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) {
|
||||||
furi_hal_vibro_on(true);
|
furi_hal_vibro_on(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification_vibro_off() {
|
static void notification_vibro_off() {
|
||||||
furi_hal_vibro_on(false);
|
furi_hal_vibro_on(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification_sound_on(float freq, float volume, bool force) {
|
static void notification_sound_on(float freq, float volume, bool force) {
|
||||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) {
|
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) {
|
||||||
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
|
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
|
||||||
furi_hal_speaker_start(freq, volume);
|
furi_hal_speaker_start(freq, volume);
|
||||||
@ -159,7 +169,7 @@ void notification_sound_on(float freq, float volume, bool force) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification_sound_off() {
|
static void notification_sound_off() {
|
||||||
if(furi_hal_speaker_is_mine()) {
|
if(furi_hal_speaker_is_mine()) {
|
||||||
furi_hal_speaker_stop();
|
furi_hal_speaker_stop();
|
||||||
furi_hal_speaker_release();
|
furi_hal_speaker_release();
|
||||||
@ -174,7 +184,7 @@ static void notification_display_timer(void* ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// message processing
|
// message processing
|
||||||
void notification_process_notification_message(
|
static void notification_process_notification_message(
|
||||||
NotificationApp* app,
|
NotificationApp* app,
|
||||||
NotificationAppMessage* message) {
|
NotificationAppMessage* message) {
|
||||||
uint32_t notification_message_index = 0;
|
uint32_t notification_message_index = 0;
|
||||||
@ -333,6 +343,9 @@ void notification_process_notification_message(
|
|||||||
reset_mask |= reset_green_mask;
|
reset_mask |= reset_green_mask;
|
||||||
reset_mask |= reset_blue_mask;
|
reset_mask |= reset_blue_mask;
|
||||||
break;
|
break;
|
||||||
|
case NotificationMessageTypeLcdContrastUpdate:
|
||||||
|
notification_apply_lcd_contrast(app);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
notification_message_index++;
|
notification_message_index++;
|
||||||
notification_message = (*message->sequence)[notification_message_index];
|
notification_message = (*message->sequence)[notification_message_index];
|
||||||
@ -361,7 +374,8 @@ void notification_process_notification_message(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) {
|
static void
|
||||||
|
notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) {
|
||||||
uint32_t notification_message_index = 0;
|
uint32_t notification_message_index = 0;
|
||||||
const NotificationMessage* notification_message;
|
const NotificationMessage* notification_message;
|
||||||
notification_message = (*message->sequence)[notification_message_index];
|
notification_message = (*message->sequence)[notification_message_index];
|
||||||
@ -548,6 +562,7 @@ int32_t notification_srv(void* p) {
|
|||||||
notification_apply_internal_led_layer(&app->led[0], 0x00);
|
notification_apply_internal_led_layer(&app->led[0], 0x00);
|
||||||
notification_apply_internal_led_layer(&app->led[1], 0x00);
|
notification_apply_internal_led_layer(&app->led[1], 0x00);
|
||||||
notification_apply_internal_led_layer(&app->led[2], 0x00);
|
notification_apply_internal_led_layer(&app->led[2], 0x00);
|
||||||
|
notification_apply_lcd_contrast(app);
|
||||||
|
|
||||||
furi_record_create(RECORD_NOTIFICATION, app);
|
furi_record_create(RECORD_NOTIFICATION, app);
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ typedef struct {
|
|||||||
Light light;
|
Light light;
|
||||||
} NotificationLedLayer;
|
} NotificationLedLayer;
|
||||||
|
|
||||||
#define NOTIFICATION_SETTINGS_VERSION 0x01
|
#define NOTIFICATION_SETTINGS_VERSION 0x02
|
||||||
#define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME)
|
#define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -41,6 +41,7 @@ typedef struct {
|
|||||||
float led_brightness;
|
float led_brightness;
|
||||||
float speaker_volume;
|
float speaker_volume;
|
||||||
uint32_t display_off_delay_ms;
|
uint32_t display_off_delay_ms;
|
||||||
|
int8_t contrast;
|
||||||
bool vibro_on;
|
bool vibro_on;
|
||||||
} NotificationSettings;
|
} NotificationSettings;
|
||||||
|
|
||||||
|
|||||||
@ -197,6 +197,10 @@ const NotificationMessage message_force_display_brightness_setting_1f = {
|
|||||||
.data.forced_settings.display_brightness = 1.0f,
|
.data.forced_settings.display_brightness = 1.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NotificationMessage message_lcd_contrast_update = {
|
||||||
|
.type = NotificationMessageTypeLcdContrastUpdate,
|
||||||
|
};
|
||||||
|
|
||||||
/****************************** Message sequences ******************************/
|
/****************************** Message sequences ******************************/
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
@ -566,3 +570,8 @@ const NotificationSequence sequence_audiovisual_alert = {
|
|||||||
&message_vibro_off,
|
&message_vibro_off,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NotificationSequence sequence_lcd_contrast_update = {
|
||||||
|
&message_lcd_contrast_update,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|||||||
@ -63,6 +63,9 @@ extern const NotificationMessage message_force_vibro_setting_on;
|
|||||||
extern const NotificationMessage message_force_vibro_setting_off;
|
extern const NotificationMessage message_force_vibro_setting_off;
|
||||||
extern const NotificationMessage message_force_display_brightness_setting_1f;
|
extern const NotificationMessage message_force_display_brightness_setting_1f;
|
||||||
|
|
||||||
|
// LCD Messages
|
||||||
|
extern const NotificationMessage message_lcd_contrast_update;
|
||||||
|
|
||||||
/****************************** Message sequences ******************************/
|
/****************************** Message sequences ******************************/
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
@ -138,6 +141,9 @@ extern const NotificationSequence sequence_success;
|
|||||||
extern const NotificationSequence sequence_error;
|
extern const NotificationSequence sequence_error;
|
||||||
extern const NotificationSequence sequence_audiovisual_alert;
|
extern const NotificationSequence sequence_audiovisual_alert;
|
||||||
|
|
||||||
|
// LCD
|
||||||
|
extern const NotificationSequence sequence_lcd_contrast_update;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -20,6 +20,34 @@ static const NotificationSequence sequence_note_c = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CONTRAST_COUNT 11
|
||||||
|
const char* const contrast_text[CONTRAST_COUNT] = {
|
||||||
|
"-5",
|
||||||
|
"-4",
|
||||||
|
"-3",
|
||||||
|
"-2",
|
||||||
|
"-1",
|
||||||
|
"0",
|
||||||
|
"+1",
|
||||||
|
"+2",
|
||||||
|
"+3",
|
||||||
|
"+4",
|
||||||
|
"+5",
|
||||||
|
};
|
||||||
|
const int32_t contrast_value[CONTRAST_COUNT] = {
|
||||||
|
-5,
|
||||||
|
-4,
|
||||||
|
-3,
|
||||||
|
-2,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
};
|
||||||
|
|
||||||
#define BACKLIGHT_COUNT 5
|
#define BACKLIGHT_COUNT 5
|
||||||
const char* const backlight_text[BACKLIGHT_COUNT] = {
|
const char* const backlight_text[BACKLIGHT_COUNT] = {
|
||||||
"0%",
|
"0%",
|
||||||
@ -64,6 +92,15 @@ const char* const vibro_text[VIBRO_COUNT] = {
|
|||||||
};
|
};
|
||||||
const bool vibro_value[VIBRO_COUNT] = {false, true};
|
const bool vibro_value[VIBRO_COUNT] = {false, true};
|
||||||
|
|
||||||
|
static void contrast_changed(VariableItem* item) {
|
||||||
|
NotificationAppSettings* app = variable_item_get_context(item);
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
|
variable_item_set_current_value_text(item, contrast_text[index]);
|
||||||
|
app->notification->settings.contrast = contrast_value[index];
|
||||||
|
notification_message(app->notification, &sequence_lcd_contrast_update);
|
||||||
|
}
|
||||||
|
|
||||||
static void backlight_changed(VariableItem* item) {
|
static void backlight_changed(VariableItem* item) {
|
||||||
NotificationAppSettings* app = variable_item_get_context(item);
|
NotificationAppSettings* app = variable_item_get_context(item);
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
@ -136,6 +173,13 @@ static NotificationAppSettings* alloc_settings() {
|
|||||||
VariableItem* item;
|
VariableItem* item;
|
||||||
uint8_t value_index;
|
uint8_t value_index;
|
||||||
|
|
||||||
|
item = variable_item_list_add(
|
||||||
|
app->variable_item_list, "LCD Contrast", CONTRAST_COUNT, contrast_changed, app);
|
||||||
|
value_index =
|
||||||
|
value_index_int32(app->notification->settings.contrast, contrast_value, CONTRAST_COUNT);
|
||||||
|
variable_item_set_current_value_index(item, value_index);
|
||||||
|
variable_item_set_current_value_text(item, contrast_text[value_index]);
|
||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
|
app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
|
||||||
value_index = value_index_float(
|
value_index = value_index_float(
|
||||||
|
|||||||
BIN
assets/dolphin/external/L2_Dj_128x64/frame_0.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_1.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_10.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_11.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_12.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_13.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_14.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_15.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_16.png
vendored
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_17.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_18.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_19.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_2.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_20.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_21.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_22.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_23.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/dolphin/external/L2_Dj_128x64/frame_24.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |