Skip to content

Commit

Permalink
add nfc playlist
Browse files Browse the repository at this point in the history
  • Loading branch information
xMasterX committed Mar 2, 2024
1 parent 94e5cbb commit b066300
Show file tree
Hide file tree
Showing 25 changed files with 1,087 additions and 0 deletions.
1 change: 1 addition & 0 deletions non_catalog_apps/nfc_playlist/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
notes.txt
25 changes: 25 additions & 0 deletions non_catalog_apps/nfc_playlist/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# FlipperZero_NFC_Playlist:
The idea behind this app is to allow for you to test multiple copies of NFC's at once as a bulk test

## How it works:
When starting the app you are greeted by a select file option where you choose the playlist you wanna run.

All the playlists should be placed in ext/apps_data/nfc_playlist and an example of how the data in the file should look can be found below.
```txt
/ext/nfc/link.nfc
/ext/nfc/link2.nfc
```
An example file can be found in the repository

## How to build
This app was design, built and tested using the <a href="https://github.com/Flipper-XFW/Xtreme-Firmware">Xtreme firmware</a> so keep that in mind when building the FAP for yourself

## Settings:
- Emulate time (How long the NFC card will be emulated for)
- Delay time (How long the gap between the cards will be)
- LED indicator (Whether or not the LED's will be on)
- Reset settings (Puts all the settings back to the defaults)

## Playlist editor:
- Delete playlist (Deletes the selected playlist)
- Rename playlist (Renames the selected playlist the new name provided)
22 changes: 22 additions & 0 deletions non_catalog_apps/nfc_playlist/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
App(
appid="nfc_playlist",
name="NFC Playlist",
apptype=FlipperAppType.EXTERNAL,
entry_point="nfc_playlist_main",
requires=["gui", "nfc"],
stack_size=4 * 1024,
fap_category="NFC",
fap_author="@acegoal07",
fap_weburl="https://github.com/acegoal07/FlipperZero_NFC_Playlist/tree/main",
fap_version="1.4",
fap_icon="icon.png",
fap_icon_assets="assets",
fap_private_libs=[
Lib(
name="worker",
),
Lib(
name="led",
),
],
)
Binary file added non_catalog_apps/nfc_playlist/assets/sub1_10px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added non_catalog_apps/nfc_playlist/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions non_catalog_apps/nfc_playlist/lib/led/nfc_playlist_led.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "nfc_playlist_led.h"

NotificationMessage blink_message_normal = {
.type = NotificationMessageTypeLedBlinkStart,
.data.led_blink.color = LightBlue | LightGreen,
.data.led_blink.on_time = 10,
.data.led_blink.period = 100
};
const NotificationSequence blink_sequence_normal = {
&blink_message_normal,
&message_do_not_reset,
NULL
};

NotificationMessage blink_message_error = {
.type = NotificationMessageTypeLedBlinkStart,
.data.led_blink.color = LightRed,
.data.led_blink.on_time = 10,
.data.led_blink.period = 100
};

const NotificationSequence blink_sequence_error = {
&blink_message_error,
&message_do_not_reset,
NULL
};

void start_blink(NfcPlaylist* nfc_playlist, int state) {
if (nfc_playlist->settings.emulate_led_indicator) {
if (state == NfcPlaylistLedState_Normal) {
notification_message_block(nfc_playlist->notification, &blink_sequence_normal);
} else if (state == NfcPlaylistLedState_Error) {
notification_message_block(nfc_playlist->notification, &blink_sequence_error);
}
}
}

void stop_blink(NfcPlaylist* nfc_playlist) {
if (nfc_playlist->settings.emulate_led_indicator) {
notification_message_block(nfc_playlist->notification, &sequence_blink_stop);
}
}
11 changes: 11 additions & 0 deletions non_catalog_apps/nfc_playlist/lib/led/nfc_playlist_led.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once
#include <../../nfc_playlist.h>
#include <notification/notification_messages.h>

typedef enum NfcPlaylistLedState {
NfcPlaylistLedState_Normal,
NfcPlaylistLedState_Error
} NfcPlaylistLedState;

void start_blink(NfcPlaylist* nfc_playlist, int state);
void stop_blink(NfcPlaylist* nfc_playlist);
83 changes: 83 additions & 0 deletions non_catalog_apps/nfc_playlist/lib/worker/nfc_playlist_worker.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include "nfc_playlist_worker.h"

NfcPlaylistWorker* nfc_playlist_worker_alloc() {
NfcPlaylistWorker* nfc_playlist_worker = malloc(sizeof(NfcPlaylistWorker));

nfc_playlist_worker->thread = furi_thread_alloc_ex("NfcPlaylistWorker", 8192, nfc_playlist_worker_task, nfc_playlist_worker);
nfc_playlist_worker->state = NfcPlaylistWorkerState_Stopped;

nfc_playlist_worker->nfc = nfc_alloc();
nfc_playlist_worker->nfc_device = nfc_device_alloc();

return nfc_playlist_worker;
}

void nfc_playlist_worker_free(NfcPlaylistWorker* nfc_playlist_worker) {
furi_assert(nfc_playlist_worker);
furi_thread_free(nfc_playlist_worker->thread);

nfc_free(nfc_playlist_worker->nfc);
nfc_device_free(nfc_playlist_worker->nfc_device);

free(nfc_playlist_worker);
}

void nfc_playlist_worker_stop(NfcPlaylistWorker* nfc_playlist_worker) {
furi_assert(nfc_playlist_worker);
if (nfc_playlist_worker->state != NfcPlaylistWorkerState_Stopped) {
nfc_playlist_worker->state = NfcPlaylistWorkerState_Stopped;
furi_thread_join(nfc_playlist_worker->thread);
}
}

void nfc_playlist_worker_start(NfcPlaylistWorker* nfc_playlist_worker) {
furi_assert(nfc_playlist_worker);
nfc_playlist_worker->state = NfcPlaylistWorkerState_Emulating;
furi_thread_start(nfc_playlist_worker->thread);
}

int32_t nfc_playlist_worker_task(void* context) {
NfcPlaylistWorker* nfc_playlist_worker = context;

if (nfc_playlist_worker->state == NfcPlaylistWorkerState_Emulating) {

nfc_playlist_worker->nfc_listener =
nfc_listener_alloc(nfc_playlist_worker->nfc,
nfc_playlist_worker->nfc_protocol,
nfc_device_get_data(nfc_playlist_worker->nfc_device, nfc_playlist_worker->nfc_protocol)
);
nfc_listener_start(nfc_playlist_worker->nfc_listener, NULL, NULL);

while(nfc_playlist_worker->state == NfcPlaylistWorkerState_Emulating) {
furi_delay_ms(50);
}

nfc_listener_stop(nfc_playlist_worker->nfc_listener);
nfc_listener_free(nfc_playlist_worker->nfc_listener);
}

nfc_playlist_worker->state = NfcPlaylistWorkerState_Stopped;

return 0;
}

bool nfc_playlist_worker_is_emulating(NfcPlaylistWorker* nfc_playlist_worker) {
if (nfc_playlist_worker->state == NfcPlaylistWorkerState_Emulating) {
return true;
}
return false;
}

void nfc_playlist_worker_set_nfc_data(NfcPlaylistWorker* nfc_playlist_worker, char* file_path) {
nfc_device_clear(nfc_playlist_worker->nfc_device);
nfc_device_load(nfc_playlist_worker->nfc_device, file_path);
nfc_playlist_worker->nfc_protocol = nfc_device_get_protocol(nfc_playlist_worker->nfc_device);
}

void nfc_playlist_worker_clear_nfc_data(NfcPlaylistWorker* nfc_playlist_worker) {
nfc_device_clear(nfc_playlist_worker->nfc_device);
}

NfcDeviceData* nfc_playlist_worker_get_nfc_data(NfcPlaylistWorker* nfc_playlist_worker) {
return nfc_playlist_worker->nfc_data;
}
33 changes: 33 additions & 0 deletions non_catalog_apps/nfc_playlist/lib/worker/nfc_playlist_worker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <nfc/nfc.h>
#include <nfc/nfc_device.h>
#include <nfc/nfc_listener.h>

typedef enum NfcPlaylistWorkerState {
NfcPlaylistWorkerState_Emulating,
NfcPlaylistWorkerState_Stopped
} NfcPlaylistWorkerState;

typedef struct NfcPlaylistWorker {
FuriThread* thread;
NfcPlaylistWorkerState state;
NfcListener* nfc_listener;
NfcDevice* nfc_device;
NfcProtocol nfc_protocol;
NfcDeviceData* nfc_data;
Nfc* nfc;
} NfcPlaylistWorker;

NfcPlaylistWorker* nfc_playlist_worker_alloc();
void nfc_playlist_worker_free(NfcPlaylistWorker* nfc_playlist_worker);
void nfc_playlist_worker_stop(NfcPlaylistWorker* nfc_playlist_worker);
void nfc_playlist_worker_start(NfcPlaylistWorker* nfc_playlist_worker);

int32_t nfc_playlist_worker_task(void* context);

bool nfc_playlist_worker_is_emulating(NfcPlaylistWorker* nfc_playlist_worker);
void nfc_playlist_worker_set_nfc_data(NfcPlaylistWorker* nfc_playlist_worker, char* file_path);
void nfc_playlist_worker_clear_nfc_data(NfcPlaylistWorker* nfc_playlist_worker);
NfcDeviceData* nfc_playlist_worker_get_nfc_data(NfcPlaylistWorker* nfc_playlist_worker);
120 changes: 120 additions & 0 deletions non_catalog_apps/nfc_playlist/nfc_playlist.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include "nfc_playlist.h"
#include "nfc_playlist_i.h"

static void (*const nfc_playlist_scene_on_enter_handlers[])(void*) = {
nfc_playlist_main_menu_scene_on_enter,
nfc_playlist_settings_scene_on_enter,
nfc_playlist_emulation_scene_on_enter,
nfc_playlist_file_select_scene_on_enter,
nfc_playlist_file_edit_scene_on_enter,
nfc_playlist_text_input_scene_on_enter
};

static bool (*const nfc_playlist_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
nfc_playlist_main_menu_scene_on_event,
nfc_playlist_settings_scene_on_event,
nfc_playlist_emulation_scene_on_event,
nfc_playlist_file_select_scene_on_event,
nfc_playlist_file_edit_scene_on_event,
nfc_playlist_text_input_scene_on_event
};

static void (*const nfc_playlist_scene_on_exit_handlers[])(void*) = {
nfc_playlist_main_menu_scene_on_exit,
nfc_playlist_settings_scene_on_exit,
nfc_playlist_emulation_scene_on_exit,
nfc_playlist_file_select_scene_on_exit,
nfc_playlist_file_edit_scene_on_exit,
nfc_playlist_text_input_scene_on_exit
};

static const SceneManagerHandlers nfc_playlist_scene_manager_handlers = {
.on_enter_handlers = nfc_playlist_scene_on_enter_handlers,
.on_event_handlers = nfc_playlist_scene_on_event_handlers,
.on_exit_handlers = nfc_playlist_scene_on_exit_handlers,
.scene_num = NfcPlaylistScene_count
};

static bool nfc_playlist_custom_callback(void* context, uint32_t custom_event) {
furi_assert(context);
NfcPlaylist* nfc_playlist = context;
return scene_manager_handle_custom_event(nfc_playlist->scene_manager, custom_event);
}

static bool nfc_playlist_back_event_callback(void* context) {
furi_assert(context);
NfcPlaylist* nfc_playlist = context;
return scene_manager_handle_back_event(nfc_playlist->scene_manager);
}

static NfcPlaylist* nfc_playlist_alloc() {
NfcPlaylist* nfc_playlist = malloc(sizeof(NfcPlaylist));
furi_assert(nfc_playlist);
nfc_playlist->scene_manager = scene_manager_alloc(&nfc_playlist_scene_manager_handlers, nfc_playlist);
nfc_playlist->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(nfc_playlist->view_dispatcher);
nfc_playlist->variable_item_list = variable_item_list_alloc();
nfc_playlist->submenu = submenu_alloc();

nfc_playlist->settings.base_file_path = furi_string_alloc_set_str("/ext/apps_data/nfc_playlist/");
nfc_playlist->settings.file_path = nfc_playlist->settings.base_file_path;
nfc_playlist->settings.file_selected = false;
nfc_playlist->settings.file_selected_check = false;
nfc_playlist->settings.emulate_timeout = default_emulate_timeout;
nfc_playlist->settings.emulate_delay = default_emulate_delay;
nfc_playlist->settings.emulate_led_indicator = default_emulate_led_indicator;

nfc_playlist->notification = furi_record_open(RECORD_NOTIFICATION);
nfc_playlist->file_browser = file_browser_alloc(nfc_playlist->settings.file_path);
nfc_playlist->text_input = text_input_alloc();
nfc_playlist->popup = popup_alloc();

view_dispatcher_set_event_callback_context(nfc_playlist->view_dispatcher, nfc_playlist);
view_dispatcher_set_custom_event_callback(nfc_playlist->view_dispatcher, nfc_playlist_custom_callback);
view_dispatcher_set_navigation_event_callback(nfc_playlist->view_dispatcher, nfc_playlist_back_event_callback);
view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Menu, submenu_get_view(nfc_playlist->submenu));
view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Settings, variable_item_list_get_view(nfc_playlist->variable_item_list));
view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup, popup_get_view(nfc_playlist->popup));
view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileSelect, file_browser_get_view(nfc_playlist->file_browser));
view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileEdit, submenu_get_view(nfc_playlist->submenu));
view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput, text_input_get_view(nfc_playlist->text_input));
return nfc_playlist;
}

static void nfc_playlist_free(NfcPlaylist* nfc_playlist) {
furi_assert(nfc_playlist);
scene_manager_free(nfc_playlist->scene_manager);
view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Menu);
view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Settings);
view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup);
view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileSelect);
view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileEdit);
view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
view_dispatcher_free(nfc_playlist->view_dispatcher);
variable_item_list_free(nfc_playlist->variable_item_list);
submenu_free(nfc_playlist->submenu);
file_browser_free(nfc_playlist->file_browser);
text_input_free(nfc_playlist->text_input);
popup_free(nfc_playlist->popup);
furi_record_close(RECORD_NOTIFICATION);
furi_string_free(nfc_playlist->settings.base_file_path);
furi_string_free(nfc_playlist->settings.file_path);
free(nfc_playlist->playlist_name);
free(nfc_playlist);
}

int32_t nfc_playlist_main(void* p) {
UNUSED(p);

NfcPlaylist* nfc_playlist = nfc_playlist_alloc();

Gui* gui = furi_record_open(RECORD_GUI);
view_dispatcher_attach_to_gui(nfc_playlist->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_MainMenu);
view_dispatcher_run(nfc_playlist->view_dispatcher);

furi_record_close(RECORD_GUI);
nfc_playlist_free(nfc_playlist);

return 0;
}
Loading

0 comments on commit b066300

Please sign in to comment.