All apps migrated!!!

This commit is contained in:
Willy-JL
2023-11-27 05:49:47 +00:00
parent 44ad3e94a5
commit c3018328b9
122 changed files with 0 additions and 19892 deletions
@@ -1,7 +0,0 @@
#define WIFI_MODULE_INIT_VERSION "WFDM_0.1"
#define MODULE_CONTEXT_INITIALIZATION WIFI_MODULE_INIT_VERSION
#define FLIPPERZERO_SERIAL_BAUD 230400
#define NA 0
-13
View File
@@ -1,13 +0,0 @@
App(
appid="esp8266_deauther",
name="[ESP8266] Deauther",
apptype=FlipperAppType.EXTERNAL,
entry_point="esp8266_deauth_app",
requires=["gui"],
stack_size=2 * 1024,
fap_icon="wifi_10px.png",
fap_category="WiFi",
fap_author="@SequoiaSan & @xMasterX",
fap_version="1.0",
fap_description="DSTIKE Deauther module interface, based on ESP8266",
)
-560
View File
@@ -1,560 +0,0 @@
#include <furi.h>
#include <furi_hal_console.h>
#include <furi_hal_gpio.h>
#include <furi_hal_power.h>
#include <furi_hal_uart.h>
#include <gui/canvas_i.h>
#include <gui/gui.h>
#include <input/input.h>
//#include <math.h>
//#include <notification/notification.h>
//#include <notification/notification_messages.h>
//#include <stdlib.h>
#include <xtreme.h>
#include "FlipperZeroWiFiDeauthModuleDefines.h"
#define UART_CH \
(xtreme_settings.uart_esp_channel == UARTDefault ? FuriHalUartIdUSART1 : FuriHalUartIdLPUART1)
#define DEAUTH_APP_DEBUG 0
#if DEAUTH_APP_DEBUG
#define APP_NAME_TAG "WiFi_Deauther"
#define DEAUTH_APP_LOG_I(format, ...) FURI_LOG_I(APP_NAME_TAG, format, ##__VA_ARGS__)
#define DEAUTH_APP_LOG_D(format, ...) FURI_LOG_D(APP_NAME_TAG, format, ##__VA_ARGS__)
#define DEAUTH_APP_LOG_E(format, ...) FURI_LOG_E(APP_NAME_TAG, format, ##__VA_ARGS__)
#else
#define DEAUTH_APP_LOG_I(format, ...)
#define DEAUTH_APP_LOG_D(format, ...)
#define DEAUTH_APP_LOG_E(format, ...)
#endif // WIFI_APP_DEBUG
#define DISABLE_CONSOLE !DEAUTH_APP_DEBUG
#define ENABLE_MODULE_POWER 1
#define ENABLE_MODULE_DETECTION 1
typedef enum EEventType // app internally defined event types
{ EventTypeKey // flipper input.h type
} EEventType;
typedef struct SPluginEvent {
EEventType m_type;
InputEvent m_input;
} SPluginEvent;
typedef enum EAppContext {
Undefined,
WaitingForModule,
Initializing,
ModuleActive,
} EAppContext;
typedef enum EWorkerEventFlags {
WorkerEventReserved = (1 << 0), // Reserved for StreamBuffer internal event
WorkerEventStop = (1 << 1),
WorkerEventRx = (1 << 2),
} EWorkerEventFlags;
typedef struct SGpioButtons {
GpioPin const* pinButtonUp;
GpioPin const* pinButtonDown;
GpioPin const* pinButtonOK;
GpioPin const* pinButtonBack;
} SGpioButtons;
typedef struct SWiFiDeauthApp {
FuriMutex* mutex;
Gui* m_gui;
FuriThread* m_worker_thread;
//NotificationApp* m_notification;
FuriStreamBuffer* m_rx_stream;
SGpioButtons m_GpioButtons;
bool m_wifiDeauthModuleInitialized;
bool m_wifiDeauthModuleAttached;
EAppContext m_context;
uint8_t m_backBuffer[128 * 8 * 8];
//uint8_t m_renderBuffer[128 * 8 * 8];
uint8_t* m_backBufferPtr;
//uint8_t* m_m_renderBufferPtr;
//uint8_t* m_originalBuffer;
//uint8_t** m_originalBufferLocation;
size_t m_canvasSize;
bool m_needUpdateGUI;
} SWiFiDeauthApp;
/////// INIT STATE ///////
static void esp8266_deauth_app_init(SWiFiDeauthApp* const app) {
app->m_context = Undefined;
app->m_canvasSize = 128 * 8 * 8;
memset(app->m_backBuffer, DEAUTH_APP_DEBUG ? 0xFF : 0x00, app->m_canvasSize);
//memset(app->m_renderBuffer, DEAUTH_APP_DEBUG ? 0xFF : 0x00, app->m_canvasSize);
//app->m_originalBuffer = NULL;
//app->m_originalBufferLocation = NULL;
//app->m_m_renderBufferPtr = app->m_renderBuffer;
app->m_backBufferPtr = app->m_backBuffer;
app->m_GpioButtons.pinButtonUp = &gpio_ext_pc3;
app->m_GpioButtons.pinButtonDown = &gpio_ext_pb2;
app->m_GpioButtons.pinButtonOK = &gpio_ext_pb3;
app->m_GpioButtons.pinButtonBack = &gpio_ext_pa4;
app->m_needUpdateGUI = false;
#if ENABLE_MODULE_POWER
app->m_wifiDeauthModuleInitialized = false;
#else
app->m_wifiDeauthModuleInitialized = true;
#endif // ENABLE_MODULE_POWER
#if ENABLE_MODULE_DETECTION
app->m_wifiDeauthModuleAttached = false;
#else
app->m_wifiDeauthModuleAttached = true;
#endif
}
static void esp8266_deauth_module_render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
SWiFiDeauthApp* app = ctx;
furi_mutex_acquire(app->mutex, FuriWaitForever);
//if(app->m_needUpdateGUI)
//{
// app->m_needUpdateGUI = false;
// //app->m_canvasSize = canvas_get_buffer_size(canvas);
// //app->m_originalBuffer = canvas_get_buffer(canvas);
// //app->m_originalBufferLocation = &u8g2_GetBufferPtr(&canvas->fb);
// //u8g2_GetBufferPtr(&canvas->fb) = app->m_m_renderBufferPtr;
//}
//uint8_t* exchangeBuffers = app->m_m_renderBufferPtr;
//app->m_m_renderBufferPtr = app->m_backBufferPtr;
//app->m_backBufferPtr = exchangeBuffers;
//if(app->m_needUpdateGUI)
//{
// //memcpy(app->m_renderBuffer, app->m_backBuffer, app->m_canvasSize);
// app->m_needUpdateGUI = false;
//}
switch(app->m_context) {
case Undefined: {
canvas_clear(canvas);
canvas_set_font(canvas, FontPrimary);
const char* strInitializing = "Something wrong";
canvas_draw_str(
canvas,
(128 / 2) - (canvas_string_width(canvas, strInitializing) / 2),
(64 / 2) /* - (canvas_current_font_height(canvas) / 2)*/,
strInitializing);
} break;
case WaitingForModule:
#if ENABLE_MODULE_DETECTION
furi_assert(!app->m_wifiDeauthModuleAttached);
if(!app->m_wifiDeauthModuleAttached) {
canvas_clear(canvas);
canvas_set_font(canvas, FontSecondary);
const char* strInitializing = "Attach WiFi Deauther module";
canvas_draw_str(
canvas,
(128 / 2) - (canvas_string_width(canvas, strInitializing) / 2),
(64 / 2) /* - (canvas_current_font_height(canvas) / 2)*/,
strInitializing);
}
#endif
break;
case Initializing:
#if ENABLE_MODULE_POWER
{
furi_assert(!app->m_wifiDeauthModuleInitialized);
if(!app->m_wifiDeauthModuleInitialized) {
canvas_set_font(canvas, FontPrimary);
const char* strInitializing = "Initializing...";
canvas_draw_str(
canvas,
(128 / 2) - (canvas_string_width(canvas, strInitializing) / 2),
(64 / 2) - (canvas_current_font_height(canvas) / 2),
strInitializing);
}
}
#endif // ENABLE_MODULE_POWER
break;
case ModuleActive: {
uint8_t* buffer = canvas->fb.tile_buf_ptr;
app->m_canvasSize = gui_get_framebuffer_size(app->m_gui);
memcpy(buffer, app->m_backBuffer, app->m_canvasSize);
} break;
default:
break;
}
furi_mutex_release(app->mutex);
}
static void
esp8266_deauth_module_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
SPluginEvent event = {.m_type = EventTypeKey, .m_input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
furi_assert(context);
SWiFiDeauthApp* app = context;
DEAUTH_APP_LOG_I("uart_echo_on_irq_cb");
if(ev == UartIrqEventRXNE) {
DEAUTH_APP_LOG_I("ev == UartIrqEventRXNE");
furi_stream_buffer_send(app->m_rx_stream, &data, 1, 0);
furi_thread_flags_set(furi_thread_get_id(app->m_worker_thread), WorkerEventRx);
}
}
static int32_t uart_worker(void* context) {
furi_assert(context);
DEAUTH_APP_LOG_I("[UART] Worker thread init");
SWiFiDeauthApp* app = context;
furi_mutex_acquire(app->mutex, FuriWaitForever);
if(app == NULL) {
return 1;
}
FuriStreamBuffer* rx_stream = app->m_rx_stream;
furi_mutex_release(app->mutex);
#if ENABLE_MODULE_POWER
bool initialized = false;
FuriString* receivedString;
receivedString = furi_string_alloc();
#endif // ENABLE_MODULE_POWER
while(true) {
uint32_t events = furi_thread_flags_wait(
WorkerEventStop | WorkerEventRx, FuriFlagWaitAny, FuriWaitForever);
furi_check((events & FuriFlagError) == 0);
if(events & WorkerEventStop) break;
if(events & WorkerEventRx) {
DEAUTH_APP_LOG_I("[UART] Received data");
SWiFiDeauthApp* app = context;
furi_mutex_acquire(app->mutex, FuriWaitForever);
if(app == NULL) {
return 1;
}
size_t dataReceivedLength = 0;
int index = 0;
do {
const uint8_t dataBufferSize = 64;
uint8_t dataBuffer[dataBufferSize];
dataReceivedLength =
furi_stream_buffer_receive(rx_stream, dataBuffer, dataBufferSize, 25);
if(dataReceivedLength > 0) {
#if ENABLE_MODULE_POWER
if(!initialized) {
if(!(dataReceivedLength > strlen(MODULE_CONTEXT_INITIALIZATION))) {
DEAUTH_APP_LOG_I("[UART] Found possible init candidate");
for(uint16_t i = 0; i < dataReceivedLength; i++) {
furi_string_push_back(receivedString, dataBuffer[i]);
}
}
} else
#endif // ENABLE_MODULE_POWER
{
DEAUTH_APP_LOG_I("[UART] Data copied to backbuffer");
memcpy(app->m_backBuffer + index, dataBuffer, dataReceivedLength);
index += dataReceivedLength;
app->m_needUpdateGUI = true;
}
}
} while(dataReceivedLength > 0);
#if ENABLE_MODULE_POWER
if(!app->m_wifiDeauthModuleInitialized) {
if(furi_string_cmp_str(receivedString, MODULE_CONTEXT_INITIALIZATION) == 0) {
DEAUTH_APP_LOG_I("[UART] Initialized");
initialized = true;
app->m_wifiDeauthModuleInitialized = true;
app->m_context = ModuleActive;
furi_string_free(receivedString);
} else {
DEAUTH_APP_LOG_I("[UART] Not an initialization command");
furi_string_reset(receivedString);
}
}
#endif // ENABLE_MODULE_POWER
furi_mutex_release(app->mutex);
}
}
return 0;
}
int32_t esp8266_deauth_app(void* p) {
UNUSED(p);
DEAUTH_APP_LOG_I("Init");
// FuriTimer* timer = furi_timer_alloc(blink_test_update, FuriTimerTypePeriodic, event_queue);
// furi_timer_start(timer, furi_kernel_get_tick_frequency());
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SPluginEvent));
SWiFiDeauthApp* app = malloc(sizeof(SWiFiDeauthApp));
esp8266_deauth_app_init(app);
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonUp, GpioModeOutputPushPull);
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonDown, GpioModeOutputPushPull);
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonOK, GpioModeOutputPushPull);
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonBack, GpioModeOutputPushPull);
furi_hal_gpio_write(app->m_GpioButtons.pinButtonUp, true);
furi_hal_gpio_write(app->m_GpioButtons.pinButtonDown, true);
furi_hal_gpio_write(app->m_GpioButtons.pinButtonOK, true);
furi_hal_gpio_write(
app->m_GpioButtons.pinButtonBack, false); // GPIO15 - Boot fails if pulled HIGH
#if ENABLE_MODULE_DETECTION
furi_hal_gpio_init(
&gpio_ext_pc0,
GpioModeInput,
GpioPullUp,
GpioSpeedLow); // Connect to the Flipper's ground just to be sure
//furi_hal_gpio_add_int_callback(pinD0, input_isr_d0, this);
app->m_context = WaitingForModule;
#else
#if ENABLE_MODULE_POWER
app->m_context = Initializing;
uint8_t attempts = 0;
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
furi_hal_power_enable_otg();
furi_delay_ms(10);
}
furi_delay_ms(200);
#else
app->m_context = ModuleActive;
#endif
#endif // ENABLE_MODULE_DETECTION
app->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!app->mutex) {
DEAUTH_APP_LOG_E("cannot create mutex\r\n");
free(app);
return 255;
}
DEAUTH_APP_LOG_I("Mutex created");
//app->m_notification = furi_record_open(RECORD_NOTIFICATION);
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, esp8266_deauth_module_render_callback, app);
view_port_input_callback_set(view_port, esp8266_deauth_module_input_callback, event_queue);
// Open GUI and register view_port
app->m_gui = furi_record_open(RECORD_GUI);
gui_add_view_port(app->m_gui, view_port, GuiLayerFullscreen);
//notification_message(app->notification, &sequence_set_only_blue_255);
app->m_rx_stream = furi_stream_buffer_alloc(1 * 1024, 1);
app->m_worker_thread = furi_thread_alloc();
furi_thread_set_name(app->m_worker_thread, "WiFiDeauthModuleUARTWorker");
furi_thread_set_stack_size(app->m_worker_thread, 1 * 1024);
furi_thread_set_context(app->m_worker_thread, app);
furi_thread_set_callback(app->m_worker_thread, uart_worker);
furi_thread_start(app->m_worker_thread);
DEAUTH_APP_LOG_I("UART thread allocated");
// Enable uart listener
#if DISABLE_CONSOLE
furi_hal_console_disable();
#endif
if(UART_CH == FuriHalUartIdUSART1) {
furi_hal_console_disable();
} else if(UART_CH == FuriHalUartIdLPUART1) {
furi_hal_uart_init(UART_CH, FLIPPERZERO_SERIAL_BAUD);
}
furi_hal_uart_set_br(FuriHalUartIdUSART1, FLIPPERZERO_SERIAL_BAUD);
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_on_irq_cb, app);
DEAUTH_APP_LOG_I("UART Listener created");
SPluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(app->mutex, FuriWaitForever);
#if ENABLE_MODULE_DETECTION
if(!app->m_wifiDeauthModuleAttached) {
if(furi_hal_gpio_read(&gpio_ext_pc0) == false) {
DEAUTH_APP_LOG_I("Module Attached");
app->m_wifiDeauthModuleAttached = true;
#if ENABLE_MODULE_POWER
app->m_context = Initializing;
uint8_t attempts2 = 0;
while(!furi_hal_power_is_otg_enabled() && attempts2++ < 3) {
furi_hal_power_enable_otg();
furi_delay_ms(10);
}
#else
app->m_context = ModuleActive;
#endif
}
}
#endif // ENABLE_MODULE_DETECTION
if(event_status == FuriStatusOk) {
if(event.m_type == EventTypeKey) {
if(app->m_wifiDeauthModuleInitialized) {
if(app->m_context == ModuleActive) {
switch(event.m_input.key) {
case InputKeyUp:
if(event.m_input.type == InputTypePress) {
DEAUTH_APP_LOG_I("Up Press");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonUp, false);
} else if(event.m_input.type == InputTypeRelease) {
DEAUTH_APP_LOG_I("Up Release");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonUp, true);
}
break;
case InputKeyDown:
if(event.m_input.type == InputTypePress) {
DEAUTH_APP_LOG_I("Down Press");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonDown, false);
} else if(event.m_input.type == InputTypeRelease) {
DEAUTH_APP_LOG_I("Down Release");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonDown, true);
}
break;
case InputKeyOk:
if(event.m_input.type == InputTypePress) {
DEAUTH_APP_LOG_I("OK Press");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonOK, false);
} else if(event.m_input.type == InputTypeRelease) {
DEAUTH_APP_LOG_I("OK Release");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonOK, true);
}
break;
case InputKeyBack:
if(event.m_input.type == InputTypePress) {
DEAUTH_APP_LOG_I("Back Press");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonBack, false);
} else if(event.m_input.type == InputTypeRelease) {
DEAUTH_APP_LOG_I("Back Release");
furi_hal_gpio_write(app->m_GpioButtons.pinButtonBack, true);
} else if(event.m_input.type == InputTypeLong) {
DEAUTH_APP_LOG_I("Back Long");
processing = false;
}
break;
default:
break;
}
}
} else {
if(event.m_input.key == InputKeyBack) {
if(event.m_input.type == InputTypeShort ||
event.m_input.type == InputTypeLong) {
processing = false;
}
}
}
}
}
#if ENABLE_MODULE_DETECTION
if(app->m_wifiDeauthModuleAttached && furi_hal_gpio_read(&gpio_ext_pc0) == true) {
DEAUTH_APP_LOG_D("Module Disconnected - Exit");
processing = false;
app->m_wifiDeauthModuleAttached = false;
app->m_wifiDeauthModuleInitialized = false;
}
#endif
view_port_update(view_port);
furi_mutex_release(app->mutex);
}
DEAUTH_APP_LOG_I("Start exit app");
furi_thread_flags_set(furi_thread_get_id(app->m_worker_thread), WorkerEventStop);
furi_thread_join(app->m_worker_thread);
furi_thread_free(app->m_worker_thread);
DEAUTH_APP_LOG_I("Thread Deleted");
// Reset GPIO pins to default state
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pb2, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pb3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pa4, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#if DISABLE_CONSOLE
furi_hal_console_enable();
#endif
if(UART_CH == FuriHalUartIdLPUART1) {
furi_hal_uart_deinit(UART_CH);
} else {
furi_hal_console_enable();
}
//*app->m_originalBufferLocation = app->m_originalBuffer;
view_port_enabled_set(view_port, false);
gui_remove_view_port(app->m_gui, view_port);
// Close gui record
furi_record_close(RECORD_GUI);
//furi_record_close(RECORD_NOTIFICATION);
app->m_gui = NULL;
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_stream_buffer_free(app->m_rx_stream);
furi_mutex_free(app->mutex);
// Free rest
free(app);
DEAUTH_APP_LOG_I("App freed");
#if ENABLE_MODULE_POWER
if(furi_hal_power_is_otg_enabled()) {
furi_hal_power_disable_otg();
}
#endif
return 0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

-13
View File
@@ -1,13 +0,0 @@
App(
appid="esp8266_ifttt_virtual_button",
name="[ESP8266] IFTTT Btn",
apptype=FlipperAppType.EXTERNAL,
entry_point="ifttt_virtual_button_app",
cdefines=["APP_IFTTT_VIRTUAL_BUTTON"],
requires=[
"gui",
],
stack_size=2 * 1024,
fap_icon="icon.png",
fap_category="WiFi",
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

-236
View File
@@ -1,236 +0,0 @@
#include "ifttt_virtual_button.h"
#define IFTTT_FOLDER "/ext/apps_data/ifttt"
#define IFTTT_CONFIG_FOLDER "/ext/apps_data/ifttt/config"
const char* CONFIG_FILE_PATH = "/ext/apps_data/ifttt/config/config.settings";
#define FLIPPERZERO_SERIAL_BAUD 115200
typedef enum ESerialCommand { ESerialCommand_Config } ESerialCommand;
Settings save_settings(Settings settings) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
if(flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) {
flipper_format_update_string_cstr(file, CONF_SSID, settings.save_ssid);
flipper_format_update_string_cstr(file, CONF_PASSWORD, settings.save_password);
flipper_format_update_string_cstr(file, CONF_KEY, settings.save_key);
flipper_format_update_string_cstr(file, CONF_EVENT, settings.save_event);
} else {
}
flipper_format_file_close(file);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return settings;
}
void save_settings_file(FlipperFormat* file, Settings* settings) {
flipper_format_write_header_cstr(file, CONFIG_FILE_HEADER, CONFIG_FILE_VERSION);
flipper_format_write_comment_cstr(file, "Enter here the SSID of the wifi network");
flipper_format_write_string_cstr(file, CONF_SSID, settings->save_ssid);
flipper_format_write_comment_cstr(file, "Enter here the PASSWORD of the wifi network");
flipper_format_write_string_cstr(file, CONF_PASSWORD, settings->save_password);
flipper_format_write_comment_cstr(file, "Enter here the WEBHOOKS of your IFTTT account");
flipper_format_write_string_cstr(file, CONF_KEY, settings->save_key);
flipper_format_write_comment_cstr(file, "Enter here the EVENT name of your trigger");
flipper_format_write_string_cstr(file, CONF_EVENT, settings->save_event);
}
Settings* load_settings() {
Settings* settings = malloc(sizeof(Settings));
settings->save_ssid = "";
settings->save_password = "";
settings->save_key = "";
settings->save_event = "";
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
FuriString* string_value = furi_string_alloc();
FuriString* text_ssid_value = furi_string_alloc();
FuriString* text_password_value = furi_string_alloc();
FuriString* text_key_value = furi_string_alloc();
FuriString* text_event_value = furi_string_alloc();
if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) != FSE_OK) {
if(flipper_format_file_open_new(file, CONFIG_FILE_PATH)) {
save_settings_file(file, settings);
}
flipper_format_file_close(file);
} else {
if(flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) {
uint32_t value;
if(flipper_format_read_header(file, string_value, &value)) {
if(flipper_format_read_string(file, CONF_SSID, text_ssid_value)) {
settings->save_ssid = malloc(furi_string_size(text_ssid_value) + 1);
strcpy(settings->save_ssid, furi_string_get_cstr(text_ssid_value));
}
if(flipper_format_read_string(file, CONF_PASSWORD, text_password_value)) {
settings->save_password = malloc(furi_string_size(text_password_value) + 1);
strcpy(settings->save_password, furi_string_get_cstr(text_password_value));
}
if(flipper_format_read_string(file, CONF_KEY, text_key_value)) {
settings->save_key = malloc(furi_string_size(text_key_value) + 1);
strcpy(settings->save_key, furi_string_get_cstr(text_key_value));
}
if(flipper_format_read_string(file, CONF_EVENT, text_event_value)) {
settings->save_event = malloc(furi_string_size(text_event_value) + 1);
strcpy(settings->save_event, furi_string_get_cstr(text_event_value));
}
}
}
flipper_format_file_close(file);
}
furi_string_free(text_ssid_value);
furi_string_free(text_password_value);
furi_string_free(text_key_value);
furi_string_free(text_event_value);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return settings;
}
void send_serial_command_config(ESerialCommand command, Settings* settings) {
uint8_t data[1] = {0};
char config_tmp[100];
strcpy(config_tmp, "config,");
strcat(config_tmp, settings->save_key);
char config_tmp2[5];
strcpy(config_tmp2, config_tmp);
strcat(config_tmp2, ",");
char config_tmp3[100];
strcpy(config_tmp3, config_tmp2);
strcat(config_tmp3, settings->save_ssid);
char config_tmp4[5];
strcpy(config_tmp4, config_tmp3);
strcat(config_tmp4, ",");
char config_tmp5[100];
strcpy(config_tmp5, config_tmp4);
strcat(config_tmp5, settings->save_password);
char config_tmp6[5];
strcpy(config_tmp6, config_tmp5);
strcat(config_tmp6, ",");
char config[350];
strcpy(config, config_tmp6);
strcat(config, settings->save_event);
int length = strlen(config);
for(int i = 0; i < length; i++) {
switch(command) {
case ESerialCommand_Config:
data[0] = config[i];
break;
default:
return;
}
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
}
}
static bool ifttt_virtual_button_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
VirtualButtonApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool ifttt_virtual_button_back_event_callback(void* context) {
furi_assert(context);
VirtualButtonApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void ifttt_virtual_button_tick_event_callback(void* context) {
furi_assert(context);
VirtualButtonApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
VirtualButtonApp* ifttt_virtual_button_app_alloc(uint32_t first_scene) {
VirtualButtonApp* app = malloc(sizeof(VirtualButtonApp));
// Records
app->gui = furi_record_open(RECORD_GUI);
app->power = furi_record_open(RECORD_POWER);
// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&virtual_button_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, ifttt_virtual_button_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, ifttt_virtual_button_back_event_callback);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, ifttt_virtual_button_tick_event_callback, 2000);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Views
app->sen_view = send_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher, VirtualButtonAppViewSendView, send_view_get_view(app->sen_view));
app->abou_view = about_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher, VirtualButtonAppViewAboutView, about_view_get_view(app->abou_view));
app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, VirtualButtonAppViewSubmenu, submenu_get_view(app->submenu));
app->dialog = dialog_ex_alloc();
view_dispatcher_add_view(
app->view_dispatcher, VirtualButtonAppViewDialog, dialog_ex_get_view(app->dialog));
// Set first scene
scene_manager_next_scene(app->scene_manager, first_scene);
return app;
}
void ifttt_virtual_button_app_free(VirtualButtonApp* app) {
furi_assert(app);
free(app->settings.save_ssid);
free(app->settings.save_password);
free(app->settings.save_key);
// Views
view_dispatcher_remove_view(app->view_dispatcher, VirtualButtonAppViewSendView);
send_view_free(app->sen_view);
view_dispatcher_remove_view(app->view_dispatcher, VirtualButtonAppViewAboutView);
about_view_free(app->abou_view);
view_dispatcher_remove_view(app->view_dispatcher, VirtualButtonAppViewSubmenu);
submenu_free(app->submenu);
view_dispatcher_remove_view(app->view_dispatcher, VirtualButtonAppViewDialog);
dialog_ex_free(app->dialog);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
// Records
furi_record_close(RECORD_POWER);
furi_record_close(RECORD_GUI);
free(app);
}
int32_t ifttt_virtual_button_app(void* p) {
UNUSED(p);
Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(storage, IFTTT_FOLDER)) {
}
if(!storage_simply_mkdir(storage, IFTTT_CONFIG_FOLDER)) {
}
furi_record_close(RECORD_STORAGE);
uint32_t first_scene = VirtualButtonAppSceneStart;
VirtualButtonApp* app = ifttt_virtual_button_app_alloc(first_scene);
memcpy(&app->settings, load_settings(), sizeof(Settings));
send_serial_command_config(ESerialCommand_Config, &(app->settings));
view_dispatcher_run(app->view_dispatcher);
ifttt_virtual_button_app_free(app);
return 0;
}
-56
View File
@@ -1,56 +0,0 @@
#pragma once
#include <furi.h>
#include <power/power_service/power.h>
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include "views/send_view.h"
#include "views/about_view.h"
#include <gui/modules/submenu.h>
#include <gui/modules/dialog_ex.h>
#include <flipper_format/flipper_format.h>
#include <flipper_format/flipper_format_i.h>
#include <storage/storage.h>
#include <furi_hal_uart.h>
#include "scenes/virtual_button_scene.h"
#define APP_NAME "[ESP8266] IFTTT Virtual Button"
#define CONF_SSID "wifi_ssid"
#define CONF_PASSWORD "wifi_password"
#define CONF_KEY "webhooks_key"
#define CONF_EVENT "event"
#define CONFIG_FILE_HEADER "IFTTT Virtual Button Config File"
#define CONFIG_FILE_VERSION 1
typedef struct {
char* save_ssid;
char* save_password;
char* save_key;
char* save_event;
} Settings;
typedef struct {
Power* power;
Gui* gui;
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;
SendView* sen_view;
AboutView* abou_view;
Submenu* submenu;
DialogEx* dialog;
PowerInfo info;
Settings settings;
} VirtualButtonApp;
typedef enum {
VirtualButtonAppViewSendView,
VirtualButtonAppViewAboutView,
VirtualButtonAppViewSubmenu,
VirtualButtonAppViewDialog,
} VirtualButtonAppView;
Settings save_settings(Settings settings);
Settings* load_settings();
@@ -1,30 +0,0 @@
#include "virtual_button_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const virtual_button_on_enter_handlers[])(void*) = {
#include "virtual_button_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const virtual_button_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "virtual_button_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const virtual_button_on_exit_handlers[])(void* context) = {
#include "virtual_button_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers virtual_button_scene_handlers = {
.on_enter_handlers = virtual_button_on_enter_handlers,
.on_event_handlers = virtual_button_on_event_handlers,
.on_exit_handlers = virtual_button_on_exit_handlers,
.scene_num = VirtualButtonAppSceneNum,
};
@@ -1,29 +0,0 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) VirtualButtonAppScene##id,
typedef enum {
#include "virtual_button_scene_config.h"
VirtualButtonAppSceneNum,
} VirtualButtonAppScene;
#undef ADD_SCENE
extern const SceneManagerHandlers virtual_button_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "virtual_button_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "virtual_button_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "virtual_button_scene_config.h"
#undef ADD_SCENE
@@ -1,26 +0,0 @@
#include "../ifttt_virtual_button.h"
static void virtual_button_scene_about_view_update_model(VirtualButtonApp* app) {
power_get_info(app->power, &app->info);
}
void virtual_button_scene_about_view_on_enter(void* context) {
VirtualButtonApp* app = context;
virtual_button_scene_about_view_update_model(app);
view_dispatcher_switch_to_view(app->view_dispatcher, VirtualButtonAppViewAboutView);
}
bool virtual_button_scene_about_view_on_event(void* context, SceneManagerEvent event) {
VirtualButtonApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
virtual_button_scene_about_view_update_model(app);
consumed = true;
}
return consumed;
}
void virtual_button_scene_about_view_on_exit(void* context) {
UNUSED(context);
}
@@ -1,3 +0,0 @@
ADD_SCENE(virtual_button, start, Start)
ADD_SCENE(virtual_button, send_view, SendView)
ADD_SCENE(virtual_button, about_view, AboutView)
@@ -1,26 +0,0 @@
#include "../ifttt_virtual_button.h"
static void virtual_button_scene_send_view_update_model(VirtualButtonApp* app) {
power_get_info(app->power, &app->info);
}
void virtual_button_scene_send_view_on_enter(void* context) {
VirtualButtonApp* app = context;
virtual_button_scene_send_view_update_model(app);
view_dispatcher_switch_to_view(app->view_dispatcher, VirtualButtonAppViewSendView);
}
bool virtual_button_scene_send_view_on_event(void* context, SceneManagerEvent event) {
VirtualButtonApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
virtual_button_scene_send_view_update_model(app);
consumed = true;
}
return consumed;
}
void virtual_button_scene_send_view_on_exit(void* context) {
UNUSED(context);
}
@@ -1,55 +0,0 @@
#include "../ifttt_virtual_button.h"
enum VirtualButtonSubmenuIndex {
VirtualButtonSubmenuIndexSendView,
VirtualButtonSubmenuIndexAboutView,
};
static void virtual_button_scene_start_submenu_callback(void* context, uint32_t index) {
furi_assert(context);
VirtualButtonApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void virtual_button_scene_start_on_enter(void* context) {
VirtualButtonApp* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu,
"Send IFTTT command",
VirtualButtonSubmenuIndexSendView,
virtual_button_scene_start_submenu_callback,
app);
submenu_add_item(
submenu,
"About",
VirtualButtonSubmenuIndexAboutView,
virtual_button_scene_start_submenu_callback,
app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, VirtualButtonAppSceneStart));
view_dispatcher_switch_to_view(app->view_dispatcher, VirtualButtonAppViewSubmenu);
}
bool virtual_button_scene_start_on_event(void* context, SceneManagerEvent event) {
VirtualButtonApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == VirtualButtonSubmenuIndexSendView) {
scene_manager_next_scene(app->scene_manager, VirtualButtonAppSceneSendView);
} else if(event.event == VirtualButtonSubmenuIndexAboutView) {
scene_manager_next_scene(app->scene_manager, VirtualButtonAppSceneAboutView);
}
scene_manager_set_scene_state(app->scene_manager, VirtualButtonAppSceneStart, event.event);
consumed = true;
}
return consumed;
}
void virtual_button_scene_start_on_exit(void* context) {
VirtualButtonApp* app = context;
submenu_reset(app->submenu);
}
-48
View File
@@ -1,48 +0,0 @@
#include "about_view.h"
#include <furi.h>
#include <gui/elements.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
struct AboutView {
View* view;
};
typedef struct {
bool connected;
} AboutViewModel;
static void about_view_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "IFTTT Virtual button");
canvas_draw_str_aligned(canvas, 0, 15, AlignLeft, AlignTop, "Version 0.2");
canvas_draw_str_aligned(canvas, 0, 50, AlignLeft, AlignTop, "press back");
}
AboutView* about_view_alloc() {
AboutView* about_view = malloc(sizeof(AboutView));
about_view->view = view_alloc();
view_set_context(about_view->view, about_view);
view_allocate_model(about_view->view, ViewModelTypeLocking, sizeof(AboutViewModel));
view_set_draw_callback(about_view->view, about_view_draw_callback);
return about_view;
}
void about_view_free(AboutView* about_view) {
furi_assert(about_view);
view_free(about_view->view);
free(about_view);
}
View* about_view_get_view(AboutView* about_view) {
furi_assert(about_view);
return about_view->view;
}
void about_view_set_data(AboutView* about_view, bool connected) {
furi_assert(about_view);
with_view_model(
about_view->view, AboutViewModel * model, { model->connected = connected; }, true);
}
-11
View File
@@ -1,11 +0,0 @@
#pragma once
#include <gui/view.h>
typedef struct AboutView AboutView;
AboutView* about_view_alloc();
void about_view_free(AboutView* about_view);
View* about_view_get_view(AboutView* about_view);
-137
View File
@@ -1,137 +0,0 @@
#include "send_view.h"
#include <furi.h>
#include <gui/elements.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <furi_hal_uart.h>
#include <string.h>
#include <stdio.h>
#define FLIPPERZERO_SERIAL_BAUD 115200
typedef enum ESerialCommand { ESerialCommand_Send } ESerialCommand;
struct SendView {
View* view;
};
typedef struct {
bool right_pressed;
bool connected;
} SendViewModel;
static void Shake(void) {
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification, &sequence_single_vibro);
furi_record_close(RECORD_NOTIFICATION);
}
void send_serial_command_send(ESerialCommand command) {
uint8_t data[1] = {0};
char name[10] = "send";
int length = strlen(name);
for(int i = 0; i < length; i++) {
switch(command) {
case ESerialCommand_Send:
data[0] = name[i];
break;
default:
return;
};
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
}
}
static void send_view_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
SendViewModel* model = context;
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(canvas, 64, 0, AlignCenter, AlignTop, "SEND MODULE");
canvas_draw_line(canvas, 0, 10, 128, 10);
canvas_draw_str_aligned(canvas, 64, 15, AlignCenter, AlignTop, "Press right to send IFTTT");
canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignTop, "command or press and hold");
canvas_draw_str_aligned(canvas, 64, 35, AlignCenter, AlignTop, "back to return to the menu");
// Right
if(model->right_pressed) {
}
}
static void send_view_process(SendView* send_view, InputEvent* event) {
with_view_model(
send_view->view,
SendViewModel * model,
{
if(event->type == InputTypePress) {
if(event->key == InputKeyUp) {
} else if(event->key == InputKeyDown) {
} else if(event->key == InputKeyLeft) {
} else if(event->key == InputKeyRight) {
model->right_pressed = true;
Shake();
send_serial_command_send(ESerialCommand_Send);
} else if(event->key == InputKeyOk) {
} else if(event->key == InputKeyBack) {
}
} else if(event->type == InputTypeRelease) {
if(event->key == InputKeyUp) {
} else if(event->key == InputKeyDown) {
} else if(event->key == InputKeyLeft) {
} else if(event->key == InputKeyRight) {
model->right_pressed = false;
} else if(event->key == InputKeyOk) {
} else if(event->key == InputKeyBack) {
}
} else if(event->type == InputTypeShort) {
if(event->key == InputKeyBack) {
}
}
},
true);
}
static bool send_view_input_callback(InputEvent* event, void* context) {
furi_assert(context);
SendView* send_view = context;
bool consumed = false;
if(event->type == InputTypeLong && event->key == InputKeyBack) {
} else {
send_view_process(send_view, event);
consumed = true;
}
return consumed;
}
SendView* send_view_alloc() {
SendView* send_view = malloc(sizeof(SendView));
send_view->view = view_alloc();
view_set_context(send_view->view, send_view);
view_allocate_model(send_view->view, ViewModelTypeLocking, sizeof(SendViewModel));
view_set_draw_callback(send_view->view, send_view_draw_callback);
view_set_input_callback(send_view->view, send_view_input_callback);
furi_hal_uart_set_br(FuriHalUartIdUSART1, FLIPPERZERO_SERIAL_BAUD);
return send_view;
}
void send_view_free(SendView* send_view) {
furi_assert(send_view);
view_free(send_view->view);
free(send_view);
}
View* send_view_get_view(SendView* send_view) {
furi_assert(send_view);
return send_view->view;
}
void send_view_set_data(SendView* send_view, bool connected) {
furi_assert(send_view);
with_view_model(
send_view->view, SendViewModel * model, { model->connected = connected; }, true);
}
-11
View File
@@ -1,11 +0,0 @@
#pragma once
#include <gui/view.h>
typedef struct SendView SendView;
SendView* send_view_alloc();
void send_view_free(SendView* send_view);
View* send_view_get_view(SendView* send_view);
-15
View File
@@ -1,15 +0,0 @@
App(
appid="morse_code",
name="Morse Code",
apptype=FlipperAppType.EXTERNAL,
entry_point="morse_code_app",
requires=[
"gui",
],
stack_size=1 * 1024,
fap_icon="morse_code_10px.png",
fap_category="Media",
fap_author="@wh00hw & @xMasterX",
fap_version="1.0",
fap_description="Simple Morse Code parser",
)
-166
View File
@@ -1,166 +0,0 @@
#include "morse_code_worker.h"
#include <furi.h>
#include <gui/gui.h>
#include <gui/elements.h>
#include <input/input.h>
#include <stdlib.h>
#include <furi_hal.h>
#include <string.h>
static const float MORSE_CODE_VOLUMES[] = {0, .25, .5, .75, 1};
typedef struct {
FuriString* words;
uint8_t volume;
uint32_t dit_delta;
} MorseCodeModel;
typedef struct {
MorseCodeModel* model;
FuriMutex** model_mutex;
FuriMessageQueue* input_queue;
ViewPort* view_port;
Gui* gui;
MorseCodeWorker* worker;
} MorseCode;
static void render_callback(Canvas* const canvas, void* ctx) {
MorseCode* morse_code = ctx;
furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
// border around the edge of the screen
canvas_set_font(canvas, FontPrimary);
//write words
elements_multiline_text_aligned(
canvas, 64, 30, AlignCenter, AlignCenter, furi_string_get_cstr(morse_code->model->words));
// volume view_port
uint8_t vol_bar_x_pos = 124;
uint8_t vol_bar_y_pos = 0;
const uint8_t volume_h = (64 / (COUNT_OF(MORSE_CODE_VOLUMES) - 1)) * morse_code->model->volume;
canvas_draw_frame(canvas, vol_bar_x_pos, vol_bar_y_pos, 4, 64);
canvas_draw_box(canvas, vol_bar_x_pos, vol_bar_y_pos + (64 - volume_h), 4, volume_h);
//dit bpms
FuriString* ditbpm = furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta);
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignCenter, furi_string_get_cstr(ditbpm));
furi_string_free(ditbpm);
//button info
elements_button_center(canvas, "Press/Hold");
furi_mutex_release(morse_code->model_mutex);
}
static void input_callback(InputEvent* input_event, void* ctx) {
MorseCode* morse_code = ctx;
furi_message_queue_put(morse_code->input_queue, input_event, FuriWaitForever);
}
static void morse_code_worker_callback(FuriString* words, void* context) {
MorseCode* morse_code = context;
furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
furi_string_set(morse_code->model->words, words);
furi_mutex_release(morse_code->model_mutex);
view_port_update(morse_code->view_port);
}
MorseCode* morse_code_alloc() {
MorseCode* instance = malloc(sizeof(MorseCode));
instance->model = malloc(sizeof(MorseCodeModel));
instance->model->words = furi_string_alloc_set_str("");
instance->model->volume = 3;
instance->model->dit_delta = 150;
instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
instance->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
instance->worker = morse_code_worker_alloc();
morse_code_worker_set_callback(instance->worker, morse_code_worker_callback, instance);
instance->view_port = view_port_alloc();
view_port_draw_callback_set(instance->view_port, render_callback, instance);
view_port_input_callback_set(instance->view_port, input_callback, instance);
// Open GUI and register view_port
instance->gui = furi_record_open(RECORD_GUI);
gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
return instance;
}
void morse_code_free(MorseCode* instance) {
gui_remove_view_port(instance->gui, instance->view_port);
furi_record_close(RECORD_GUI);
view_port_free(instance->view_port);
morse_code_worker_free(instance->worker);
furi_message_queue_free(instance->input_queue);
furi_mutex_free(instance->model_mutex);
furi_string_free(instance->model->words);
free(instance->model);
free(instance);
}
int32_t morse_code_app() {
MorseCode* morse_code = morse_code_alloc();
InputEvent input;
morse_code_worker_start(morse_code->worker);
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
while(furi_message_queue_get(morse_code->input_queue, &input, FuriWaitForever) ==
FuriStatusOk) {
furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
if(input.key == InputKeyBack && input.type == InputTypeLong) {
furi_mutex_release(morse_code->model_mutex);
break;
} else if(input.key == InputKeyBack && input.type == InputTypeShort) {
morse_code_worker_reset_text(morse_code->worker);
furi_string_reset(morse_code->model->words);
} else if(input.key == InputKeyOk) {
if(input.type == InputTypePress)
morse_code_worker_play(morse_code->worker, true);
else if(input.type == InputTypeRelease)
morse_code_worker_play(morse_code->worker, false);
} else if(input.key == InputKeyUp && input.type == InputTypePress) {
if(morse_code->model->volume < COUNT_OF(MORSE_CODE_VOLUMES) - 1)
morse_code->model->volume++;
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
} else if(input.key == InputKeyDown && input.type == InputTypePress) {
if(morse_code->model->volume > 0) morse_code->model->volume--;
morse_code_worker_set_volume(
morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
} else if(input.key == InputKeyLeft && input.type == InputTypePress) {
if(morse_code->model->dit_delta > 10) morse_code->model->dit_delta -= 10;
morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
} else if(input.key == InputKeyRight && input.type == InputTypePress) {
if(morse_code->model->dit_delta >= 10) morse_code->model->dit_delta += 10;
morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
}
FURI_LOG_D(
"Input",
"%s %s %ld",
input_get_key_name(input.key),
input_get_type_name(input.type),
input.sequence);
furi_mutex_release(morse_code->model_mutex);
view_port_update(morse_code->view_port);
}
morse_code_worker_stop(morse_code->worker);
morse_code_free(morse_code);
return 0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

-183
View File
@@ -1,183 +0,0 @@
#include "morse_code_worker.h"
#include <furi_hal.h>
#include <lib/flipper_format/flipper_format.h>
#define TAG "MorseCodeWorker"
#define MORSE_CODE_VERSION 0
//A-Z0-1
const char morse_array[36][6] = {".-", "-...", "-.-.", "-..", ".", "..-.",
"--.", "....", "..", ".---", "-.-", ".-..",
"--", "-.", "---", ".--.", "--.-", ".-.",
"...", "-", "..-", "...-", ".--", "-..-",
"-.--", "--..", ".----", "..---", "...--", "....-",
".....", "-....", "--...", "---..", "----.", "-----"};
const char symbol_array[36] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
struct MorseCodeWorker {
FuriThread* thread;
MorseCodeWorkerCallback callback;
void* callback_context;
bool is_running;
bool play;
float volume;
uint32_t dit_delta;
FuriString* buffer;
FuriString* words;
};
void morse_code_worker_fill_buffer(MorseCodeWorker* instance, uint32_t duration) {
FURI_LOG_D("MorseCode: Duration", "%ld", duration);
if(duration <= instance->dit_delta)
furi_string_push_back(instance->buffer, *DOT);
else if(duration <= (instance->dit_delta * 3))
furi_string_push_back(instance->buffer, *LINE);
else
furi_string_reset(instance->buffer);
if(furi_string_size(instance->buffer) > 5) furi_string_reset(instance->buffer);
FURI_LOG_D("MorseCode: Buffer", "%s", furi_string_get_cstr(instance->buffer));
}
void morse_code_worker_fill_letter(MorseCodeWorker* instance) {
if(furi_string_size(instance->words) > 63) furi_string_reset(instance->words);
for(size_t i = 0; i < sizeof(morse_array); i++) {
if(furi_string_cmp_str(instance->buffer, morse_array[i]) == 0) {
furi_string_push_back(instance->words, symbol_array[i]);
break;
}
}
furi_string_reset(instance->buffer);
FURI_LOG_D("MorseCode: Words", "%s", furi_string_get_cstr(instance->words));
}
static int32_t morse_code_worker_thread_callback(void* context) {
furi_assert(context);
MorseCodeWorker* instance = context;
bool was_playing = false;
uint32_t start_tick = 0;
uint32_t end_tick = 0;
bool pushed = true;
bool spaced = true;
while(instance->is_running) {
furi_delay_ms(SLEEP);
if(instance->play) {
if(!was_playing) {
start_tick = furi_get_tick();
if(furi_hal_speaker_acquire(1000)) {
furi_hal_speaker_start(FREQUENCY, instance->volume);
}
was_playing = true;
}
} else {
if(was_playing) {
pushed = false;
spaced = false;
if(furi_hal_speaker_is_mine()) {
furi_hal_speaker_stop();
furi_hal_speaker_release();
}
end_tick = furi_get_tick();
was_playing = false;
morse_code_worker_fill_buffer(instance, end_tick - start_tick);
start_tick = 0;
}
}
if(!pushed) {
if(end_tick + (instance->dit_delta * 3) < furi_get_tick()) {
//NEW LETTER
if(!furi_string_empty(instance->buffer)) {
morse_code_worker_fill_letter(instance);
if(instance->callback)
instance->callback(instance->words, instance->callback_context);
} else {
spaced = true;
}
pushed = true;
}
}
if(!spaced) {
if(end_tick + (instance->dit_delta * 7) < furi_get_tick()) {
//NEW WORD
furi_string_push_back(instance->words, *SPACE);
if(instance->callback)
instance->callback(instance->words, instance->callback_context);
spaced = true;
}
}
}
return 0;
}
MorseCodeWorker* morse_code_worker_alloc() {
MorseCodeWorker* instance = malloc(sizeof(MorseCodeWorker));
instance->thread = furi_thread_alloc();
furi_thread_set_name(instance->thread, "MorseCodeWorker");
furi_thread_set_stack_size(instance->thread, 1024);
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, morse_code_worker_thread_callback);
instance->play = false;
instance->volume = 1.0f;
instance->dit_delta = 150;
instance->buffer = furi_string_alloc_set_str("");
instance->words = furi_string_alloc_set_str("");
return instance;
}
void morse_code_worker_free(MorseCodeWorker* instance) {
furi_assert(instance);
furi_string_free(instance->buffer);
furi_string_free(instance->words);
furi_thread_free(instance->thread);
free(instance);
}
void morse_code_worker_set_callback(
MorseCodeWorker* instance,
MorseCodeWorkerCallback callback,
void* context) {
furi_assert(instance);
instance->callback = callback;
instance->callback_context = context;
}
void morse_code_worker_play(MorseCodeWorker* instance, bool play) {
furi_assert(instance);
instance->play = play;
}
void morse_code_worker_set_volume(MorseCodeWorker* instance, float level) {
furi_assert(instance);
instance->volume = level;
}
void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta) {
furi_assert(instance);
instance->dit_delta = delta;
}
void morse_code_worker_reset_text(MorseCodeWorker* instance) {
furi_assert(instance);
furi_string_reset(instance->buffer);
furi_string_reset(instance->words);
}
void morse_code_worker_start(MorseCodeWorker* instance) {
furi_assert(instance);
furi_assert(instance->is_running == false);
instance->is_running = true;
furi_thread_start(instance->thread);
FURI_LOG_D("MorseCode: Start", "is Running");
}
void morse_code_worker_stop(MorseCodeWorker* instance) {
furi_assert(instance);
furi_assert(instance->is_running == true);
instance->play = false;
instance->is_running = false;
furi_thread_join(instance->thread);
FURI_LOG_D("MorseCode: Stop", "Stop");
}
-36
View File
@@ -1,36 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <furi.h>
#define FREQUENCY 261.63f
#define SLEEP 10
#define DOT "."
#define LINE "-"
#define SPACE " "
typedef void (*MorseCodeWorkerCallback)(FuriString* buffer, void* context);
typedef struct MorseCodeWorker MorseCodeWorker;
MorseCodeWorker* morse_code_worker_alloc();
void morse_code_worker_free(MorseCodeWorker* instance);
void morse_code_worker_set_callback(
MorseCodeWorker* instance,
MorseCodeWorkerCallback callback,
void* context);
void morse_code_worker_start(MorseCodeWorker* instance);
void morse_code_worker_stop(MorseCodeWorker* instance);
void morse_code_worker_play(MorseCodeWorker* instance, bool play);
void morse_code_worker_reset_text(MorseCodeWorker* instance);
void morse_code_worker_set_volume(MorseCodeWorker* instance, float level);
void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta);
-13
View File
@@ -1,13 +0,0 @@
App(
appid="multi_converter",
name="Multi Converter",
apptype=FlipperAppType.EXTERNAL,
entry_point="multi_converter_app",
requires=["gui"],
stack_size=1 * 1024,
fap_icon="converter_10px.png",
fap_category="Tools",
fap_author="@theisolinearchip",
fap_version="1.0",
fap_description="A multi-unit converter written with an easy and expandable system for adding new units and conversion methods",
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

-164
View File
@@ -1,164 +0,0 @@
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include "multi_converter_definitions.h"
#include "multi_converter_mode_display.h"
#include "multi_converter_mode_select.h"
static void multi_converter_render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
const MultiConverterState* multi_converter_state = ctx;
furi_mutex_acquire(multi_converter_state->mutex, FuriWaitForever);
if(multi_converter_state->mode == ModeDisplay) {
multi_converter_mode_display_draw(canvas, multi_converter_state);
} else {
multi_converter_mode_select_draw(canvas, multi_converter_state);
}
furi_mutex_release(multi_converter_state->mutex);
}
static void
multi_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
MultiConverterEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void multi_converter_init(MultiConverterState* const multi_converter_state) {
// initial default values
multi_converter_state->buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS] = '\0';
multi_converter_state->buffer_dest[MULTI_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminators
multi_converter_state->unit_type_orig = UnitTypeDec;
multi_converter_state->unit_type_dest = UnitTypeHex;
multi_converter_state->keyboard_lock = 0;
// init the display view
multi_converter_mode_display_reset(multi_converter_state);
// init the select view
multi_converter_mode_select_reset(multi_converter_state);
// set ModeDisplay as the current mode
multi_converter_state->mode = ModeDisplay;
}
// main entry point
int32_t multi_converter_app(void* p) {
UNUSED(p);
// get event queue
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(MultiConverterEvent));
// allocate state
MultiConverterState* multi_converter_state = malloc(sizeof(MultiConverterState));
// set mutex for plugin state (different threads can access it)
multi_converter_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!multi_converter_state->mutex) {
FURI_LOG_E("MultiConverter", "cannot create mutex\r\n");
furi_message_queue_free(event_queue);
free(multi_converter_state);
return 255;
}
// register callbacks for drawing and input processing
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, multi_converter_render_callback, multi_converter_state);
view_port_input_callback_set(view_port, multi_converter_input_callback, event_queue);
// open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
multi_converter_init(multi_converter_state);
// main loop
MultiConverterEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(multi_converter_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey && !multi_converter_state->keyboard_lock) {
if(multi_converter_state->mode == ModeDisplay) {
if(event.input.key == InputKeyBack) {
if(event.input.type == InputTypePress) processing = false;
} else if(event.input.key == InputKeyOk) { // the "ok" press can be short or long
MultiConverterModeTrigger t = None;
if(event.input.type == InputTypeLong)
t = multi_converter_mode_display_ok(1, multi_converter_state);
else if(event.input.type == InputTypeShort)
t = multi_converter_mode_display_ok(0, multi_converter_state);
if(t == Reset) {
multi_converter_mode_select_reset(multi_converter_state);
multi_converter_state->mode = ModeSelector;
}
} else {
if(event.input.type == InputTypePress)
multi_converter_mode_display_navigation(
event.input.key, multi_converter_state);
}
} else { // ModeSelect
if(event.input.type == InputTypePress) {
switch(event.input.key) {
default:
break;
case InputKeyBack:
case InputKeyOk: {
MultiConverterModeTrigger t = multi_converter_mode_select_exit(
event.input.key == InputKeyOk ? 1 : 0, multi_converter_state);
if(t == Reset) {
multi_converter_mode_display_reset(multi_converter_state);
} else if(t == Convert) {
multi_converter_mode_display_convert(multi_converter_state);
}
multi_converter_state->keyboard_lock = 1;
multi_converter_state->mode = ModeDisplay;
break;
}
case InputKeyLeft:
case InputKeyRight:
multi_converter_mode_select_switch(multi_converter_state);
break;
case InputKeyUp:
multi_converter_mode_select_change_unit(-1, multi_converter_state);
break;
case InputKeyDown:
multi_converter_mode_select_change_unit(1, multi_converter_state);
break;
}
}
}
} else if(multi_converter_state->keyboard_lock) {
multi_converter_state->keyboard_lock = 0;
}
}
view_port_update(view_port);
furi_mutex_release(multi_converter_state->mutex);
}
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(multi_converter_state->mutex);
free(multi_converter_state);
return 0;
}
@@ -1,83 +0,0 @@
#pragma once
#define MULTI_CONVERTER_NUMBER_DIGITS 9
typedef enum {
EventTypeKey,
} EventType;
typedef struct {
InputEvent input;
EventType type;
} MultiConverterEvent;
typedef enum {
ModeDisplay,
ModeSelector,
} MultiConverterMode;
typedef enum {
None,
Reset,
Convert,
} MultiConverterModeTrigger;
// new units goes here, used as index to the main multi_converter_available_units array (multi_converter_units.h)
typedef enum {
UnitTypeDec,
UnitTypeHex,
UnitTypeBin,
UnitTypeCelsius,
UnitTypeFahernheit,
UnitTypeKelvin,
UnitTypeKilometers,
UnitTypeMeters,
UnitTypeCentimeters,
UnitTypeMiles,
UnitTypeFeet,
UnitTypeInches,
UnitTypeDegree,
UnitTypeRadian,
} MultiConverterUnitType;
typedef struct {
MultiConverterUnitType selected_unit_type_orig;
MultiConverterUnitType selected_unit_type_dest;
uint8_t select_orig;
} MultiConverterModeSelect;
typedef struct {
uint8_t cursor; // cursor position when typing
int8_t key; // hover key
uint8_t comma; // comma already added? (only one comma allowed)
uint8_t negative; // is negative?
} MultiConverterModeDisplay;
typedef struct MultiConverterUnit MultiConverterUnit;
typedef struct MultiConverterState MultiConverterState;
struct MultiConverterUnit {
uint8_t allow_comma;
uint8_t allow_negative;
uint8_t max_number_keys;
char mini_name[4];
char name[12];
void (*convert_function)(MultiConverterState* const);
uint8_t (*allowed_function)(MultiConverterUnitType);
};
struct MultiConverterState {
FuriMutex* mutex;
char buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS + 1];
char buffer_dest[MULTI_CONVERTER_NUMBER_DIGITS + 1];
MultiConverterUnitType unit_type_orig;
MultiConverterUnitType unit_type_dest;
MultiConverterMode mode;
MultiConverterModeDisplay display;
MultiConverterModeSelect select;
uint8_t keyboard_lock; // used to create a small lock when switching from SELECT to DISPLAY modes
// (debouncing, basically; otherwise it switch modes twice 'cause it's too fast!)
};
@@ -1,326 +0,0 @@
#include "multi_converter_mode_display.h"
#define MULTI_CONVERTER_DISPLAY_KEYS 18 // [0] to [F] + [BACK] + [SELECT]
#define MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE 0 // long press
#define MULTI_CONVERTER_DISPLAY_KEY_COMMA 1 // long press
#define MULTI_CONVERTER_DISPLAY_KEY_DEL 16
#define MULTI_CONVERTER_DISPLAY_KEY_SELECT 17
#define MULTI_CONVERTER_DISPLAY_CHAR_COMMA '.'
#define MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE '-'
#define MULTI_CONVERTER_DISPLAY_CHAR_DEL '<'
#define MULTI_CONVERTER_DISPLAY_CHAR_SELECT '#'
#define MULTI_CONVERTER_DISPLAY_CHAR_BLANK ' '
#define MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN 3
#define MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT 8
void multi_converter_mode_display_convert(MultiConverterState* const multi_converter_state) {
// 1.- if origin == destination (in theory user won't be allowed to choose the same options, but it's kinda "valid"...)
// just copy buffer_orig to buffer_dest and that's it
if(multi_converter_state->unit_type_orig == multi_converter_state->unit_type_dest) {
memcpy(
multi_converter_state->buffer_dest,
multi_converter_state->buffer_orig,
MULTI_CONVERTER_NUMBER_DIGITS);
return;
}
// 2.- origin_buffer has not null functions
if(multi_converter_get_unit(multi_converter_state->unit_type_orig).convert_function == NULL ||
multi_converter_get_unit(multi_converter_state->unit_type_orig).allowed_function == NULL)
return;
// 3.- valid destination type (using allowed_destinations function)
if(!multi_converter_get_unit(multi_converter_state->unit_type_orig)
.allowed_function(multi_converter_state->unit_type_dest))
return;
multi_converter_get_unit(multi_converter_state->unit_type_orig)
.convert_function(multi_converter_state);
}
void multi_converter_mode_display_draw(
Canvas* const canvas,
const MultiConverterState* multi_converter_state) {
canvas_set_color(canvas, ColorBlack);
// ORIGIN
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(
canvas, 2, 10, multi_converter_get_unit(multi_converter_state->unit_type_orig).mini_name);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 2 + 30, 10, multi_converter_state->buffer_orig);
// DESTINATION
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(
canvas,
2,
10 + 12,
multi_converter_get_unit(multi_converter_state->unit_type_dest).mini_name);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 2 + 30, 10 + 12, multi_converter_state->buffer_dest);
// SEPARATOR_LINE
canvas_draw_line(canvas, 2, 25, 128 - 3, 25);
// KEYBOARD
uint8_t _x = 5;
uint8_t _y = 25 + 15; // line + 10
for(int i = 0; i < MULTI_CONVERTER_DISPLAY_KEYS; i++) {
char g;
if(i < 10)
g = (i + '0');
else if(i < 16)
g = ((i - 10) + 'A');
else if(i == MULTI_CONVERTER_DISPLAY_KEY_DEL)
g = MULTI_CONVERTER_DISPLAY_CHAR_DEL;
else
g = MULTI_CONVERTER_DISPLAY_CHAR_SELECT;
uint8_t g_w = canvas_glyph_width(canvas, g);
if(i < 16 &&
i > multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys -
1) {
// some units won't use the full [0] - [F] keyboard, in those situations just hide the char
// (won't be selectable anyway, so no worries here; this is just about drawing stuff)
g = MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
}
// currently hover key is highlighted
if((multi_converter_state->display).key == i) {
canvas_draw_box(
canvas,
_x - MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
_y - (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN),
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w +
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2);
canvas_set_color(canvas, ColorWhite);
} else {
canvas_draw_frame(
canvas,
_x - MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
_y - (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN),
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w +
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2);
}
// draw key
canvas_draw_glyph(canvas, _x, _y, g);
// certain keys have long_press features, draw whatever they're using there too
if(i == MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE) {
canvas_draw_box(
canvas,
_x + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w - 4,
_y + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN - 2,
4,
2);
} else if(i == MULTI_CONVERTER_DISPLAY_KEY_COMMA) {
canvas_draw_box(
canvas,
_x + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w - 2,
_y + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN - 2,
2,
2);
}
// back to black
canvas_set_color(canvas, ColorBlack);
if(i < 8) {
_x += g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + 2;
} else if(i == 8) {
_y += (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2) +
3;
_x = 8; // some padding at the beginning on second line
} else {
_x += g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + 1;
}
}
}
void multi_converter_mode_display_navigation(
InputKey key,
MultiConverterState* const multi_converter_state) {
// first move to keyboard position, then check if the ORIGIN allows that specific key, if not jump to the "closest one"
switch(key) {
default:
break;
case InputKeyUp:
case InputKeyDown:
if((multi_converter_state->display).key >= 9)
(multi_converter_state->display).key -= 9;
else
(multi_converter_state->display).key += 9;
break;
case InputKeyLeft:
case InputKeyRight:
(multi_converter_state->display).key += (key == InputKeyLeft ? -1 : 1);
if((multi_converter_state->display).key > MULTI_CONVERTER_DISPLAY_KEYS - 1)
(multi_converter_state->display).key = 0;
else if((multi_converter_state->display).key < 0)
(multi_converter_state->display).key = MULTI_CONVERTER_DISPLAY_KEYS - 1;
break;
}
// if destination key is disabled by max_number_keys, move to the closest one
// (this could be improved with more accurate keys movements, probably...)
if(multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys >= 16)
return; // weird, since this means "do not show any number on the keyboard, but just in case..."
int8_t i = -1;
if(key == InputKeyRight || key == InputKeyDown) i = 1;
while((multi_converter_state->display).key < 16 &&
(multi_converter_state->display).key >
multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys -
1) {
(multi_converter_state->display).key += i;
if((multi_converter_state->display).key > MULTI_CONVERTER_DISPLAY_KEYS - 1)
(multi_converter_state->display).key = 0;
else if((multi_converter_state->display).key < 0)
(multi_converter_state->display).key = MULTI_CONVERTER_DISPLAY_KEYS - 1;
}
}
void multi_converter_mode_display_reset(MultiConverterState* const multi_converter_state) {
// clean the buffers
for(int i = 0; i < MULTI_CONVERTER_NUMBER_DIGITS; i++) {
multi_converter_state->buffer_orig[i] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
multi_converter_state->buffer_dest[i] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
}
// reset the display flags and index
multi_converter_state->display.cursor = 0;
multi_converter_state->display.key = 0;
multi_converter_state->display.comma = 0;
multi_converter_state->display.negative = 0;
}
void multi_converter_mode_display_toggle_negative(
MultiConverterState* const multi_converter_state) {
if(multi_converter_get_unit(multi_converter_state->unit_type_orig).allow_negative) {
if(!(multi_converter_state->display).negative) {
// shift origin buffer one to right + add the "-" sign (last digit will be lost)
for(int i = MULTI_CONVERTER_NUMBER_DIGITS - 1; i > 0; i--) {
// we could avoid the blanks, but nevermind
multi_converter_state->buffer_orig[i] = multi_converter_state->buffer_orig[i - 1];
}
multi_converter_state->buffer_orig[0] = MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE;
// only increment cursor if we're not out of bound
if((multi_converter_state->display).cursor < MULTI_CONVERTER_NUMBER_DIGITS)
(multi_converter_state->display).cursor++;
} else {
// shift origin buffer one to left, append ' ' on the end
for(int i = 0; i < MULTI_CONVERTER_NUMBER_DIGITS - 1; i++) {
if(multi_converter_state->buffer_orig[i] == MULTI_CONVERTER_DISPLAY_CHAR_BLANK)
break;
multi_converter_state->buffer_orig[i] = multi_converter_state->buffer_orig[i + 1];
}
multi_converter_state->buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS - 1] =
MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
(multi_converter_state->display).cursor--;
}
// toggle flag
(multi_converter_state->display).negative ^= 1;
}
}
void multi_converter_mode_display_add_comma(MultiConverterState* const multi_converter_state) {
if(!multi_converter_get_unit(multi_converter_state->unit_type_orig).allow_comma ||
(multi_converter_state->display).comma || !(multi_converter_state->display).cursor ||
((multi_converter_state->display).cursor == (MULTI_CONVERTER_NUMBER_DIGITS - 1)))
return; // maybe not allowerd; or one comma already in place; also cannot add commas as first or last chars
// set flag to one
(multi_converter_state->display).comma = 1;
multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
MULTI_CONVERTER_DISPLAY_CHAR_COMMA;
(multi_converter_state->display).cursor++;
}
void multi_converter_mode_display_add_number(MultiConverterState* const multi_converter_state) {
if((multi_converter_state->display).key >
multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys - 1)
return;
if((multi_converter_state->display).key < 10) {
multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
(multi_converter_state->display).key + '0';
} else {
multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
((multi_converter_state->display).key - 10) + 'A';
}
(multi_converter_state->display).cursor++;
}
MultiConverterModeTrigger multi_converter_mode_display_ok(
uint8_t long_press,
MultiConverterState* const multi_converter_state) {
if((multi_converter_state->display).key < MULTI_CONVERTER_DISPLAY_KEY_DEL) {
if((multi_converter_state->display).cursor >= MULTI_CONVERTER_NUMBER_DIGITS)
return None; // limit reached, ignore
// long press on 0 toggle NEGATIVE if allowed, on 1 adds COMMA if allowed
if(long_press) {
if((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE) {
// toggle negative
multi_converter_mode_display_toggle_negative(multi_converter_state);
} else if((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_COMMA) {
// add comma
multi_converter_mode_display_add_comma(multi_converter_state);
}
} else {
// regular keys
multi_converter_mode_display_add_number(multi_converter_state);
}
multi_converter_mode_display_convert(multi_converter_state);
} else if((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_DEL) {
if((multi_converter_state->display).cursor > 0) (multi_converter_state->display).cursor--;
if(multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] ==
MULTI_CONVERTER_DISPLAY_CHAR_COMMA)
(multi_converter_state->display).comma = 0;
if(multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] ==
MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE)
(multi_converter_state->display).negative = 0;
multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
multi_converter_mode_display_convert(multi_converter_state);
} else { // MULTI_CONVERTER_DISPLAY_KEY_SELECT
return Reset;
}
return None;
}
@@ -1,61 +0,0 @@
#pragma once
#include <input/input.h>
#include <gui/gui.h>
#include "multi_converter_definitions.h"
#include "multi_converter_units.h"
//
// performs a unit conversion from origin to source buffers, if there's any error, overflow or
// non-compatible format (which shouldn't happen, but just in case) abort conversion and outputs
// some "?" strings on the buffer or something similar
//
void multi_converter_mode_display_convert(MultiConverterState* const multi_converter_state);
//
// draw the main DISPLAY view with the current multi_converter_state values
//
void multi_converter_mode_display_draw(
Canvas* const canvas,
const MultiConverterState* multi_converter_state);
//
// keyboard navigation on DISPLAY mode (NAVIGATION only, no BACK nor OK - InputKey guaranteed to be left/right/up/down)
//
void multi_converter_mode_display_navigation(
InputKey key,
MultiConverterState* const multi_converter_state);
//
// reset the DISPLAY mode with the current units, cleaning the buffers and different flags;
// call this when exiting the SELECT mode / changing the units
//
void multi_converter_mode_display_reset(MultiConverterState* const multi_converter_state);
//
// toggle the negative flag on current selected buffer ONLY if the unit allows negative numbers
// (adding negative number may crop the last char on the buffer; it cannot be recovered)
//
void multi_converter_mode_display_toggle_negative(MultiConverterState* const multi_converter_state);
//
// add a comma/dot/decimal separator/whatever on current selected buffer ONLY if the unit allows it
// (only ONE comma allowed, not in the beginning nor end)
//
void multi_converter_mode_display_add_comma(MultiConverterState* const multi_converter_state);
//
// add a regular number to the buffer if it's <= the max_number_keys from the unit (not necessary
// since the draw and navigation functions won't allow a trigger for an invalid number, but still
// to keep the "checks" policy on each "add key" function...)
//
void multi_converter_mode_display_add_number(MultiConverterState* const multi_converter_state);
//
// handle the OK action when selecting a specific key on the keyboard (add a number, a symbol, change mode...)
// returns a ModeTrigger enum value: may or may not let to a mode change on the main loop (WON'T change the mode here)
//
MultiConverterModeTrigger multi_converter_mode_display_ok(
uint8_t long_press,
MultiConverterState* const multi_converter_state);
@@ -1,210 +0,0 @@
#include "multi_converter_mode_select.h"
#define MULTI_CONVERTER_LIST_ENTRIES_COUNT 3
#define MULTI_CONVERTER_INFO_STRING_FROM "FROM:"
#define MULTI_CONVERTER_INFO_STRING_TO "TO:"
#define MULTI_CONVERTER_INFO_STRING_OK "OK: Change"
#define MULTI_CONVERTER_INFO_STRING_BACK "BACK: Cancel"
void multi_converter_mode_select_draw_destination_offset(
uint8_t x,
uint8_t y,
int8_t d,
Canvas* const canvas,
const MultiConverterState* multi_converter_state) {
int i = 1;
while(
i <
MULTI_CONVERTER_AVAILABLE_UNITS) { // in case there's no match, to avoid an endless loop (in theory shouldn't happen, but...)
int ut = multi_converter_get_unit_type_offset(
(multi_converter_state->select).selected_unit_type_dest, i * d);
if(multi_converter_available_units[(multi_converter_state->select).selected_unit_type_orig]
.allowed_function(ut) &&
(multi_converter_state->select).selected_unit_type_orig != ut) {
canvas_draw_str(canvas, x, y, multi_converter_available_units[ut].name);
break;
}
i++;
}
}
void multi_converter_mode_select_draw_selected_unit(
uint8_t x,
uint8_t y,
MultiConverterUnitType unit_type,
Canvas* const canvas) {
canvas_draw_box(
canvas,
x - 2,
y - 10,
canvas_string_width(canvas, multi_converter_available_units[unit_type].name) + 4,
13);
canvas_set_color(canvas, ColorWhite);
canvas_draw_str(canvas, x, y, multi_converter_available_units[unit_type].name);
canvas_set_color(canvas, ColorBlack);
}
void multi_converter_mode_select_draw(
Canvas* const canvas,
const MultiConverterState* multi_converter_state) {
int y = 10;
int x = 10;
canvas_set_color(canvas, ColorBlack);
// FROM
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_FROM);
canvas_set_font(canvas, FontSecondary);
// offset -1
y += 12;
canvas_draw_str(
canvas,
x,
y,
multi_converter_available_units[multi_converter_get_unit_type_offset(
(multi_converter_state->select).selected_unit_type_orig,
-1)]
.name);
// current selected element
y += 12;
multi_converter_mode_select_draw_selected_unit(
x, y, (multi_converter_state->select).selected_unit_type_orig, canvas);
if((multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">");
// offset +1
y += 12;
canvas_draw_str(
canvas,
x,
y,
multi_converter_available_units[multi_converter_get_unit_type_offset(
(multi_converter_state->select).selected_unit_type_orig,
1)]
.name);
// TO
y = 10;
x = 70;
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_TO);
canvas_set_font(canvas, FontSecondary);
// offset -1: go back from current selected destination and find the first one valid (even if it's itself)
y += 12;
multi_converter_mode_select_draw_destination_offset(x, y, -1, canvas, multi_converter_state);
// current selected element
y += 12;
multi_converter_mode_select_draw_selected_unit(
x, y, (multi_converter_state->select).selected_unit_type_dest, canvas);
if(!(multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">");
// offset +1: same but on the opposite direction
y += 12;
multi_converter_mode_select_draw_destination_offset(x, y, 1, canvas, multi_converter_state);
// OK / CANCEL
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(
canvas, 0, 64 - 12, canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_OK) + 4, 12);
canvas_draw_box(
canvas,
128 - 4 - canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_BACK),
64 - 12,
canvas_string_width(canvas, "BACK: Cancel") + 4,
12);
canvas_set_color(canvas, ColorWhite);
canvas_draw_str(canvas, 2, 64 - 3, MULTI_CONVERTER_INFO_STRING_OK);
canvas_draw_str(
canvas,
128 - 2 - canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_BACK),
64 - 3,
MULTI_CONVERTER_INFO_STRING_BACK);
}
void multi_converter_mode_select_reset(MultiConverterState* const multi_converter_state) {
// initial pre-selected values are equal to the current selected values
(multi_converter_state->select).selected_unit_type_orig =
multi_converter_state->unit_type_orig;
(multi_converter_state->select).selected_unit_type_dest =
multi_converter_state->unit_type_dest;
(multi_converter_state->select).select_orig = 1;
}
MultiConverterModeTrigger multi_converter_mode_select_exit(
uint8_t save_changes,
MultiConverterState* const multi_converter_state) {
if(save_changes) {
multi_converter_state->unit_type_dest =
(multi_converter_state->select).selected_unit_type_dest;
if(multi_converter_state->unit_type_orig ==
(multi_converter_state->select).selected_unit_type_orig) {
// if the ORIGIN unit didn't changed, just trigger the convert
return Convert;
} else {
multi_converter_state->unit_type_orig =
(multi_converter_state->select).selected_unit_type_orig;
multi_converter_state->unit_type_dest =
(multi_converter_state->select).selected_unit_type_dest;
return Reset;
}
}
return None;
}
void multi_converter_mode_select_switch(MultiConverterState* const multi_converter_state) {
(multi_converter_state->select).select_orig ^= 1;
}
void multi_converter_mode_select_change_unit(
int8_t direction,
MultiConverterState* const multi_converter_state) {
MultiConverterUnitType d;
if((multi_converter_state->select).select_orig) {
(multi_converter_state->select).selected_unit_type_orig =
multi_converter_get_unit_type_offset(
(multi_converter_state->select).selected_unit_type_orig, direction);
d = (multi_converter_state->select).selected_unit_type_dest;
} else {
d = ((multi_converter_state->select).selected_unit_type_dest + direction) %
MULTI_CONVERTER_AVAILABLE_UNITS;
}
// check each unit with the ORIGIN allowed_function() to make sure we're selecting a valid DESTINATION
// (when changing the ORIGIN unit the DIRECTION in which we'll switch the DESTINATION will be the SAME);
// also notice that ORIGIN must be DIFFERENT than DESTINATION
int i = 0;
while(i < MULTI_CONVERTER_AVAILABLE_UNITS) {
if(multi_converter_available_units[(multi_converter_state->select).selected_unit_type_orig]
.allowed_function(d) &&
(multi_converter_state->select).selected_unit_type_orig != d) {
(multi_converter_state->select).selected_unit_type_dest = d;
break;
}
d = multi_converter_get_unit_type_offset(d, direction);
i++;
}
}
@@ -1,73 +0,0 @@
#pragma once
#include <stdlib.h>
#include <input/input.h>
#include <gui/gui.h>
#include "multi_converter_definitions.h"
#include "multi_converter_units.h"
//
// aux draw function for units offsets and draw stuff
//
void multi_converter_mode_select_draw_destination_offset(
uint8_t x,
uint8_t y,
int8_t d,
Canvas* const canvas,
const MultiConverterState* multi_converter_state);
void multi_converter_mode_select_draw_selected_unit(
uint8_t x,
uint8_t y,
MultiConverterUnitType unit_type,
Canvas* const canvas);
//
// draw the main SELECT view with the current multi_converter_state values
//
void multi_converter_mode_select_draw(
Canvas* const canvas,
const MultiConverterState* multi_converter_state);
//
// reset the SELECT mode view, showing as "pre-selected" the current working units
//
void multi_converter_mode_select_reset(MultiConverterState* const multi_converter_state);
//
// exit from SELECT mode and go back to display view, if save_changes == 1 use the current SELECT view info
// to modify the current selected units and reset the views properly (usually if the ORIGIN unit has been
// changed, reset everything; otherwise just trigger the convert function with a new DESTINATION)
//
// currently this function DON'T CHECK invalid unit relations (the navigation and display functions will
// prevent weird behaviours, so for now we're trusting the selected_unit_orig/dest_type values)
//
// returns an enum code MultiConverterDisplayTrigger based on doing nothing (cancel), triggering the display
// convert method or reseting the whole display mode (when fully changing the units)
//
// notice the MODE CHANGE itself is not done here but in the main loop (outside the call) via the ModeTrigger enum element
//
MultiConverterModeTrigger multi_converter_mode_select_exit(
uint8_t save_changes,
MultiConverterState* const multi_converter_state);
//
// switch between selecting the ORIGIN or the DESTINATION unit on DISPLAY mode (since there're only
// two options, both left/right arrow keys acts as toggles, no "direction" required)
//
void multi_converter_mode_select_switch(MultiConverterState* const multi_converter_state);
//
// change the selected unit on SELECTED mode, using the select_orig flag to check if we're switching the
// ORIGIN or the DESTINATION unit; the DIRECTION (up or down to travel the array) is set as a param
//
// when switching the ORIGIN one, reset the DESTINATION to the first valid unit (if the current one is not
// valid anymore); when switching the DESTINATION one, an allowed_function() check is performed in order to
// properly set a valid destination unit.
//
// (notice the draw step also perform which units are valid to display, so no worries about that here)
//
void multi_converter_mode_select_change_unit(
int8_t direction,
MultiConverterState* const multi_converter_state);
@@ -1,261 +0,0 @@
#include "multi_converter_units.h"
#define MULTI_CONVERTER_CHAR_OVERFLOW '#'
#define MULTI_CONVERTER_MAX_SUPORTED_INT 999999999
#define multi_converter_unit_set_overflow(b) \
for(int _i = 0; _i < MULTI_CONVERTER_NUMBER_DIGITS; _i++) \
b[_i] = MULTI_CONVERTER_CHAR_OVERFLOW;
//
// DEC / HEX / BIN conversion
//
void multi_converter_unit_dec_hex_bin_convert(MultiConverterState* const multi_converter_state) {
char dest[MULTI_CONVERTER_NUMBER_DIGITS];
int i = 0;
uint8_t overflow = 0;
int a = 0;
int r = 0;
uint8_t f = 1;
switch(multi_converter_state->unit_type_orig) {
default:
break;
case UnitTypeDec: {
a = atoi(multi_converter_state->buffer_orig);
f = (multi_converter_state->unit_type_dest == UnitTypeHex ? 16 : 2);
break;
}
case UnitTypeHex:
a = strtol(multi_converter_state->buffer_orig, NULL, 16);
f = (multi_converter_state->unit_type_dest == UnitTypeDec ? 10 : 2);
break;
case UnitTypeBin:
a = strtol(multi_converter_state->buffer_orig, NULL, 2);
f = (multi_converter_state->unit_type_dest == UnitTypeDec ? 10 : 16);
break;
}
while(a > 0) {
r = a % f;
dest[i] = r + (r < 10 ? '0' : ('A' - 10));
a /= f;
if(i++ >= MULTI_CONVERTER_NUMBER_DIGITS) {
overflow = 1;
break;
}
}
if(overflow) {
multi_converter_unit_set_overflow(multi_converter_state->buffer_dest);
} else {
// copy DEST (reversed) to destination and append empty chars at the end
for(int j = 0; j < MULTI_CONVERTER_NUMBER_DIGITS; j++) {
if(i >= 1)
multi_converter_state->buffer_dest[j] = dest[--i];
else
multi_converter_state->buffer_dest[j] = ' ';
}
}
}
uint8_t multi_converter_unit_dec_hex_bin_allowed(MultiConverterUnitType unit_type) {
return (unit_type == UnitTypeDec || unit_type == UnitTypeHex || unit_type == UnitTypeBin);
}
//
// CEL / FAR / KEL
//
void multi_converter_unit_temperature_convert(MultiConverterState* const multi_converter_state) {
double a = strtof(multi_converter_state->buffer_orig, NULL);
uint8_t overflow = 0;
switch(multi_converter_state->unit_type_orig) {
default:
break;
case UnitTypeCelsius:
if(multi_converter_state->unit_type_dest == UnitTypeFahernheit) {
// celsius to fahrenheit
a = (a * ((double)1.8)) + 32;
} else { // UnitTypeKelvin
a += ((double)273.15);
}
break;
case UnitTypeFahernheit:
// fahrenheit to celsius, always
a = (a - 32) / ((double)1.8);
if(multi_converter_state->unit_type_dest == UnitTypeKelvin) {
// if kelvin, add
a += ((double)273.15);
}
break;
case UnitTypeKelvin:
// kelvin to celsius, always
a -= ((double)273.15);
if(multi_converter_state->unit_type_dest == UnitTypeFahernheit) {
// if fahernheit, convert
a = (a * ((double)1.8)) + 32;
}
break;
}
if(overflow) {
multi_converter_unit_set_overflow(multi_converter_state->buffer_dest);
} else {
int ret = snprintf(
multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%.3lf", a);
if(ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest);
}
}
uint8_t multi_converter_unit_temperature_allowed(MultiConverterUnitType unit_type) {
return (
unit_type == UnitTypeCelsius || unit_type == UnitTypeFahernheit ||
unit_type == UnitTypeKelvin);
}
//
// KM / M / CM / MILES / FEET / INCHES
//
void multi_converter_unit_distance_convert(MultiConverterState* const multi_converter_state) {
double a = strtof(multi_converter_state->buffer_orig, NULL);
uint8_t overflow = 0;
switch(multi_converter_state->unit_type_orig) {
default:
break;
case UnitTypeKilometers:
if(multi_converter_state->unit_type_dest == UnitTypeMeters)
a *= ((double)1000);
else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters)
a *= ((double)100000);
else if(multi_converter_state->unit_type_dest == UnitTypeMiles)
a *= ((double)0.6213711);
else if(multi_converter_state->unit_type_dest == UnitTypeFeet)
a *= ((double)3280.839895013);
else if(multi_converter_state->unit_type_dest == UnitTypeInches)
a *= ((double)39370.078740157);
break;
case UnitTypeMeters:
if(multi_converter_state->unit_type_dest == UnitTypeKilometers)
a /= ((double)1000);
else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters)
a *= ((double)100);
else if(multi_converter_state->unit_type_dest == UnitTypeMiles)
a *= ((double)0.0006213711);
else if(multi_converter_state->unit_type_dest == UnitTypeFeet)
a *= ((double)3.280839895013);
else if(multi_converter_state->unit_type_dest == UnitTypeInches)
a *= ((double)39.370078740157);
break;
case UnitTypeCentimeters:
if(multi_converter_state->unit_type_dest == UnitTypeKilometers)
a /= ((double)100000);
else if(multi_converter_state->unit_type_dest == UnitTypeMeters)
a /= ((double)100);
else if(multi_converter_state->unit_type_dest == UnitTypeMiles)
a *= ((double)0.000006213711);
else if(multi_converter_state->unit_type_dest == UnitTypeFeet)
a *= ((double)0.03280839895013);
else if(multi_converter_state->unit_type_dest == UnitTypeInches)
a *= ((double)0.39370078740157);
break;
case UnitTypeMiles:
if(multi_converter_state->unit_type_dest == UnitTypeKilometers)
a *= ((double)1.609344);
else if(multi_converter_state->unit_type_dest == UnitTypeMeters)
a *= ((double)1609.344);
else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters)
a *= ((double)160934.4);
else if(multi_converter_state->unit_type_dest == UnitTypeFeet)
a *= ((double)5280);
else if(multi_converter_state->unit_type_dest == UnitTypeInches)
a *= ((double)63360);
break;
case UnitTypeFeet:
if(multi_converter_state->unit_type_dest == UnitTypeKilometers)
a *= ((double)0.0003048);
else if(multi_converter_state->unit_type_dest == UnitTypeMeters)
a *= ((double)0.3048);
else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters)
a *= ((double)30.48);
else if(multi_converter_state->unit_type_dest == UnitTypeMiles)
a *= ((double)0.000189393939394);
else if(multi_converter_state->unit_type_dest == UnitTypeInches)
a *= ((double)12);
break;
case UnitTypeInches:
if(multi_converter_state->unit_type_dest == UnitTypeKilometers)
a *= ((double)0.0000254);
else if(multi_converter_state->unit_type_dest == UnitTypeMeters)
a *= ((double)0.0254);
else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters)
a *= ((double)2.54);
else if(multi_converter_state->unit_type_dest == UnitTypeMiles)
a *= ((double)0.0000157828282828);
else if(multi_converter_state->unit_type_dest == UnitTypeFeet)
a *= ((double)0.0833333333333);
break;
}
if(overflow) {
multi_converter_unit_set_overflow(multi_converter_state->buffer_dest);
} else {
int ret = snprintf(
multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%lf", a);
if(ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest);
}
}
uint8_t multi_converter_unit_distance_allowed(MultiConverterUnitType unit_type) {
return (
unit_type == UnitTypeKilometers || unit_type == UnitTypeMeters ||
unit_type == UnitTypeCentimeters || unit_type == UnitTypeMiles ||
unit_type == UnitTypeFeet || unit_type == UnitTypeInches);
}
//
// DEG / RAD
//
void multi_converter_unit_angle_convert(MultiConverterState* const multi_converter_state) {
double a = strtof(multi_converter_state->buffer_orig, NULL);
uint8_t overflow = 0;
switch(multi_converter_state->unit_type_orig) {
default:
break;
case UnitTypeDegree:
if(multi_converter_state->unit_type_dest == UnitTypeRadian) a *= ((double)0.0174532925199);
break;
case UnitTypeRadian:
if(multi_converter_state->unit_type_dest == UnitTypeDegree) a *= ((double)57.2957795131);
break;
}
if(overflow) {
multi_converter_unit_set_overflow(multi_converter_state->buffer_dest);
} else {
int ret = snprintf(
multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%lf", a);
if(ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest);
}
}
uint8_t multi_converter_unit_angle_allowed(MultiConverterUnitType unit_type) {
return (unit_type == UnitTypeDegree || unit_type == UnitTypeRadian);
}
@@ -1,171 +0,0 @@
#pragma once
#include <input/input.h>
#include <gui/gui.h>
#include "multi_converter_definitions.h"
#define MULTI_CONVERTER_AVAILABLE_UNITS 14
#define multi_converter_get_unit(unit_type) multi_converter_available_units[unit_type]
#define multi_converter_get_unit_type_offset(unit_type, offset) \
(((unit_type + offset) % MULTI_CONVERTER_AVAILABLE_UNITS + MULTI_CONVERTER_AVAILABLE_UNITS) % \
MULTI_CONVERTER_AVAILABLE_UNITS)
// the modulo operation will fail with extremely large values on the units array
// DEC / HEX / BIN
void multi_converter_unit_dec_hex_bin_convert(MultiConverterState* const multi_converter_state);
uint8_t multi_converter_unit_dec_hex_bin_allowed(MultiConverterUnitType);
// CEL / FAR / KEL
void multi_converter_unit_temperature_convert(MultiConverterState* const multi_converter_state);
uint8_t multi_converter_unit_temperature_allowed(MultiConverterUnitType);
// KM / M / CM / MILES / FEET / INCHES
void multi_converter_unit_distance_convert(MultiConverterState* const multi_converter_state);
uint8_t multi_converter_unit_distance_allowed(MultiConverterUnitType);
// DEG / RAD
void multi_converter_unit_angle_convert(MultiConverterState* const multi_converter_state);
uint8_t multi_converter_unit_angle_allowed(MultiConverterUnitType unit_type);
//
// each unit is made of comma? + negative? + keyboard_length + mini_name + name + convert function + allowed function
// (setting functions as NULL will cause convert / select options to be ignored)
//
static const MultiConverterUnit multi_converter_unit_dec = {
0,
0,
10,
"DEC\0",
"Decimal\0",
multi_converter_unit_dec_hex_bin_convert,
multi_converter_unit_dec_hex_bin_allowed};
static const MultiConverterUnit multi_converter_unit_hex = {
0,
0,
16,
"HEX\0",
"Hexadecimal\0",
multi_converter_unit_dec_hex_bin_convert,
multi_converter_unit_dec_hex_bin_allowed};
static const MultiConverterUnit multi_converter_unit_bin = {
0,
0,
2,
"BIN\0",
"Binary\0",
multi_converter_unit_dec_hex_bin_convert,
multi_converter_unit_dec_hex_bin_allowed};
static const MultiConverterUnit multi_converter_unit_cel = {
1,
1,
10,
"CEL\0",
"Celsius\0",
multi_converter_unit_temperature_convert,
multi_converter_unit_temperature_allowed};
static const MultiConverterUnit multi_converter_unit_far = {
1,
1,
10,
"FAR\0",
"Fahernheit\0",
multi_converter_unit_temperature_convert,
multi_converter_unit_temperature_allowed};
static const MultiConverterUnit multi_converter_unit_kel = {
1,
1,
10,
"KEL\0",
"Kelvin\0",
multi_converter_unit_temperature_convert,
multi_converter_unit_temperature_allowed};
static const MultiConverterUnit multi_converter_unit_km = {
1,
0,
10,
"KM\0",
"Kilometers\0",
multi_converter_unit_distance_convert,
multi_converter_unit_distance_allowed};
static const MultiConverterUnit multi_converter_unit_m = {
1,
0,
10,
"M\0",
"Meters\0",
multi_converter_unit_distance_convert,
multi_converter_unit_distance_allowed};
static const MultiConverterUnit multi_converter_unit_cm = {
1,
0,
10,
"CM\0",
"Centimeters\0",
multi_converter_unit_distance_convert,
multi_converter_unit_distance_allowed};
static const MultiConverterUnit multi_converter_unit_mi = {
1,
0,
10,
"MI\0",
"Miles\0",
multi_converter_unit_distance_convert,
multi_converter_unit_distance_allowed};
static const MultiConverterUnit multi_converter_unit_ft = {
1,
0,
10,
"FT\0",
"Feet\0",
multi_converter_unit_distance_convert,
multi_converter_unit_distance_allowed};
static const MultiConverterUnit multi_converter_unit_in = {
1,
0,
10,
" \"\0",
"Inches\0",
multi_converter_unit_distance_convert,
multi_converter_unit_distance_allowed};
static const MultiConverterUnit multi_converter_unit_deg = {
1,
0,
10,
"DEG\0",
"Degree\0",
multi_converter_unit_angle_convert,
multi_converter_unit_angle_allowed};
static const MultiConverterUnit multi_converter_unit_rad = {
1,
0,
10,
"RAD\0",
"Radian\0",
multi_converter_unit_angle_convert,
multi_converter_unit_angle_allowed};
// index order set by the MultiConverterUnitType enum element (multi_converter_definitions.h)
static const MultiConverterUnit multi_converter_available_units[MULTI_CONVERTER_AVAILABLE_UNITS] = {
[UnitTypeDec] = multi_converter_unit_dec,
[UnitTypeHex] = multi_converter_unit_hex,
[UnitTypeBin] = multi_converter_unit_bin,
[UnitTypeCelsius] = multi_converter_unit_cel,
[UnitTypeFahernheit] = multi_converter_unit_far,
[UnitTypeKelvin] = multi_converter_unit_kel,
[UnitTypeKilometers] = multi_converter_unit_km,
[UnitTypeMeters] = multi_converter_unit_m,
[UnitTypeCentimeters] = multi_converter_unit_cm,
[UnitTypeMiles] = multi_converter_unit_mi,
[UnitTypeFeet] = multi_converter_unit_ft,
[UnitTypeInches] = multi_converter_unit_in,
[UnitTypeDegree] = multi_converter_unit_deg,
[UnitTypeRadian] = multi_converter_unit_rad,
};
-11
View File
@@ -1,11 +0,0 @@
App(
appid="multi_dice",
name="Multi-Dice",
apptype=FlipperAppType.EXTERNAL,
entry_point="dice_app",
cdefines=["APP_DICE"],
requires=["gui"],
stack_size=2 * 1024,
fap_icon="dice.png",
fap_category="Games",
)
-558
View File
@@ -1,558 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include "furi_hal_random.h"
#include <gui/elements.h>
#include <gui/gui.h>
#include <input/input.h>
#define TAG "Dice Roller"
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType type;
InputEvent input;
} PluginEvent;
typedef struct {
FuriMutex* mutex;
FuriMessageQueue* event_queue;
FuriHalRtcDateTime datetime;
uint8_t diceSelect;
uint8_t diceQty;
uint8_t diceRoll;
uint8_t playerOneScore;
uint8_t playerTwoScore;
char rollTime[1][15];
char diceType[1][11];
char strings[5][45];
char theScores[1][45];
bool letsRoll;
} DiceState;
static void dice_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void dice_render_callback(Canvas* const canvas, void* ctx) {
DiceState* state = ctx;
if(furi_mutex_acquire(state->mutex, 200) != FuriStatusOk) {
// Can't obtain mutex, requeue render
PluginEvent event = {.type = EventTypeTick};
furi_message_queue_put(state->event_queue, &event, 0);
return;
}
canvas_set_font(canvas, FontSecondary);
if(state->diceSelect < 220) {
if(state->diceQty == 1) {
elements_button_left(canvas, "x1");
} else if(state->diceQty == 2) {
elements_button_left(canvas, "x2");
} else if(state->diceQty == 3) {
elements_button_left(canvas, "x3");
} else if(state->diceQty == 4) {
elements_button_left(canvas, "x4");
} else if(state->diceQty == 5) {
elements_button_left(canvas, "x5");
} else if(state->diceQty == 6) {
elements_button_left(canvas, "x6");
}
}
if(state->letsRoll) {
furi_hal_rtc_get_datetime(&state->datetime);
uint8_t hour = state->datetime.hour;
char strAMPM[3];
snprintf(strAMPM, sizeof(strAMPM), "%s", "AM");
if(hour > 12) {
hour -= 12;
snprintf(strAMPM, sizeof(strAMPM), "%s", "PM");
}
snprintf(
state->rollTime[0],
sizeof(state->rollTime[0]),
"%.2d:%.2d:%.2d %s",
hour,
state->datetime.minute,
state->datetime.second,
strAMPM);
if(state->diceSelect == 229) {
const char* eightBall[] = {
"It is certain",
"Without a doubt",
"You may rely on it",
"Yes definitely",
"It is decidedly so",
"As I see it, yes",
"Most likely",
"Yes",
"Outlook good",
"Signs point to yes",
"Reply hazy try again",
"Better not tell you now",
"Ask again later",
"Cannot predict now",
"Concentrate and ask again",
"Don't count on it",
"Outlook not so good",
"My sources say no",
"Very doubtful",
"My reply is no"};
state->diceRoll =
((rand() % state->diceSelect) + 1); // JUST TO GET IT GOING? AND FIX BUG
snprintf(state->diceType[0], sizeof(state->diceType[0]), "%s", "8BALL");
snprintf(
state->strings[0],
sizeof(state->strings[0]),
"%s at %s",
state->diceType[0],
state->rollTime[0]);
uint8_t d1_i = rand() % COUNT_OF(eightBall);
snprintf(state->strings[1], sizeof(state->strings[1]), "%s", eightBall[d1_i]);
} else if(state->diceSelect == 228) {
const char* eightBall[] = {
"I'd do it.",
"Hell, yeah!",
"You bet your life!",
"What are you waiting for?",
"You could do worse things.",
"Sure, I won't tell.",
"Yeah, you got this. Would I lie to you?",
"Looks like fun to me. ",
"Yeah, sure, why not?",
"DO IT!!!",
"Who's it gonna hurt?",
"Can you blame someone else?",
"Ask me again later.",
"Maybe, maybe not, I can't tell right now. ",
"Are you the betting type? ",
"Don't blame me if you get caught.",
"What have you got to lose?",
"I wouldn't if I were you.",
"My money's on the snowball.",
"Oh Hell no!"};
state->diceRoll =
((rand() % state->diceSelect) + 1); // JUST TO GET IT GOING? AND FIX BUG
snprintf(state->diceType[0], sizeof(state->diceType[0]), "%s", "Devil Ball");
snprintf(
state->strings[0],
sizeof(state->strings[0]),
"%s at %s",
state->diceType[0],
state->rollTime[0]);
uint8_t d1_i = rand() % COUNT_OF(eightBall);
snprintf(state->strings[1], sizeof(state->strings[1]), "%s", eightBall[d1_i]);
} else if(state->diceSelect == 230) {
const char* diceOne[] = {
"Nibble",
"Massage",
"Touch",
"Caress",
"Pet",
"Fondle",
"Suck",
"Lick",
"Blow",
"Kiss",
"???"};
const char* diceTwo[] = {
"Navel",
"Ears",
"Lips",
"Neck",
"Hand",
"Thigh",
"Nipple",
"Breasts",
"???",
"Genitals"};
state->diceRoll =
((rand() % state->diceSelect) + 1); // JUST TO GET IT GOING? AND FIX BUG
snprintf(state->diceType[0], sizeof(state->diceType[0]), "%s", "SEX?");
snprintf(
state->strings[0],
sizeof(state->strings[0]),
"%s at %s",
state->diceType[0],
state->rollTime[0]);
uint8_t d1_i = rand() % COUNT_OF(diceOne);
uint8_t d2_i = rand() % COUNT_OF(diceTwo);
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%s %s",
diceOne[d1_i],
diceTwo[d2_i]);
} else if(state->diceSelect == 231) {
const char* deckOne[] = {"2H", "2C", "2D", "2S", "3H", "3C", "3D", "3S", "4H",
"4C", "4D", "4S", "5H", "5C", "5D", "5S", "6H", "6C",
"6D", "6S", "7H", "7C", "7D", "7S", "8H", "8C", "8D",
"8S", "9H", "9C", "9D", "9S", "10H", "10C", "10D", "10S",
"JH", "JC", "JD", "JS", "QH", "QC", "QD", "QS", "KH",
"KC", "KD", "KS", "AH", "AC", "AD", "AS"};
char* deckTwo[] = {"2H", "2C", "2D", "2S", "3H", "3C", "3D", "3S", "4H",
"4C", "4D", "4S", "5H", "5C", "5D", "5S", "6H", "6C",
"6D", "6S", "7H", "7C", "7D", "7S", "8H", "8C", "8D",
"8S", "9H", "9C", "9D", "9S", "10H", "10C", "10D", "10S",
"JH", "JC", "JD", "JS", "QH", "QC", "QD", "QS", "KH",
"KC", "KD", "KS", "AH", "AC", "AD"}; // ONE LESS SINCE ONE WILL BE REMOVED
state->diceRoll =
((rand() % state->diceSelect) + 1); // JUST TO GET IT GOING? AND FIX BUG
snprintf(state->diceType[0], sizeof(state->diceType[0]), "%s", "WAR!");
snprintf(
state->strings[0],
sizeof(state->strings[0]),
"%s at %s",
state->diceType[0],
state->rollTime[0]);
uint8_t d1_i = rand() % COUNT_OF(deckOne);
// INITIALIZE WITH PLACEHOLDERS TO AVOID MAYBE UNINITIALIZED ERROR
for(uint8_t i = 0; i < COUNT_OF(deckOne); i++) {
if(i < d1_i) {
snprintf(deckTwo[i], 8, "%s", deckOne[i]);
} else if(i > d1_i) {
snprintf(deckTwo[i - 1], 8, "%s", deckOne[i]);
}
}
uint8_t d2_i = rand() % COUNT_OF(deckTwo);
if(d1_i > d2_i) {
state->playerOneScore++;
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%s > %s",
deckOne[d1_i],
deckTwo[d2_i]);
} else {
state->playerTwoScore++;
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%s < %s",
deckOne[d1_i],
deckTwo[d2_i]);
}
} else if(state->diceSelect == 232) {
const char* diceOne[] = {
"You", "You choose", "Nobody", "Everyone", "Nose goes", "Player to your right"};
const char* diceTwo[] = {
"take a tiny toke",
"just chill",
"take 2 tokes",
"take a huge hit",
"bogart it",
"take a puff"};
const char* diceThree[] = {
"while humming a tune",
"with your eyes closed",
"on your knees",
"while holding your nose",
"while spinning in a circle",
"in slow motion"};
const char* diceFour[] = {
"twice",
"then tell a joke",
"then laugh as hard as you can",
"with the player to your left",
"then sing a song",
"then do a dance"};
state->diceRoll =
((rand() % state->diceSelect) + 1); // JUST TO GET IT GOING? AND FIX BUG
snprintf(state->diceType[0], sizeof(state->diceType[0]), "%s", "WEED!");
snprintf(
state->strings[0],
sizeof(state->strings[0]),
"%s at %s",
state->diceType[0],
state->rollTime[0]);
uint8_t d1_i = rand() % COUNT_OF(diceOne);
uint8_t d2_i = rand() % COUNT_OF(diceTwo);
uint8_t d3_i = rand() % COUNT_OF(diceThree);
uint8_t d4_i = rand() % COUNT_OF(diceFour);
snprintf(state->strings[1], sizeof(state->strings[1]), "%s", diceOne[d1_i]);
snprintf(state->strings[2], sizeof(state->strings[2]), "%s", diceTwo[d2_i]);
snprintf(state->strings[3], sizeof(state->strings[3]), "%s", diceThree[d3_i]);
snprintf(state->strings[4], sizeof(state->strings[4]), "%s", diceFour[d4_i]);
} else {
state->diceRoll = ((rand() % state->diceSelect) + 1);
snprintf(
state->diceType[0], sizeof(state->diceType[0]), "%s%d", "d", state->diceSelect);
snprintf(
state->strings[0],
sizeof(state->strings[0]),
"%d%s at %s",
state->diceQty,
state->diceType[0],
state->rollTime[0]);
if(state->diceQty == 1) {
snprintf(state->strings[1], sizeof(state->strings[1]), "%d", state->diceRoll);
} else if(state->diceQty == 2) {
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%d %d",
state->diceRoll,
((rand() % state->diceSelect) + 1));
} else if(state->diceQty == 3) {
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%d %d %d",
state->diceRoll,
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1));
} else if(state->diceQty == 4) {
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%d %d %d %d",
state->diceRoll,
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1));
} else if(state->diceQty == 5) {
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%d %d %d %d %d",
state->diceRoll,
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1));
} else if(state->diceQty == 6) {
snprintf(
state->strings[1],
sizeof(state->strings[1]),
"%d %d %d %d %d %d",
state->diceRoll,
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1),
((rand() % state->diceSelect) + 1));
}
}
state->letsRoll = false;
}
furi_mutex_release(state->mutex);
if(state->diceRoll != 0) {
if(state->diceSelect == 232) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, state->strings[0]);
canvas_draw_str_aligned(canvas, 64, 18, AlignCenter, AlignCenter, state->strings[1]);
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignCenter, state->strings[2]);
canvas_draw_str_aligned(canvas, 64, 34, AlignCenter, AlignCenter, state->strings[3]);
canvas_draw_str_aligned(canvas, 64, 42, AlignCenter, AlignCenter, state->strings[4]);
} else if(state->diceSelect == 228 || state->diceSelect == 229) {
canvas_set_font(canvas, FontBatteryPercent);
canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignCenter, state->strings[1]);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, state->strings[0]);
} else {
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignCenter, state->strings[1]);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, state->strings[0]);
}
if(state->diceSelect == 231 &&
!(state->playerOneScore == 0 && state->playerTwoScore == 0)) {
canvas_set_font(canvas, FontSecondary);
snprintf(
state->theScores[0],
sizeof(state->theScores[0]),
"%d %d",
state->playerOneScore,
state->playerTwoScore);
canvas_draw_str_aligned(canvas, 64, 34, AlignCenter, AlignCenter, state->theScores[0]);
}
}
if(state->diceSelect == 229 || state->diceSelect == 228) {
elements_button_center(canvas, "Shake");
} else if(state->diceSelect == 231) {
elements_button_center(canvas, "Draw");
} else {
elements_button_center(canvas, "Roll");
}
if(state->diceSelect == 2) {
elements_button_right(canvas, "d2");
} else if(state->diceSelect == 3) {
elements_button_right(canvas, "d3");
} else if(state->diceSelect == 4) {
elements_button_right(canvas, "d4");
} else if(state->diceSelect == 6) {
elements_button_right(canvas, "d6");
} else if(state->diceSelect == 8) {
elements_button_right(canvas, "d8");
} else if(state->diceSelect == 10) {
elements_button_right(canvas, "d10");
} else if(state->diceSelect == 12) {
elements_button_right(canvas, "d12");
} else if(state->diceSelect == 20) {
elements_button_right(canvas, "d20");
} else if(state->diceSelect == 59) {
elements_button_right(canvas, "d59");
} else if(state->diceSelect == 69) {
elements_button_right(canvas, "d69");
} else if(state->diceSelect == 100) {
elements_button_right(canvas, "d100");
} else if(state->diceSelect == 229) {
elements_button_right(canvas, "8BALL");
} else if(state->diceSelect == 228) {
elements_button_right(canvas, "DBALL");
} else if(state->diceSelect == 230) {
elements_button_right(canvas, "SEX");
} else if(state->diceSelect == 231) {
elements_button_right(canvas, "WAR");
} else if(state->diceSelect == 232) {
elements_button_right(canvas, "WEED");
}
}
static void dice_state_init(DiceState* const state) {
memset(state, 0, sizeof(DiceState));
furi_hal_rtc_get_datetime(&state->datetime);
state->diceSelect = 20;
state->diceQty = 1;
state->diceRoll = 0;
state->playerOneScore = 0;
state->playerTwoScore = 0;
state->letsRoll = false;
}
static void dice_tick(void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
PluginEvent event = {.type = EventTypeTick};
// It's OK to lose this event if system overloaded
furi_message_queue_put(event_queue, &event, 0);
}
int32_t dice_app(void* p) {
UNUSED(p);
DiceState* plugin_state = malloc(sizeof(DiceState));
dice_state_init(plugin_state);
plugin_state->event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
if(plugin_state->event_queue == NULL) {
FURI_LOG_E(TAG, "cannot create event queue\n");
free(plugin_state);
return 255;
}
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(plugin_state->mutex == NULL) {
FURI_LOG_E(TAG, "cannot create mutex\n");
furi_message_queue_free(plugin_state->event_queue);
free(plugin_state);
return 255;
}
FuriTimer* timer =
furi_timer_alloc(dice_tick, FuriTimerTypePeriodic, plugin_state->event_queue);
if(timer == NULL) {
FURI_LOG_E(TAG, "cannot create timer\n");
furi_mutex_free(plugin_state->mutex);
furi_message_queue_free(plugin_state->event_queue);
free(plugin_state);
return 255;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, dice_render_callback, plugin_state);
view_port_input_callback_set(view_port, dice_input_callback, plugin_state->event_queue);
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
furi_timer_start(timer, furi_kernel_get_tick_frequency());
// Main loop
PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(plugin_state->event_queue, &event, 100);
if(event_status == FuriStatusOk) {
if(event.type == EventTypeKey) {
if(event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
switch(event.input.key) {
case InputKeyUp:
break;
case InputKeyDown:
break;
case InputKeyRight:
if(plugin_state->diceSelect == 2) {
plugin_state->diceSelect = 3;
} else if(plugin_state->diceSelect == 3) {
plugin_state->diceSelect = 4;
} else if(plugin_state->diceSelect == 4) {
plugin_state->diceSelect = 6;
} else if(plugin_state->diceSelect == 6) {
plugin_state->diceSelect = 8;
} else if(plugin_state->diceSelect == 8) {
plugin_state->diceSelect = 10;
} else if(plugin_state->diceSelect == 10) {
plugin_state->diceSelect = 12;
} else if(plugin_state->diceSelect == 12) {
plugin_state->diceSelect = 20;
} else if(plugin_state->diceSelect == 20) {
plugin_state->diceSelect = 100;
} else if(plugin_state->diceSelect == 100) {
plugin_state->diceSelect = 230;
} else if(plugin_state->diceSelect == 230) {
plugin_state->playerOneScore = 0;
plugin_state->playerTwoScore = 0;
plugin_state->diceSelect = 231;
} else if(plugin_state->diceSelect == 231) {
plugin_state->diceSelect = 229;
} else if(plugin_state->diceSelect == 229) {
plugin_state->diceSelect = 228;
} else if(plugin_state->diceSelect == 228) {
plugin_state->diceSelect = 232;
} else if(plugin_state->diceSelect == 232) {
plugin_state->diceSelect = 59;
} else if(plugin_state->diceSelect == 59) {
plugin_state->diceSelect = 69;
} else {
plugin_state->diceSelect = 2;
}
break;
case InputKeyLeft:
if(plugin_state->diceQty <= 5) {
plugin_state->diceQty = plugin_state->diceQty + 1;
} else {
plugin_state->diceQty = 1;
}
break;
case InputKeyOk:
plugin_state->letsRoll = true;
break;
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
} else if(event.type == EventTypeTick) {
// furi_hal_rtc_get_datetime(&plugin_state->datetime);
}
view_port_update(view_port);
furi_mutex_release(plugin_state->mutex);
} else {
// FURI_LOG_D(TAG, "osMessageQueue: event timeout");
}
}
// Cleanup
furi_timer_free(timer);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
view_port_free(view_port);
furi_message_queue_free(plugin_state->event_queue);
furi_mutex_free(plugin_state->mutex);
free(plugin_state);
return 0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

-14
View File
@@ -1,14 +0,0 @@
App(
appid="music_beeper",
name="Music Beeper",
apptype=FlipperAppType.EXTERNAL,
entry_point="music_beeper_app",
requires=[
"gui",
"dialogs",
],
stack_size=2 * 1024,
fap_icon="music_10px.png",
fap_icon_assets="icons",
fap_category="Media",
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

-368
View File
@@ -1,368 +0,0 @@
#include "music_beeper_worker.h"
#include <furi.h>
#include <furi_hal.h>
#include "music_beeper_icons.h"
#include <assets_icons.h>
#include <gui/gui.h>
#include <dialogs/dialogs.h>
#include <storage/storage.h>
#define TAG "MusicBeeper"
#define MUSIC_BEEPER_APP_PATH_FOLDER EXT_PATH("music_player")
#define MUSIC_BEEPER_APP_EXTENSION "*"
#define MUSIC_BEEPER_SEMITONE_HISTORY_SIZE 4
typedef struct {
uint8_t semitone_history[MUSIC_BEEPER_SEMITONE_HISTORY_SIZE];
uint8_t duration_history[MUSIC_BEEPER_SEMITONE_HISTORY_SIZE];
uint8_t volume;
uint8_t semitone;
uint8_t dots;
uint8_t duration;
float position;
} MusicBeeperModel;
typedef struct {
MusicBeeperModel* model;
FuriMutex** model_mutex;
FuriMessageQueue* input_queue;
ViewPort* view_port;
Gui* gui;
MusicBeeperWorker* worker;
} MusicBeeper;
static const float MUSIC_BEEPER_VOLUMES[] = {0, .25, .5, .75, 1};
static const char* semitone_to_note(int8_t semitone) {
switch(semitone) {
case 0:
return "C";
case 1:
return "C#";
case 2:
return "D";
case 3:
return "D#";
case 4:
return "E";
case 5:
return "F";
case 6:
return "F#";
case 7:
return "G";
case 8:
return "G#";
case 9:
return "A";
case 10:
return "A#";
case 11:
return "B";
default:
return "--";
}
}
static bool is_white_note(uint8_t semitone, uint8_t id) {
switch(semitone) {
case 0:
if(id == 0) return true;
break;
case 2:
if(id == 1) return true;
break;
case 4:
if(id == 2) return true;
break;
case 5:
if(id == 3) return true;
break;
case 7:
if(id == 4) return true;
break;
case 9:
if(id == 5) return true;
break;
case 11:
if(id == 6) return true;
break;
default:
break;
}
return false;
}
static bool is_black_note(uint8_t semitone, uint8_t id) {
switch(semitone) {
case 1:
if(id == 0) return true;
break;
case 3:
if(id == 1) return true;
break;
case 6:
if(id == 3) return true;
break;
case 8:
if(id == 4) return true;
break;
case 10:
if(id == 5) return true;
break;
default:
break;
}
return false;
}
static void render_callback(Canvas* canvas, void* ctx) {
MusicBeeper* music_beeper = ctx;
furi_check(furi_mutex_acquire(music_beeper->model_mutex, FuriWaitForever) == FuriStatusOk);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 0, 12, "MusicBeeper");
uint8_t x_pos = 0;
uint8_t y_pos = 24;
const uint8_t white_w = 10;
const uint8_t white_h = 40;
const int8_t black_x = 6;
const int8_t black_y = -5;
const uint8_t black_w = 8;
const uint8_t black_h = 32;
// white keys
for(size_t i = 0; i < 7; i++) {
if(is_white_note(music_beeper->model->semitone, i)) {
canvas_draw_box(canvas, x_pos + white_w * i, y_pos, white_w + 1, white_h);
} else {
canvas_draw_frame(canvas, x_pos + white_w * i, y_pos, white_w + 1, white_h);
}
}
// black keys
for(size_t i = 0; i < 7; i++) {
if(i != 2 && i != 6) {
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(
canvas, x_pos + white_w * i + black_x, y_pos + black_y, black_w + 1, black_h);
canvas_set_color(canvas, ColorBlack);
if(is_black_note(music_beeper->model->semitone, i)) {
canvas_draw_box(
canvas, x_pos + white_w * i + black_x, y_pos + black_y, black_w + 1, black_h);
} else {
canvas_draw_frame(
canvas, x_pos + white_w * i + black_x, y_pos + black_y, black_w + 1, black_h);
}
}
}
// volume view_port
x_pos = 124;
y_pos = 0;
const uint8_t volume_h =
(64 / (COUNT_OF(MUSIC_BEEPER_VOLUMES) - 1)) * music_beeper->model->volume;
canvas_draw_frame(canvas, x_pos, y_pos, 4, 64);
canvas_draw_box(canvas, x_pos, y_pos + (64 - volume_h), 4, volume_h);
// note stack view_port
x_pos = 73;
y_pos = 0;
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_frame(canvas, x_pos, y_pos, 49, 64);
canvas_draw_line(canvas, x_pos + 28, 0, x_pos + 28, 64);
char duration_text[16];
for(uint8_t i = 0; i < MUSIC_BEEPER_SEMITONE_HISTORY_SIZE; i++) {
if(music_beeper->model->duration_history[i] == 0xFF) {
snprintf(duration_text, 15, "--");
} else {
snprintf(duration_text, 15, "%d", music_beeper->model->duration_history[i]);
}
if(i == 0) {
canvas_draw_box(canvas, x_pos, y_pos + 48, 49, 16);
canvas_set_color(canvas, ColorWhite);
} else {
canvas_set_color(canvas, ColorBlack);
}
canvas_draw_str(
canvas,
x_pos + 4,
64 - 16 * i - 3,
semitone_to_note(music_beeper->model->semitone_history[i]));
canvas_draw_str(canvas, x_pos + 31, 64 - 16 * i - 3, duration_text);
canvas_draw_line(canvas, x_pos, 64 - 16 * i, x_pos + 48, 64 - 16 * i);
}
furi_mutex_release(music_beeper->model_mutex);
}
static void input_callback(InputEvent* input_event, void* ctx) {
MusicBeeper* music_beeper = ctx;
if(input_event->type == InputTypeShort) {
furi_message_queue_put(music_beeper->input_queue, input_event, 0);
}
}
static void music_beeper_worker_callback(
uint8_t semitone,
uint8_t dots,
uint8_t duration,
float position,
void* context) {
MusicBeeper* music_beeper = context;
furi_check(furi_mutex_acquire(music_beeper->model_mutex, FuriWaitForever) == FuriStatusOk);
for(size_t i = 0; i < MUSIC_BEEPER_SEMITONE_HISTORY_SIZE - 1; i++) {
size_t r = MUSIC_BEEPER_SEMITONE_HISTORY_SIZE - 1 - i;
music_beeper->model->duration_history[r] = music_beeper->model->duration_history[r - 1];
music_beeper->model->semitone_history[r] = music_beeper->model->semitone_history[r - 1];
}
semitone = (semitone == 0xFF) ? 0xFF : semitone % 12;
music_beeper->model->semitone = semitone;
music_beeper->model->dots = dots;
music_beeper->model->duration = duration;
music_beeper->model->position = position;
music_beeper->model->semitone_history[0] = semitone;
music_beeper->model->duration_history[0] = duration;
furi_mutex_release(music_beeper->model_mutex);
view_port_update(music_beeper->view_port);
}
void music_beeper_clear(MusicBeeper* instance) {
memset(instance->model->duration_history, 0xff, MUSIC_BEEPER_SEMITONE_HISTORY_SIZE);
memset(instance->model->semitone_history, 0xff, MUSIC_BEEPER_SEMITONE_HISTORY_SIZE);
music_beeper_worker_clear(instance->worker);
}
MusicBeeper* music_beeper_alloc() {
MusicBeeper* instance = malloc(sizeof(MusicBeeper));
instance->model = malloc(sizeof(MusicBeeperModel));
instance->model->volume = 4;
instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
instance->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
instance->worker = music_beeper_worker_alloc();
music_beeper_worker_set_volume(
instance->worker, MUSIC_BEEPER_VOLUMES[instance->model->volume]);
music_beeper_worker_set_callback(instance->worker, music_beeper_worker_callback, instance);
music_beeper_clear(instance);
instance->view_port = view_port_alloc();
view_port_draw_callback_set(instance->view_port, render_callback, instance);
view_port_input_callback_set(instance->view_port, input_callback, instance);
// Open GUI and register view_port
instance->gui = furi_record_open(RECORD_GUI);
gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
return instance;
}
void music_beeper_free(MusicBeeper* instance) {
gui_remove_view_port(instance->gui, instance->view_port);
furi_record_close(RECORD_GUI);
view_port_free(instance->view_port);
music_beeper_worker_free(instance->worker);
furi_message_queue_free(instance->input_queue);
furi_mutex_free(instance->model_mutex);
free(instance->model);
free(instance);
}
int32_t music_beeper_app(void* p) {
MusicBeeper* music_beeper = music_beeper_alloc();
FuriString* file_path;
file_path = furi_string_alloc();
do {
if(p && strlen(p)) {
furi_string_set(file_path, (const char*)p);
} else {
furi_string_set(file_path, MUSIC_BEEPER_APP_PATH_FOLDER);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, MUSIC_BEEPER_APP_EXTENSION, &I_music_10px);
browser_options.base_path = MUSIC_BEEPER_APP_PATH_FOLDER;
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options);
furi_record_close(RECORD_DIALOGS);
if(!res) {
FURI_LOG_E(TAG, "No file selected");
break;
}
}
if(!music_beeper_worker_load(music_beeper->worker, furi_string_get_cstr(file_path))) {
FURI_LOG_E(TAG, "Unable to load file");
break;
}
music_beeper_worker_start(music_beeper->worker);
InputEvent input;
while(furi_message_queue_get(music_beeper->input_queue, &input, FuriWaitForever) ==
FuriStatusOk) {
furi_check(
furi_mutex_acquire(music_beeper->model_mutex, FuriWaitForever) == FuriStatusOk);
if(input.key == InputKeyBack) {
furi_mutex_release(music_beeper->model_mutex);
break;
} else if(input.key == InputKeyUp) {
if(music_beeper->model->volume < COUNT_OF(MUSIC_BEEPER_VOLUMES) - 1)
music_beeper->model->volume++;
music_beeper_worker_set_volume(
music_beeper->worker, MUSIC_BEEPER_VOLUMES[music_beeper->model->volume]);
} else if(input.key == InputKeyDown) {
if(music_beeper->model->volume > 0) music_beeper->model->volume--;
music_beeper_worker_set_volume(
music_beeper->worker, MUSIC_BEEPER_VOLUMES[music_beeper->model->volume]);
}
furi_mutex_release(music_beeper->model_mutex);
view_port_update(music_beeper->view_port);
}
music_beeper_worker_stop(music_beeper->worker);
if(p && strlen(p)) break; // Exit instead of going to browser if launched with arg
music_beeper_clear(music_beeper);
} while(1);
furi_string_free(file_path);
music_beeper_free(music_beeper);
return 0;
}
-48
View File
@@ -1,48 +0,0 @@
#include <furi.h>
#include <cli/cli.h>
#include <storage/storage.h>
#include "music_beeper_worker.h"
static void music_beeper_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(context);
MusicBeeperWorker* music_beeper_worker = music_beeper_worker_alloc();
Storage* storage = furi_record_open(RECORD_STORAGE);
do {
if(storage_common_stat(storage, furi_string_get_cstr(args), NULL) == FSE_OK) {
if(!music_beeper_worker_load(music_beeper_worker, furi_string_get_cstr(args))) {
printf("Failed to open file %s\r\n", furi_string_get_cstr(args));
break;
}
} else {
if(!music_beeper_worker_load_rtttl_from_string(
music_beeper_worker, furi_string_get_cstr(args))) {
printf("Argument is not a file or RTTTL\r\n");
break;
}
}
printf("Press CTRL+C to stop\r\n");
music_beeper_worker_set_volume(music_beeper_worker, 1.0f);
music_beeper_worker_start(music_beeper_worker);
while(!cli_cmd_interrupt_received(cli)) {
furi_delay_ms(50);
}
music_beeper_worker_stop(music_beeper_worker);
} while(0);
furi_record_close(RECORD_STORAGE);
music_beeper_worker_free(music_beeper_worker);
}
void music_beeper_on_system_start() {
#ifdef SRV_CLI
Cli* cli = furi_record_open(RECORD_CLI);
cli_add_command(cli, "music_beeper", CliCommandFlagDefault, music_beeper_cli, NULL);
furi_record_close(RECORD_CLI);
#else
UNUSED(music_beeper_cli);
#endif
}
-510
View File
@@ -1,510 +0,0 @@
#include "music_beeper_worker.h"
#include <furi_hal.h>
#include <furi.h>
#include <storage/storage.h>
#include <lib/flipper_format/flipper_format.h>
#include <m-array.h>
#define TAG "MusicBeeperWorker"
#define MUSIC_BEEPER_FILETYPE "Flipper Music Format"
#define MUSIC_BEEPER_VERSION 0
#define SEMITONE_PAUSE 0xFF
#define NOTE_C4 261.63f
#define NOTE_C4_SEMITONE (4.0f * 12.0f)
#define TWO_POW_TWELTH_ROOT 1.059463094359f
typedef struct {
uint8_t semitone;
uint8_t duration;
uint8_t dots;
} NoteBlock;
ARRAY_DEF(NoteBlockArray, NoteBlock, M_POD_OPLIST);
struct MusicBeeperWorker {
FuriThread* thread;
bool should_work;
MusicBeeperWorkerCallback callback;
void* callback_context;
float volume;
uint32_t bpm;
uint32_t duration;
uint32_t octave;
NoteBlockArray_t notes;
};
static int32_t music_beeper_worker_thread_callback(void* context) {
furi_assert(context);
MusicBeeperWorker* instance = context;
NoteBlockArray_it_t it;
NoteBlockArray_it(it, instance->notes);
if(furi_hal_speaker_acquire(1000)) {
while(instance->should_work) {
if(NoteBlockArray_end_p(it)) {
NoteBlockArray_it(it, instance->notes);
furi_delay_ms(10);
} else {
NoteBlock* note_block = NoteBlockArray_ref(it);
float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE;
float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4);
float duration = 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm /
note_block->duration;
uint32_t dots = note_block->dots;
while(dots > 0) {
duration += duration / 2;
dots--;
}
uint32_t next_tick = furi_get_tick() + duration;
float volume = instance->volume;
if(instance->callback) {
instance->callback(
note_block->semitone,
note_block->dots,
note_block->duration,
0.0,
instance->callback_context);
}
furi_hal_speaker_stop();
furi_hal_speaker_start(frequency, volume);
while(instance->should_work && furi_get_tick() < next_tick) {
volume *= 1;
furi_hal_speaker_set_volume(volume);
furi_delay_ms(2);
}
NoteBlockArray_next(it);
}
}
furi_hal_speaker_stop();
furi_hal_speaker_release();
} else {
FURI_LOG_E(TAG, "Speaker system is busy with another process.");
}
return 0;
}
MusicBeeperWorker* music_beeper_worker_alloc() {
MusicBeeperWorker* instance = malloc(sizeof(MusicBeeperWorker));
NoteBlockArray_init(instance->notes);
instance->thread = furi_thread_alloc();
furi_thread_set_name(instance->thread, "MusicBeeperWorker");
furi_thread_set_stack_size(instance->thread, 1024);
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, music_beeper_worker_thread_callback);
instance->volume = 1.0f;
return instance;
}
void music_beeper_worker_clear(MusicBeeperWorker* instance) {
NoteBlockArray_reset(instance->notes);
}
void music_beeper_worker_free(MusicBeeperWorker* instance) {
furi_assert(instance);
furi_thread_free(instance->thread);
NoteBlockArray_clear(instance->notes);
free(instance);
}
static bool is_digit(const char c) {
return isdigit(c) != 0;
}
static bool is_letter(const char c) {
return islower(c) != 0 || isupper(c) != 0;
}
static bool is_space(const char c) {
return c == ' ' || c == '\t';
}
static size_t extract_number(const char* string, uint32_t* number) {
size_t ret = 0;
*number = 0;
while(is_digit(*string)) {
*number *= 10;
*number += (*string - '0');
string++;
ret++;
}
return ret;
}
static size_t extract_dots(const char* string, uint32_t* number) {
size_t ret = 0;
*number = 0;
while(*string == '.') {
*number += 1;
string++;
ret++;
}
return ret;
}
static size_t extract_char(const char* string, char* symbol) {
if(is_letter(*string)) {
*symbol = *string;
return 1;
} else {
return 0;
}
}
static size_t extract_sharp(const char* string, char* symbol) {
if(*string == '#' || *string == '_') {
*symbol = '#';
return 1;
} else {
return 0;
}
}
static size_t skip_till(const char* string, const char symbol) {
size_t ret = 0;
while(*string != '\0' && *string != symbol) {
string++;
ret++;
}
if(*string != symbol) {
ret = 0;
}
return ret;
}
static bool music_beeper_worker_add_note(
MusicBeeperWorker* instance,
uint8_t semitone,
uint8_t duration,
uint8_t dots) {
NoteBlock note_block;
note_block.semitone = semitone;
note_block.duration = duration;
note_block.dots = dots;
NoteBlockArray_push_back(instance->notes, note_block);
return true;
}
static int8_t note_to_semitone(const char note) {
switch(note) {
case 'C':
return 0;
// C#
case 'D':
return 2;
// D#
case 'E':
return 4;
case 'F':
return 5;
// F#
case 'G':
return 7;
// G#
case 'A':
return 9;
// A#
case 'B':
return 11;
default:
return 0;
}
}
static bool music_beeper_worker_parse_notes(MusicBeeperWorker* instance, const char* string) {
const char* cursor = string;
bool result = true;
while(*cursor != '\0') {
if(!is_space(*cursor)) {
uint32_t duration = 0;
char note_char = '\0';
char sharp_char = '\0';
uint32_t octave = 0;
uint32_t dots = 0;
// Parsing
cursor += extract_number(cursor, &duration);
cursor += extract_char(cursor, &note_char);
cursor += extract_sharp(cursor, &sharp_char);
cursor += extract_number(cursor, &octave);
cursor += extract_dots(cursor, &dots);
// Post processing
note_char = toupper(note_char);
if(!duration) {
duration = instance->duration;
}
if(!octave) {
octave = instance->octave;
}
// Validation
bool is_valid = true;
is_valid &= (duration >= 1 && duration <= 128);
is_valid &= ((note_char >= 'A' && note_char <= 'G') || note_char == 'P');
is_valid &= (sharp_char == '#' || sharp_char == '\0');
is_valid &= (octave <= 16);
is_valid &= (dots <= 16);
if(!is_valid) {
FURI_LOG_E(
TAG,
"Invalid note: %lu%c%c%lu.%lu",
duration,
note_char == '\0' ? '_' : note_char,
sharp_char == '\0' ? '_' : sharp_char,
octave,
dots);
result = false;
break;
}
// Note to semitones
uint8_t semitone = 0;
if(note_char == 'P') {
semitone = SEMITONE_PAUSE;
} else {
semitone += octave * 12;
semitone += note_to_semitone(note_char);
semitone += sharp_char == '#' ? 1 : 0;
}
if(music_beeper_worker_add_note(instance, semitone, duration, dots)) {
FURI_LOG_D(
TAG,
"Added note: %c%c%lu.%lu = %u %lu",
note_char == '\0' ? '_' : note_char,
sharp_char == '\0' ? '_' : sharp_char,
octave,
dots,
semitone,
duration);
} else {
FURI_LOG_E(
TAG,
"Invalid note: %c%c%lu.%lu = %u %lu",
note_char == '\0' ? '_' : note_char,
sharp_char == '\0' ? '_' : sharp_char,
octave,
dots,
semitone,
duration);
}
cursor += skip_till(cursor, ',');
}
if(*cursor != '\0') cursor++;
}
return result;
}
bool music_beeper_worker_load(MusicBeeperWorker* instance, const char* file_path) {
furi_assert(instance);
furi_assert(file_path);
bool ret = false;
if(strcasestr(file_path, ".fmf")) {
ret = music_beeper_worker_load_fmf_from_file(instance, file_path);
} else {
ret = music_beeper_worker_load_rtttl_from_file(instance, file_path);
}
return ret;
}
bool music_beeper_worker_load_fmf_from_file(MusicBeeperWorker* instance, const char* file_path) {
furi_assert(instance);
furi_assert(file_path);
bool result = false;
FuriString* temp_str;
temp_str = furi_string_alloc();
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_existing(file, file_path)) break;
uint32_t version = 0;
if(!flipper_format_read_header(file, temp_str, &version)) break;
if(furi_string_cmp_str(temp_str, MUSIC_BEEPER_FILETYPE) ||
(version != MUSIC_BEEPER_VERSION)) {
FURI_LOG_E(TAG, "Incorrect file format or version");
break;
}
if(!flipper_format_read_uint32(file, "BPM", &instance->bpm, 1)) {
FURI_LOG_E(TAG, "BPM is missing");
break;
}
if(!flipper_format_read_uint32(file, "Duration", &instance->duration, 1)) {
FURI_LOG_E(TAG, "Duration is missing");
break;
}
if(!flipper_format_read_uint32(file, "Octave", &instance->octave, 1)) {
FURI_LOG_E(TAG, "Octave is missing");
break;
}
if(!flipper_format_read_string(file, "Notes", temp_str)) {
FURI_LOG_E(TAG, "Notes is missing");
break;
}
if(!music_beeper_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) {
break;
}
result = true;
} while(false);
furi_record_close(RECORD_STORAGE);
flipper_format_free(file);
furi_string_free(temp_str);
return result;
}
bool music_beeper_worker_load_rtttl_from_file(MusicBeeperWorker* instance, const char* file_path) {
furi_assert(instance);
furi_assert(file_path);
bool result = false;
FuriString* content;
content = furi_string_alloc();
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
do {
if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
FURI_LOG_E(TAG, "Unable to open file");
break;
};
uint16_t ret = 0;
do {
uint8_t buffer[65] = {0};
ret = storage_file_read(file, buffer, sizeof(buffer) - 1);
for(size_t i = 0; i < ret; i++) {
furi_string_push_back(content, buffer[i]);
}
} while(ret > 0);
furi_string_trim(content);
if(!furi_string_size(content)) {
FURI_LOG_E(TAG, "Empty file");
break;
}
if(!music_beeper_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) {
FURI_LOG_E(TAG, "Invalid file content");
break;
}
result = true;
} while(0);
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
furi_string_free(content);
return result;
}
bool music_beeper_worker_load_rtttl_from_string(MusicBeeperWorker* instance, const char* string) {
furi_assert(instance);
const char* cursor = string;
// Skip name
cursor += skip_till(cursor, ':');
if(*cursor != ':') {
return false;
}
// Duration
cursor += skip_till(cursor, '=');
if(*cursor != '=') {
return false;
}
cursor++;
cursor += extract_number(cursor, &instance->duration);
// Octave
cursor += skip_till(cursor, '=');
if(*cursor != '=') {
return false;
}
cursor++;
cursor += extract_number(cursor, &instance->octave);
// BPM
cursor += skip_till(cursor, '=');
if(*cursor != '=') {
return false;
}
cursor++;
cursor += extract_number(cursor, &instance->bpm);
// Notes
cursor += skip_till(cursor, ':');
if(*cursor != ':') {
return false;
}
cursor++;
if(!music_beeper_worker_parse_notes(instance, cursor)) {
return false;
}
return true;
}
void music_beeper_worker_set_callback(
MusicBeeperWorker* instance,
MusicBeeperWorkerCallback callback,
void* context) {
furi_assert(instance);
instance->callback = callback;
instance->callback_context = context;
}
void music_beeper_worker_set_volume(MusicBeeperWorker* instance, float volume) {
furi_assert(instance);
instance->volume = volume;
}
void music_beeper_worker_start(MusicBeeperWorker* instance) {
furi_assert(instance);
furi_assert(instance->should_work == false);
instance->should_work = true;
furi_thread_start(instance->thread);
}
void music_beeper_worker_stop(MusicBeeperWorker* instance) {
furi_assert(instance);
furi_assert(instance->should_work == true);
instance->should_work = false;
furi_thread_join(instance->thread);
}
@@ -1,46 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*MusicBeeperWorkerCallback)(
uint8_t semitone,
uint8_t dots,
uint8_t duration,
float position,
void* context);
typedef struct MusicBeeperWorker MusicBeeperWorker;
MusicBeeperWorker* music_beeper_worker_alloc();
void music_beeper_worker_clear(MusicBeeperWorker* instance);
void music_beeper_worker_free(MusicBeeperWorker* instance);
bool music_beeper_worker_load(MusicBeeperWorker* instance, const char* file_path);
bool music_beeper_worker_load_fmf_from_file(MusicBeeperWorker* instance, const char* file_path);
bool music_beeper_worker_load_rtttl_from_file(MusicBeeperWorker* instance, const char* file_path);
bool music_beeper_worker_load_rtttl_from_string(MusicBeeperWorker* instance, const char* string);
void music_beeper_worker_set_callback(
MusicBeeperWorker* instance,
MusicBeeperWorkerCallback callback,
void* context);
void music_beeper_worker_set_volume(MusicBeeperWorker* instance, float volume);
void music_beeper_worker_start(MusicBeeperWorker* instance);
void music_beeper_worker_stop(MusicBeeperWorker* instance);
#ifdef __cplusplus
}
#endif
-25
View File
@@ -1,25 +0,0 @@
App(
appid="nrf24mousejacker",
name="[NRF24] Mouse Jacker",
apptype=FlipperAppType.EXTERNAL,
entry_point="mousejacker_app",
requires=[
"gui",
"dialogs",
],
stack_size=2 * 1024,
fap_icon="mouse_10px.png",
fap_category="GPIO",
fap_author="@mothball187 & @xMasterX",
fap_version="1.0",
fap_description="App works with NRF24 Sniffer app to perform mousejack attacks",
fap_icon_assets="images",
fap_private_libs=[
Lib(
name="nrf24",
sources=[
"nrf24.c",
],
),
],
)
-546
View File
@@ -1,546 +0,0 @@
#include "nrf24.h"
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_resources.h>
#include <assert.h>
#include <string.h>
void nrf24_init() {
// this is needed if multiple SPI devices are connected to the same bus but with different CS pins
if(xtreme_settings.spi_nrf24_handle == SpiDefault) {
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeOutputPushPull);
furi_hal_gpio_write(&gpio_ext_pc3, true);
} else if(xtreme_settings.spi_nrf24_handle == SpiExtra) {
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
furi_hal_gpio_write(&gpio_ext_pa4, true);
}
furi_hal_spi_bus_handle_init(nrf24_HANDLE);
furi_hal_spi_acquire(nrf24_HANDLE);
furi_hal_gpio_init(nrf24_CE_PIN, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
furi_hal_gpio_write(nrf24_CE_PIN, false);
}
void nrf24_deinit() {
furi_hal_spi_release(nrf24_HANDLE);
furi_hal_spi_bus_handle_deinit(nrf24_HANDLE);
furi_hal_gpio_write(nrf24_CE_PIN, false);
furi_hal_gpio_init(nrf24_CE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
// resetting the CS pins to floating
if(xtreme_settings.spi_nrf24_handle == SpiDefault) {
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeAnalog);
} else if(xtreme_settings.spi_nrf24_handle == SpiExtra) {
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog);
}
}
void nrf24_spi_trx(
FuriHalSpiBusHandle* handle,
uint8_t* tx,
uint8_t* rx,
uint8_t size,
uint32_t timeout) {
UNUSED(timeout);
furi_hal_gpio_write(handle->cs, false);
furi_hal_spi_bus_trx(handle, tx, rx, size, nrf24_TIMEOUT);
furi_hal_gpio_write(handle->cs, true);
}
uint8_t nrf24_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t data) {
uint8_t tx[2] = {W_REGISTER | (REGISTER_MASK & reg), data};
uint8_t rx[2] = {0};
nrf24_spi_trx(handle, tx, rx, 2, nrf24_TIMEOUT);
return rx[0];
}
uint8_t
nrf24_write_buf_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size) {
uint8_t tx[size + 1];
uint8_t rx[size + 1];
memset(rx, 0, size + 1);
tx[0] = W_REGISTER | (REGISTER_MASK & reg);
memcpy(&tx[1], data, size);
nrf24_spi_trx(handle, tx, rx, size + 1, nrf24_TIMEOUT);
return rx[0];
}
uint8_t nrf24_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size) {
uint8_t tx[size + 1];
uint8_t rx[size + 1];
memset(rx, 0, size + 1);
tx[0] = R_REGISTER | (REGISTER_MASK & reg);
memset(&tx[1], 0, size);
nrf24_spi_trx(handle, tx, rx, size + 1, nrf24_TIMEOUT);
memcpy(data, &rx[1], size);
return rx[0];
}
uint8_t nrf24_flush_rx(FuriHalSpiBusHandle* handle) {
uint8_t tx[] = {FLUSH_RX};
uint8_t rx[] = {0};
nrf24_spi_trx(handle, tx, rx, 1, nrf24_TIMEOUT);
return rx[0];
}
uint8_t nrf24_flush_tx(FuriHalSpiBusHandle* handle) {
uint8_t tx[] = {FLUSH_TX};
uint8_t rx[] = {0};
nrf24_spi_trx(handle, tx, rx, 1, nrf24_TIMEOUT);
return rx[0];
}
uint8_t nrf24_get_maclen(FuriHalSpiBusHandle* handle) {
uint8_t maclen;
nrf24_read_reg(handle, REG_SETUP_AW, &maclen, 1);
maclen &= 3;
return maclen + 2;
}
uint8_t nrf24_set_maclen(FuriHalSpiBusHandle* handle, uint8_t maclen) {
assert(maclen > 1 && maclen < 6);
uint8_t status = 0;
status = nrf24_write_reg(handle, REG_SETUP_AW, maclen - 2);
return status;
}
uint8_t nrf24_status(FuriHalSpiBusHandle* handle) {
uint8_t status;
uint8_t tx[] = {R_REGISTER | (REGISTER_MASK & REG_STATUS)};
nrf24_spi_trx(handle, tx, &status, 1, nrf24_TIMEOUT);
return status;
}
uint32_t nrf24_get_rate(FuriHalSpiBusHandle* handle) {
uint8_t setup = 0;
uint32_t rate = 0;
nrf24_read_reg(handle, REG_RF_SETUP, &setup, 1);
setup &= 0x28;
if(setup == 0x20)
rate = 250000; // 250kbps
else if(setup == 0x08)
rate = 2000000; // 2Mbps
else if(setup == 0x00)
rate = 1000000; // 1Mbps
return rate;
}
uint8_t nrf24_set_rate(FuriHalSpiBusHandle* handle, uint32_t rate) {
uint8_t r6 = 0;
uint8_t status = 0;
if(!rate) rate = 2000000;
nrf24_read_reg(handle, REG_RF_SETUP, &r6, 1); // RF_SETUP register
r6 = r6 & (~0x28); // Clear rate fields.
if(rate == 2000000)
r6 = r6 | 0x08;
else if(rate == 1000000)
r6 = r6;
else if(rate == 250000)
r6 = r6 | 0x20;
status = nrf24_write_reg(handle, REG_RF_SETUP, r6); // Write new rate.
return status;
}
uint8_t nrf24_get_chan(FuriHalSpiBusHandle* handle) {
uint8_t channel = 0;
nrf24_read_reg(handle, REG_RF_CH, &channel, 1);
return channel;
}
uint8_t nrf24_set_chan(FuriHalSpiBusHandle* handle, uint8_t chan) {
uint8_t status;
status = nrf24_write_reg(handle, REG_RF_CH, chan);
return status;
}
uint8_t nrf24_get_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac) {
uint8_t size = 0;
uint8_t status = 0;
size = nrf24_get_maclen(handle);
status = nrf24_read_reg(handle, REG_RX_ADDR_P0, mac, size);
return status;
}
uint8_t nrf24_set_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size) {
uint8_t status = 0;
uint8_t clearmac[] = {0, 0, 0, 0, 0};
nrf24_set_maclen(handle, size);
nrf24_write_buf_reg(handle, REG_RX_ADDR_P0, clearmac, 5);
status = nrf24_write_buf_reg(handle, REG_RX_ADDR_P0, mac, size);
return status;
}
uint8_t nrf24_get_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac) {
uint8_t size = 0;
uint8_t status = 0;
size = nrf24_get_maclen(handle);
status = nrf24_read_reg(handle, REG_TX_ADDR, mac, size);
return status;
}
uint8_t nrf24_set_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size) {
uint8_t status = 0;
uint8_t clearmac[] = {0, 0, 0, 0, 0};
nrf24_set_maclen(handle, size);
nrf24_write_buf_reg(handle, REG_TX_ADDR, clearmac, 5);
status = nrf24_write_buf_reg(handle, REG_TX_ADDR, mac, size);
return status;
}
uint8_t nrf24_get_packetlen(FuriHalSpiBusHandle* handle) {
uint8_t len = 0;
nrf24_read_reg(handle, RX_PW_P0, &len, 1);
return len;
}
uint8_t nrf24_set_packetlen(FuriHalSpiBusHandle* handle, uint8_t len) {
uint8_t status = 0;
status = nrf24_write_reg(handle, RX_PW_P0, len);
return status;
}
uint8_t
nrf24_rxpacket(FuriHalSpiBusHandle* handle, uint8_t* packet, uint8_t* packetsize, bool full) {
uint8_t status = 0;
uint8_t size = 0;
uint8_t tx_pl_wid[] = {R_RX_PL_WID, 0};
uint8_t rx_pl_wid[] = {0, 0};
uint8_t tx_cmd[33] = {0}; // 32 max payload size + 1 for command
uint8_t tmp_packet[33] = {0};
status = nrf24_status(handle);
if(status & 0x40) {
if(full)
size = nrf24_get_packetlen(handle);
else {
nrf24_spi_trx(handle, tx_pl_wid, rx_pl_wid, 2, nrf24_TIMEOUT);
size = rx_pl_wid[1];
}
tx_cmd[0] = R_RX_PAYLOAD;
nrf24_spi_trx(handle, tx_cmd, tmp_packet, size + 1, nrf24_TIMEOUT);
nrf24_write_reg(handle, REG_STATUS, 0x40); // clear bit.
memcpy(packet, &tmp_packet[1], size);
} else if(status == 0) {
nrf24_flush_rx(handle);
nrf24_write_reg(handle, REG_STATUS, 0x40); // clear bit.
}
*packetsize = size;
return status;
}
uint8_t nrf24_txpacket(FuriHalSpiBusHandle* handle, uint8_t* payload, uint8_t size, bool ack) {
uint8_t status = 0;
uint8_t tx[size + 1];
uint8_t rx[size + 1];
memset(tx, 0, size + 1);
memset(rx, 0, size + 1);
if(!ack)
tx[0] = W_TX_PAYLOAD_NOACK;
else
tx[0] = W_TX_PAYLOAD;
memcpy(&tx[1], payload, size);
nrf24_spi_trx(handle, tx, rx, size + 1, nrf24_TIMEOUT);
nrf24_set_tx_mode(handle);
while(!(status & (TX_DS | MAX_RT))) status = nrf24_status(handle);
if(status & MAX_RT) nrf24_flush_tx(handle);
nrf24_set_idle(handle);
nrf24_write_reg(handle, REG_STATUS, TX_DS | MAX_RT);
return status & TX_DS;
}
uint8_t nrf24_power_up(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg = cfg | 2;
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
furi_delay_ms(5000);
return status;
}
uint8_t nrf24_set_idle(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg &= 0xfc; // clear bottom two bits to power down the radio
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
//nr204_write_reg(handle, REG_EN_RXADDR, 0x0);
furi_hal_gpio_write(nrf24_CE_PIN, false);
return status;
}
uint8_t nrf24_set_rx_mode(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
//status = nrf24_write_reg(handle, REG_CONFIG, 0x0F); // enable 2-byte CRC, PWR_UP, and PRIM_RX
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg |= 0x03; // PWR_UP, and PRIM_RX
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
//nr204_write_reg(REG_EN_RXADDR, 0x03) // Set RX Pipe 0 and 1
furi_hal_gpio_write(nrf24_CE_PIN, true);
furi_delay_ms(2000);
return status;
}
uint8_t nrf24_set_tx_mode(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
furi_hal_gpio_write(nrf24_CE_PIN, false);
nrf24_write_reg(handle, REG_STATUS, 0x30);
//status = nrf24_write_reg(handle, REG_CONFIG, 0x0E); // enable 2-byte CRC, PWR_UP
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg &= 0xfe; // disable PRIM_RX
cfg |= 0x02; // PWR_UP
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
furi_hal_gpio_write(nrf24_CE_PIN, true);
furi_delay_ms(2);
return status;
}
void nrf24_configure(
FuriHalSpiBusHandle* handle,
uint8_t rate,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t channel,
bool noack,
bool disable_aa) {
assert(channel <= 125);
assert(rate == 1 || rate == 2);
if(rate == 2)
rate = 8; // 2Mbps
else
rate = 0; // 1Mbps
nrf24_write_reg(handle, REG_CONFIG, 0x00); // Stop nRF
nrf24_set_idle(handle);
nrf24_write_reg(handle, REG_STATUS, 0x1c); // clear interrupts
if(disable_aa)
nrf24_write_reg(handle, REG_EN_AA, 0x00); // Disable Shockburst
else
nrf24_write_reg(handle, REG_EN_AA, 0x1F); // Enable Shockburst
nrf24_write_reg(handle, REG_DYNPD, 0x3F); // enable dynamic payload length on all pipes
if(noack)
nrf24_write_reg(handle, REG_FEATURE, 0x05); // disable payload-with-ack, enable noack
else {
nrf24_write_reg(handle, REG_CONFIG, 0x0C); // 2 byte CRC
nrf24_write_reg(handle, REG_FEATURE, 0x07); // enable dyn payload and ack
nrf24_write_reg(
handle, REG_SETUP_RETR, 0x1f); // 15 retries for AA, 500us auto retransmit delay
}
nrf24_set_idle(handle);
nrf24_flush_rx(handle);
nrf24_flush_tx(handle);
if(maclen) nrf24_set_maclen(handle, maclen);
if(srcmac) nrf24_set_src_mac(handle, srcmac, maclen);
if(dstmac) nrf24_set_dst_mac(handle, dstmac, maclen);
nrf24_write_reg(handle, REG_RF_CH, channel);
nrf24_write_reg(handle, REG_RF_SETUP, rate);
furi_delay_ms(200);
}
void nrf24_init_promisc_mode(FuriHalSpiBusHandle* handle, uint8_t channel, uint8_t rate) {
//uint8_t preamble[] = {0x55, 0x00}; // little endian
uint8_t preamble[] = {0xAA, 0x00}; // little endian
//uint8_t preamble[] = {0x00, 0x55}; // little endian
//uint8_t preamble[] = {0x00, 0xAA}; // little endian
nrf24_write_reg(handle, REG_CONFIG, 0x00); // Stop nRF
nrf24_write_reg(handle, REG_STATUS, 0x1c); // clear interrupts
nrf24_write_reg(handle, REG_DYNPD, 0x0); // disable shockburst
nrf24_write_reg(handle, REG_EN_AA, 0x00); // Disable Shockburst
nrf24_write_reg(handle, REG_FEATURE, 0x05); // disable payload-with-ack, enable noack
nrf24_set_maclen(handle, 2); // shortest address
nrf24_set_src_mac(handle, preamble, 2); // set src mac to preamble bits to catch everything
nrf24_set_packetlen(handle, 32); // set max packet length
nrf24_set_idle(handle);
nrf24_flush_rx(handle);
nrf24_flush_tx(handle);
nrf24_write_reg(handle, REG_RF_CH, channel);
nrf24_write_reg(handle, REG_RF_SETUP, rate);
// prime for RX, no checksum
nrf24_write_reg(handle, REG_CONFIG, 0x03); // PWR_UP and PRIM_RX, disable AA and CRC
furi_hal_gpio_write(nrf24_CE_PIN, true);
furi_delay_ms(100);
}
void hexlify(uint8_t* in, uint8_t size, char* out) {
memset(out, 0, size * 2);
for(int i = 0; i < size; i++)
snprintf(out + strlen(out), sizeof(out + strlen(out)), "%02X", in[i]);
}
uint64_t bytes_to_int64(uint8_t* bytes, uint8_t size, bool bigendian) {
uint64_t ret = 0;
for(int i = 0; i < size; i++)
if(bigendian)
ret |= bytes[i] << ((size - 1 - i) * 8);
else
ret |= bytes[i] << (i * 8);
return ret;
}
void int64_to_bytes(uint64_t val, uint8_t* out, bool bigendian) {
for(int i = 0; i < 8; i++) {
if(bigendian)
out[i] = (val >> ((7 - i) * 8)) & 0xff;
else
out[i] = (val >> (i * 8)) & 0xff;
}
}
uint32_t bytes_to_int32(uint8_t* bytes, bool bigendian) {
uint32_t ret = 0;
for(int i = 0; i < 4; i++)
if(bigendian)
ret |= bytes[i] << ((3 - i) * 8);
else
ret |= bytes[i] << (i * 8);
return ret;
}
void int32_to_bytes(uint32_t val, uint8_t* out, bool bigendian) {
for(int i = 0; i < 4; i++) {
if(bigendian)
out[i] = (val >> ((3 - i) * 8)) & 0xff;
else
out[i] = (val >> (i * 8)) & 0xff;
}
}
uint64_t bytes_to_int16(uint8_t* bytes, bool bigendian) {
uint16_t ret = 0;
for(int i = 0; i < 2; i++)
if(bigendian)
ret |= bytes[i] << ((1 - i) * 8);
else
ret |= bytes[i] << (i * 8);
return ret;
}
void int16_to_bytes(uint16_t val, uint8_t* out, bool bigendian) {
for(int i = 0; i < 2; i++) {
if(bigendian)
out[i] = (val >> ((1 - i) * 8)) & 0xff;
else
out[i] = (val >> (i * 8)) & 0xff;
}
}
// handle iffyness with preamble processing sometimes being a bit (literally) off
void alt_address_old(uint8_t* packet, uint8_t* altaddr) {
uint8_t macmess_hi_b[4];
uint8_t macmess_lo_b[2];
uint32_t macmess_hi;
uint16_t macmess_lo;
uint8_t preserved;
// get first 6 bytes into 32-bit and 16-bit variables
memcpy(macmess_hi_b, packet, 4);
memcpy(macmess_lo_b, packet + 4, 2);
macmess_hi = bytes_to_int32(macmess_hi_b, true);
//preserve least 7 bits from hi that will be shifted down to lo
preserved = macmess_hi & 0x7f;
macmess_hi >>= 7;
macmess_lo = bytes_to_int16(macmess_lo_b, true);
macmess_lo >>= 7;
macmess_lo = (preserved << 9) | macmess_lo;
int32_to_bytes(macmess_hi, macmess_hi_b, true);
int16_to_bytes(macmess_lo, macmess_lo_b, true);
memcpy(altaddr, &macmess_hi_b[1], 3);
memcpy(altaddr + 3, macmess_lo_b, 2);
}
bool validate_address(uint8_t* addr) {
uint8_t bad[][3] = {{0x55, 0x55}, {0xAA, 0xAA}, {0x00, 0x00}, {0xFF, 0xFF}};
for(int i = 0; i < 4; i++)
for(int j = 0; j < 2; j++)
if(!memcmp(addr + j * 2, bad[i], 2)) return false;
return true;
}
bool nrf24_sniff_address(FuriHalSpiBusHandle* handle, uint8_t maclen, uint8_t* address) {
bool found = false;
uint8_t packet[32] = {0};
uint8_t packetsize;
//char printit[65];
uint8_t status = 0;
status = nrf24_rxpacket(handle, packet, &packetsize, true);
if(status & 0x40) {
if(validate_address(packet)) {
for(int i = 0; i < maclen; i++) address[i] = packet[maclen - 1 - i];
/*
alt_address(packet, packet);
for(i = 0; i < maclen; i++)
address[i + 5] = packet[maclen - 1 - i];
*/
//memcpy(address, packet, maclen);
//hexlify(packet, packetsize, printit);
found = true;
}
}
return found;
}
uint8_t nrf24_find_channel(
FuriHalSpiBusHandle* handle,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t rate,
uint8_t min_channel,
uint8_t max_channel,
bool autoinit) {
uint8_t ping_packet[] = {0x0f, 0x0f, 0x0f, 0x0f}; // this can be anything, we just need an ack
uint8_t ch = max_channel + 1; // means fail
nrf24_configure(handle, rate, srcmac, dstmac, maclen, 2, false, false);
for(ch = min_channel; ch <= max_channel + 1; ch++) {
nrf24_write_reg(handle, REG_RF_CH, ch);
if(nrf24_txpacket(handle, ping_packet, 4, true)) break;
}
if(autoinit) {
FURI_LOG_D("nrf24", "initializing radio for channel %d", ch);
nrf24_configure(handle, rate, srcmac, dstmac, maclen, ch, false, false);
return ch;
}
return ch;
}
bool nrf24_check_connected(FuriHalSpiBusHandle* handle) {
uint8_t status = nrf24_status(handle);
if(status != 0x00) {
return true;
} else {
return false;
}
}
-376
View File
@@ -1,376 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <furi_hal_spi.h>
#include <xtreme.h>
#ifdef __cplusplus
extern "C" {
#endif
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define ACTIVATE 0x50
#define R_RX_PL_WID 0x60
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define W_TX_PAYLOAD_NOACK 0xB0
#define W_ACK_PAYLOAD 0xA8
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define RF24_NOP 0xFF
#define REG_CONFIG 0x00
#define REG_EN_AA 0x01
#define REG_EN_RXADDR 0x02
#define REG_SETUP_AW 0x03
#define REG_SETUP_RETR 0x04
#define REG_DYNPD 0x1C
#define REG_FEATURE 0x1D
#define REG_RF_SETUP 0x06
#define REG_STATUS 0x07
#define REG_RX_ADDR_P0 0x0A
#define REG_RF_CH 0x05
#define REG_TX_ADDR 0x10
#define RX_PW_P0 0x11
#define TX_DS 0x20
#define MAX_RT 0x10
#define nrf24_TIMEOUT 500
#define nrf24_CE_PIN &gpio_ext_pb2
#define nrf24_HANDLE \
(xtreme_settings.spi_nrf24_handle == SpiDefault ? &furi_hal_spi_bus_handle_external : \
&furi_hal_spi_bus_handle_external_extra)
/* Low level API */
/** Write device register
*
* @param handle - pointer to FuriHalSpiHandle
* @param reg - register
* @param data - data to write
*
* @return device status
*/
uint8_t nrf24_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t data);
/** Write buffer to device register
*
* @param handle - pointer to FuriHalSpiHandle
* @param reg - register
* @param data - data to write
* @param size - size of data to write
*
* @return device status
*/
uint8_t nrf24_write_buf_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size);
/** Read device register
*
* @param handle - pointer to FuriHalSpiHandle
* @param reg - register
* @param[out] data - pointer to data
*
* @return device status
*/
uint8_t nrf24_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size);
/** Power up the radio for operation
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_power_up(FuriHalSpiBusHandle* handle);
/** Power down the radio
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_set_idle(FuriHalSpiBusHandle* handle);
/** Sets the radio to RX mode
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_set_rx_mode(FuriHalSpiBusHandle* handle);
/** Sets the radio to TX mode
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_set_tx_mode(FuriHalSpiBusHandle* handle);
/*=============================================================================================================*/
/* High level API */
/** Must call this before using any other nrf24 API
*
*/
void nrf24_init();
/** Must call this when we end using nrf24 device
*
*/
void nrf24_deinit();
/** Send flush rx command
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_flush_rx(FuriHalSpiBusHandle* handle);
/** Send flush tx command
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_flush_tx(FuriHalSpiBusHandle* handle);
/** Gets the RX packet length in data pipe 0
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return packet length in data pipe 0
*/
uint8_t nrf24_get_packetlen(FuriHalSpiBusHandle* handle);
/** Sets the RX packet length in data pipe 0
*
* @param handle - pointer to FuriHalSpiHandle
* @param len - length to set
*
* @return device status
*/
uint8_t nrf24_set_packetlen(FuriHalSpiBusHandle* handle, uint8_t len);
/** Gets configured length of MAC address
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return MAC address length
*/
uint8_t nrf24_get_maclen(FuriHalSpiBusHandle* handle);
/** Sets configured length of MAC address
*
* @param handle - pointer to FuriHalSpiHandle
* @param maclen - length to set MAC address to, must be greater than 1 and less than 6
*
* @return MAC address length
*/
uint8_t nrf24_set_maclen(FuriHalSpiBusHandle* handle, uint8_t maclen);
/** Gets the current status flags from the STATUS register
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return status flags
*/
uint8_t nrf24_status(FuriHalSpiBusHandle* handle);
/** Gets the current transfer rate
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return transfer rate in bps
*/
uint32_t nrf24_get_rate(FuriHalSpiBusHandle* handle);
/** Sets the transfer rate
*
* @param handle - pointer to FuriHalSpiHandle
* @param rate - the transfer rate in bps
*
* @return device status
*/
uint8_t nrf24_set_rate(FuriHalSpiBusHandle* handle, uint32_t rate);
/** Gets the current channel
* In nrf24, the channel number is multiplied times 1MHz and added to 2400MHz to get the frequency
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return channel
*/
uint8_t nrf24_get_chan(FuriHalSpiBusHandle* handle);
/** Sets the channel
*
* @param handle - pointer to FuriHalSpiHandle
* @param frequency - the frequency in hertz
*
* @return device status
*/
uint8_t nrf24_set_chan(FuriHalSpiBusHandle* handle, uint8_t chan);
/** Gets the source mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param[out] mac - the source mac address
*
* @return device status
*/
uint8_t nrf24_get_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac);
/** Sets the source mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param mac - the mac address to set
* @param size - the size of the mac address (2 to 5)
*
* @return device status
*/
uint8_t nrf24_set_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size);
/** Gets the dest mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param[out] mac - the source mac address
*
* @return device status
*/
uint8_t nrf24_get_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac);
/** Sets the dest mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param mac - the mac address to set
* @param size - the size of the mac address (2 to 5)
*
* @return device status
*/
uint8_t nrf24_set_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size);
/** Reads RX packet
*
* @param handle - pointer to FuriHalSpiHandle
* @param[out] packet - the packet contents
* @param[out] packetsize - size of the received packet
* @param full - boolean set to true, packet length is determined by RX_PW_P0 register, false it is determined by dynamic payload length command
*
* @return device status
*/
uint8_t
nrf24_rxpacket(FuriHalSpiBusHandle* handle, uint8_t* packet, uint8_t* packetsize, bool full);
/** Sends TX packet
*
* @param handle - pointer to FuriHalSpiHandle
* @param packet - the packet contents
* @param size - packet size
* @param ack - boolean to determine whether an ACK is required for the packet or not
*
* @return device status
*/
uint8_t nrf24_txpacket(FuriHalSpiBusHandle* handle, uint8_t* payload, uint8_t size, bool ack);
/** Configure the radio
* This is not comprehensive, but covers a lot of the common configuration options that may be changed
* @param handle - pointer to FuriHalSpiHandle
* @param rate - transfer rate in Mbps (1 or 2)
* @param srcmac - source mac address
* @param dstmac - destination mac address
* @param maclen - length of mac address
* @param channel - channel to tune to
* @param noack - if true, disable auto-acknowledge
* @param disable_aa - if true, disable ShockBurst
*
*/
void nrf24_configure(
FuriHalSpiBusHandle* handle,
uint8_t rate,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t channel,
bool noack,
bool disable_aa);
/** Configures the radio for "promiscuous mode" and primes it for rx
* This is not an actual mode of the nrf24, but this function exploits a few bugs in the chip that allows it to act as if it were.
* See http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html for details.
* @param handle - pointer to FuriHalSpiHandle
* @param channel - channel to tune to
* @param rate - transfer rate in Mbps (1 or 2)
*/
void nrf24_init_promisc_mode(FuriHalSpiBusHandle* handle, uint8_t channel, uint8_t rate);
/** Listens for a packet and returns first possible address sniffed
* Call this only after calling nrf24_init_promisc_mode
* @param handle - pointer to FuriHalSpiHandle
* @param maclen - length of target mac address
* @param[out] addresses - sniffed address
*
* @return success
*/
bool nrf24_sniff_address(FuriHalSpiBusHandle* handle, uint8_t maclen, uint8_t* address);
/** Sends ping packet on each channel for designated tx mac looking for ack
*
* @param handle - pointer to FuriHalSpiHandle
* @param srcmac - source address
* @param dstmac - destination address
* @param maclen - length of address
* @param rate - transfer rate in Mbps (1 or 2)
* @param min_channel - channel to start with
* @param max_channel - channel to end at
* @param autoinit - if true, automatically configure radio for this channel
*
* @return channel that the address is listening on, if this value is above the max_channel param, it failed
*/
uint8_t nrf24_find_channel(
FuriHalSpiBusHandle* handle,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t rate,
uint8_t min_channel,
uint8_t max_channel,
bool autoinit);
/** Converts 64 bit value into uint8_t array
* @param val - 64-bit integer
* @param[out] out - bytes out
* @param bigendian - if true, convert as big endian, otherwise little endian
*/
void int64_to_bytes(uint64_t val, uint8_t* out, bool bigendian);
/** Converts 32 bit value into uint8_t array
* @param val - 32-bit integer
* @param[out] out - bytes out
* @param bigendian - if true, convert as big endian, otherwise little endian
*/
void int32_to_bytes(uint32_t val, uint8_t* out, bool bigendian);
/** Converts uint8_t array into 32 bit value
* @param bytes - uint8_t array
* @param bigendian - if true, convert as big endian, otherwise little endian
*
* @return 32-bit value
*/
uint32_t bytes_to_int32(uint8_t* bytes, bool bigendian);
/** Check if the nrf24 is connected
* @param handle - pointer to FuriHalSpiHandle
*
* @return true if connected, otherwise false
*/
bool nrf24_check_connected(FuriHalSpiBusHandle* handle);
#ifdef __cplusplus
}
#endif
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

-407
View File
@@ -1,407 +0,0 @@
#include <furi.h>
#include <gui/gui.h>
#include <dialogs/dialogs.h>
#include <input/input.h>
#include <stdlib.h>
#include <furi_hal.h>
#include <furi_hal_gpio.h>
#include <furi_hal_spi.h>
#include <furi_hal_interrupt.h>
#include <furi_hal_resources.h>
#include <notification/notification_messages.h>
#include <nrf24.h>
#include "mousejacker_ducky.h"
#include "nrf24mousejacker_icons.h"
#include <assets_icons.h>
#define TAG "mousejacker"
#define LOGITECH_MAX_CHANNEL 85
#define NRFSNIFF_APP_PATH_FOLDER_ADDRESSES EXT_PATH("apps_data/nrf24sniff/addresses.txt")
#define BADKB_FOLDER EXT_PATH("badkb")
#define MOUSEJACKER_APP_PATH_EXTENSION ".txt"
#define MAX_ADDRS 100
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType type;
InputEvent input;
} PluginEvent;
uint8_t addrs_count = 0;
int8_t addr_idx = 0;
uint8_t loaded_addrs[MAX_ADDRS][6]; // first byte is rate, the rest are the address
char target_fmt_text[] = "Target addr: %s";
char target_address_str[12] = "None";
char target_text[30];
char index_text[30];
static void render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
const PluginState* plugin_state = ctx;
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
// border around the edge of the screen
canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_set_font(canvas, FontSecondary);
if(!plugin_state->addr_err && !plugin_state->ducky_err && !plugin_state->is_thread_running &&
!plugin_state->is_ducky_running) {
snprintf(target_text, sizeof(target_text), target_fmt_text, target_address_str);
canvas_draw_str_aligned(canvas, 7, 10, AlignLeft, AlignBottom, target_text);
canvas_draw_str_aligned(canvas, 22, 20, AlignLeft, AlignBottom, "<- select address ->");
snprintf(
index_text, sizeof(index_text), "Address index: %d/%d", addr_idx + 1, addrs_count);
canvas_draw_str_aligned(canvas, 10, 30, AlignLeft, AlignBottom, index_text);
canvas_draw_str_aligned(canvas, 10, 40, AlignLeft, AlignBottom, "Press Ok button to ");
canvas_draw_str_aligned(canvas, 10, 50, AlignLeft, AlignBottom, "browse for ducky script");
if(!plugin_state->is_nrf24_connected) {
canvas_draw_str_aligned(
canvas, 10, 60, AlignLeft, AlignBottom, "Connect NRF24 to GPIO!");
}
} else if(plugin_state->addr_err) {
canvas_draw_str_aligned(
canvas, 10, 10, AlignLeft, AlignBottom, "Error: No nrf24sniff folder");
canvas_draw_str_aligned(canvas, 10, 20, AlignLeft, AlignBottom, "or addresses.txt file");
canvas_draw_str_aligned(
canvas, 10, 30, AlignLeft, AlignBottom, "loading error / empty file");
canvas_draw_str_aligned(
canvas, 7, 40, AlignLeft, AlignBottom, "Run (NRF24: Sniff) app first!");
} else if(plugin_state->ducky_err) {
canvas_draw_str_aligned(
canvas, 3, 10, AlignLeft, AlignBottom, "Error: No mousejacker folder");
canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "or duckyscript file");
canvas_draw_str_aligned(canvas, 3, 30, AlignLeft, AlignBottom, "loading error");
} else if(plugin_state->is_thread_running && !plugin_state->is_ducky_running) {
canvas_draw_str_aligned(canvas, 3, 10, AlignLeft, AlignBottom, "Loading...");
canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "Please wait!");
} else if(plugin_state->is_thread_running && plugin_state->is_ducky_running) {
canvas_draw_str_aligned(canvas, 3, 10, AlignLeft, AlignBottom, "Running duckyscript");
canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "Please wait!");
canvas_draw_str_aligned(
canvas, 3, 30, AlignLeft, AlignBottom, "Press back to exit (if it stuck)");
} else {
canvas_draw_str_aligned(canvas, 3, 10, AlignLeft, AlignBottom, "Unknown Error");
canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "press back");
canvas_draw_str_aligned(canvas, 3, 30, AlignLeft, AlignBottom, "to exit");
}
furi_mutex_release(plugin_state->mutex);
}
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void mousejacker_state_init(PluginState* const plugin_state) {
plugin_state->is_thread_running = false;
plugin_state->is_nrf24_connected = true;
}
static void hexlify(uint8_t* in, uint8_t size, char* out) {
memset(out, 0, size * 2);
for(int i = 0; i < size; i++)
snprintf(out + strlen(out), sizeof(out + strlen(out)), "%02X", in[i]);
}
static bool open_ducky_script(Stream* stream, PluginState* plugin_state) {
DialogsApp* dialogs = furi_record_open("dialogs");
bool result = false;
FuriString* path;
path = furi_string_alloc();
furi_string_set(path, BADKB_FOLDER);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, MOUSEJACKER_APP_PATH_EXTENSION, &I_badkb_10px);
browser_options.hide_ext = false;
bool ret = dialog_file_browser_show(dialogs, path, path, &browser_options);
furi_record_close("dialogs");
if(ret) {
if(!file_stream_open(stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
FURI_LOG_D(TAG, "Cannot open file \"%s\"", furi_string_get_cstr(path));
} else {
result = true;
}
}
furi_string_free(path);
plugin_state->is_ducky_running = true;
return result;
}
static bool open_addrs_file(Stream* stream) {
bool result = false;
FuriString* path;
path = furi_string_alloc();
furi_string_set(path, NRFSNIFF_APP_PATH_FOLDER_ADDRESSES);
if(!file_stream_open(stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
FURI_LOG_D(TAG, "Cannot open file \"%s\"", furi_string_get_cstr(path));
} else {
result = true;
}
furi_string_free(path);
return result;
}
static bool process_ducky_file(
Stream* file_stream,
uint8_t* addr,
uint8_t addr_size,
uint8_t rate,
PluginState* plugin_state) {
size_t file_size = 0;
size_t bytes_read = 0;
uint8_t* file_buf;
bool loaded = false;
FURI_LOG_D(TAG, "opening ducky script");
if(open_ducky_script(file_stream, plugin_state)) {
file_size = stream_size(file_stream);
if(file_size == (size_t)0) {
FURI_LOG_D(TAG, "load failed. file_size: %d", file_size);
plugin_state->is_ducky_running = false;
return loaded;
}
file_buf = malloc(file_size);
memset(file_buf, 0, file_size);
bytes_read = stream_read(file_stream, file_buf, file_size);
if(bytes_read == file_size) {
FURI_LOG_D(TAG, "executing ducky script");
mj_process_ducky_script(
nrf24_HANDLE, addr, addr_size, rate, (char*)file_buf, plugin_state);
FURI_LOG_D(TAG, "finished execution");
loaded = true;
} else {
FURI_LOG_D(TAG, "load failed. file size: %d", file_size);
}
free(file_buf);
}
plugin_state->is_ducky_running = false;
return loaded;
}
static bool load_addrs_file(Stream* file_stream) {
size_t file_size = 0;
size_t bytes_read = 0;
uint8_t* file_buf;
char* line_ptr;
uint8_t rate;
uint8_t addrlen = 0;
uint32_t counter = 0;
uint8_t addr[5] = {0};
uint32_t i_addr_lo = 0;
uint32_t i_addr_hi = 0;
bool loaded = false;
FURI_LOG_D(TAG, "opening addrs file");
addrs_count = 0;
if(open_addrs_file(file_stream)) {
file_size = stream_size(file_stream);
if(file_size == (size_t)0) {
FURI_LOG_D(TAG, "load failed. file_size: %d", file_size);
return loaded;
}
file_buf = malloc(file_size);
memset(file_buf, 0, file_size);
bytes_read = stream_read(file_stream, file_buf, file_size);
if(bytes_read == file_size) {
FURI_LOG_D(TAG, "loading addrs file");
char* line = strtok((char*)file_buf, "\n");
while(line != NULL) {
line_ptr = strstr((char*)line, ",");
*line_ptr = 0;
rate = atoi(line_ptr + 1);
addrlen = (uint8_t)(strlen(line) / 2);
i_addr_lo = strtoul(line + 2, NULL, 16);
line[2] = (char)0;
i_addr_hi = strtoul(line, NULL, 16);
int32_to_bytes(i_addr_lo, &addr[1], true);
addr[0] = (uint8_t)(i_addr_hi & 0xFF);
memset(loaded_addrs[counter], rate, 1);
memcpy(&loaded_addrs[counter++][1], addr, addrlen);
addrs_count++;
line = strtok(NULL, "\n");
loaded = true;
}
} else {
FURI_LOG_D(TAG, "load failed. file size: %d", file_size);
}
free(file_buf);
}
return loaded;
}
// entrypoint for worker
static int32_t mj_worker_thread(void* ctx) {
PluginState* plugin_state = ctx;
bool ducky_ok = false;
if(!plugin_state->addr_err) {
plugin_state->is_thread_running = true;
plugin_state->file_stream = file_stream_alloc(plugin_state->storage);
nrf24_find_channel(
nrf24_HANDLE,
loaded_addrs[addr_idx] + 1,
loaded_addrs[addr_idx] + 1,
5,
loaded_addrs[addr_idx][0],
2,
LOGITECH_MAX_CHANNEL,
true);
ducky_ok = process_ducky_file(
plugin_state->file_stream,
loaded_addrs[addr_idx] + 1,
5,
loaded_addrs[addr_idx][0],
plugin_state);
if(!ducky_ok) {
plugin_state->ducky_err = true;
} else {
plugin_state->ducky_err = false;
}
stream_free(plugin_state->file_stream);
}
plugin_state->is_thread_running = false;
return 0;
}
int32_t mousejacker_app(void* p) {
UNUSED(p);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
PluginState* plugin_state = malloc(sizeof(PluginState));
mousejacker_state_init(plugin_state);
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!plugin_state->mutex) {
FURI_LOG_E("mousejacker", "cannot create mutex\r\n");
furi_message_queue_free(event_queue);
free(plugin_state);
return 255;
}
uint8_t attempts = 0;
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
furi_hal_power_enable_otg();
furi_delay_ms(10);
}
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, plugin_state);
view_port_input_callback_set(view_port, input_callback, event_queue);
// Open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
plugin_state->storage = furi_record_open(RECORD_STORAGE);
plugin_state->file_stream = file_stream_alloc(plugin_state->storage);
plugin_state->mjthread = furi_thread_alloc();
furi_thread_set_name(plugin_state->mjthread, "MJ Worker");
furi_thread_set_stack_size(plugin_state->mjthread, 2048);
furi_thread_set_context(plugin_state->mjthread, plugin_state);
furi_thread_set_callback(plugin_state->mjthread, mj_worker_thread);
// spawn load file dialog to choose sniffed addresses file
if(load_addrs_file(plugin_state->file_stream)) {
addr_idx = 0;
hexlify(&loaded_addrs[addr_idx][1], 5, target_address_str);
plugin_state->addr_err = false;
} else {
plugin_state->addr_err = true;
}
stream_free(plugin_state->file_stream);
nrf24_init();
PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress) {
switch(event.input.key) {
case InputKeyUp:
break;
case InputKeyDown:
break;
case InputKeyRight:
if(!plugin_state->addr_err) {
addr_idx++;
if(addr_idx >= addrs_count) addr_idx = 0;
hexlify(loaded_addrs[addr_idx] + 1, 5, target_address_str);
}
break;
case InputKeyLeft:
if(!plugin_state->addr_err) {
addr_idx--;
if(addr_idx < 0) addr_idx = addrs_count - 1;
hexlify(loaded_addrs[addr_idx] + 1, 5, target_address_str);
}
break;
case InputKeyOk:
if(!plugin_state->addr_err) {
if(!nrf24_check_connected(nrf24_HANDLE)) {
plugin_state->is_nrf24_connected = false;
view_port_update(view_port);
notification_message(notification, &sequence_error);
} else if(!plugin_state->is_thread_running) {
furi_thread_start(plugin_state->mjthread);
view_port_update(view_port);
}
}
break;
case InputKeyBack:
plugin_state->close_thread_please = true;
if(plugin_state->is_thread_running && plugin_state->mjthread) {
furi_thread_join(
plugin_state->mjthread); // wait until thread is finished
}
plugin_state->close_thread_please = false;
processing = false;
break;
default:
break;
}
}
}
}
view_port_update(view_port);
furi_mutex_release(plugin_state->mutex);
}
furi_thread_free(plugin_state->mjthread);
nrf24_deinit();
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_STORAGE);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(plugin_state->mutex);
free(plugin_state);
if(furi_hal_power_is_otg_enabled()) {
furi_hal_power_disable_otg();
}
return 0;
}
@@ -1,460 +0,0 @@
#include "mousejacker_ducky.h"
static const char ducky_cmd_comment[] = {"REM"};
static const char ducky_cmd_delay[] = {"DELAY "};
static const char ducky_cmd_string[] = {"STRING "};
static const char ducky_cmd_altstring[] = {"ALTSTRING "};
static const char ducky_cmd_repeat[] = {"REPEAT "};
static uint8_t LOGITECH_HID_TEMPLATE[] =
{0x00, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static uint8_t LOGITECH_HELLO[] = {0x00, 0x4F, 0x00, 0x04, 0xB0, 0x10, 0x00, 0x00, 0x00, 0xED};
static uint8_t LOGITECH_KEEPALIVE[] = {0x00, 0x40, 0x00, 0x55, 0x6B};
uint8_t prev_hid = 0;
static bool holding_ctrl = false;
static bool holding_shift = false;
static bool holding_alt = false;
static bool holding_gui = false;
#define RT_THRESHOLD 50
#define LOGITECH_MIN_CHANNEL 2
#define LOGITECH_MAX_CHANNEL 83
#define LOGITECH_KEEPALIVE_SIZE 5
#define LOGITECH_HID_TEMPLATE_SIZE 10
#define LOGITECH_HELLO_SIZE 10
#define TAG "mousejacker_ducky"
MJDuckyKey mj_ducky_keys[] = {{" ", 44, 0}, {"!", 30, 2}, {"\"", 52, 2},
{"#", 32, 2}, {"$", 33, 2}, {"%", 34, 2},
{"&", 36, 2}, {"'", 52, 0}, {"(", 38, 2},
{")", 39, 2}, {"*", 37, 2}, {"+", 46, 2},
{",", 54, 0}, {"-", 45, 0}, {".", 55, 0},
{"/", 56, 0}, {"0", 39, 0}, {"1", 30, 0},
{"2", 31, 0}, {"3", 32, 0}, {"4", 33, 0},
{"5", 34, 0}, {"6", 35, 0}, {"7", 36, 0},
{"8", 37, 0}, {"9", 38, 0}, {":", 51, 2},
{";", 51, 0}, {"<", 54, 2}, {"=", 46, 0},
{">", 55, 2}, {"?", 56, 2}, {"@", 31, 2},
{"A", 4, 2}, {"B", 5, 2}, {"C", 6, 2},
{"D", 7, 2}, {"E", 8, 2}, {"F", 9, 2},
{"G", 10, 2}, {"H", 11, 2}, {"I", 12, 2},
{"J", 13, 2}, {"K", 14, 2}, {"L", 15, 2},
{"M", 16, 2}, {"N", 17, 2}, {"O", 18, 2},
{"P", 19, 2}, {"Q", 20, 2}, {"R", 21, 2},
{"S", 22, 2}, {"T", 23, 2}, {"U", 24, 2},
{"V", 25, 2}, {"W", 26, 2}, {"X", 27, 2},
{"Y", 28, 2}, {"Z", 29, 2}, {"[", 47, 0},
{"\\", 49, 0}, {"]", 48, 0}, {"^", 35, 2},
{"_", 45, 2}, {"`", 53, 0}, {"a", 4, 0},
{"b", 5, 0}, {"c", 6, 0}, {"d", 7, 0},
{"e", 8, 0}, {"f", 9, 0}, {"g", 10, 0},
{"h", 11, 0}, {"i", 12, 0}, {"j", 13, 0},
{"k", 14, 0}, {"l", 15, 0}, {"m", 16, 0},
{"n", 17, 0}, {"o", 18, 0}, {"p", 19, 0},
{"q", 20, 0}, {"r", 21, 0}, {"s", 22, 0},
{"t", 23, 0}, {"u", 24, 0}, {"v", 25, 0},
{"w", 26, 0}, {"x", 27, 0}, {"y", 28, 0},
{"z", 29, 0}, {"{", 47, 2}, {"|", 49, 2},
{"}", 48, 2}, {"~", 53, 2}, {"BACKSPACE", 42, 0},
{"", 0, 0}, {"ALT", 0, 4}, {"SHIFT", 0, 2},
{"CTRL", 0, 1}, {"GUI", 0, 8}, {"SCROLLLOCK", 71, 0},
{"ENTER", 40, 0}, {"F12", 69, 0}, {"HOME", 74, 0},
{"F10", 67, 0}, {"F9", 66, 0}, {"ESCAPE", 41, 0},
{"PAGEUP", 75, 0}, {"TAB", 43, 0}, {"PRINTSCREEN", 70, 0},
{"F2", 59, 0}, {"CAPSLOCK", 57, 0}, {"F1", 58, 0},
{"F4", 61, 0}, {"F6", 63, 0}, {"F8", 65, 0},
{"DOWNARROW", 81, 0}, {"DELETE", 42, 0}, {"RIGHT", 79, 0},
{"F3", 60, 0}, {"DOWN", 81, 0}, {"DEL", 76, 0},
{"END", 77, 0}, {"INSERT", 73, 0}, {"F5", 62, 0},
{"LEFTARROW", 80, 0}, {"RIGHTARROW", 79, 0}, {"PAGEDOWN", 78, 0},
{"PAUSE", 72, 0}, {"SPACE", 44, 0}, {"UPARROW", 82, 0},
{"F11", 68, 0}, {"F7", 64, 0}, {"UP", 82, 0},
{"LEFT", 80, 0}, {"NUM 1", 89, 0}, {"NUM 2", 90, 0},
{"NUM 3", 91, 0}, {"NUM 4", 92, 0}, {"NUM 5", 93, 0},
{"NUM 6", 94, 0}, {"NUM 7", 95, 0}, {"NUM 8", 96, 0},
{"NUM 9", 97, 0}, {"NUM 0", 98, 0}};
/*
static bool mj_ducky_get_number(const char* param, uint32_t* val) {
uint32_t value = 0;
if(sscanf(param, "%lu", &value) == 1) {
*val = value;
return true;
}
return false;
}
*/
static uint32_t mj_ducky_get_command_len(const char* line) {
uint32_t len = strlen(line);
for(uint32_t i = 0; i < len; i++) {
if(line[i] == ' ') return i;
}
return 0;
}
static bool mj_get_ducky_key(char* key, size_t keylen, MJDuckyKey* dk) {
//FURI_LOG_D(TAG, "looking up key %s with length %d", key, keylen);
for(uint i = 0; i < sizeof(mj_ducky_keys) / sizeof(MJDuckyKey); i++) {
if(strlen(mj_ducky_keys[i].name) == keylen &&
!strncmp(mj_ducky_keys[i].name, key, keylen)) {
memcpy(dk, &mj_ducky_keys[i], sizeof(MJDuckyKey));
return true;
}
}
return false;
}
static void checksum(uint8_t* payload, uint len) {
// This is also from the KeyKeriki paper
// Thanks Thorsten and Max!
uint8_t cksum = 0xff;
for(uint n = 0; n < len - 2; n++) cksum = (cksum - payload[n]) & 0xff;
cksum = (cksum + 1) & 0xff;
payload[len - 1] = cksum;
}
static void inject_packet(
FuriHalSpiBusHandle* handle,
uint8_t* addr,
uint8_t addr_size,
uint8_t rate,
uint8_t* payload,
size_t payload_size,
PluginState* plugin_state) {
uint8_t rt_count = 0;
while(1) {
if(!plugin_state->is_thread_running || plugin_state->close_thread_please) {
return;
}
if(nrf24_txpacket(handle, payload, payload_size, true)) {
break;
}
rt_count++;
// retransmit threshold exceeded, scan for new channel
if(rt_count > RT_THRESHOLD) {
if(nrf24_find_channel(
handle,
addr,
addr,
addr_size,
rate,
LOGITECH_MIN_CHANNEL,
LOGITECH_MAX_CHANNEL,
true) > LOGITECH_MAX_CHANNEL) {
return; // fail
}
//FURI_LOG_D("mj", "find channel passed, %d", tessst);
rt_count = 0;
}
}
}
static void build_hid_packet(uint8_t mod, uint8_t hid, uint8_t* payload) {
memcpy(payload, LOGITECH_HID_TEMPLATE, LOGITECH_HID_TEMPLATE_SIZE);
payload[2] = mod;
payload[3] = hid;
checksum(payload, LOGITECH_HID_TEMPLATE_SIZE);
}
static void release_key(
FuriHalSpiBusHandle* handle,
uint8_t* addr,
uint8_t addr_size,
uint8_t rate,
PluginState* plugin_state) {
// This function release keys currently pressed, but keep pressing special keys
// if holding mod keys variable are set to true
uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0};
build_hid_packet(
0 | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3,
0,
hid_payload);
inject_packet(
handle,
addr,
addr_size,
rate,
hid_payload,
LOGITECH_HID_TEMPLATE_SIZE,
plugin_state); // empty hid packet
}
static void send_hid_packet(
FuriHalSpiBusHandle* handle,
uint8_t* addr,
uint8_t addr_size,
uint8_t rate,
uint8_t mod,
uint8_t hid,
PluginState* plugin_state) {
uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0};
if(hid == prev_hid) release_key(handle, addr, addr_size, rate, plugin_state);
prev_hid = hid;
build_hid_packet(
mod | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3,
hid,
hid_payload);
inject_packet(
handle, addr, addr_size, rate, hid_payload, LOGITECH_HID_TEMPLATE_SIZE, plugin_state);
furi_delay_ms(12);
}
static bool ducky_end_line(const char chr) {
return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
}
// returns false if there was an error processing script line
static bool mj_process_ducky_line(
FuriHalSpiBusHandle* handle,
uint8_t* addr,
uint8_t addr_size,
uint8_t rate,
char* line,
char* prev_line,
PluginState* plugin_state) {
MJDuckyKey dk;
uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0};
char* line_tmp = line;
uint32_t line_len = strlen(line);
if(!plugin_state->is_thread_running || plugin_state->close_thread_please) {
return true;
}
for(uint32_t i = 0; i < line_len; i++) {
if((line_tmp[i] != ' ') && (line_tmp[i] != '\t') && (line_tmp[i] != '\n')) {
line_tmp = &line_tmp[i];
break; // Skip spaces and tabs
}
if(i == line_len - 1) return true; // Skip empty lines
}
FURI_LOG_D(TAG, "line: %s", line_tmp);
// General commands
if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) {
// REM - comment line
return true;
} else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) {
// DELAY
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
uint32_t delay_val = 0;
delay_val = atoi(line_tmp);
if(delay_val > 0) {
uint32_t delay_count = delay_val / 10;
build_hid_packet(0, 0, hid_payload);
inject_packet(
handle,
addr,
addr_size,
rate,
hid_payload,
LOGITECH_HID_TEMPLATE_SIZE,
plugin_state); // empty hid packet
for(uint32_t i = 0; i < delay_count; i++) {
if(!plugin_state->is_thread_running || plugin_state->close_thread_please) {
return true;
}
inject_packet(
handle,
addr,
addr_size,
rate,
LOGITECH_KEEPALIVE,
LOGITECH_KEEPALIVE_SIZE,
plugin_state);
furi_delay_ms(10);
}
return true;
}
return false;
} else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
// STRING
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
for(size_t i = 0; i < strlen(line_tmp); i++) {
if(!mj_get_ducky_key(&line_tmp[i], 1, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
}
return true;
} else if(strncmp(line_tmp, ducky_cmd_altstring, strlen(ducky_cmd_altstring)) == 0) {
// ALTSTRING
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
for(size_t i = 0; i < strlen(line_tmp); i++) {
if((line_tmp[i] < ' ') || (line_tmp[i] > '~')) {
continue; // Skip non-printable chars
}
char alt_code[4];
// Getting altcode of the char
snprintf(alt_code, 4, "%u", line_tmp[i]);
uint8_t j = 0;
while(!ducky_end_line(alt_code[j])) {
char pad_num[5] = {'N', 'U', 'M', ' ', alt_code[j]};
if(!mj_get_ducky_key(pad_num, 5, &dk)) return false;
holding_alt = true;
FURI_LOG_D(TAG, "Sending %s", pad_num);
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
j++;
}
holding_alt = false;
release_key(handle, addr, addr_size, rate, plugin_state);
}
return true;
} else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) {
// REPEAT
uint32_t repeat_cnt = 0;
if(prev_line == NULL) return false;
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
repeat_cnt = atoi(line_tmp);
if(repeat_cnt < 2) return false;
FURI_LOG_D(TAG, "repeating %s %ld times", prev_line, repeat_cnt);
for(uint32_t i = 0; i < repeat_cnt; i++)
mj_process_ducky_line(handle, addr, addr_size, rate, prev_line, NULL, plugin_state);
return true;
} else if(strncmp(line_tmp, "ALT", strlen("ALT")) == 0) {
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
holding_alt = true;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
holding_alt = false;
return true;
} else if(
strncmp(line_tmp, "GUI", strlen("GUI")) == 0 ||
strncmp(line_tmp, "WINDOWS", strlen("WINDOWS")) == 0 ||
strncmp(line_tmp, "COMMAND", strlen("COMMAND")) == 0) {
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
holding_gui = true;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
holding_gui = false;
return true;
} else if(
strncmp(line_tmp, "CTRL-ALT", strlen("CTRL-ALT")) == 0 ||
strncmp(line_tmp, "CONTROL-ALT", strlen("CONTROL-ALT")) == 0) {
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
holding_ctrl = true;
holding_alt = true;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
holding_ctrl = false;
holding_alt = false;
return true;
} else if(
strncmp(line_tmp, "CTRL-SHIFT", strlen("CTRL-SHIFT")) == 0 ||
strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) {
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
holding_ctrl = true;
holding_shift = true;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
holding_ctrl = false;
holding_shift = false;
return true;
} else if(
strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 ||
strncmp(line_tmp, "CONTROL", strlen("CONTROL")) == 0) {
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
holding_ctrl = true;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
holding_ctrl = false;
return true;
} else if(strncmp(line_tmp, "SHIFT", strlen("SHIFT")) == 0) {
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
holding_shift = true;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
holding_shift = false;
return true;
} else if(
strncmp(line_tmp, "ESC", strlen("ESC")) == 0 ||
strncmp(line_tmp, "APP", strlen("APP")) == 0 ||
strncmp(line_tmp, "ESCAPE", strlen("ESCAPE")) == 0) {
if(!mj_get_ducky_key("ESCAPE", 6, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
} else if(strncmp(line_tmp, "ENTER", strlen("ENTER")) == 0) {
if(!mj_get_ducky_key("ENTER", 5, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
} else if(
strncmp(line_tmp, "UP", strlen("UP")) == 0 ||
strncmp(line_tmp, "UPARROW", strlen("UPARROW")) == 0) {
if(!mj_get_ducky_key("UP", 2, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
} else if(
strncmp(line_tmp, "DOWN", strlen("DOWN")) == 0 ||
strncmp(line_tmp, "DOWNARROW", strlen("DOWNARROW")) == 0) {
if(!mj_get_ducky_key("DOWN", 4, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
} else if(
strncmp(line_tmp, "LEFT", strlen("LEFT")) == 0 ||
strncmp(line_tmp, "LEFTARROW", strlen("LEFTARROW")) == 0) {
if(!mj_get_ducky_key("LEFT", 4, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
} else if(
strncmp(line_tmp, "RIGHT", strlen("RIGHT")) == 0 ||
strncmp(line_tmp, "RIGHTARROW", strlen("RIGHTARROW")) == 0) {
if(!mj_get_ducky_key("RIGHT", 5, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
} else if(strncmp(line_tmp, "SPACE", strlen("SPACE")) == 0) {
if(!mj_get_ducky_key("SPACE", 5, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
} else if(strncmp(line_tmp, "TAB", strlen("TAB")) == 0) {
if(!mj_get_ducky_key("TAB", 3, &dk)) return false;
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
return true;
}
return false;
}
void mj_process_ducky_script(
FuriHalSpiBusHandle* handle,
uint8_t* addr,
uint8_t addr_size,
uint8_t rate,
char* script,
PluginState* plugin_state) {
uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0};
char* prev_line = NULL;
inject_packet(
handle, addr, addr_size, rate, LOGITECH_HELLO, LOGITECH_HELLO_SIZE, plugin_state);
char* line = strtok(script, "\n");
while(line != NULL) {
if(strcmp(&line[strlen(line) - 1], "\r") == 0) line[strlen(line) - 1] = (char)0;
if(!mj_process_ducky_line(handle, addr, addr_size, rate, line, prev_line, plugin_state))
FURI_LOG_D(TAG, "unable to process ducky script line: %s", line);
prev_line = line;
line = strtok(NULL, "\n");
}
build_hid_packet(0, 0, hid_payload);
inject_packet(
handle,
addr,
addr_size,
rate,
hid_payload,
LOGITECH_HID_TEMPLATE_SIZE,
plugin_state); // empty hid packet at end
}
@@ -1,46 +0,0 @@
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <furi_hal_spi.h>
#include <stdio.h>
#include <string.h>
#include <nrf24.h>
#include <furi.h>
#include <furi_hal.h>
#include <toolbox/stream/file_stream.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
char* name;
uint8_t hid;
uint8_t mod;
} MJDuckyKey;
typedef struct {
FuriMutex* mutex;
bool ducky_err;
bool addr_err;
bool is_thread_running;
bool is_ducky_running;
bool is_nrf24_connected;
bool close_thread_please;
Storage* storage;
FuriThread* mjthread;
Stream* file_stream;
} PluginState;
void mj_process_ducky_script(
FuriHalSpiBusHandle* handle,
uint8_t* addr,
uint8_t addr_size,
uint8_t rate,
char* script,
PluginState* plugin_state);
#ifdef __cplusplus
}
#endif
-21
View File
@@ -1,21 +0,0 @@
App(
appid="nrf24sniff",
name="[NRF24] Sniffer",
apptype=FlipperAppType.EXTERNAL,
entry_point="nrfsniff_app",
requires=["gui"],
stack_size=2 * 1024,
fap_icon="nrfsniff_10px.png",
fap_category="GPIO",
fap_author="@mothball187 & @xMasterX",
fap_version="1.0",
fap_description="App captures addresses to use with NRF24 Mouse Jacker app to perform mousejack attacks",
fap_private_libs=[
Lib(
name="nrf24",
sources=[
"nrf24.c",
],
),
],
)
-546
View File
@@ -1,546 +0,0 @@
#include "nrf24.h"
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_resources.h>
#include <assert.h>
#include <string.h>
void nrf24_init() {
// this is needed if multiple SPI devices are connected to the same bus but with different CS pins
if(xtreme_settings.spi_nrf24_handle == SpiDefault) {
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeOutputPushPull);
furi_hal_gpio_write(&gpio_ext_pc3, true);
} else if(xtreme_settings.spi_nrf24_handle == SpiExtra) {
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
furi_hal_gpio_write(&gpio_ext_pa4, true);
}
furi_hal_spi_bus_handle_init(nrf24_HANDLE);
furi_hal_spi_acquire(nrf24_HANDLE);
furi_hal_gpio_init(nrf24_CE_PIN, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
furi_hal_gpio_write(nrf24_CE_PIN, false);
}
void nrf24_deinit() {
furi_hal_spi_release(nrf24_HANDLE);
furi_hal_spi_bus_handle_deinit(nrf24_HANDLE);
furi_hal_gpio_write(nrf24_CE_PIN, false);
furi_hal_gpio_init(nrf24_CE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
// resetting the CS pins to floating
if(xtreme_settings.spi_nrf24_handle == SpiDefault) {
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeAnalog);
} else if(xtreme_settings.spi_nrf24_handle == SpiExtra) {
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog);
}
}
void nrf24_spi_trx(
FuriHalSpiBusHandle* handle,
uint8_t* tx,
uint8_t* rx,
uint8_t size,
uint32_t timeout) {
UNUSED(timeout);
furi_hal_gpio_write(handle->cs, false);
furi_hal_spi_bus_trx(handle, tx, rx, size, nrf24_TIMEOUT);
furi_hal_gpio_write(handle->cs, true);
}
uint8_t nrf24_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t data) {
uint8_t tx[2] = {W_REGISTER | (REGISTER_MASK & reg), data};
uint8_t rx[2] = {0};
nrf24_spi_trx(handle, tx, rx, 2, nrf24_TIMEOUT);
return rx[0];
}
uint8_t
nrf24_write_buf_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size) {
uint8_t tx[size + 1];
uint8_t rx[size + 1];
memset(rx, 0, size + 1);
tx[0] = W_REGISTER | (REGISTER_MASK & reg);
memcpy(&tx[1], data, size);
nrf24_spi_trx(handle, tx, rx, size + 1, nrf24_TIMEOUT);
return rx[0];
}
uint8_t nrf24_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size) {
uint8_t tx[size + 1];
uint8_t rx[size + 1];
memset(rx, 0, size + 1);
tx[0] = R_REGISTER | (REGISTER_MASK & reg);
memset(&tx[1], 0, size);
nrf24_spi_trx(handle, tx, rx, size + 1, nrf24_TIMEOUT);
memcpy(data, &rx[1], size);
return rx[0];
}
uint8_t nrf24_flush_rx(FuriHalSpiBusHandle* handle) {
uint8_t tx[] = {FLUSH_RX};
uint8_t rx[] = {0};
nrf24_spi_trx(handle, tx, rx, 1, nrf24_TIMEOUT);
return rx[0];
}
uint8_t nrf24_flush_tx(FuriHalSpiBusHandle* handle) {
uint8_t tx[] = {FLUSH_TX};
uint8_t rx[] = {0};
nrf24_spi_trx(handle, tx, rx, 1, nrf24_TIMEOUT);
return rx[0];
}
uint8_t nrf24_get_maclen(FuriHalSpiBusHandle* handle) {
uint8_t maclen;
nrf24_read_reg(handle, REG_SETUP_AW, &maclen, 1);
maclen &= 3;
return maclen + 2;
}
uint8_t nrf24_set_maclen(FuriHalSpiBusHandle* handle, uint8_t maclen) {
assert(maclen > 1 && maclen < 6);
uint8_t status = 0;
status = nrf24_write_reg(handle, REG_SETUP_AW, maclen - 2);
return status;
}
uint8_t nrf24_status(FuriHalSpiBusHandle* handle) {
uint8_t status;
uint8_t tx[] = {R_REGISTER | (REGISTER_MASK & REG_STATUS)};
nrf24_spi_trx(handle, tx, &status, 1, nrf24_TIMEOUT);
return status;
}
uint32_t nrf24_get_rate(FuriHalSpiBusHandle* handle) {
uint8_t setup = 0;
uint32_t rate = 0;
nrf24_read_reg(handle, REG_RF_SETUP, &setup, 1);
setup &= 0x28;
if(setup == 0x20)
rate = 250000; // 250kbps
else if(setup == 0x08)
rate = 2000000; // 2Mbps
else if(setup == 0x00)
rate = 1000000; // 1Mbps
return rate;
}
uint8_t nrf24_set_rate(FuriHalSpiBusHandle* handle, uint32_t rate) {
uint8_t r6 = 0;
uint8_t status = 0;
if(!rate) rate = 2000000;
nrf24_read_reg(handle, REG_RF_SETUP, &r6, 1); // RF_SETUP register
r6 = r6 & (~0x28); // Clear rate fields.
if(rate == 2000000)
r6 = r6 | 0x08;
else if(rate == 1000000)
r6 = r6;
else if(rate == 250000)
r6 = r6 | 0x20;
status = nrf24_write_reg(handle, REG_RF_SETUP, r6); // Write new rate.
return status;
}
uint8_t nrf24_get_chan(FuriHalSpiBusHandle* handle) {
uint8_t channel = 0;
nrf24_read_reg(handle, REG_RF_CH, &channel, 1);
return channel;
}
uint8_t nrf24_set_chan(FuriHalSpiBusHandle* handle, uint8_t chan) {
uint8_t status;
status = nrf24_write_reg(handle, REG_RF_CH, chan);
return status;
}
uint8_t nrf24_get_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac) {
uint8_t size = 0;
uint8_t status = 0;
size = nrf24_get_maclen(handle);
status = nrf24_read_reg(handle, REG_RX_ADDR_P0, mac, size);
return status;
}
uint8_t nrf24_set_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size) {
uint8_t status = 0;
uint8_t clearmac[] = {0, 0, 0, 0, 0};
nrf24_set_maclen(handle, size);
nrf24_write_buf_reg(handle, REG_RX_ADDR_P0, clearmac, 5);
status = nrf24_write_buf_reg(handle, REG_RX_ADDR_P0, mac, size);
return status;
}
uint8_t nrf24_get_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac) {
uint8_t size = 0;
uint8_t status = 0;
size = nrf24_get_maclen(handle);
status = nrf24_read_reg(handle, REG_TX_ADDR, mac, size);
return status;
}
uint8_t nrf24_set_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size) {
uint8_t status = 0;
uint8_t clearmac[] = {0, 0, 0, 0, 0};
nrf24_set_maclen(handle, size);
nrf24_write_buf_reg(handle, REG_TX_ADDR, clearmac, 5);
status = nrf24_write_buf_reg(handle, REG_TX_ADDR, mac, size);
return status;
}
uint8_t nrf24_get_packetlen(FuriHalSpiBusHandle* handle) {
uint8_t len = 0;
nrf24_read_reg(handle, RX_PW_P0, &len, 1);
return len;
}
uint8_t nrf24_set_packetlen(FuriHalSpiBusHandle* handle, uint8_t len) {
uint8_t status = 0;
status = nrf24_write_reg(handle, RX_PW_P0, len);
return status;
}
uint8_t
nrf24_rxpacket(FuriHalSpiBusHandle* handle, uint8_t* packet, uint8_t* packetsize, bool full) {
uint8_t status = 0;
uint8_t size = 0;
uint8_t tx_pl_wid[] = {R_RX_PL_WID, 0};
uint8_t rx_pl_wid[] = {0, 0};
uint8_t tx_cmd[33] = {0}; // 32 max payload size + 1 for command
uint8_t tmp_packet[33] = {0};
status = nrf24_status(handle);
if(status & 0x40) {
if(full)
size = nrf24_get_packetlen(handle);
else {
nrf24_spi_trx(handle, tx_pl_wid, rx_pl_wid, 2, nrf24_TIMEOUT);
size = rx_pl_wid[1];
}
tx_cmd[0] = R_RX_PAYLOAD;
nrf24_spi_trx(handle, tx_cmd, tmp_packet, size + 1, nrf24_TIMEOUT);
nrf24_write_reg(handle, REG_STATUS, 0x40); // clear bit.
memcpy(packet, &tmp_packet[1], size);
} else if(status == 0) {
nrf24_flush_rx(handle);
nrf24_write_reg(handle, REG_STATUS, 0x40); // clear bit.
}
*packetsize = size;
return status;
}
uint8_t nrf24_txpacket(FuriHalSpiBusHandle* handle, uint8_t* payload, uint8_t size, bool ack) {
uint8_t status = 0;
uint8_t tx[size + 1];
uint8_t rx[size + 1];
memset(tx, 0, size + 1);
memset(rx, 0, size + 1);
if(!ack)
tx[0] = W_TX_PAYLOAD_NOACK;
else
tx[0] = W_TX_PAYLOAD;
memcpy(&tx[1], payload, size);
nrf24_spi_trx(handle, tx, rx, size + 1, nrf24_TIMEOUT);
nrf24_set_tx_mode(handle);
while(!(status & (TX_DS | MAX_RT))) status = nrf24_status(handle);
if(status & MAX_RT) nrf24_flush_tx(handle);
nrf24_set_idle(handle);
nrf24_write_reg(handle, REG_STATUS, TX_DS | MAX_RT);
return status & TX_DS;
}
uint8_t nrf24_power_up(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg = cfg | 2;
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
furi_delay_ms(5000);
return status;
}
uint8_t nrf24_set_idle(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg &= 0xfc; // clear bottom two bits to power down the radio
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
//nr204_write_reg(handle, REG_EN_RXADDR, 0x0);
furi_hal_gpio_write(nrf24_CE_PIN, false);
return status;
}
uint8_t nrf24_set_rx_mode(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
//status = nrf24_write_reg(handle, REG_CONFIG, 0x0F); // enable 2-byte CRC, PWR_UP, and PRIM_RX
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg |= 0x03; // PWR_UP, and PRIM_RX
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
//nr204_write_reg(REG_EN_RXADDR, 0x03) // Set RX Pipe 0 and 1
furi_hal_gpio_write(nrf24_CE_PIN, true);
furi_delay_ms(2000);
return status;
}
uint8_t nrf24_set_tx_mode(FuriHalSpiBusHandle* handle) {
uint8_t status = 0;
uint8_t cfg = 0;
furi_hal_gpio_write(nrf24_CE_PIN, false);
nrf24_write_reg(handle, REG_STATUS, 0x30);
//status = nrf24_write_reg(handle, REG_CONFIG, 0x0E); // enable 2-byte CRC, PWR_UP
nrf24_read_reg(handle, REG_CONFIG, &cfg, 1);
cfg &= 0xfe; // disable PRIM_RX
cfg |= 0x02; // PWR_UP
status = nrf24_write_reg(handle, REG_CONFIG, cfg);
furi_hal_gpio_write(nrf24_CE_PIN, true);
furi_delay_ms(2);
return status;
}
void nrf24_configure(
FuriHalSpiBusHandle* handle,
uint8_t rate,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t channel,
bool noack,
bool disable_aa) {
assert(channel <= 125);
assert(rate == 1 || rate == 2);
if(rate == 2)
rate = 8; // 2Mbps
else
rate = 0; // 1Mbps
nrf24_write_reg(handle, REG_CONFIG, 0x00); // Stop nRF
nrf24_set_idle(handle);
nrf24_write_reg(handle, REG_STATUS, 0x1c); // clear interrupts
if(disable_aa)
nrf24_write_reg(handle, REG_EN_AA, 0x00); // Disable Shockburst
else
nrf24_write_reg(handle, REG_EN_AA, 0x1F); // Enable Shockburst
nrf24_write_reg(handle, REG_DYNPD, 0x3F); // enable dynamic payload length on all pipes
if(noack)
nrf24_write_reg(handle, REG_FEATURE, 0x05); // disable payload-with-ack, enable noack
else {
nrf24_write_reg(handle, REG_CONFIG, 0x0C); // 2 byte CRC
nrf24_write_reg(handle, REG_FEATURE, 0x07); // enable dyn payload and ack
nrf24_write_reg(
handle, REG_SETUP_RETR, 0x1f); // 15 retries for AA, 500us auto retransmit delay
}
nrf24_set_idle(handle);
nrf24_flush_rx(handle);
nrf24_flush_tx(handle);
if(maclen) nrf24_set_maclen(handle, maclen);
if(srcmac) nrf24_set_src_mac(handle, srcmac, maclen);
if(dstmac) nrf24_set_dst_mac(handle, dstmac, maclen);
nrf24_write_reg(handle, REG_RF_CH, channel);
nrf24_write_reg(handle, REG_RF_SETUP, rate);
furi_delay_ms(200);
}
void nrf24_init_promisc_mode(FuriHalSpiBusHandle* handle, uint8_t channel, uint8_t rate) {
//uint8_t preamble[] = {0x55, 0x00}; // little endian
uint8_t preamble[] = {0xAA, 0x00}; // little endian
//uint8_t preamble[] = {0x00, 0x55}; // little endian
//uint8_t preamble[] = {0x00, 0xAA}; // little endian
nrf24_write_reg(handle, REG_CONFIG, 0x00); // Stop nRF
nrf24_write_reg(handle, REG_STATUS, 0x1c); // clear interrupts
nrf24_write_reg(handle, REG_DYNPD, 0x0); // disable shockburst
nrf24_write_reg(handle, REG_EN_AA, 0x00); // Disable Shockburst
nrf24_write_reg(handle, REG_FEATURE, 0x05); // disable payload-with-ack, enable noack
nrf24_set_maclen(handle, 2); // shortest address
nrf24_set_src_mac(handle, preamble, 2); // set src mac to preamble bits to catch everything
nrf24_set_packetlen(handle, 32); // set max packet length
nrf24_set_idle(handle);
nrf24_flush_rx(handle);
nrf24_flush_tx(handle);
nrf24_write_reg(handle, REG_RF_CH, channel);
nrf24_write_reg(handle, REG_RF_SETUP, rate);
// prime for RX, no checksum
nrf24_write_reg(handle, REG_CONFIG, 0x03); // PWR_UP and PRIM_RX, disable AA and CRC
furi_hal_gpio_write(nrf24_CE_PIN, true);
furi_delay_ms(100);
}
void hexlify(uint8_t* in, uint8_t size, char* out) {
memset(out, 0, size * 2);
for(int i = 0; i < size; i++)
snprintf(out + strlen(out), sizeof(out + strlen(out)), "%02X", in[i]);
}
uint64_t bytes_to_int64(uint8_t* bytes, uint8_t size, bool bigendian) {
uint64_t ret = 0;
for(int i = 0; i < size; i++)
if(bigendian)
ret |= bytes[i] << ((size - 1 - i) * 8);
else
ret |= bytes[i] << (i * 8);
return ret;
}
void int64_to_bytes(uint64_t val, uint8_t* out, bool bigendian) {
for(int i = 0; i < 8; i++) {
if(bigendian)
out[i] = (val >> ((7 - i) * 8)) & 0xff;
else
out[i] = (val >> (i * 8)) & 0xff;
}
}
uint32_t bytes_to_int32(uint8_t* bytes, bool bigendian) {
uint32_t ret = 0;
for(int i = 0; i < 4; i++)
if(bigendian)
ret |= bytes[i] << ((3 - i) * 8);
else
ret |= bytes[i] << (i * 8);
return ret;
}
void int32_to_bytes(uint32_t val, uint8_t* out, bool bigendian) {
for(int i = 0; i < 4; i++) {
if(bigendian)
out[i] = (val >> ((3 - i) * 8)) & 0xff;
else
out[i] = (val >> (i * 8)) & 0xff;
}
}
uint64_t bytes_to_int16(uint8_t* bytes, bool bigendian) {
uint16_t ret = 0;
for(int i = 0; i < 2; i++)
if(bigendian)
ret |= bytes[i] << ((1 - i) * 8);
else
ret |= bytes[i] << (i * 8);
return ret;
}
void int16_to_bytes(uint16_t val, uint8_t* out, bool bigendian) {
for(int i = 0; i < 2; i++) {
if(bigendian)
out[i] = (val >> ((1 - i) * 8)) & 0xff;
else
out[i] = (val >> (i * 8)) & 0xff;
}
}
// handle iffyness with preamble processing sometimes being a bit (literally) off
void alt_address_old(uint8_t* packet, uint8_t* altaddr) {
uint8_t macmess_hi_b[4];
uint8_t macmess_lo_b[2];
uint32_t macmess_hi;
uint16_t macmess_lo;
uint8_t preserved;
// get first 6 bytes into 32-bit and 16-bit variables
memcpy(macmess_hi_b, packet, 4);
memcpy(macmess_lo_b, packet + 4, 2);
macmess_hi = bytes_to_int32(macmess_hi_b, true);
//preserve least 7 bits from hi that will be shifted down to lo
preserved = macmess_hi & 0x7f;
macmess_hi >>= 7;
macmess_lo = bytes_to_int16(macmess_lo_b, true);
macmess_lo >>= 7;
macmess_lo = (preserved << 9) | macmess_lo;
int32_to_bytes(macmess_hi, macmess_hi_b, true);
int16_to_bytes(macmess_lo, macmess_lo_b, true);
memcpy(altaddr, &macmess_hi_b[1], 3);
memcpy(altaddr + 3, macmess_lo_b, 2);
}
bool validate_address(uint8_t* addr) {
uint8_t bad[][3] = {{0x55, 0x55}, {0xAA, 0xAA}, {0x00, 0x00}, {0xFF, 0xFF}};
for(int i = 0; i < 4; i++)
for(int j = 0; j < 2; j++)
if(!memcmp(addr + j * 2, bad[i], 2)) return false;
return true;
}
bool nrf24_sniff_address(FuriHalSpiBusHandle* handle, uint8_t maclen, uint8_t* address) {
bool found = false;
uint8_t packet[32] = {0};
uint8_t packetsize;
//char printit[65];
uint8_t status = 0;
status = nrf24_rxpacket(handle, packet, &packetsize, true);
if(status & 0x40) {
if(validate_address(packet)) {
for(int i = 0; i < maclen; i++) address[i] = packet[maclen - 1 - i];
/*
alt_address(packet, packet);
for(i = 0; i < maclen; i++)
address[i + 5] = packet[maclen - 1 - i];
*/
//memcpy(address, packet, maclen);
//hexlify(packet, packetsize, printit);
found = true;
}
}
return found;
}
uint8_t nrf24_find_channel(
FuriHalSpiBusHandle* handle,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t rate,
uint8_t min_channel,
uint8_t max_channel,
bool autoinit) {
uint8_t ping_packet[] = {0x0f, 0x0f, 0x0f, 0x0f}; // this can be anything, we just need an ack
uint8_t ch = max_channel + 1; // means fail
nrf24_configure(handle, rate, srcmac, dstmac, maclen, 2, false, false);
for(ch = min_channel; ch <= max_channel + 1; ch++) {
nrf24_write_reg(handle, REG_RF_CH, ch);
if(nrf24_txpacket(handle, ping_packet, 4, true)) break;
}
if(autoinit) {
FURI_LOG_D("nrf24", "initializing radio for channel %d", ch);
nrf24_configure(handle, rate, srcmac, dstmac, maclen, ch, false, false);
return ch;
}
return ch;
}
bool nrf24_check_connected(FuriHalSpiBusHandle* handle) {
uint8_t status = nrf24_status(handle);
if(status != 0x00) {
return true;
} else {
return false;
}
}
-376
View File
@@ -1,376 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <furi_hal_spi.h>
#include <xtreme.h>
#ifdef __cplusplus
extern "C" {
#endif
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define ACTIVATE 0x50
#define R_RX_PL_WID 0x60
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define W_TX_PAYLOAD_NOACK 0xB0
#define W_ACK_PAYLOAD 0xA8
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define RF24_NOP 0xFF
#define REG_CONFIG 0x00
#define REG_EN_AA 0x01
#define REG_EN_RXADDR 0x02
#define REG_SETUP_AW 0x03
#define REG_SETUP_RETR 0x04
#define REG_DYNPD 0x1C
#define REG_FEATURE 0x1D
#define REG_RF_SETUP 0x06
#define REG_STATUS 0x07
#define REG_RX_ADDR_P0 0x0A
#define REG_RF_CH 0x05
#define REG_TX_ADDR 0x10
#define RX_PW_P0 0x11
#define TX_DS 0x20
#define MAX_RT 0x10
#define nrf24_TIMEOUT 500
#define nrf24_CE_PIN &gpio_ext_pb2
#define nrf24_HANDLE \
(xtreme_settings.spi_nrf24_handle == SpiDefault ? &furi_hal_spi_bus_handle_external : \
&furi_hal_spi_bus_handle_external_extra)
/* Low level API */
/** Write device register
*
* @param handle - pointer to FuriHalSpiHandle
* @param reg - register
* @param data - data to write
*
* @return device status
*/
uint8_t nrf24_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t data);
/** Write buffer to device register
*
* @param handle - pointer to FuriHalSpiHandle
* @param reg - register
* @param data - data to write
* @param size - size of data to write
*
* @return device status
*/
uint8_t nrf24_write_buf_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size);
/** Read device register
*
* @param handle - pointer to FuriHalSpiHandle
* @param reg - register
* @param[out] data - pointer to data
*
* @return device status
*/
uint8_t nrf24_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data, uint8_t size);
/** Power up the radio for operation
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_power_up(FuriHalSpiBusHandle* handle);
/** Power down the radio
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_set_idle(FuriHalSpiBusHandle* handle);
/** Sets the radio to RX mode
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_set_rx_mode(FuriHalSpiBusHandle* handle);
/** Sets the radio to TX mode
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_set_tx_mode(FuriHalSpiBusHandle* handle);
/*=============================================================================================================*/
/* High level API */
/** Must call this before using any other nrf24 API
*
*/
void nrf24_init();
/** Must call this when we end using nrf24 device
*
*/
void nrf24_deinit();
/** Send flush rx command
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_flush_rx(FuriHalSpiBusHandle* handle);
/** Send flush tx command
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return device status
*/
uint8_t nrf24_flush_tx(FuriHalSpiBusHandle* handle);
/** Gets the RX packet length in data pipe 0
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return packet length in data pipe 0
*/
uint8_t nrf24_get_packetlen(FuriHalSpiBusHandle* handle);
/** Sets the RX packet length in data pipe 0
*
* @param handle - pointer to FuriHalSpiHandle
* @param len - length to set
*
* @return device status
*/
uint8_t nrf24_set_packetlen(FuriHalSpiBusHandle* handle, uint8_t len);
/** Gets configured length of MAC address
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return MAC address length
*/
uint8_t nrf24_get_maclen(FuriHalSpiBusHandle* handle);
/** Sets configured length of MAC address
*
* @param handle - pointer to FuriHalSpiHandle
* @param maclen - length to set MAC address to, must be greater than 1 and less than 6
*
* @return MAC address length
*/
uint8_t nrf24_set_maclen(FuriHalSpiBusHandle* handle, uint8_t maclen);
/** Gets the current status flags from the STATUS register
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return status flags
*/
uint8_t nrf24_status(FuriHalSpiBusHandle* handle);
/** Gets the current transfer rate
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return transfer rate in bps
*/
uint32_t nrf24_get_rate(FuriHalSpiBusHandle* handle);
/** Sets the transfer rate
*
* @param handle - pointer to FuriHalSpiHandle
* @param rate - the transfer rate in bps
*
* @return device status
*/
uint8_t nrf24_set_rate(FuriHalSpiBusHandle* handle, uint32_t rate);
/** Gets the current channel
* In nrf24, the channel number is multiplied times 1MHz and added to 2400MHz to get the frequency
*
* @param handle - pointer to FuriHalSpiHandle
*
* @return channel
*/
uint8_t nrf24_get_chan(FuriHalSpiBusHandle* handle);
/** Sets the channel
*
* @param handle - pointer to FuriHalSpiHandle
* @param frequency - the frequency in hertz
*
* @return device status
*/
uint8_t nrf24_set_chan(FuriHalSpiBusHandle* handle, uint8_t chan);
/** Gets the source mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param[out] mac - the source mac address
*
* @return device status
*/
uint8_t nrf24_get_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac);
/** Sets the source mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param mac - the mac address to set
* @param size - the size of the mac address (2 to 5)
*
* @return device status
*/
uint8_t nrf24_set_src_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size);
/** Gets the dest mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param[out] mac - the source mac address
*
* @return device status
*/
uint8_t nrf24_get_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac);
/** Sets the dest mac address
*
* @param handle - pointer to FuriHalSpiHandle
* @param mac - the mac address to set
* @param size - the size of the mac address (2 to 5)
*
* @return device status
*/
uint8_t nrf24_set_dst_mac(FuriHalSpiBusHandle* handle, uint8_t* mac, uint8_t size);
/** Reads RX packet
*
* @param handle - pointer to FuriHalSpiHandle
* @param[out] packet - the packet contents
* @param[out] packetsize - size of the received packet
* @param full - boolean set to true, packet length is determined by RX_PW_P0 register, false it is determined by dynamic payload length command
*
* @return device status
*/
uint8_t
nrf24_rxpacket(FuriHalSpiBusHandle* handle, uint8_t* packet, uint8_t* packetsize, bool full);
/** Sends TX packet
*
* @param handle - pointer to FuriHalSpiHandle
* @param packet - the packet contents
* @param size - packet size
* @param ack - boolean to determine whether an ACK is required for the packet or not
*
* @return device status
*/
uint8_t nrf24_txpacket(FuriHalSpiBusHandle* handle, uint8_t* payload, uint8_t size, bool ack);
/** Configure the radio
* This is not comprehensive, but covers a lot of the common configuration options that may be changed
* @param handle - pointer to FuriHalSpiHandle
* @param rate - transfer rate in Mbps (1 or 2)
* @param srcmac - source mac address
* @param dstmac - destination mac address
* @param maclen - length of mac address
* @param channel - channel to tune to
* @param noack - if true, disable auto-acknowledge
* @param disable_aa - if true, disable ShockBurst
*
*/
void nrf24_configure(
FuriHalSpiBusHandle* handle,
uint8_t rate,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t channel,
bool noack,
bool disable_aa);
/** Configures the radio for "promiscuous mode" and primes it for rx
* This is not an actual mode of the nrf24, but this function exploits a few bugs in the chip that allows it to act as if it were.
* See http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html for details.
* @param handle - pointer to FuriHalSpiHandle
* @param channel - channel to tune to
* @param rate - transfer rate in Mbps (1 or 2)
*/
void nrf24_init_promisc_mode(FuriHalSpiBusHandle* handle, uint8_t channel, uint8_t rate);
/** Listens for a packet and returns first possible address sniffed
* Call this only after calling nrf24_init_promisc_mode
* @param handle - pointer to FuriHalSpiHandle
* @param maclen - length of target mac address
* @param[out] addresses - sniffed address
*
* @return success
*/
bool nrf24_sniff_address(FuriHalSpiBusHandle* handle, uint8_t maclen, uint8_t* address);
/** Sends ping packet on each channel for designated tx mac looking for ack
*
* @param handle - pointer to FuriHalSpiHandle
* @param srcmac - source address
* @param dstmac - destination address
* @param maclen - length of address
* @param rate - transfer rate in Mbps (1 or 2)
* @param min_channel - channel to start with
* @param max_channel - channel to end at
* @param autoinit - if true, automatically configure radio for this channel
*
* @return channel that the address is listening on, if this value is above the max_channel param, it failed
*/
uint8_t nrf24_find_channel(
FuriHalSpiBusHandle* handle,
uint8_t* srcmac,
uint8_t* dstmac,
uint8_t maclen,
uint8_t rate,
uint8_t min_channel,
uint8_t max_channel,
bool autoinit);
/** Converts 64 bit value into uint8_t array
* @param val - 64-bit integer
* @param[out] out - bytes out
* @param bigendian - if true, convert as big endian, otherwise little endian
*/
void int64_to_bytes(uint64_t val, uint8_t* out, bool bigendian);
/** Converts 32 bit value into uint8_t array
* @param val - 32-bit integer
* @param[out] out - bytes out
* @param bigendian - if true, convert as big endian, otherwise little endian
*/
void int32_to_bytes(uint32_t val, uint8_t* out, bool bigendian);
/** Converts uint8_t array into 32 bit value
* @param bytes - uint8_t array
* @param bigendian - if true, convert as big endian, otherwise little endian
*
* @return 32-bit value
*/
uint32_t bytes_to_int32(uint8_t* bytes, bool bigendian);
/** Check if the nrf24 is connected
* @param handle - pointer to FuriHalSpiHandle
*
* @return true if connected, otherwise false
*/
bool nrf24_check_connected(FuriHalSpiBusHandle* handle);
#ifdef __cplusplus
}
#endif
-473
View File
@@ -1,473 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <notification/notification_messages.h>
#include <stdlib.h>
#include <nrf24.h>
#include <toolbox/stream/file_stream.h>
#define LOGITECH_MAX_CHANNEL 85
#define COUNT_THRESHOLD 2
#define DEFAULT_SAMPLE_TIME 4000
#define MAX_ADDRS 100
#define MAX_CONFIRMED 32
#define NRFSNIFF_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX
#define NRFSNIFF_APP_FILENAME "addresses.txt"
#define TAG "nrfsniff"
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType type;
InputEvent input;
} PluginEvent;
typedef struct {
FuriMutex* mutex;
} PluginState;
char rate_text_fmt[] = "Transfer rate: %dMbps";
char sample_text_fmt[] = "Sample Time: %d ms";
char channel_text_fmt[] = "Channel: %d Sniffing: %s";
char preamble_text_fmt[] = "Preamble: %02X";
char sniff_text_fmt[] = "Found: %d Unique: %u";
char addresses_header_text[] = "Address,rate";
char sniffed_address_fmt[] = "%s,%d";
char rate_text[46];
char channel_text[38];
char sample_text[32];
char preamble_text[14];
char sniff_text[38];
char sniffed_address[14];
uint8_t target_channel = 0;
uint32_t found_count = 0;
uint32_t unique_saved_count = 0;
uint32_t sample_time = DEFAULT_SAMPLE_TIME;
uint8_t target_rate = 8; // rate can be either 8 (2Mbps) or 0 (1Mbps)
uint8_t target_preamble[] = {0xAA, 0x00};
uint8_t sniffing_state = false;
char top_address[12];
uint8_t candidates[MAX_ADDRS][5] = {0}; // last 100 sniffed addresses
uint32_t counts[MAX_ADDRS];
uint8_t confirmed[MAX_CONFIRMED][5] = {0}; // first 32 confirmed addresses
uint8_t confirmed_idx = 0;
uint32_t total_candidates = 0;
uint32_t candidate_idx = 0;
static int get_addr_index(uint8_t* addr, uint8_t addr_size) {
for(uint32_t i = 0; i < total_candidates; i++) {
uint8_t* arr_item = candidates[i];
if(!memcmp(arr_item, addr, addr_size)) return i;
}
return -1;
}
static int get_highest_idx() {
uint32_t highest = 0;
int highest_idx = 0;
for(uint32_t i = 0; i < total_candidates; i++) {
if(counts[i] > highest) {
highest = counts[i];
highest_idx = i;
}
}
return highest_idx;
}
// if array is full, start over from beginning
static void insert_addr(uint8_t* addr, uint8_t addr_size) {
if(candidate_idx >= MAX_ADDRS) candidate_idx = 0;
memcpy(candidates[candidate_idx], addr, addr_size);
counts[candidate_idx] = 1;
if(total_candidates < MAX_ADDRS) total_candidates++;
candidate_idx++;
}
static void render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
const PluginState* plugin_state = ctx;
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
uint8_t rate = 2;
char sniffing[] = "Yes";
// border around the edge of the screen
canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_set_font(canvas, FontSecondary);
if(target_rate == 0) rate = 1;
if(!sniffing_state) strcpy(sniffing, "No");
snprintf(rate_text, sizeof(rate_text), rate_text_fmt, (int)rate);
snprintf(channel_text, sizeof(channel_text), channel_text_fmt, (int)target_channel, sniffing);
snprintf(sample_text, sizeof(sample_text), sample_text_fmt, (int)sample_time);
//snprintf(preamble_text, sizeof(preamble_text), preamble_text_fmt, target_preamble[0]);
snprintf(sniff_text, sizeof(sniff_text), sniff_text_fmt, found_count, unique_saved_count);
snprintf(
sniffed_address, sizeof(sniffed_address), sniffed_address_fmt, top_address, (int)rate);
canvas_draw_str_aligned(canvas, 10, 10, AlignLeft, AlignBottom, rate_text);
canvas_draw_str_aligned(canvas, 10, 20, AlignLeft, AlignBottom, sample_text);
canvas_draw_str_aligned(canvas, 10, 30, AlignLeft, AlignBottom, channel_text);
//canvas_draw_str_aligned(canvas, 10, 30, AlignLeft, AlignBottom, preamble_text);
canvas_draw_str_aligned(canvas, 10, 40, AlignLeft, AlignBottom, sniff_text);
canvas_draw_str_aligned(canvas, 30, 50, AlignLeft, AlignBottom, addresses_header_text);
canvas_draw_str_aligned(canvas, 30, 60, AlignLeft, AlignBottom, sniffed_address);
furi_mutex_release(plugin_state->mutex);
}
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void hexlify(uint8_t* in, uint8_t size, char* out) {
memset(out, 0, size * 2);
for(int i = 0; i < size; i++)
snprintf(out + strlen(out), sizeof(out + strlen(out)), "%02X", in[i]);
}
static bool save_addr_to_file(
Storage* storage,
uint8_t* data,
uint8_t size,
NotificationApp* notification) {
size_t file_size = 0;
uint8_t linesize = 0;
char filepath[42] = {0};
char addrline[14] = {0};
char ending[4];
uint8_t* file_contents;
uint8_t rate = 1;
Stream* stream = file_stream_alloc(storage);
if(target_rate == 8) rate = 2;
snprintf(ending, sizeof(ending), ",%d\n", rate);
hexlify(data, size, addrline);
strcat(addrline, ending);
linesize = strlen(addrline);
strcpy(filepath, NRFSNIFF_APP_PATH_FOLDER);
strcat(filepath, "/");
strcat(filepath, NRFSNIFF_APP_FILENAME);
stream_seek(stream, 0, StreamOffsetFromStart);
// check if address already exists in file
if(file_stream_open(stream, filepath, FSAM_READ_WRITE, FSOM_OPEN_APPEND)) {
bool found = false;
file_size = stream_size(stream);
stream_seek(stream, 0, StreamOffsetFromStart);
if(file_size > 0) {
file_contents = malloc(file_size + 1);
memset(file_contents, 0, file_size + 1);
if(stream_read(stream, file_contents, file_size) > 0) {
char* line = strtok((char*)file_contents, "\n");
while(line != NULL) {
if(!memcmp(line, addrline, 12)) {
found = true;
break;
}
line = strtok(NULL, "\n");
}
}
free(file_contents);
}
if(found) {
FURI_LOG_I(TAG, "Address exists in file. Ending save process.");
stream_free(stream);
return false;
} else {
if(stream_write(stream, (uint8_t*)addrline, linesize) != linesize) {
FURI_LOG_I(TAG, "Failed to write bytes to file stream.");
stream_free(stream);
return false;
} else {
FURI_LOG_I(TAG, "Found a new address: %s", addrline);
FURI_LOG_I(TAG, "Save successful!");
notification_message(notification, &sequence_success);
stream_free(stream);
unique_saved_count++;
return true;
}
}
} else {
FURI_LOG_I(TAG, "Cannot open file \"%s\"", filepath);
stream_free(stream);
return false;
}
}
void alt_address(uint8_t* addr, uint8_t* altaddr) {
uint8_t macmess_hi_b[4];
uint32_t macmess_hi;
uint8_t macmess_lo;
uint8_t preserved;
uint8_t tmpaddr[5];
// swap bytes
for(int i = 0; i < 5; i++) tmpaddr[i] = addr[4 - i];
// get address into 32-bit and 8-bit variables
memcpy(macmess_hi_b, tmpaddr, 4);
macmess_lo = tmpaddr[4];
macmess_hi = bytes_to_int32(macmess_hi_b, true);
//preserve lowest bit from hi to shift to low
preserved = macmess_hi & 1;
macmess_hi >>= 1;
macmess_lo >>= 1;
macmess_lo = (preserved << 7) | macmess_lo;
int32_to_bytes(macmess_hi, macmess_hi_b, true);
memcpy(tmpaddr, macmess_hi_b, 4);
tmpaddr[4] = macmess_lo;
// swap bytes back
for(int i = 0; i < 5; i++) altaddr[i] = tmpaddr[4 - i];
}
static bool previously_confirmed(uint8_t* addr) {
bool found = false;
for(int i = 0; i < MAX_CONFIRMED; i++) {
if(!memcmp(confirmed[i], addr, 5)) {
found = true;
break;
}
}
return found;
}
static void wrap_up(Storage* storage, NotificationApp* notification) {
uint8_t ch;
uint8_t addr[5];
uint8_t altaddr[5];
char trying[12];
int idx;
uint8_t rate = 0;
if(target_rate == 8) rate = 2;
nrf24_set_idle(nrf24_HANDLE);
while(true) {
idx = get_highest_idx();
if(counts[idx] < COUNT_THRESHOLD) break;
counts[idx] = 0;
memcpy(addr, candidates[idx], 5);
hexlify(addr, 5, trying);
FURI_LOG_I(TAG, "trying address %s", trying);
ch = nrf24_find_channel(nrf24_HANDLE, addr, addr, 5, rate, 2, LOGITECH_MAX_CHANNEL, false);
FURI_LOG_I(TAG, "find_channel returned %d", (int)ch);
if(ch > LOGITECH_MAX_CHANNEL) {
alt_address(addr, altaddr);
hexlify(altaddr, 5, trying);
FURI_LOG_I(TAG, "trying alternate address %s", trying);
ch = nrf24_find_channel(
nrf24_HANDLE, altaddr, altaddr, 5, rate, 2, LOGITECH_MAX_CHANNEL, false);
FURI_LOG_I(TAG, "find_channel returned %d", (int)ch);
memcpy(addr, altaddr, 5);
}
if(ch <= LOGITECH_MAX_CHANNEL) {
hexlify(addr, 5, top_address);
found_count++;
save_addr_to_file(storage, addr, 5, notification);
if(confirmed_idx < MAX_CONFIRMED) memcpy(confirmed[confirmed_idx++], addr, 5);
break;
}
}
}
static void clear_cache() {
found_count = 0;
unique_saved_count = 0;
confirmed_idx = 0;
candidate_idx = 0;
target_channel = 2;
total_candidates = 0;
memset(candidates, 0, sizeof(candidates));
memset(counts, 0, sizeof(counts));
memset(confirmed, 0, sizeof(confirmed));
}
static void start_sniffing() {
nrf24_init_promisc_mode(nrf24_HANDLE, target_channel, target_rate);
}
int32_t nrfsniff_app(void* p) {
UNUSED(p);
uint8_t address[5] = {0};
uint32_t start = 0;
hexlify(address, 5, top_address);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
PluginState* plugin_state = malloc(sizeof(PluginState));
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!plugin_state->mutex) {
furi_message_queue_free(event_queue);
FURI_LOG_E(TAG, "cannot create mutex\r\n");
free(plugin_state);
return 255;
}
uint8_t attempts = 0;
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
furi_hal_power_enable_otg();
furi_delay_ms(10);
}
nrf24_init();
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, plugin_state);
view_port_input_callback_set(view_port, input_callback, event_queue);
// Open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_migrate(storage, EXT_PATH("nrfsniff"), NRFSNIFF_APP_PATH_FOLDER);
storage_common_mkdir(storage, NRFSNIFF_APP_PATH_FOLDER);
PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress ||
(event.input.type == InputTypeLong && event.input.key == InputKeyBack)) {
switch(event.input.key) {
case InputKeyUp:
// toggle rate 1/2Mbps
if(!sniffing_state) {
if(target_rate == 0)
target_rate = 8;
else
target_rate = 0;
}
break;
case InputKeyDown:
// toggle preamble
if(!sniffing_state) {
if(target_preamble[0] == 0x55)
target_preamble[0] = 0xAA;
else
target_preamble[0] = 0x55;
nrf24_set_src_mac(nrf24_HANDLE, target_preamble, 2);
}
break;
case InputKeyRight:
// increment channel
//if(!sniffing_state && target_channel <= LOGITECH_MAX_CHANNEL)
// target_channel++;
sample_time += 500;
break;
case InputKeyLeft:
// decrement channel
//if(!sniffing_state && target_channel > 0) target_channel--;
if(sample_time > 500) sample_time -= 500;
break;
case InputKeyOk:
// toggle sniffing
if(nrf24_check_connected(nrf24_HANDLE)) {
sniffing_state = !sniffing_state;
if(sniffing_state) {
clear_cache();
start_sniffing();
start = furi_get_tick();
} else {
wrap_up(storage, notification);
}
} else {
notification_message(notification, &sequence_error);
}
break;
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}
}
if(sniffing_state) {
if(nrf24_sniff_address(nrf24_HANDLE, 5, address)) {
int idx;
uint8_t* top_addr;
if(!previously_confirmed(address)) {
idx = get_addr_index(address, 5);
if(idx == -1)
insert_addr(address, 5);
else
counts[idx]++;
top_addr = candidates[get_highest_idx()];
hexlify(top_addr, 5, top_address);
}
}
if(furi_get_tick() - start >= sample_time) {
target_channel++;
if(target_channel > LOGITECH_MAX_CHANNEL) target_channel = 2;
{
wrap_up(storage, notification);
start_sniffing();
}
start = furi_get_tick();
}
}
view_port_update(view_port);
furi_mutex_release(plugin_state->mutex);
}
clear_cache();
sample_time = DEFAULT_SAMPLE_TIME;
target_rate = 8; // rate can be either 8 (2Mbps) or 0 (1Mbps)
sniffing_state = false;
nrf24_deinit();
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_STORAGE);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(plugin_state->mutex);
free(plugin_state);
if(furi_hal_power_is_otg_enabled()) {
furi_hal_power_disable_otg();
}
return 0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

-16
View File
@@ -1,16 +0,0 @@
App(
appid="ocarina",
name="Ocarina",
apptype=FlipperAppType.EXTERNAL,
entry_point="ocarina_app",
cdefines=["APP_OCARINA"],
requires=["gui"],
stack_size=1 * 1024,
fap_icon="music_10px.png",
fap_category="Media",
fap_icon_assets="icons",
fap_author="@invalidna-me",
fap_weburl="https://github.com/invalidna-me/flipperzero-ocarina",
fap_version="1.0",
fap_description="A basic Ocarina (of Time), Controls are the same as the N64 version of the Ocarina of Time",
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

-134
View File
@@ -1,134 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#define NOTE_UP 587.33f
#define NOTE_LEFT 493.88f
#define NOTE_RIGHT 440.00f
#define NOTE_DOWN 349.23
#define NOTE_OK 293.66f
typedef struct {
FuriMutex* model_mutex;
FuriMessageQueue* event_queue;
ViewPort* view_port;
Gui* gui;
} Ocarina;
void draw_callback(Canvas* canvas, void* ctx) {
Ocarina* ocarina = ctx;
furi_check(furi_mutex_acquire(ocarina->model_mutex, FuriWaitForever) == FuriStatusOk);
//canvas_draw_box(canvas, ocarina->model->x, ocarina->model->y, 4, 4);
canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_draw_str(canvas, 50, 10, "Ocarina");
canvas_draw_str(canvas, 30, 20, "OK button for A");
furi_mutex_release(ocarina->model_mutex);
}
void input_callback(InputEvent* input, void* ctx) {
Ocarina* ocarina = ctx;
// Puts input onto event queue with priority 0, and waits until completion.
furi_message_queue_put(ocarina->event_queue, input, FuriWaitForever);
}
Ocarina* ocarina_alloc() {
Ocarina* instance = malloc(sizeof(Ocarina));
instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
instance->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
instance->view_port = view_port_alloc();
view_port_draw_callback_set(instance->view_port, draw_callback, instance);
view_port_input_callback_set(instance->view_port, input_callback, instance);
instance->gui = furi_record_open("gui");
gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
return instance;
}
void ocarina_free(Ocarina* instance) {
view_port_enabled_set(instance->view_port, false); // Disabsles our ViewPort
gui_remove_view_port(instance->gui, instance->view_port); // Removes our ViewPort from the Gui
furi_record_close("gui"); // Closes the gui record
view_port_free(instance->view_port); // Frees memory allocated by view_port_alloc
furi_message_queue_free(instance->event_queue);
furi_mutex_free(instance->model_mutex);
if(furi_hal_speaker_is_mine()) {
furi_hal_speaker_stop();
furi_hal_speaker_release();
}
free(instance);
}
int32_t ocarina_app(void* p) {
UNUSED(p);
Ocarina* ocarina = ocarina_alloc();
InputEvent event;
for(bool processing = true; processing;) {
// Pops a message off the queue and stores it in `event`.
// No message priority denoted by NULL, and 100 ticks of timeout.
FuriStatus status = furi_message_queue_get(ocarina->event_queue, &event, 100);
furi_check(furi_mutex_acquire(ocarina->model_mutex, FuriWaitForever) == FuriStatusOk);
float volume = 1.0f;
if(status == FuriStatusOk) {
if(event.type == InputTypePress) {
switch(event.key) {
case InputKeyUp:
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
furi_hal_speaker_start(NOTE_UP, volume);
}
break;
case InputKeyDown:
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
furi_hal_speaker_start(NOTE_DOWN, volume);
}
break;
case InputKeyLeft:
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
furi_hal_speaker_start(NOTE_LEFT, volume);
}
break;
case InputKeyRight:
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
furi_hal_speaker_start(NOTE_RIGHT, volume);
}
break;
case InputKeyOk:
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
furi_hal_speaker_start(NOTE_OK, volume);
}
break;
case InputKeyBack:
processing = false;
break;
default:
break;
}
} else if(event.type == InputTypeRelease) {
if(furi_hal_speaker_is_mine()) {
furi_hal_speaker_stop();
furi_hal_speaker_release();
}
}
}
furi_mutex_release(ocarina->model_mutex);
view_port_update(ocarina->view_port); // signals our draw callback
}
ocarina_free(ocarina);
return 0;
}
-11
View File
@@ -1,11 +0,0 @@
App(
appid="orgasmotron",
name="Orgasmotron",
apptype=FlipperAppType.EXTERNAL,
entry_point="orgasmotron_app",
cdefines=["ORGASMOTRON"],
requires=["gui"],
stack_size=1 * 1024,
fap_icon="orgasmotron_10px.png",
fap_category="Tools",
)
-163
View File
@@ -1,163 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <notification/notification_messages.h>
typedef struct {
FuriMutex* mutex;
int mode;
} PluginState;
void vibro_test_draw_callback(Canvas* canvas, void* ctx) {
UNUSED(ctx);
canvas_clear(canvas);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 2, 10, "Vibro Modes");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 22, "UP: Pulsed");
canvas_draw_str(canvas, 2, 34, "LEFT: strong / RIGHT: Soft");
canvas_draw_str(canvas, 2, 46, "DOWN: Pleasure combo");
canvas_draw_str(canvas, 2, 58, "OK: Pause");
}
void vibro_test_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}
void delay(int milliseconds) {
furi_thread_flags_wait(0, FuriFlagWaitAny, milliseconds);
}
int32_t orgasmotron_app(void* p) {
UNUSED(p);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
PluginState* plugin_state = malloc(sizeof(PluginState));
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!plugin_state->mutex) {
FURI_LOG_E("Orgasmatron", "cannot create mutex\r\n");
free(plugin_state);
return 255;
}
// Configure view port
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, vibro_test_draw_callback, NULL);
view_port_input_callback_set(view_port, vibro_test_input_callback, event_queue);
// Register view port in GUI
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
InputEvent event;
bool processing = true;
size_t i = 0;
while(processing) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 50);
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
if(event.key == InputKeyBack && event.type == InputTypeShort) {
//Exit Application
plugin_state->mode = 0;
processing = false;
}
if(event.key == InputKeyOk &&
(event.type == InputTypePress || event.type == InputTypeRelease)) {
plugin_state->mode = 0;
}
if(event.key == InputKeyLeft &&
(event.type == InputTypePress || event.type == InputTypeRelease)) {
notification_message(notification, &sequence_set_green_255);
plugin_state->mode = 1;
}
if(event.key == InputKeyRight &&
(event.type == InputTypePress || event.type == InputTypeRelease)) {
notification_message(notification, &sequence_set_green_255);
plugin_state->mode = 3;
}
if(event.key == InputKeyUp &&
(event.type == InputTypePress || event.type == InputTypeRelease)) {
notification_message(notification, &sequence_set_green_255);
plugin_state->mode = 2;
}
if(event.key == InputKeyDown &&
(event.type == InputTypePress || event.type == InputTypeRelease)) {
notification_message(notification, &sequence_set_green_255);
plugin_state->mode = 4;
}
i = 0;
}
if(plugin_state->mode == 0) {
//Stop Vibration
if(i == 0) {
notification_message(notification, &sequence_reset_vibro);
notification_message(notification, &sequence_reset_green);
i++;
}
} else if(plugin_state->mode == 1) {
//Full power
if(i == 0) {
notification_message(notification, &sequence_set_vibro_on);
i++;
}
} else if(plugin_state->mode == 2) {
//Pulsed Vibration
i++;
if(i == 1) {
notification_message(notification, &sequence_set_vibro_on);
}
if(i == 3) {
notification_message(notification, &sequence_reset_vibro);
}
if(i == 4) {
i = 0;
}
} else if(plugin_state->mode == 3) {
//Soft power
i++;
if(i == 1) {
notification_message(notification, &sequence_set_vibro_on);
}
if(i == 2) {
notification_message(notification, &sequence_reset_vibro);
i = 0;
}
} else if(plugin_state->mode == 4) {
//Special Sequence
i++;
if(i < 23) {
if(i % 2) {
notification_message(notification, &sequence_set_vibro_on);
} else {
notification_message(notification, &sequence_reset_vibro);
}
} else if(i < 40) {
if(i == 24 || i == 33) {
notification_message(notification, &sequence_set_vibro_on);
} else if(i == 32) {
notification_message(notification, &sequence_reset_vibro);
}
} else if(i == 41) {
notification_message(notification, &sequence_reset_vibro);
i = 0;
}
}
furi_mutex_release(plugin_state->mutex);
}
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_mutex_free(plugin_state->mutex);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_GUI);
return 0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

-17
View File
@@ -1,17 +0,0 @@
App(
appid="flipper_pong",
name="Pong",
apptype=FlipperAppType.EXTERNAL,
entry_point="flipper_pong_app",
cdefines=["APP_FLIPPER_PONG"],
requires=[
"gui",
],
stack_size=1 * 1024,
fap_icon="pong.png",
fap_category="Games",
fap_author="@nmrr & @SimplyMinimal",
fap_weburl="https://github.com/nmrr/flipperzero-pong",
fap_version="1.1",
fap_description="Simple pong game",
)
-293
View File
@@ -1,293 +0,0 @@
// CC0 1.0 Universal (CC0 1.0)
// Public Domain Dedication
// https://github.com/nmrr
#include <stdio.h>
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <notification/notification_messages.h>
#include <furi_hal_random.h>
#define SCREEN_SIZE_X 128
#define SCREEN_SIZE_Y 64
#define FPS 20
#define PAD_SIZE_X 3
#define PAD_SIZE_Y 8
#define PLAYER1_PAD_SPEED 4
#define PLAYER2_PAD_SPEED 2
#define BALL_SIZE 4
typedef enum {
EventTypeInput,
ClockEventTypeTick,
} EventType;
typedef struct {
EventType type;
InputEvent input;
} EventApp;
typedef struct Players {
FuriMutex* mutex;
uint8_t player1_X, player1_Y, player2_X, player2_Y;
uint16_t player1_score, player2_score;
uint8_t ball_X, ball_Y, ball_X_speed, ball_Y_speed, ball_X_direction, ball_Y_direction;
} Players;
static void draw_callback(Canvas* canvas, void* ctx) {
furi_assert(ctx);
Players* playersMutex = ctx;
furi_mutex_acquire(playersMutex->mutex, FuriWaitForever);
canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_draw_box(
canvas, playersMutex->player1_X, playersMutex->player1_Y, PAD_SIZE_X, PAD_SIZE_Y);
canvas_draw_box(
canvas, playersMutex->player2_X, playersMutex->player2_Y, PAD_SIZE_X, PAD_SIZE_Y);
canvas_draw_box(canvas, playersMutex->ball_X, playersMutex->ball_Y, BALL_SIZE, BALL_SIZE);
canvas_set_font(canvas, FontPrimary);
canvas_set_font_direction(canvas, CanvasDirectionBottomToTop);
char buffer[16];
snprintf(
buffer,
sizeof(buffer),
"%u - %u",
playersMutex->player1_score,
playersMutex->player2_score);
canvas_draw_str_aligned(
canvas, SCREEN_SIZE_X / 2 + 15, SCREEN_SIZE_Y / 2 + 2, AlignCenter, AlignTop, buffer);
furi_mutex_release(playersMutex->mutex);
}
static void input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
EventApp event = {.type = EventTypeInput, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void clock_tick(void* ctx) {
furi_assert(ctx);
FuriMessageQueue* queue = ctx;
EventApp event = {.type = ClockEventTypeTick};
furi_message_queue_put(queue, &event, 0);
}
bool insidePad(uint8_t x, uint8_t y, uint8_t playerX, uint8_t playerY) {
if(x >= playerX && x <= playerX + PAD_SIZE_X && y >= playerY && y <= playerY + PAD_SIZE_Y)
return true;
return false;
}
uint8_t changeSpeed() {
uint8_t randomuint8[1];
while(1) {
furi_hal_random_fill_buf(randomuint8, 1);
randomuint8[0] &= 0b00000011;
if(randomuint8[0] >= 1) break;
}
return randomuint8[0];
}
uint8_t changeDirection() {
uint8_t randomuint8[1];
furi_hal_random_fill_buf(randomuint8, 1);
randomuint8[0] &= 0b1;
return randomuint8[0];
}
int32_t flipper_pong_app(void* p) {
UNUSED(p);
EventApp event;
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp));
Players players;
players.player1_X = SCREEN_SIZE_X - PAD_SIZE_X - 1;
players.player1_Y = SCREEN_SIZE_Y / 2 - PAD_SIZE_Y / 2;
players.player1_score = 0;
players.player2_X = 1;
players.player2_Y = SCREEN_SIZE_Y / 2 - PAD_SIZE_Y / 2;
players.player2_score = 0;
players.ball_X = SCREEN_SIZE_X / 2 - BALL_SIZE / 2;
players.ball_Y = SCREEN_SIZE_Y / 2 - BALL_SIZE / 2;
players.ball_X_speed = 1;
players.ball_Y_speed = 1;
players.ball_X_direction = changeDirection();
players.ball_Y_direction = changeDirection();
players.mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!players.mutex) {
furi_message_queue_free(event_queue);
return 255;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, draw_callback, &players);
view_port_input_callback_set(view_port, input_callback, event_queue);
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
if(players.ball_X_direction == 0)
notification_message(notification, &sequence_set_only_red_255);
else
notification_message(notification, &sequence_set_only_blue_255);
FuriTimer* timer = furi_timer_alloc(clock_tick, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, 1000 / FPS);
while(1) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever);
furi_mutex_acquire(players.mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
if(event.type == EventTypeInput) {
if(event.input.key == InputKeyBack) {
furi_mutex_release(players.mutex);
notification_message(notification, &sequence_set_only_green_255);
break;
} else if(event.input.key == InputKeyUp) {
if(players.player1_Y >= 1 + PLAYER1_PAD_SPEED)
players.player1_Y -= PLAYER1_PAD_SPEED;
else
players.player1_Y = 1;
} else if(event.input.key == InputKeyDown) {
if(players.player1_Y <= SCREEN_SIZE_Y - PAD_SIZE_Y - PLAYER1_PAD_SPEED - 1)
players.player1_Y += PLAYER1_PAD_SPEED;
else
players.player1_Y = SCREEN_SIZE_Y - PAD_SIZE_Y - 1;
}
} else if(event.type == ClockEventTypeTick) {
if(players.ball_X + BALL_SIZE / 2 <= SCREEN_SIZE_X * 0.35 &&
players.ball_X_direction == 0) {
if(players.ball_Y + BALL_SIZE / 2 < players.player2_Y + PAD_SIZE_Y / 2) {
if(players.player2_Y >= 1 + PLAYER2_PAD_SPEED)
players.player2_Y -= PLAYER2_PAD_SPEED;
else
players.player2_Y = 1;
} else if(players.ball_Y + BALL_SIZE / 2 > players.player2_Y + PAD_SIZE_Y / 2) {
if(players.player2_Y <= SCREEN_SIZE_Y - PAD_SIZE_Y - PLAYER2_PAD_SPEED - 1)
players.player2_Y += PLAYER2_PAD_SPEED;
else
players.player2_Y = SCREEN_SIZE_Y - PAD_SIZE_Y - 1;
}
}
uint8_t ball_corner_X[4] = {
players.ball_X,
players.ball_X + BALL_SIZE,
players.ball_X + BALL_SIZE,
players.ball_X};
uint8_t ball_corner_Y[4] = {
players.ball_Y,
players.ball_Y,
players.ball_Y + BALL_SIZE,
players.ball_Y + BALL_SIZE};
bool insidePlayer1 = false, insidePlayer2 = false;
for(int i = 0; i < 4; i++) {
if(insidePad(
ball_corner_X[i],
ball_corner_Y[i],
players.player1_X,
players.player1_Y) == true) {
insidePlayer1 = true;
break;
}
if(insidePad(
ball_corner_X[i],
ball_corner_Y[i],
players.player2_X,
players.player2_Y) == true) {
insidePlayer2 = true;
break;
}
}
if(insidePlayer1 == true) {
players.ball_X_direction = 0;
players.ball_X -= players.ball_X_speed;
players.ball_X_speed = changeSpeed();
players.ball_Y_speed = changeSpeed();
notification_message(notification, &sequence_set_only_red_255);
} else if(insidePlayer2 == true) {
players.ball_X_direction = 1;
players.ball_X += players.ball_X_speed;
players.ball_X_speed = changeSpeed();
players.ball_Y_speed = changeSpeed();
notification_message(notification, &sequence_set_only_blue_255);
} else {
if(players.ball_X_direction == 1) {
if(players.ball_X <=
SCREEN_SIZE_X - BALL_SIZE - 1 - players.ball_X_speed) {
players.ball_X += players.ball_X_speed;
} else {
players.ball_X = SCREEN_SIZE_X / 2 - BALL_SIZE / 2;
players.ball_Y = SCREEN_SIZE_Y / 2 - BALL_SIZE / 2;
players.ball_X_speed = 1;
players.ball_Y_speed = 1;
players.ball_X_direction = 0;
players.player2_score++;
notification_message(notification, &sequence_set_only_red_255);
}
} else {
if(players.ball_X >= 1 + players.ball_X_speed) {
players.ball_X -= players.ball_X_speed;
} else {
players.ball_X = SCREEN_SIZE_X / 2 - BALL_SIZE / 2;
players.ball_Y = SCREEN_SIZE_Y / 2 - BALL_SIZE / 2;
players.ball_X_speed = 1;
players.ball_Y_speed = 1;
players.ball_X_direction = 1;
players.player1_score++;
notification_message(notification, &sequence_set_only_blue_255);
}
}
}
if(players.ball_Y_direction == 1) {
if(players.ball_Y <= SCREEN_SIZE_Y - BALL_SIZE - 1 - players.ball_Y_speed) {
players.ball_Y += players.ball_Y_speed;
} else {
players.ball_Y = SCREEN_SIZE_Y - BALL_SIZE - 1;
players.ball_X_speed = changeSpeed();
players.ball_Y_speed = changeSpeed();
players.ball_Y_direction = 0;
}
} else {
if(players.ball_Y >= 1 + players.ball_Y_speed) {
players.ball_Y -= players.ball_Y_speed;
} else {
players.ball_Y = 1;
players.ball_X_speed = changeSpeed();
players.ball_Y_speed = changeSpeed();
players.ball_Y_direction = 1;
}
}
}
}
furi_mutex_release(players.mutex);
view_port_update(view_port);
}
notification_message(notification, &sequence_reset_rgb);
furi_message_queue_free(event_queue);
furi_mutex_free(players.mutex);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_timer_free(timer);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
return 0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

-52
View File
@@ -1,52 +0,0 @@
App(
appid="sam",
name="SAM AYBABTU",
apptype=FlipperAppType.EXTERNAL,
entry_point="sam_app",
requires=[
"gui",
"dialogs",
],
stack_size=4 * 1024,
fap_icon="music_10px.png",
fap_category="Media",
)
App(
appid="sam_yes",
name="SAM YES",
apptype=FlipperAppType.EXTERNAL,
entry_point="sam_app_yes",
requires=[
"gui",
"dialogs",
],
stack_size=4 * 1024,
fap_icon="music_10px.png",
fap_category="Media",
)
App(
appid="sam_no",
name="SAM NO",
apptype=FlipperAppType.EXTERNAL,
entry_point="sam_app_no",
requires=[
"gui",
"dialogs",
],
stack_size=4 * 1024,
fap_icon="music_10px.png",
fap_category="Media",
)
App(
appid="sam_wtf",
name="SAM WTF",
apptype=FlipperAppType.EXTERNAL,
entry_point="sam_app_wtf",
requires=[
"gui",
"dialogs",
],
stack_size=4 * 1024,
fap_icon="music_10px.png",
fap_category="Media",
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

-46
View File
@@ -1,46 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include "stm32_sam.h"
// WOULD BE COOL IF SOMEONE MADE A TEXT ENTRY SCREEN TO HAVE IT READ WHAT IS ENTERED TO TEXT
STM32SAM voice;
extern "C" int32_t sam_app(void* p) {
UNUSED(p);
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say(
"All your base are belong to us. You have no chance to survive make your time. ha. ha. ha. GOOD BYE. ");
furi_hal_speaker_release();
}
return 0;
}
extern "C" int32_t sam_app_yes(void* p) {
UNUSED(p);
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say("Yes");
furi_hal_speaker_release();
}
return 0;
}
extern "C" int32_t sam_app_no(void* p) {
UNUSED(p);
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say("No");
furi_hal_speaker_release();
}
return 0;
}
extern "C" int32_t sam_app_wtf(void* p) {
UNUSED(p);
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say("What The Fuck");
furi_hal_speaker_release();
}
return 0;
}
File diff suppressed because it is too large Load Diff
-96
View File
@@ -1,96 +0,0 @@
#include <furi.h>
#ifndef __STM32SAM__
#define __STM32SAM__
// SAM Text-To-Speech (TTS), ported from https://github.com/s-macke/SAM
class STM32SAM {
public:
STM32SAM(uint32_t STM32SAM_SPEED);
STM32SAM();
void begin(void);
void
sam(const char* argv,
unsigned char phonetic,
unsigned char singmode,
unsigned char pitch,
unsigned char speed,
unsigned char mouth,
unsigned char throat);
void
sam(char* argv,
unsigned char phonetic,
unsigned char singmode,
unsigned char pitch,
unsigned char speed,
unsigned char mouth,
unsigned char throat);
void say(const char* argv);
void say(char* argv);
void sing(const char* argv);
void sing(char* argv);
void sayPhonetic(const char* argv);
void sayPhonetic(char* argv);
void singPhonetic(const char* argv);
void singPhonetic(char* argv);
void setVoice(
unsigned char _pitch = 64,
unsigned char _speed = 72,
unsigned char _mouth = 128,
unsigned char _throat = 128);
void setPitch(unsigned char _pitch = 64);
void setSpeed(unsigned char _speed = 72);
void setMouth(unsigned char _mouth = 128);
void setThroat(unsigned char _throat = 128);
private:
void SetAUDIO(unsigned char main_volume);
void Output8BitAry(int index, unsigned char ary[5]);
void Output8Bit(int index, unsigned char A);
unsigned char Read(unsigned char p, unsigned char Y);
void Write(unsigned char p, unsigned char Y, unsigned char value);
void RenderSample(unsigned char* mem66);
void Render();
void AddInflection(unsigned char mem48, unsigned char phase1);
void SetMouthThroat();
unsigned char trans(unsigned char mem39212, unsigned char mem39213);
void SetInput(char* _input);
void Init();
int SAMMain();
void PrepareOutput();
void Insert(
unsigned char position /*var57*/,
unsigned char mem60,
unsigned char mem59,
unsigned char mem58);
void InsertBreath();
void CopyStress();
int Parser1();
void SetPhonemeLength();
void Code41240();
void Parser2();
void AdjustLengths();
void Code47503(unsigned char mem52);
void Code37055(unsigned char mem59);
void Code37066(unsigned char mem58);
unsigned char GetRuleByte(unsigned short mem62, unsigned char Y);
int TextToPhonemes(unsigned char* input); // Code36484
uint32_t _STM32SAM_SPEED;
unsigned char speed;
unsigned char pitch;
unsigned char mouth;
unsigned char throat;
unsigned char phonetic;
unsigned char singmode;
}; // STM32SAM class
#endif
-17
View File
@@ -1,17 +0,0 @@
App(
appid="uhf_rfid",
name="[YRM100] UHF RFID",
apptype=FlipperAppType.EXTERNAL,
targets=["f7"],
entry_point="uhf_app_main",
requires=[
"storage",
"gui",
],
stack_size=8 * 1024,
order=30,
fap_icon="uhf_10px.png",
fap_category="GPIO",
fap_icon_assets="icons",
fap_icon_assets_symbol="uhf_rfid",
)
-30
View File
@@ -1,30 +0,0 @@
#include "uhf_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const uhf_on_enter_handlers[])(void*) = {
#include "uhf_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const uhf_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "uhf_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const uhf_on_exit_handlers[])(void* context) = {
#include "uhf_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers uhf_scene_handlers = {
.on_enter_handlers = uhf_on_enter_handlers,
.on_event_handlers = uhf_on_event_handlers,
.on_exit_handlers = uhf_on_exit_handlers,
.scene_num = UHFSceneNum,
};
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) UHFScene##id,
typedef enum {
#include "uhf_scene_config.h"
UHFSceneNum,
} UHFScene;
#undef ADD_SCENE
extern const SceneManagerHandlers uhf_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "uhf_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "uhf_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "uhf_scene_config.h"
#undef ADD_SCENE
@@ -1,18 +0,0 @@
ADD_SCENE(uhf, verify, Verify)
ADD_SCENE(uhf, start, Start)
ADD_SCENE(uhf, read_tag, ReadTag)
ADD_SCENE(uhf, read_tag_success, ReadTagSuccess)
ADD_SCENE(uhf, tag_menu, TagMenu)
ADD_SCENE(uhf, save_name, SaveName)
ADD_SCENE(uhf, save_success, SaveSuccess)
ADD_SCENE(uhf, saved_menu, SavedMenu)
ADD_SCENE(uhf, file_select, FileSelect)
ADD_SCENE(uhf, device_info, DeviceInfo)
ADD_SCENE(uhf, delete, Delete)
ADD_SCENE(uhf, delete_success, DeleteSuccess)
ADD_SCENE(uhf, write_tag, WriteTag)
ADD_SCENE(uhf, write_tag_success, WriteTagSuccess)
ADD_SCENE(uhf, settings, Settings)
// ADD_SCENE(uhf, read_factory_success, ReadFactorySuccess)
// ADD_SCENE(uhf, write_key, WriteKey)
// ADD_SCENE(uhf, key_menu, KeyMenu)
@@ -1,50 +0,0 @@
#include "../uhf_app_i.h"
void uhf_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
UHFApp* uhf_app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
}
}
void uhf_scene_delete_on_enter(void* context) {
UHFApp* uhf_app = context;
// Setup Custom Widget view
char temp_str[64];
snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", uhf_app->uhf_device->dev_name);
widget_add_text_box_element(
uhf_app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false);
widget_add_button_element(
uhf_app->widget, GuiButtonTypeLeft, "Back", uhf_scene_delete_widget_callback, uhf_app);
widget_add_button_element(
uhf_app->widget, GuiButtonTypeRight, "Delete", uhf_scene_delete_widget_callback, uhf_app);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
}
bool uhf_scene_delete_on_event(void* context, SceneManagerEvent event) {
UHFApp* uhf_app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
return scene_manager_previous_scene(uhf_app->scene_manager);
} else if(event.event == GuiButtonTypeRight) {
if(uhf_device_delete(uhf_app->uhf_device, true)) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneDeleteSuccess);
} else {
scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneStart);
}
consumed = true;
}
}
return consumed;
}
void uhf_scene_delete_on_exit(void* context) {
UHFApp* uhf_app = context;
widget_reset(uhf_app->widget);
}
@@ -1,40 +0,0 @@
#include "../uhf_app_i.h"
void uhf_scene_delete_success_popup_callback(void* context) {
UHFApp* uhf_app = context;
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventViewExit);
}
void uhf_scene_delete_success_on_enter(void* context) {
UHFApp* uhf_app = context;
// Setup view
Popup* popup = uhf_app->popup;
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, uhf_app);
popup_set_callback(popup, uhf_scene_delete_success_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
}
bool uhf_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
UHFApp* uhf_app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == UHFCustomEventViewExit) {
consumed = scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneStart);
}
}
return consumed;
}
void uhf_scene_delete_success_on_exit(void* context) {
UHFApp* uhf_app = context;
// Clear view
popup_reset(uhf_app->popup);
}
@@ -1,133 +0,0 @@
#include "../uhf_app_i.h"
#include <dolphin/dolphin.h>
typedef enum { EPC_INFO, TID_INFO, USER_INFO } UHFTagInfo;
static UHFTagInfo current_info;
char* get_current_bank_info_str() {
switch(current_info) {
case EPC_INFO:
return "EPC Bank";
case TID_INFO:
return "TID Bank";
case USER_INFO:
return "User Bank";
}
return "";
}
char* get_next_bank_info_str() {
switch(current_info) {
case EPC_INFO:
current_info = TID_INFO;
return "TID";
case TID_INFO:
current_info = USER_INFO;
return "USER";
case USER_INFO:
current_info = EPC_INFO;
return "EPC";
}
return "";
}
void uhf_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) {
UHFApp* uhf_app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
}
}
void change_view_on_event(UHFApp* uhf_app) {
UHFTag* uhf_tag = uhf_app->uhf_device->uhf_tag_wrapper->uhf_tag;
FuriString* furi_temp_str;
furi_temp_str = furi_string_alloc();
char* temp_str;
size_t length;
widget_reset(uhf_app->widget);
widget_add_string_element(
uhf_app->widget, 64, 5, AlignCenter, AlignCenter, FontPrimary, get_current_bank_info_str());
switch(current_info) {
case EPC_INFO:
temp_str = convertToHexString(uhf_tag->epc->data, uhf_tag->epc->size);
length = uhf_tag->epc->size;
break;
case TID_INFO:
temp_str = convertToHexString(uhf_tag->tid->data, uhf_tag->tid->size);
length = uhf_tag->tid->size;
break;
case USER_INFO:
temp_str = convertToHexString(uhf_tag->user->data, uhf_tag->user->size);
length = uhf_tag->user->size;
break;
default:
temp_str = NULL;
length = 0;
break;
}
furi_string_cat_printf(furi_temp_str, "Length: %d bytes", length);
widget_add_string_element(
uhf_app->widget,
3,
12,
AlignLeft,
AlignTop,
FontKeyboard,
furi_string_get_cstr(furi_temp_str));
widget_add_string_multiline_element(
uhf_app->widget, 3, 24, AlignLeft, AlignTop, FontKeyboard, temp_str);
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeRight,
get_next_bank_info_str(),
uhf_scene_device_info_widget_callback,
uhf_app);
widget_add_button_element(
uhf_app->widget, GuiButtonTypeLeft, "Back", uhf_scene_device_info_widget_callback, uhf_app);
furi_string_free(furi_temp_str);
free(temp_str);
}
void uhf_scene_device_info_on_enter(void* context) {
UHFApp* uhf_app = context;
current_info = EPC_INFO;
dolphin_deed(DolphinDeedNfcReadSuccess);
change_view_on_event(uhf_app);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
}
bool uhf_scene_device_info_on_event(void* context, SceneManagerEvent event) {
UHFApp* uhf_app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) return false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(uhf_app->scene_manager);
} else if(event.event == GuiButtonTypeRight) {
change_view_on_event(uhf_app);
} else if(event.event == UHFCustomEventViewExit) {
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_previous_scene(uhf_app->scene_manager);
consumed = true;
}
return consumed;
}
void uhf_scene_device_info_on_exit(void* context) {
UHFApp* uhf_app = context;
// Clear views
widget_reset(uhf_app->widget);
}
@@ -1,23 +0,0 @@
#include "../uhf_app_i.h"
void uhf_scene_file_select_on_enter(void* context) {
UHFApp* uhf_app = context;
// Process file_select return
uhf_device_set_loading_callback(uhf_app->uhf_device, uhf_show_loading_popup, uhf_app);
if(uhf_file_select(uhf_app->uhf_device)) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSavedMenu);
} else {
scene_manager_search_and_switch_to_previous_scene(uhf_app->scene_manager, UHFSceneStart);
}
uhf_device_set_loading_callback(uhf_app->uhf_device, NULL, uhf_app);
}
bool uhf_scene_file_select_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void uhf_scene_file_select_on_exit(void* context) {
UNUSED(context);
}
@@ -1,45 +0,0 @@
#include "../uhf_app_i.h"
#include <dolphin/dolphin.h>
void uhf_read_tag_worker_callback(UHFWorkerEvent event, void* ctx) {
UHFApp* uhf_app = ctx;
if(event == UHFWorkerEventSuccess) {
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventWorkerExit);
}
}
void uhf_scene_read_tag_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
dolphin_deed(DolphinDeedNfcRead);
// Setup view
Popup* popup = uhf_app->popup;
popup_set_header(popup, "Detecting\n[UHF] RFID\nTag", 68, 30, AlignLeft, AlignTop);
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
// Start worker
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
uhf_worker_start(
uhf_app->worker, UHFWorkerStateDetectSingle, uhf_read_tag_worker_callback, uhf_app);
uhf_blink_start(uhf_app);
}
bool uhf_scene_read_tag_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
bool consumed = false;
if(event.event == UHFCustomEventWorkerExit) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneReadTagSuccess);
consumed = true;
}
return consumed;
}
void uhf_scene_read_tag_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
// Stop worker
uhf_worker_stop(uhf_app->worker);
// Clear view
popup_reset(uhf_app->popup);
uhf_blink_stop(uhf_app);
}
@@ -1,111 +0,0 @@
#include "../uhf_app_i.h"
#include <dolphin/dolphin.h>
void uhf_read_tag_success_worker_callback(UHFWorkerEvent event, void* ctx) {
UNUSED(event);
UNUSED(ctx);
}
void uhf_scene_read_card_success_widget_callback(GuiButtonType result, InputType type, void* ctx) {
furi_assert(ctx);
UHFApp* uhf_app = ctx;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
}
}
void uhf_scene_read_tag_success_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
UHFTag* uhf_tag = uhf_app->worker->uhf_tag_wrapper->uhf_tag;
FuriString* temp_str = furi_string_alloc();
dolphin_deed(DolphinDeedNfcReadSuccess);
// Send notification
notification_message(uhf_app->notifications, &sequence_success);
widget_add_string_element(
uhf_app->widget, 32, 5, AlignLeft, AlignCenter, FontPrimary, "Read Success");
widget_add_string_element(uhf_app->widget, 3, 18, AlignLeft, AlignCenter, FontPrimary, "PC :");
widget_add_string_element(
uhf_app->widget, 66, 18, AlignLeft, AlignCenter, FontPrimary, "CRC :");
widget_add_string_element(
uhf_app->widget, 3, 32, AlignLeft, AlignCenter, FontPrimary, "EPC :");
furi_string_cat_printf(temp_str, "%04X", uhf_tag->epc->pc);
widget_add_string_element(
uhf_app->widget,
26,
19,
AlignLeft,
AlignCenter,
FontKeyboard,
furi_string_get_cstr(temp_str));
furi_string_reset(temp_str);
furi_string_cat_printf(temp_str, "%04X", uhf_tag->epc->crc);
widget_add_string_element(
uhf_app->widget,
96,
19,
AlignLeft,
AlignCenter,
FontKeyboard,
furi_string_get_cstr(temp_str));
char* epc = convertToHexString(uhf_tag->epc->data, uhf_tag->epc->size);
if(epc != NULL) {
widget_add_string_multiline_element(
uhf_app->widget, 34, 29, AlignLeft, AlignTop, FontKeyboard, epc);
}
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeRight,
"More",
uhf_scene_read_card_success_widget_callback,
uhf_app);
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeLeft,
"Exit",
uhf_scene_read_card_success_widget_callback,
uhf_app);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
free(epc);
furi_string_free(temp_str);
}
bool uhf_scene_read_tag_success_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
bool consumed = false;
if(event.event == SceneManagerEventTypeBack) {
uhf_app->worker->state = UHFWorkerStateStop;
}
if(event.type == SceneManagerEventTypeCustom) {
// if 'exit' is pressed go back to home screen
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneStart);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneTagMenu);
consumed = true;
} else if(event.event == GuiButtonTypeCenter) {
// consumed = scene_manager_search_and_switch_to_another_scene(
// picopass->scene_manager, PicopassSceneStart);
}
}
return consumed;
}
void uhf_scene_read_tag_success_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
// // Stop worker
uhf_worker_stop(uhf_app->worker);
// Clear view
popup_reset(uhf_app->popup);
// clear widget
widget_reset(uhf_app->widget);
}
@@ -1,74 +0,0 @@
#include "../uhf_app_i.h"
#include <lib/toolbox/name_generator.h>
#include <gui/modules/validators.h>
#include <toolbox/path.h>
void uhf_scene_save_name_text_input_callback(void* context) {
UHFApp* uhf_app = context;
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventTextInputDone);
}
void uhf_scene_save_name_on_enter(void* context) {
UHFApp* uhf_app = context;
// Setup view
TextInput* text_input = uhf_app->text_input;
name_generator_make_random(uhf_app->text_store, sizeof(uhf_app->text_store));
text_input_set_header_text(text_input, "Name the tag");
text_input_set_result_callback(
text_input,
uhf_scene_save_name_text_input_callback,
uhf_app,
uhf_app->text_store,
UHF_DEV_NAME_MAX_LEN,
true);
FuriString* folder_path;
folder_path = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
if(furi_string_end_with(uhf_app->uhf_device->load_path, UHF_APP_EXTENSION)) {
path_extract_dirname(furi_string_get_cstr(uhf_app->uhf_device->load_path), folder_path);
}
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
furi_string_get_cstr(folder_path), UHF_APP_EXTENSION, uhf_app->uhf_device->dev_name);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewTextInput);
furi_string_free(folder_path);
}
bool uhf_scene_save_name_on_event(void* context, SceneManagerEvent event) {
UHFApp* uhf_app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == UHFCustomEventTextInputDone) {
strlcpy(
uhf_app->uhf_device->dev_name,
uhf_app->text_store,
strlen(uhf_app->text_store) + 1);
if(uhf_device_save(uhf_app->uhf_device, uhf_app->text_store)) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSaveSuccess);
consumed = true;
} else {
consumed = scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneStart);
}
}
}
return consumed;
}
void uhf_scene_save_name_on_exit(void* context) {
UHFApp* uhf_app = context;
// Clear view
void* validator_context = text_input_get_validator_callback_context(uhf_app->text_input);
text_input_set_validator(uhf_app->text_input, NULL, NULL);
validator_is_file_free(validator_context);
text_input_reset(uhf_app->text_input);
}
@@ -1,47 +0,0 @@
#include "../uhf_app_i.h"
#include <dolphin/dolphin.h>
void uhf_scene_save_success_popup_callback(void* context) {
UHFApp* uhf_app = context;
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventViewExit);
}
void uhf_scene_save_success_on_enter(void* context) {
UHFApp* uhf_app = context;
dolphin_deed(DolphinDeedNfcSave);
// Setup view
Popup* popup = uhf_app->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, uhf_app);
popup_set_callback(popup, uhf_scene_save_success_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
}
bool uhf_scene_save_success_on_event(void* context, SceneManagerEvent event) {
UHFApp* uhf_app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == UHFCustomEventViewExit) {
if(scene_manager_has_previous_scene(uhf_app->scene_manager, UHFSceneTagMenu)) {
consumed = scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneTagMenu);
} else {
consumed = scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneStart);
}
}
}
return consumed;
}
void uhf_scene_save_success_on_exit(void* context) {
UHFApp* uhf_app = context;
// Clear view
popup_reset(uhf_app->popup);
}
@@ -1,59 +0,0 @@
#include "../uhf_app_i.h"
enum SubmenuIndex {
SubmenuIndexDelete,
SubmenuIndexInfo,
SubmenuIndexWrite,
};
void uhf_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
UHFApp* uhf_app = context;
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, index);
}
void uhf_scene_saved_menu_on_enter(void* context) {
UHFApp* uhf_app = context;
Submenu* submenu = uhf_app->submenu;
submenu_add_item(
submenu, "Delete", SubmenuIndexDelete, uhf_scene_saved_menu_submenu_callback, uhf_app);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, uhf_scene_saved_menu_submenu_callback, uhf_app);
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, uhf_scene_saved_menu_submenu_callback, uhf_app);
submenu_set_selected_item(
uhf_app->submenu,
scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneSavedMenu));
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
}
bool uhf_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
UHFApp* uhf_app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(uhf_app->scene_manager, UHFSceneSavedMenu, event.event);
if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneDelete);
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneDeviceInfo);
consumed = true;
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneWriteTag);
consumed = true;
}
}
return consumed;
}
void uhf_scene_saved_menu_on_exit(void* context) {
UHFApp* uhf_app = context;
submenu_reset(uhf_app->submenu);
}
@@ -1,122 +0,0 @@
#include "../uhf_app_i.h"
#include "../uhf_module.h"
void uhf_settings_set_module_baudrate(VariableItem* item) {
M100Module* uhf_module = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(index >= BAUD_RATES_COUNT) {
return;
}
uint32_t baudrate = BAUD_RATES[index];
m100_set_baudrate(uhf_module, baudrate);
char text_buf[10];
snprintf(text_buf, sizeof(text_buf), "%lu", uhf_module->baudrate);
variable_item_set_current_value_text(item, text_buf);
}
void uhf_settings_set_module_powerdb(VariableItem* item) {
M100Module* uhf_module = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(index >= POWER_DBM_COUNT) {
return;
}
uint16_t power = POWER_DBM[index];
m100_set_transmitting_power(uhf_module, power);
char text_buf[10];
snprintf(text_buf, sizeof(text_buf), "%ddBm", uhf_module->transmitting_power);
variable_item_set_current_value_text(item, text_buf);
}
void uhf_settings_set_module_working_region(VariableItem* item) {
M100Module* uhf_module = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(index >= WORKING_REGIONS_COUNT) {
return;
}
WorkingRegion region = WORKING_REGIONS[index];
m100_set_working_region(uhf_module, region);
variable_item_set_current_value_text(item, WORKING_REGIONS_STR[index]);
}
uint8_t uhf_settings_get_module_baudrate_index(M100Module* module) {
for(uint8_t i = 0; i < BAUD_RATES_COUNT; i++) {
if(BAUD_RATES[i] == module->baudrate) {
return i;
}
}
return 0;
}
uint8_t uhf_settings_get_module_power_index(M100Module* module) {
for(uint8_t i = 0; i < BAUD_RATES_COUNT; i++) {
if(POWER_DBM[i] == module->transmitting_power) {
return i;
}
}
return 0;
}
uint8_t uhf_settings_get_module_working_region_index(M100Module* module) {
for(uint8_t i = 0; i < WORKING_REGIONS_COUNT; i++) {
if(WORKING_REGIONS[i] == module->region) {
return i;
}
}
return 0;
}
void uhf_scene_settings_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
M100Module* uhf_module = uhf_app->worker->module;
VariableItem* item;
VariableItemList* variable_item_list = uhf_app->variable_item_list;
uint8_t value_index = uhf_settings_get_module_baudrate_index(uhf_module);
char text_buf[10];
snprintf(text_buf, sizeof(text_buf), "%lu", uhf_module->baudrate);
item = variable_item_list_add(
variable_item_list,
"Baudrate:",
BAUD_RATES_COUNT,
uhf_settings_set_module_baudrate,
uhf_module);
variable_item_set_current_value_text(item, text_buf);
variable_item_set_current_value_index(item, value_index);
value_index = uhf_settings_get_module_power_index(uhf_module);
item = variable_item_list_add(
variable_item_list,
"Power(DBM):",
POWER_DBM_COUNT,
uhf_settings_set_module_powerdb,
uhf_module);
snprintf(text_buf, sizeof(text_buf), "%ddBm", uhf_module->transmitting_power);
variable_item_set_current_value_text(item, text_buf);
variable_item_set_current_value_index(item, value_index);
value_index = uhf_settings_get_module_working_region_index(uhf_module);
item = variable_item_list_add(
variable_item_list,
"Region:",
WORKING_REGIONS_COUNT,
uhf_settings_set_module_working_region,
uhf_module);
variable_item_set_current_value_text(item, WORKING_REGIONS_STR[value_index]);
variable_item_set_current_value_index(item, value_index);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewVariableItemList);
}
bool uhf_scene_settings_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
UNUSED(uhf_app);
UNUSED(event);
return false;
}
void uhf_scene_settings_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
variable_item_list_set_selected_item(uhf_app->variable_item_list, 0);
variable_item_list_reset(uhf_app->variable_item_list);
}
-54
View File
@@ -1,54 +0,0 @@
#include "../uhf_app_i.h"
enum SubmenuIndex { SubmenuIndexRead, SubmenuIndexSaved, SubmenuIndexSettings };
void uhf_scene_start_submenu_callback(void* ctx, uint32_t index) {
UHFApp* uhf_app = ctx;
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, index);
}
void uhf_scene_start_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
Submenu* submenu = uhf_app->submenu;
submenu_add_item(
submenu, "Read Tag", SubmenuIndexRead, uhf_scene_start_submenu_callback, uhf_app);
submenu_add_item(
submenu, "Saved", SubmenuIndexSaved, uhf_scene_start_submenu_callback, uhf_app);
submenu_add_item(
submenu, "Settings", SubmenuIndexSettings, uhf_scene_start_submenu_callback, uhf_app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneStart));
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
}
bool uhf_scene_start_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexRead) {
scene_manager_set_scene_state(uhf_app->scene_manager, UHFSceneStart, SubmenuIndexRead);
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneReadTag);
consumed = true;
} else if(event.event == SubmenuIndexSaved) {
// Explicitly save state so that the correct item is
// reselected if the user cancels loading a file.
scene_manager_set_scene_state(
uhf_app->scene_manager, UHFSceneStart, SubmenuIndexSaved);
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneFileSelect);
consumed = true;
} else if(event.event == SubmenuIndexSettings) {
scene_manager_set_scene_state(
uhf_app->scene_manager, UHFSceneStart, SubmenuIndexSettings);
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSettings);
consumed = true;
}
}
return consumed;
}
void uhf_scene_start_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
submenu_reset(uhf_app->submenu);
}
@@ -1,58 +0,0 @@
#include "../uhf_app_i.h"
enum SubmenuIndex {
SubmenuIndexSave,
SubmenuIndexChangeKey,
};
void uhf_scene_tag_menu_submenu_callback(void* ctx, uint32_t index) {
UHFApp* uhf_app = ctx;
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, index);
}
void uhf_scene_tag_menu_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
Submenu* submenu = uhf_app->submenu;
submenu_add_item(
submenu, "Save", SubmenuIndexSave, uhf_scene_tag_menu_submenu_callback, uhf_app);
submenu_add_item(
submenu, "Change Key", SubmenuIndexChangeKey, uhf_scene_tag_menu_submenu_callback, uhf_app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneTagMenu));
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
}
bool uhf_scene_tag_menu_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) {
scene_manager_set_scene_state(
uhf_app->scene_manager, UHFSceneTagMenu, SubmenuIndexSave);
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSaveName);
consumed = true;
}
// else if(event.event == SubmenuIndexChangeKey) {
// scene_manager_set_scene_state(
// picopass->scene_manager, UHFSceneTagMenu, SubmenuIndexChangeKey);
// scene_manager_next_scene(picopass->scene_manager, PicopassSceneKeyMenu);
// consumed = true;
// }
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneStart);
}
return consumed;
}
void uhf_scene_tag_menu_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
submenu_reset(uhf_app->submenu);
}
-147
View File
@@ -1,147 +0,0 @@
#include "../uhf_app_i.h"
bool verify_success = false;
FuriString* temp_str;
void uhf_scene_verify_callback_event(UHFWorkerEvent event, void* ctx) {
UNUSED(ctx);
UHFApp* uhf_app = ctx;
if(event == UHFWorkerEventSuccess) verify_success = true;
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventVerifyDone);
}
void uhf_scene_verify_widget_callback(GuiButtonType result, InputType type, void* ctx) {
furi_assert(ctx);
UHFApp* uhf_app = ctx;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
}
}
void uhf_scene_verify_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
uhf_worker_start(
uhf_app->worker, UHFWorkerStateVerify, uhf_scene_verify_callback_event, uhf_app);
temp_str = furi_string_alloc();
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
}
bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
bool consumed = false;
if(event.event == SceneManagerEventTypeBack) {
uhf_app->worker->state = UHFWorkerStateStop;
} else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneStart);
consumed = true;
} else if(event.event == GuiButtonTypeLeft) {
if(!verify_success) {
widget_reset(uhf_app->widget);
furi_string_reset(temp_str);
uhf_worker_stop(uhf_app->worker);
// furi_hal_gpio_write(&gpio_ext, false);
// furi_delay_ms(50);
// furi_hal_gpio_write(&gpio_ext_pa7, true);
// furi_delay_ms(50);
uhf_worker_start(
uhf_app->worker,
UHFWorkerStateVerify,
uhf_scene_verify_callback_event,
uhf_app);
}
} else if(event.event == UHFCustomEventVerifyDone) {
if(verify_success) {
widget_reset(uhf_app->widget);
furi_string_reset(temp_str);
M100Module* module = uhf_app->worker->module;
widget_add_string_element(
uhf_app->widget, 64, 5, AlignCenter, AlignCenter, FontPrimary, "Module Info");
// hardware info
furi_string_cat_str(temp_str, "HW Version: ");
furi_string_cat_str(temp_str, module->info->hw_version);
widget_add_string_element(
uhf_app->widget,
1,
15,
AlignLeft,
AlignTop,
FontSecondary,
furi_string_get_cstr(temp_str));
furi_string_reset(temp_str);
// software info
furi_string_cat_str(temp_str, "SW Version: ");
furi_string_cat_str(temp_str, module->info->sw_version);
widget_add_string_element(
uhf_app->widget,
1,
27,
AlignLeft,
AlignTop,
FontSecondary,
furi_string_get_cstr(temp_str));
furi_string_reset(temp_str);
// manufacturer info
furi_string_cat_str(temp_str, "Manufacturer: ");
furi_string_cat_str(temp_str, module->info->manufacturer);
widget_add_string_element(
uhf_app->widget,
1,
39,
AlignLeft,
AlignTop,
FontSecondary,
furi_string_get_cstr(temp_str));
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeRight,
"Continue",
uhf_scene_verify_widget_callback,
uhf_app);
} else {
widget_add_string_element(
uhf_app->widget,
64,
5,
AlignCenter,
AlignCenter,
FontPrimary,
"No UHF Module found");
widget_add_string_multiline_element(
uhf_app->widget,
64,
30,
AlignCenter,
AlignCenter,
FontSecondary,
"Please refer to the git@frux-c/uhf_rfid for help.");
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeLeft,
"Retry",
uhf_scene_verify_widget_callback,
uhf_app);
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeRight,
"Skip",
uhf_scene_verify_widget_callback,
uhf_app);
}
}
}
return consumed;
}
void uhf_scene_verify_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
// Clear string
furi_string_free(temp_str);
// Stop worker
uhf_worker_stop(uhf_app->worker);
// clear widget
widget_reset(uhf_app->widget);
}
@@ -1,49 +0,0 @@
#include "../uhf_app_i.h"
#include <dolphin/dolphin.h>
void uhf_write_tag_worker_callback(UHFWorkerEvent event, void* ctx) {
UHFApp* uhf_app = ctx;
if(event == UHFWorkerEventSuccess) {
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventWorkerExit);
}
// } else if(event == UHFWorkerEventAborted) {
// scene_manager_search_and_switch_to_previous_scene(uhf_app->scene_manager, UHFSceneStart);
// }
}
void uhf_scene_write_tag_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
dolphin_deed(DolphinDeedNfcRead);
// Setup view
Popup* popup = uhf_app->popup;
popup_set_header(popup, "Writing\n[UHF] RFID\nTag", 68, 30, AlignLeft, AlignTop);
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
// Start worker
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
uhf_worker_start(
uhf_app->worker, UHFWorkerStateWriteSingle, uhf_write_tag_worker_callback, uhf_app);
uhf_blink_start(uhf_app);
}
bool uhf_scene_write_tag_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
bool consumed = false;
if(event.event == UHFCustomEventWorkerExit) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneWriteTagSuccess);
consumed = true;
}
return consumed;
}
void uhf_scene_write_tag_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
// Stop worker
uhf_worker_stop(uhf_app->worker);
// Clear view
popup_reset(uhf_app->popup);
uhf_blink_stop(uhf_app);
}
@@ -1,94 +0,0 @@
#include "../uhf_app_i.h"
#include <dolphin/dolphin.h>
void uhf_write_tag_success_worker_callback(UHFWorkerEvent event, void* ctx) {
UNUSED(event);
UNUSED(ctx);
}
void uhf_scene_write_tag_success_widget_callback(GuiButtonType result, InputType type, void* ctx) {
furi_assert(ctx);
UHFApp* uhf_app = ctx;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
}
}
void uhf_scene_write_tag_success_on_enter(void* ctx) {
UHFApp* uhf_app = ctx;
dolphin_deed(DolphinDeedNfcReadSuccess);
// Send notification
notification_message(uhf_app->notifications, &sequence_success);
widget_add_string_element(
uhf_app->widget, 32, 5, AlignLeft, AlignCenter, FontPrimary, "Write Success");
// widget_add_string_element(uhf_app->widget, 3, 18, AlignLeft, AlignCenter, FontPrimary, "PC :");
// widget_add_string_element(
// uhf_app->widget, 66, 18, AlignLeft, AlignCenter, FontPrimary, "CRC :");
// widget_add_string_element(
// uhf_app->widget, 3, 32, AlignLeft, AlignCenter, FontPrimary, "EPC :");
// char* pc = convertToHexString(uhf_tag->pc, 2);
// widget_add_string_element(uhf_app->widget, 26, 19, AlignLeft, AlignCenter, FontKeyboard, pc);
// char* crc = convertToHexString(uhf_tag->crc, 2);
// widget_add_string_element(uhf_app->widget, 96, 19, AlignLeft, AlignCenter, FontKeyboard, crc);
// char* epc = convertToHexString(uhf_tag->epc + 2, uhf_tag->epc_length - 2);
// widget_add_string_multiline_element(
// uhf_app->widget, 34, 29, AlignLeft, AlignTop, FontKeyboard, epc);
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeRight,
"More",
uhf_scene_write_tag_success_widget_callback,
uhf_app);
widget_add_button_element(
uhf_app->widget,
GuiButtonTypeLeft,
"Exit",
uhf_scene_write_tag_success_widget_callback,
uhf_app);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
// free(pc);
// free(crc);
// free(epc);
}
bool uhf_scene_write_tag_success_on_event(void* ctx, SceneManagerEvent event) {
UHFApp* uhf_app = ctx;
bool consumed = false;
if(event.event == SceneManagerEventTypeBack) {
uhf_app->worker->state = UHFWorkerStateStop;
}
if(event.type == SceneManagerEventTypeCustom) {
// if 'exit' is pressed go back to home screen
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_search_and_switch_to_previous_scene(
uhf_app->scene_manager, UHFSceneStart);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneTagMenu);
consumed = true;
} else if(event.event == GuiButtonTypeCenter) {
// consumed = scene_manager_search_and_switch_to_another_scene(
// picopass->scene_manager, PicopassSceneStart);
}
}
return consumed;
}
void uhf_scene_write_tag_success_on_exit(void* ctx) {
UHFApp* uhf_app = ctx;
// // Stop worker
uhf_worker_stop(uhf_app->worker);
// Clear view
popup_reset(uhf_app->popup);
// clear widget
widget_reset(uhf_app->widget);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

-214
View File
@@ -1,214 +0,0 @@
#include "uhf_app_i.h"
char* convertToHexString(uint8_t* array, size_t length) {
if(array == NULL || length == 0) {
return " ";
}
FuriString* temp_str = furi_string_alloc();
for(size_t i = 0; i < length; i++) {
furi_string_cat_printf(temp_str, "%02X ", array[i]);
}
const char* furi_str = furi_string_get_cstr(temp_str);
size_t str_len = strlen(furi_str);
char* str = (char*)malloc(sizeof(char) * str_len);
memcpy(str, furi_str, str_len);
furi_string_free(temp_str);
return str;
}
bool uhf_custom_event_callback(void* ctx, uint32_t event) {
furi_assert(ctx);
UHFApp* uhf_app = ctx;
return scene_manager_handle_custom_event(uhf_app->scene_manager, event);
}
bool uhf_back_event_callback(void* ctx) {
furi_assert(ctx);
UHFApp* uhf_app = ctx;
return scene_manager_handle_back_event(uhf_app->scene_manager);
}
void uhf_tick_event_callback(void* ctx) {
furi_assert(ctx);
UHFApp* uhf_app = ctx;
scene_manager_handle_tick_event(uhf_app->scene_manager);
}
UHFApp* uhf_alloc() {
UHFApp* uhf_app = (UHFApp*)malloc(sizeof(UHFApp));
uhf_app->view_dispatcher = view_dispatcher_alloc();
uhf_app->scene_manager = scene_manager_alloc(&uhf_scene_handlers, uhf_app);
view_dispatcher_enable_queue(uhf_app->view_dispatcher);
view_dispatcher_set_event_callback_context(uhf_app->view_dispatcher, uhf_app);
view_dispatcher_set_custom_event_callback(uhf_app->view_dispatcher, uhf_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
uhf_app->view_dispatcher, uhf_back_event_callback);
view_dispatcher_set_tick_event_callback(
uhf_app->view_dispatcher, uhf_tick_event_callback, 100);
// Open GUI record
uhf_app->gui = furi_record_open(RECORD_GUI);
view_dispatcher_attach_to_gui(
uhf_app->view_dispatcher, uhf_app->gui, ViewDispatcherTypeFullscreen);
// Variable Item List
uhf_app->variable_item_list = variable_item_list_alloc();
//worker
uhf_app->worker = uhf_worker_alloc();
// device
uhf_app->uhf_device = uhf_device_alloc();
UHFTagWrapper* uhf_tag_wrapper = uhf_tag_wrapper_alloc();
// // point tag object to worker
uhf_app->worker->uhf_tag_wrapper = uhf_tag_wrapper;
uhf_app->uhf_device->uhf_tag_wrapper = uhf_tag_wrapper;
// Open Notification record
uhf_app->notifications = furi_record_open(RECORD_NOTIFICATION);
// Variable Item List
uhf_app->variable_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
uhf_app->view_dispatcher,
UHFViewVariableItemList,
variable_item_list_get_view(uhf_app->variable_item_list));
// Submenu
uhf_app->submenu = submenu_alloc();
view_dispatcher_add_view(
uhf_app->view_dispatcher, UHFViewMenu, submenu_get_view(uhf_app->submenu));
// Popup
uhf_app->popup = popup_alloc();
view_dispatcher_add_view(
uhf_app->view_dispatcher, UHFViewPopup, popup_get_view(uhf_app->popup));
// Loading
uhf_app->loading = loading_alloc();
view_dispatcher_add_view(
uhf_app->view_dispatcher, UHFViewLoading, loading_get_view(uhf_app->loading));
// Text Input
uhf_app->text_input = text_input_alloc();
view_dispatcher_add_view(
uhf_app->view_dispatcher, UHFViewTextInput, text_input_get_view(uhf_app->text_input));
// Custom Widget
uhf_app->widget = widget_alloc();
view_dispatcher_add_view(
uhf_app->view_dispatcher, UHFViewWidget, widget_get_view(uhf_app->widget));
return uhf_app;
}
void uhf_free(UHFApp* uhf_app) {
furi_assert(uhf_app);
// Submenu
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewMenu);
submenu_free(uhf_app->submenu);
// Popup
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewPopup);
popup_free(uhf_app->popup);
// Loading
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewLoading);
loading_free(uhf_app->loading);
// TextInput
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewTextInput);
text_input_free(uhf_app->text_input);
// Custom Widget
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewWidget);
widget_free(uhf_app->widget);
// Tag
uhf_tag_wrapper_free(uhf_app->worker->uhf_tag_wrapper);
// Worker
uhf_worker_stop(uhf_app->worker);
uhf_worker_free(uhf_app->worker);
// Device
uhf_device_free(uhf_app->uhf_device);
// View Dispatcher
view_dispatcher_free(uhf_app->view_dispatcher);
// Scene Manager
scene_manager_free(uhf_app->scene_manager);
// GUI
furi_record_close(RECORD_GUI);
uhf_app->gui = NULL;
// Variable Item List
variable_item_list_free(uhf_app->variable_item_list);
// Notifications
furi_record_close(RECORD_NOTIFICATION);
uhf_app->notifications = NULL;
free(uhf_app);
}
static const NotificationSequence uhf_sequence_blink_start_cyan = {
&message_blink_start_10,
&message_blink_set_color_cyan,
&message_do_not_reset,
NULL,
};
static const NotificationSequence uhf_sequence_blink_stop = {
&message_blink_stop,
NULL,
};
void uhf_blink_start(UHFApp* uhf_app) {
notification_message(uhf_app->notifications, &uhf_sequence_blink_start_cyan);
}
void uhf_blink_stop(UHFApp* uhf_app) {
notification_message(uhf_app->notifications, &uhf_sequence_blink_stop);
}
void uhf_show_loading_popup(void* ctx, bool show) {
UHFApp* uhf_app = ctx;
if(show) {
// Raise timer priority so that animations can play
furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewLoading);
} else {
// Restore default timer priority
furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
}
}
int32_t uhf_app_main(void* ctx) {
UNUSED(ctx);
UHFApp* uhf_app = uhf_alloc();
// enable 5v pin
furi_hal_power_enable_otg();
// init pin a2
// furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUDRATE);
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneVerify);
view_dispatcher_run(uhf_app->view_dispatcher);
// disable 5v pin
furi_hal_power_disable_otg();
// furi_hal_gpio_disable_int_callback()
// exit app
uhf_free(uhf_app);
return 0;
}
-3
View File
@@ -1,3 +0,0 @@
#pragma once
typedef struct UHFApp UHFApp;
-110
View File
@@ -1,110 +0,0 @@
#pragma once
#include <furi.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <notification/notification_messages.h>
#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include <gui/modules/loading.h>
#include <gui/modules/text_input.h>
#include <gui/modules/widget.h>
#include <gui/modules/variable_item_list.h>
#include <input/input.h>
#include "uhf_app.h"
#include "uhf_worker.h"
#include "uhf_device.h"
#include "scenes/uhf_scene.h"
#include <storage/storage.h>
#include <lib/toolbox/path.h>
#include <toolbox/path.h>
#include <flipper_format/flipper_format.h>
#include <uhf_rfid_icons.h>
#include <assets_icons.h>
#define UHF_TEXT_STORE_SIZE 128
// #define UHF_APPS_DATA_FOLDER EXT_PATH("apps_data")
// #define UHF_APPS_STORAGE_FOLDER
// UHF_APPS_DATA_FOLDER "/"
// "uhf_rfid"
// #define UHF_FILE_EXTENSION ".uhf"
enum UHFCustomEvent {
// Reserve first 100 events for button types and indexes, starting from 0
UHFCustomEventReserved = 100,
UHFCustomEventVerifyDone,
UHFCustomEventViewExit,
UHFCustomEventWorkerExit,
UHFCustomEventByteInputDone,
UHFCustomEventTextInputDone,
UHFCustomEventSceneSettingLock,
};
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
struct UHFApp {
UHFWorker* worker;
ViewDispatcher* view_dispatcher;
Gui* gui;
NotificationApp* notifications;
SceneManager* scene_manager;
VariableItemList* variable_item_list;
// Storage* storage;
UHFDevice* uhf_device;
char text_store[UHF_TEXT_STORE_SIZE + 1];
FuriString* text_box_store;
// Common Views
Submenu* submenu;
Popup* popup;
Loading* loading;
TextInput* text_input;
Widget* widget;
};
typedef enum {
UHFViewMenu,
UHFViewPopup,
UHFViewLoading,
UHFViewTextInput,
UHFViewWidget,
UHFViewVariableItemList,
} UHFView;
UHFApp* uhf_app_alloc();
void uhf_text_store_set(UHFApp* uhf, const char* text, ...);
void uhf_text_store_clear(UHFApp* uhf);
void uhf_blink_start(UHFApp* uhf);
void uhf_blink_stop(UHFApp* uhf);
void uhf_show_loading_popup(void* context, bool show);
/** Check if memory is set to pattern
*
* @warning zero size will return false
*
* @param[in] data Pointer to the byte array
* @param[in] pattern The pattern
* @param[in] size The byte array size
*
* @return True if memory is set to pattern, false otherwise
*/
bool uhf_is_memset(const uint8_t* data, const uint8_t pattern, size_t size);
char* convertToHexString(uint8_t* array, size_t length);
// bool uhf_save_read_data(UHFResponseData* uhf_response_data, Storage* storage, const char* filename);
-69
View File
@@ -1,69 +0,0 @@
#include "uhf_buffer.h"
#include <stdlib.h>
#include <string.h>
Buffer* buffer_alloc(size_t initial_capacity) {
Buffer* buf = (Buffer*)malloc(sizeof(Buffer));
buf->data = (uint8_t*)malloc(sizeof(uint8_t) * initial_capacity);
if(!buf->data) {
free(buf);
return NULL;
}
buf->size = 0;
buf->capacity = initial_capacity;
return buf;
}
bool buffer_append_single(Buffer* buf, uint8_t data) {
if(buf->closed) return false;
if(buf->size + 1 > buf->capacity) {
size_t new_capacity = buf->capacity * 2;
uint8_t* new_data = (uint8_t*)realloc(buf->data, sizeof(uint8_t) * new_capacity);
if(!new_data) return false;
buf->data = new_data;
buf->capacity = new_capacity;
}
buf->data[buf->size++] = data;
return true;
}
bool buffer_append(Buffer* buf, uint8_t* data, size_t data_size) {
if(buf->closed) return false;
if(buf->size + data_size > buf->capacity) {
size_t new_capacity = buf->capacity * 2;
uint8_t* new_data = (uint8_t*)realloc(buf->data, new_capacity);
if(!new_data) return false;
buf->data = new_data;
buf->capacity = new_capacity;
}
memcpy((void*)&buf->data[buf->size], data, data_size);
buf->size += data_size;
return true;
}
uint8_t* buffer_get_data(Buffer* buf) {
return buf->data;
}
size_t buffer_get_size(Buffer* buf) {
return buf->size;
}
void buffer_close(Buffer* buf) {
buf->closed = true;
}
void buffer_reset(Buffer* buf) {
for(size_t i = 0; i < MAX_BUFFER_SIZE; i++) {
buf->data[i] = 0;
}
buf->size = 0;
buf->closed = false;
}
void buffer_free(Buffer* buf) {
free(buf->data);
free(buf);
}
-22
View File
@@ -1,22 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#define MAX_BUFFER_SIZE 200
typedef struct Buffer {
uint8_t* data;
size_t size;
size_t capacity;
bool closed;
} Buffer;
Buffer* buffer_alloc(size_t inital_capacity);
bool buffer_append_single(Buffer* buf, uint8_t value);
bool buffer_append(Buffer* buf, uint8_t* data, size_t size);
uint8_t* buffer_get_data(Buffer* buf);
size_t buffer_get_size(Buffer* buf);
void buffer_close(Buffer* buf);
void buffer_reset(Buffer* buf);
void buffer_free(Buffer* buf);
-350
View File
@@ -1,350 +0,0 @@
#include "uhf_device.h"
#include <toolbox/path.h>
#include <flipper_format/flipper_format.h>
#include <uhf_rfid_icons.h>
#include <assets_icons.h>
#define TAG "UHFDevice"
static const char* uhf_file_header = "Flipper UHF RFID device";
static const uint32_t uhf_file_version = 1;
// static const uint8_t bank_data_start = 20;
// static const uint8_t bank_data_length = 16;
UHFDevice* uhf_device_alloc() {
UHFDevice* uhf_device = malloc(sizeof(UHFDevice));
uhf_device->storage = furi_record_open(RECORD_STORAGE);
uhf_device->dialogs = furi_record_open(RECORD_DIALOGS);
uhf_device->load_path = furi_string_alloc();
return uhf_device;
}
void uhf_device_set_name(UHFDevice* dev, const char* name) {
furi_assert(dev);
strlcpy(dev->dev_name, name, UHF_DEV_NAME_MAX_LEN);
}
static bool uhf_device_save_file(
UHFDevice* dev,
const char* dev_name,
const char* folder,
const char* extension,
bool use_load_path) {
furi_assert(dev);
UHFTag* uhf_tag = dev->uhf_tag_wrapper->uhf_tag;
bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
FuriString* temp_str;
temp_str = furi_string_alloc();
do {
if(use_load_path && !furi_string_empty(dev->load_path)) {
// Get directory name
path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str);
// Make path to file to save
furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension);
} else {
// First remove uhf device file if it was saved
furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
}
// Open file
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
// Write header
if(!flipper_format_write_header_cstr(file, uhf_file_header, uhf_file_version)) break;
// Reserved bank might be added
// todo : maybe
uint32_t temp_arr[1];
uint8_t temp_arr2[2];
// write pc
temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) >> 8) & 0xFF;
temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) & 0xFF);
if(!flipper_format_write_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
// write crc
temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) >> 8) & 0xFF;
temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) & 0xFF);
if(!flipper_format_write_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
// write epc
temp_arr[0] = uhf_tag_get_epc_size(uhf_tag);
if(!flipper_format_write_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
if(!flipper_format_write_hex(
file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
break;
// write tid
temp_arr[0] = uhf_tag_get_tid_size(uhf_tag);
if(!flipper_format_write_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
if(!flipper_format_write_hex(
file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
break;
// write user
temp_arr[0] = uhf_tag_get_user_size(uhf_tag);
if(!flipper_format_write_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
if(!flipper_format_write_hex(
file,
UHF_USER_BANK_LABEL,
uhf_tag_get_user(uhf_tag),
uhf_tag_get_user_size(uhf_tag)))
break;
saved = true;
} while(0);
if(!saved) {
dialog_message_show_storage_error(dev->dialogs, "Can not save\nfile");
}
furi_string_free(temp_str);
flipper_format_free(file);
return saved;
}
bool uhf_device_save(UHFDevice* dev, const char* dev_name) {
return uhf_device_save_file(
dev, dev_name, STORAGE_APP_DATA_PATH_PREFIX, UHF_APP_EXTENSION, true);
return false;
}
// uncomment
static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dialog) {
bool parsed = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
// UHFResponseData* uhf_response_data = dev->dev_data;
FuriString* temp_str;
temp_str = furi_string_alloc();
bool deprecated_version = false;
UHFTag* uhf_tag = uhf_tag_alloc();
uhf_tag_reset(uhf_tag);
uint32_t temp_arr[1];
if(dev->loading_cb) {
dev->loading_cb(dev->loading_cb_ctx, true);
}
do {
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
// Read and verify file header
uint32_t version = 0;
if(!flipper_format_read_header(file, temp_str, &version)) break;
if(furi_string_cmp_str(temp_str, uhf_file_header) || (version != uhf_file_version)) {
deprecated_version = true;
break;
}
// read pc
uint8_t temp_arr2[2];
if(!flipper_format_read_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
uhf_tag_set_epc_pc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
// read crc
if(!flipper_format_read_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
uhf_tag_set_epc_crc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
// read epc
if(!flipper_format_read_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
uhf_tag_set_epc_size(uhf_tag, temp_arr[0]);
if(!flipper_format_read_hex(
file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
break;
// read tid
if(!flipper_format_read_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
uhf_tag_set_tid_size(uhf_tag, temp_arr[0]);
if(!flipper_format_read_hex(
file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
break;
// read user
if(!flipper_format_read_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
uhf_tag_set_user_size(uhf_tag, temp_arr[0]);
if(!flipper_format_read_hex(
file,
UHF_USER_BANK_LABEL,
uhf_tag_get_user(uhf_tag),
uhf_tag_get_user_size(uhf_tag)))
break;
parsed = true;
} while(false);
if(dev->loading_cb) {
dev->loading_cb(dev->loading_cb_ctx, false);
}
if((!parsed) && (show_dialog)) {
if(deprecated_version) {
dialog_message_show_storage_error(dev->dialogs, "File format deprecated");
} else {
dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
}
}
uhf_tag_wrapper_set_tag(dev->uhf_tag_wrapper, uhf_tag);
furi_string_free(temp_str);
flipper_format_free(file);
return parsed;
}
// void picopass_device_clear(UHFDevice* dev) {
// furi_assert(dev);
// picopass_device_data_clear(&dev->dev_data);
// memset(&dev->dev_data, 0, sizeof(dev->dev_data));
// dev->format = PicopassDeviceSaveFormatHF;
// furi_string_reset(dev->load_path);
// }
void uhf_device_free(UHFDevice* uhf_dev) {
furi_assert(uhf_dev);
furi_record_close(RECORD_STORAGE);
furi_record_close(RECORD_DIALOGS);
furi_string_free(uhf_dev->load_path);
free(uhf_dev);
}
bool uhf_file_select(UHFDevice* dev) {
furi_assert(dev);
FuriString* uhf_app_folder;
uhf_app_folder = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, UHF_APP_EXTENSION, &I_Nfc_10px);
browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
bool res =
dialog_file_browser_show(dev->dialogs, dev->load_path, uhf_app_folder, &browser_options);
furi_string_free(uhf_app_folder);
if(res) {
FuriString* filename;
filename = furi_string_alloc();
path_extract_filename(dev->load_path, filename, true);
strncpy(dev->dev_name, furi_string_get_cstr(filename), UHF_DEV_NAME_MAX_LEN);
res = uhf_device_load_data(dev, dev->load_path, true);
if(res) {
uhf_device_set_name(dev, dev->dev_name);
}
furi_string_free(filename);
}
return res;
}
// void uhf_device_data_clear(UHFDevice* dev_data) {
// for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
// memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data));
// }
// dev_data->pacs.legacy = false;
// dev_data->pacs.se_enabled = false;
// dev_data->pacs.elite_kdf = false;
// dev_data->pacs.pin_length = 0;
// }
bool uhf_device_delete(UHFDevice* dev, bool use_load_path) {
furi_assert(dev);
bool deleted = false;
FuriString* file_path;
file_path = furi_string_alloc();
do {
// Delete original file
if(use_load_path && !furi_string_empty(dev->load_path)) {
furi_string_set(file_path, dev->load_path);
} else {
furi_string_printf(file_path, APP_DATA_PATH("%s%s"), dev->dev_name, UHF_APP_EXTENSION);
}
if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break;
deleted = true;
} while(0);
if(!deleted) {
dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
}
furi_string_free(file_path);
return deleted;
}
void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback, void* context) {
furi_assert(dev);
dev->loading_cb = callback;
dev->loading_cb_ctx = context;
}
// ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) {
// uint8_t key[32] = {0};
// memcpy(key, picopass_iclass_decryptionkey, sizeof(picopass_iclass_decryptionkey));
// mbedtls_des3_context ctx;
// mbedtls_des3_init(&ctx);
// mbedtls_des3_set2key_dec(&ctx, key);
// mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
// mbedtls_des3_free(&ctx);
// return ERR_NONE;
// }
// ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) {
// ReturnCode err;
// pacs->biometrics = AA1[6].data[4];
// pacs->pin_length = AA1[6].data[6] & 0x0F;
// pacs->encryption = AA1[6].data[7];
// if(pacs->encryption == PicopassDeviceEncryption3DES) {
// FURI_LOG_D(TAG, "3DES Encrypted");
// err = picopass_device_decrypt(AA1[7].data, pacs->credential);
// if(err != ERR_NONE) {
// FURI_LOG_E(TAG, "decrypt error %d", err);
// return err;
// }
// err = picopass_device_decrypt(AA1[8].data, pacs->pin0);
// if(err != ERR_NONE) {
// FURI_LOG_E(TAG, "decrypt error %d", err);
// return err;
// }
// err = picopass_device_decrypt(AA1[9].data, pacs->pin1);
// if(err != ERR_NONE) {
// FURI_LOG_E(TAG, "decrypt error %d", err);
// return err;
// }
// } else if(pacs->encryption == PicopassDeviceEncryptionNone) {
// FURI_LOG_D(TAG, "No Encryption");
// memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN);
// memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN);
// memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN);
// } else if(pacs->encryption == PicopassDeviceEncryptionDES) {
// FURI_LOG_D(TAG, "DES Encrypted");
// } else {
// FURI_LOG_D(TAG, "Unknown encryption");
// }
// pacs->sio = (AA1[10].data[0] == 0x30); // rough check
// return ERR_NONE;
// }
// ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record) {
// uint32_t* halves = (uint32_t*)data;
// if(halves[0] == 0) {
// uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1]));
// record->bitLength = 31 - leading0s;
// } else {
// uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0]));
// record->bitLength = 63 - leading0s;
// }
// FURI_LOG_D(TAG, "bitLength: %d", record->bitLength);
// if(record->bitLength == 26) {
// uint8_t* v4 = data + 4;
// uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24);
// record->CardNumber = (bot >> 1) & 0xFFFF;
// record->FacilityCode = (bot >> 17) & 0xFF;
// FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber);
// record->valid = true;
// } else {
// record->CardNumber = 0;
// record->FacilityCode = 0;
// record->valid = false;
// }
// return ERR_NONE;
// }
-54
View File
@@ -1,54 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <mbedtls/des.h>
#include "uhf_tag.h"
#define UHF_DEV_NAME_MAX_LEN 22
#define UHF_EPC_BANK_LENGTH_LABEL "EPC_LENGTH"
#define UHF_TID_BANK_LENGTH_LABEL "TID_LENGTH"
#define UHF_USER_BANK_LENGTH_LABEL "USER_LENGTH"
#define UHF_EPC_PC_LABEL "PC"
#define UHF_EPC_CRC_LABEL "CRC"
#define UHF_RFU_BANK_LABEL "RFU"
#define UHF_EPC_BANK_LABEL "EPC"
#define UHF_TID_BANK_LABEL "TID"
#define UHF_USER_BANK_LABEL "USER"
#define UHF_APP_EXTENSION ".uhf"
typedef void (*UHFLoadingCallback)(void* context, bool state);
typedef struct {
Storage* storage;
DialogsApp* dialogs;
UHFTagWrapper* uhf_tag_wrapper;
char dev_name[UHF_DEV_NAME_MAX_LEN + 1];
FuriString* load_path;
UHFLoadingCallback loading_cb;
void* loading_cb_ctx;
} UHFDevice;
UHFDevice* uhf_device_alloc();
void uhf_device_free(UHFDevice* uhf_dev);
void uhf_device_set_name(UHFDevice* dev, const char* name);
bool uhf_device_save(UHFDevice* dev, const char* dev_name);
bool uhf_file_select(UHFDevice* dev);
// void uhf_device_data_clear(PicopassDeviceData* dev_data);
void uhf_device_clear(UHFDevice* dev);
bool uhf_device_delete(UHFDevice* dev, bool use_load_path);
void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback, void* context);
// ReturnCode uhf_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs);
// ReturnCode uhf_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record);
-388
View File
@@ -1,388 +0,0 @@
#include "uhf_module.h"
#include "uhf_module_cmd.h"
#define DELAY_MS 100
#define WAIT_TICK 8000 // max wait time in between each byte
volatile uint16_t tick = 0;
void rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
UNUSED(event);
Buffer* buffer = ctx;
if(buffer->closed) return; // buffer closed
buffer_append_single(buffer, data); // append data
if(data == FRAME_END) buffer_close(buffer); // end of frame
tick = WAIT_TICK; // reset tick
}
static M100ResponseType setup_and_send_rx(M100Module* module, uint8_t* cmd, size_t cmd_length) {
buffer_reset(module->buf);
tick = WAIT_TICK;
furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, cmd_length);
while(--tick) {
furi_delay_us(5);
}
buffer_close(module->buf);
// Validation Checks
uint8_t* data = buffer_get_data(module->buf);
size_t length = buffer_get_size(module->buf);
// check if size > 0
if(!length) return M100EmptyResponse;
// check if data is valid
if(data[0] != FRAME_START || data[length - 1] != FRAME_END) return M100ValidationFail;
// check if checksum is correct
if(checksum(data + 1, length - 3) != data[length - 2]) return M100ChecksumFail;
return M100SuccessResponse;
}
M100ModuleInfo* m100_module_info_alloc() {
M100ModuleInfo* module_info = (M100ModuleInfo*)malloc(sizeof(M100ModuleInfo));
return module_info;
}
void m100_module_info_free(M100ModuleInfo* module_info) {
free(module_info->hw_version);
free(module_info->sw_version);
free(module_info->manufacturer);
free(module_info);
}
M100Module* m100_module_alloc() {
M100Module* module = (M100Module*)malloc(sizeof(M100Module));
module->info = m100_module_info_alloc();
module->buf = buffer_alloc(MAX_BUFFER_SIZE);
module->baudrate = DEFAULT_BAUDRATE;
module->transmitting_power = DEFAULT_TRANSMITTING_POWER;
module->region = DEFAULT_WORKING_REGION;
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
return module;
}
void m100_module_free(M100Module* module) {
m100_module_info_free(module->info);
buffer_free(module->buf);
free(module);
}
uint8_t checksum(const uint8_t* data, size_t length) {
// CheckSum8 Modulo 256
// Sum of Bytes % 256
uint64_t sum_val = 0x00;
for(size_t i = 0; i < length; i++) {
sum_val += data[i];
}
return (uint8_t)(sum_val % 0x100);
}
uint16_t crc16_genibus(const uint8_t* data, size_t length) {
uint16_t crc = 0xFFFF; // Initial value
uint16_t polynomial = 0x1021; // CRC-16/GENIBUS polynomial
for(size_t i = 0; i < length; i++) {
crc ^= (data[i] << 8); // Move byte into MSB of 16bit CRC
for(int j = 0; j < 8; j++) {
if(crc & 0x8000) {
crc = (crc << 1) ^ polynomial;
} else {
crc <<= 1;
}
}
}
return crc ^ 0xFFFF; // Post-inversion
}
char* _m100_info_helper(M100Module* module, char** info) {
if(!buffer_get_size(module->buf)) return NULL;
uint8_t* data = buffer_get_data(module->buf);
uint16_t payload_len = data[3];
payload_len = (payload_len << 8) + data[4];
FuriString* temp_str = furi_string_alloc();
for(int i = 0; i < payload_len; i++) {
furi_string_cat_printf(temp_str, "%c", data[6 + i]);
}
if(*info == NULL) {
*info = (char*)malloc(sizeof(char) * payload_len);
} else {
for(size_t i = 0; i < strlen(*info); i++) {
(*info)[i] = 0;
}
}
memcpy(*info, furi_string_get_cstr(temp_str), payload_len);
furi_string_free(temp_str);
return *info;
}
char* m100_get_hardware_version(M100Module* module) {
setup_and_send_rx(module, (uint8_t*)&CMD_HW_VERSION.cmd[0], CMD_HW_VERSION.length);
return _m100_info_helper(module, &module->info->hw_version);
}
char* m100_get_software_version(M100Module* module) {
setup_and_send_rx(module, (uint8_t*)&CMD_SW_VERSION.cmd[0], CMD_SW_VERSION.length);
return _m100_info_helper(module, &module->info->sw_version);
}
char* m100_get_manufacturers(M100Module* module) {
setup_and_send_rx(module, (uint8_t*)&CMD_MANUFACTURERS.cmd[0], CMD_MANUFACTURERS.length);
return _m100_info_helper(module, &module->info->manufacturer);
}
M100ResponseType m100_single_poll(M100Module* module, UHFTag* uhf_tag) {
M100ResponseType rp_type =
setup_and_send_rx(module, (uint8_t*)&CMD_SINGLE_POLLING.cmd[0], CMD_SINGLE_POLLING.length);
if(rp_type != M100SuccessResponse) return rp_type;
uint8_t* data = buffer_get_data(module->buf);
size_t length = buffer_get_size(module->buf);
uint16_t pc = data[6];
uint16_t crc = 0;
// mask out epc length from protocol control
size_t epc_len = pc;
epc_len >>= 3;
epc_len *= 2;
// get protocol control
pc <<= 8;
pc += data[7];
// get cyclic redundency check
crc = data[8 + epc_len];
crc <<= 8;
crc += data[8 + epc_len + 1];
// validate checksum
if(checksum(data + 1, length - 3) != data[length - 2]) return M100ValidationFail;
// validate crc
if(crc16_genibus(data + 6, epc_len + 2) != crc) return M100ValidationFail;
uhf_tag_set_epc_pc(uhf_tag, pc);
uhf_tag_set_epc_crc(uhf_tag, crc);
uhf_tag_set_epc(uhf_tag, data + 8, epc_len);
return M100SuccessResponse;
}
M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag) {
// Set select
uint8_t cmd[MAX_BUFFER_SIZE];
size_t cmd_length = CMD_SET_SELECT_PARAMETER.length;
size_t mask_length_bytes = uhf_tag->epc->size;
size_t mask_length_bits = mask_length_bytes * 8;
// payload len == sel param len + ptr len + mask len + epc len
size_t payload_len = 7 + mask_length_bytes;
memcpy(cmd, CMD_SET_SELECT_PARAMETER.cmd, cmd_length);
// set new length
cmd_length = 12 + mask_length_bytes + 2;
// set payload length
cmd[3] = (payload_len >> 8) & 0xFF;
cmd[4] = payload_len & 0xFF;
// set select param
cmd[5] = 0x01; // 0x00=rfu, 0x01=epc, 0x10=tid, 0x11=user
// set ptr
cmd[9] = 0x20; // epc data begins after 0x20
// set mask length
cmd[10] = mask_length_bits;
// truncate
cmd[11] = false;
// set mask
memcpy((void*)&cmd[12], uhf_tag->epc->data, mask_length_bytes);
// set checksum
cmd[cmd_length - 2] = checksum(cmd + 1, 11 + mask_length_bytes);
// end frame
cmd[cmd_length - 1] = FRAME_END;
setup_and_send_rx(module, cmd, 12 + mask_length_bytes + 3);
uint8_t* data = buffer_get_data(module->buf);
if(checksum(data + 1, 5) != data[6]) return M100ValidationFail; // error in rx
if(data[5] != 0x00) return M100ValidationFail; // error if not 0
return M100SuccessResponse;
}
UHFTag* m100_get_select_param(M100Module* module) {
buffer_reset(module->buf);
furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->buf);
furi_hal_uart_tx(
FuriHalUartIdUSART1,
(uint8_t*)&CMD_GET_SELECT_PARAMETER.cmd,
CMD_GET_SELECT_PARAMETER.length);
furi_delay_ms(DELAY_MS);
// UHFTag* uhf_tag = uhf_tag_alloc();
// uint8_t* data = buffer_get_data(module->buf);
// size_t mask_length =
// uhf_tag_set_epc(uhf_tag, data + 12, )
// TODO : implement
return NULL;
}
M100ResponseType m100_read_label_data_storage(
M100Module* module,
UHFTag* uhf_tag,
BankType bank,
uint32_t access_pwd,
uint16_t word_count) {
/*
Will probably remove UHFTag as param and get it from get selected tag
*/
if(bank == EPCBank) return M100SuccessResponse;
uint8_t cmd[MAX_BUFFER_SIZE];
size_t cmd_length = CMD_READ_LABEL_DATA_STORAGE_AREA.length;
memcpy(cmd, CMD_READ_LABEL_DATA_STORAGE_AREA.cmd, cmd_length);
// set access password
cmd[5] = (access_pwd >> 24) & 0xFF;
cmd[6] = (access_pwd >> 16) & 0xFF;
cmd[7] = (access_pwd >> 8) & 0xFF;
cmd[8] = access_pwd & 0xFF;
// set mem bank
cmd[9] = (uint8_t)bank;
// set word counter
cmd[12] = (word_count >> 8) & 0xFF;
cmd[13] = word_count & 0xFF;
// calc checksum
cmd[cmd_length - 2] = checksum(cmd + 1, cmd_length - 3);
M100ResponseType rp_type = setup_and_send_rx(module, cmd, cmd_length);
if(rp_type != M100SuccessResponse) return rp_type;
uint8_t* data = buffer_get_data(module->buf);
uint8_t rtn_command = data[2];
uint16_t payload_len = data[3];
payload_len = (payload_len << 8) + data[4];
if(rtn_command == 0xFF) {
if(payload_len == 0x01) return M100NoTagResponse;
return M100MemoryOverrun;
}
size_t ptr_offset = 5 /*<-ptr offset*/ + uhf_tag_get_epc_size(uhf_tag) + 3 /*<-pc + ul*/;
size_t bank_data_length = payload_len - (ptr_offset - 5 /*dont include the offset*/);
if(bank == TIDBank) {
uhf_tag_set_tid(uhf_tag, data + ptr_offset, bank_data_length);
} else if(bank == UserBank) {
uhf_tag_set_user(uhf_tag, data + ptr_offset, bank_data_length);
}
return M100SuccessResponse;
}
M100ResponseType m100_write_label_data_storage(
M100Module* module,
UHFTag* saved_tag,
UHFTag* selected_tag,
BankType bank,
uint16_t source_address,
uint32_t access_pwd) {
uint8_t cmd[MAX_BUFFER_SIZE];
size_t cmd_length = CMD_WRITE_LABEL_DATA_STORE.length;
memcpy(cmd, CMD_WRITE_LABEL_DATA_STORE.cmd, cmd_length);
uint16_t payload_len = 9;
uint16_t data_length = 0;
if(bank == ReservedBank) {
// access pwd len + kill pwd len
payload_len += 4;
data_length = 4;
} else if(bank == EPCBank) {
// epc len + pc len
payload_len += 4 + uhf_tag_get_epc_size(saved_tag);
data_length = 4 + uhf_tag_get_epc_size(saved_tag);
// set data
uint8_t tmp_arr[4];
tmp_arr[0] = (uint8_t)((uhf_tag_get_epc_crc(selected_tag) >> 8) & 0xFF);
tmp_arr[1] = (uint8_t)(uhf_tag_get_epc_crc(selected_tag) & 0xFF);
tmp_arr[2] = (uint8_t)((uhf_tag_get_epc_pc(saved_tag) >> 8) & 0xFF);
tmp_arr[3] = (uint8_t)(uhf_tag_get_epc_pc(saved_tag) & 0xFF);
memcpy(cmd + 14, tmp_arr, 4);
memcpy(cmd + 18, uhf_tag_get_epc(saved_tag), uhf_tag_get_epc_size(saved_tag));
} else if(bank == UserBank) {
payload_len += uhf_tag_get_user_size(saved_tag);
data_length = uhf_tag_get_user_size(saved_tag);
// set data
memcpy(cmd + 14, uhf_tag_get_user(saved_tag), uhf_tag_get_user_size(saved_tag));
}
// set payload length
cmd[3] = (payload_len >> 8) & 0xFF;
cmd[4] = payload_len & 0xFF;
// set access password
cmd[5] = (access_pwd >> 24) & 0xFF;
cmd[6] = (access_pwd >> 16) & 0xFF;
cmd[7] = (access_pwd >> 8) & 0xFF;
cmd[8] = access_pwd & 0xFF;
// set membank
cmd[9] = (uint8_t)bank;
// set source address
cmd[10] = (source_address >> 8) & 0xFF;
cmd[11] = source_address & 0xFF;
// set data length
size_t data_length_words = data_length / 2;
cmd[12] = (data_length_words >> 8) & 0xFF;
cmd[13] = data_length_words & 0xFF;
// update cmd len
cmd_length = 7 + payload_len;
// calculate checksum
cmd[cmd_length - 2] = checksum(cmd + 1, cmd_length - 3);
cmd[cmd_length - 1] = FRAME_END;
// send cmd
// furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
// furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, cmd_length);
// unsigned int delay = DELAY_MS / 2;
// unsigned int timeout = 15;
// while(!buffer_get_size(module->buf)) {
// furi_delay_ms(delay);
// if(!timeout--) break;
// }
setup_and_send_rx(module, cmd, cmd_length);
uint8_t* buff_data = buffer_get_data(module->buf);
size_t buff_length = buffer_get_size(module->buf);
if(buff_data[2] == 0xFF && buff_length == 8)
return M100NoTagResponse;
else if(buff_data[2] == 0xFF)
return M100ValidationFail;
return M100SuccessResponse;
}
void m100_set_baudrate(M100Module* module, uint32_t baudrate) {
size_t length = CMD_SET_COMMUNICATION_BAUD_RATE.length;
uint8_t cmd[length];
memcpy(cmd, CMD_SET_COMMUNICATION_BAUD_RATE.cmd, length);
uint16_t br_mod = baudrate / 100; // module format
cmd[6] = 0xFF & br_mod; // pow LSB
cmd[5] = 0xFF & (br_mod >> 8); // pow MSB
cmd[length - 2] = checksum(cmd + 1, length - 3);
furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, length);
furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate);
module->baudrate = baudrate;
}
bool m100_set_working_region(M100Module* module, WorkingRegion region) {
size_t length = CMD_SET_WORK_AREA.length;
uint8_t cmd[length];
memcpy(cmd, CMD_SET_WORK_AREA.cmd, length);
cmd[5] = (uint8_t)region;
cmd[length - 2] = checksum(cmd + 1, length - 3);
setup_and_send_rx(module, cmd, length);
module->region = region;
return true;
}
bool m100_set_transmitting_power(M100Module* module, uint16_t power) {
size_t length = CMD_SET_TRANSMITTING_POWER.length;
uint8_t cmd[length];
memcpy(cmd, CMD_SET_TRANSMITTING_POWER.cmd, length);
cmd[5] = (power >> 8) & 0xFF;
cmd[6] = power & 0xFF;
cmd[length - 2] = checksum(cmd + 1, length - 3);
setup_and_send_rx(module, cmd, length);
module->transmitting_power = power;
return true;
}
bool m100_set_freq_hopping(M100Module* module, bool hopping) {
UNUSED(module);
UNUSED(hopping);
return true;
}
bool m100_set_power(M100Module* module, uint8_t* power) {
UNUSED(module);
UNUSED(power);
return true;
}
uint32_t m100_get_baudrate(M100Module* module) {
return module->baudrate;
}
-82
View File
@@ -1,82 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <furi_hal.h>
#include "uhf_tag.h"
#include "uhf_buffer.h"
#include "uhf_tag.h"
#include <furi_hal.h>
#include "uhf_module_settings.h"
#define FRAME_START 0xBB
#define FRAME_END 0x7E
#define DEFAULT_BAUDRATE BAUD_RATES[BAUD_RATES_COUNT - 1]
#define DEFAULT_TRANSMITTING_POWER POWER_DBM[POWER_DBM_COUNT - 1]
#define DEFAULT_WORKING_REGION WR_US
typedef struct {
char* hw_version;
char* sw_version;
char* manufacturer;
} M100ModuleInfo;
typedef enum {
M100SuccessResponse,
M100ValidationFail,
M100NoTagResponse,
M100MemoryOverrun,
M100EmptyResponse,
M100ChecksumFail
} M100ResponseType;
typedef struct {
M100ModuleInfo* info;
uint32_t baudrate;
WorkingRegion region;
uint16_t region_frequency;
uint16_t transmitting_power;
bool freq_hopping;
Buffer* buf;
} M100Module;
M100ModuleInfo* m100_module_info_alloc();
void m100_module_info_free(M100ModuleInfo* module_info);
M100Module* m100_module_alloc();
void m100_module_free(M100Module* module);
uint16_t crc16_genibus(const uint8_t* data, size_t length);
uint8_t checksum(const uint8_t* data, size_t length);
uint8_t get_baudrate_count();
// Function prototypes
char* m100_get_hardware_version(M100Module* module);
char* m100_get_software_version(M100Module* module);
char* m100_get_manufacturers(M100Module* module);
void m100_set_baudrate(M100Module* module, uint32_t baudrate);
bool m100_set_working_region(M100Module* module, WorkingRegion region);
bool m100_set_transmitting_power(M100Module* module, uint16_t power);
bool m100_set_freq_hopping(M100Module* module, bool hopping);
bool m100_set_power(M100Module* module, uint8_t* power);
// gen2 cmds
M100ResponseType m100_single_poll(M100Module* module, UHFTag* uhf_tag);
M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag);
M100ResponseType m100_read_label_data_storage(
M100Module* module,
UHFTag* uhf_tag,
BankType bank,
uint32_t access_pwd,
uint16_t word_count);
M100ResponseType m100_write_label_data_storage(
M100Module* module,
UHFTag* saved_tag,
UHFTag* selected_tag,
BankType bank,
uint16_t source_address,
uint32_t access_pwd);
uint32_t m100_get_baudrate(M100Module* module);
-89
View File
@@ -1,89 +0,0 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef struct {
const uint8_t* cmd;
size_t length;
} Command;
// Define the command data arrays
static const uint8_t CMD_HW_VERSION_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x7E};
static const uint8_t CMD_SW_VERSION_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x01, 0x05, 0x7E};
static const uint8_t CMD_MANUFACTURERS_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x02, 0x06, 0x7E};
static const uint8_t CMD_SINGLE_POLLING_DATA[] = {0xBB, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7E};
static const uint8_t CMD_MULTIPLE_POLLING_DATA[] =
{0xBB, 0x00, 0x27, 0x00, 0x03, 0x22, 0x27, 0x10, 0x83, 0x7E};
static const uint8_t CMD_STOP_MULTIPLE_POLLING_DATA[] = {0xBB, 0x00, 0x28, 0x00, 0x00, 0x28, 0x7E};
static const uint8_t CMD_SET_SELECT_PARAMETER_DATA[] = {0xBB, 0x00, 0x0C, 0x00, 0x13, 0x01, 0x00,
0x00, 0x00, 0x20, 0x60, 0x00, 0x30, 0x75,
0x1F, 0xEB, 0x70, 0x5C, 0x59, 0x04, 0xE3,
0xD5, 0x0D, 0x70, 0xAD, 0x7E};
static const uint8_t CMD_GET_SELECT_PARAMETER_DATA[] = {0xBB, 0x00, 0x0B, 0x00, 0x00, 0x0B, 0x7E};
static const uint8_t CMD_SET_SELECT_MODE_DATA[] = {0xBB, 0x00, 0x12, 0x00, 0x01, 0x01, 0x14, 0x7E};
static const uint8_t CMD_READ_LABEL_DATA_STORAGE_AREA_DATA[] =
{0xBB, 0x00, 0x39, 0x00, 0x09, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x45, 0x7E};
static const uint8_t CMD_WRITE_LABEL_DATA_STORE_DATA[] = {0xBB, 0x00, 0x49, 0x00, 0x0D, 0x00, 0x00,
0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02,
0x12, 0x34, 0x56, 0x78, 0x6D, 0x7E};
static const uint8_t CMD_LOCK_LABEL_DATA_STORE_DATA[] =
{0xBB, 0x00, 0x82, 0x00, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x80, 0x09, 0x7E};
static const uint8_t CMD_INACTIVATE_KILL_TAG_DATA[] =
{0xBB, 0x00, 0x65, 0x00, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0x67, 0x7E};
static const uint8_t CMD_SET_COMMUNICATION_BAUD_RATE_DATA[] =
{0xBB, 0x00, 0x11, 0x00, 0x02, 0x00, 0xC0, 0xD3, 0x7E};
static const uint8_t CMD_GET_QUERY_PARAMETERS_DATA[] = {0xBB, 0x00, 0x0D, 0x00, 0x00, 0x0D, 0x7E};
static const uint8_t CMD_SET_QUERY_PARAMETER_DATA[] =
{0xBB, 0x00, 0x0E, 0x00, 0x02, 0x10, 0x20, 0x40, 0x7E};
static const uint8_t CMD_SET_WORK_AREA_DATA[] = {0xBB, 0x00, 0x07, 0x00, 0x01, 0x01, 0x09, 0x7E};
static const uint8_t CMD_SET_TRANSMITTING_POWER_DATA[] =
{0xBB, 0x00, 0xB6, 0x00, 0x02, 0x07, 0xD0, 0x8F, 0x7E};
// Define the Command structs
static const Command CMD_HW_VERSION = {CMD_HW_VERSION_DATA, sizeof(CMD_HW_VERSION_DATA)};
static const Command CMD_SW_VERSION = {CMD_SW_VERSION_DATA, sizeof(CMD_SW_VERSION_DATA)};
static const Command CMD_MANUFACTURERS = {CMD_MANUFACTURERS_DATA, sizeof(CMD_MANUFACTURERS_DATA)};
static const Command CMD_SINGLE_POLLING = {
CMD_SINGLE_POLLING_DATA,
sizeof(CMD_SINGLE_POLLING_DATA)};
static const Command CMD_MULTIPLE_POLLING = {
CMD_MULTIPLE_POLLING_DATA,
sizeof(CMD_MULTIPLE_POLLING_DATA)};
static const Command CMD_STOP_MULTIPLE_POLLING = {
CMD_STOP_MULTIPLE_POLLING_DATA,
sizeof(CMD_STOP_MULTIPLE_POLLING_DATA)};
static const Command CMD_SET_SELECT_PARAMETER = {
CMD_SET_SELECT_PARAMETER_DATA,
sizeof(CMD_SET_SELECT_PARAMETER_DATA)};
static const Command CMD_GET_SELECT_PARAMETER = {
CMD_GET_SELECT_PARAMETER_DATA,
sizeof(CMD_GET_SELECT_PARAMETER_DATA)};
static const Command CMD_SET_SELECT_MODE = {
CMD_SET_SELECT_MODE_DATA,
sizeof(CMD_SET_SELECT_MODE_DATA)};
static const Command CMD_READ_LABEL_DATA_STORAGE_AREA = {
CMD_READ_LABEL_DATA_STORAGE_AREA_DATA,
sizeof(CMD_READ_LABEL_DATA_STORAGE_AREA_DATA)};
static const Command CMD_WRITE_LABEL_DATA_STORE = {
CMD_WRITE_LABEL_DATA_STORE_DATA,
sizeof(CMD_WRITE_LABEL_DATA_STORE_DATA)};
static const Command CMD_LOCK_LABEL_DATA_STORE = {
CMD_LOCK_LABEL_DATA_STORE_DATA,
sizeof(CMD_LOCK_LABEL_DATA_STORE_DATA)};
static const Command CMD_INACTIVATE_KILL_TAG = {
CMD_INACTIVATE_KILL_TAG_DATA,
sizeof(CMD_INACTIVATE_KILL_TAG_DATA)};
static const Command CMD_SET_COMMUNICATION_BAUD_RATE = {
CMD_SET_COMMUNICATION_BAUD_RATE_DATA,
sizeof(CMD_SET_COMMUNICATION_BAUD_RATE_DATA)};
static const Command CMD_GET_QUERY_PARAMETERS = {
CMD_GET_QUERY_PARAMETERS_DATA,
sizeof(CMD_GET_QUERY_PARAMETERS_DATA)};
static const Command CMD_SET_QUERY_PARAMETER = {
CMD_SET_QUERY_PARAMETER_DATA,
sizeof(CMD_SET_QUERY_PARAMETER_DATA)};
static const Command CMD_SET_WORK_AREA = {CMD_SET_WORK_AREA_DATA, sizeof(CMD_SET_WORK_AREA_DATA)};
static const Command CMD_SET_TRANSMITTING_POWER = {
CMD_SET_TRANSMITTING_POWER_DATA,
sizeof(CMD_SET_TRANSMITTING_POWER_DATA)};
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include <stdint.h>
// UHF module regions
typedef enum {
WR_CHINA_900 = 1, // Freq_CH-920.125M
WR_US, // Freq_CH-902.25M
WR_EU, // Freq_CH-865.1M
WR_CHINA_800, // Freq_CH-840.125M
WR_KOREA = 6 // Freq_CH-917.1M
} WorkingRegion;
// UHF module baudrates
static const uint32_t BAUD_RATES[] = {9600, 19200, 115200};
static const uint8_t BAUD_RATES_COUNT = sizeof(BAUD_RATES) / sizeof(BAUD_RATES[0]);
// RF Power Setting
static const uint8_t POWER_DBM[] = {12, 14, 17, 20}; // To be determined ...
static const uint8_t POWER_DBM_COUNT = sizeof(POWER_DBM) / sizeof(POWER_DBM[0]);
// UHF WorkingArea
static const char* WORKING_REGIONS_STR[] = {"CN1", "US", "EU", "CN2", "KR"};
static const uint8_t __working_region_str =
sizeof(WORKING_REGIONS_STR) / sizeof(WORKING_REGIONS_STR[0]);
static const WorkingRegion WORKING_REGIONS[] = {WR_CHINA_900, WR_US, WR_EU, WR_CHINA_800, WR_KOREA};
static const uint8_t WORKING_REGIONS_COUNT = sizeof(WORKING_REGIONS) / sizeof(WORKING_REGIONS[0]);
// UHF WorkingChannel
// static const string WORKING_CHANNELS_STR[] = {"China 900MHz", "US", "EU", "China 800MHz", "Korea"};
// static const WorkingChannel WORKING_CHANNELS[] = {WC_CHINA_900, WC_US, WC_EU, WC_CHINA_800, WC_KOREA};
// static const uint8_t WORKING_CHANNELS_COUNT = sizeof(WORKING_CHANNELS) / sizeof(WORKING_CHANNELS[0]);
-116
View File
@@ -1,116 +0,0 @@
#include "uhf_tag.h"
#include <stdlib.h>
#include <string.h>
UHFTagWrapper* uhf_tag_wrapper_alloc() {
UHFTagWrapper* uhf_tag_wrapper = (UHFTagWrapper*)malloc(sizeof(UHFTagWrapper));
uhf_tag_wrapper->uhf_tag = NULL;
return uhf_tag_wrapper;
}
void uhf_tag_wrapper_set_tag(UHFTagWrapper* uhf_tag_wrapper, UHFTag* uhf_tag) {
if(uhf_tag_wrapper->uhf_tag != NULL) {
uhf_tag_free(uhf_tag_wrapper->uhf_tag);
}
uhf_tag_wrapper->uhf_tag = uhf_tag;
}
void uhf_tag_wrapper_free(UHFTagWrapper* uhf_tag_wrapper) {
uhf_tag_free(uhf_tag_wrapper->uhf_tag);
free(uhf_tag_wrapper);
}
UHFTag* uhf_tag_alloc() {
UHFTag* uhf_tag = (UHFTag*)malloc(sizeof(UHFTag));
uhf_tag->reserved = (ReservedMemoryBank*)malloc(sizeof(ReservedMemoryBank));
uhf_tag->epc = (EPCMemoryBank*)malloc(sizeof(EPCMemoryBank));
uhf_tag->tid = (TIDMemoryBank*)malloc(sizeof(TIDMemoryBank));
uhf_tag->user = (UserMemoryBank*)malloc(sizeof(UserMemoryBank));
return uhf_tag;
}
void uhf_tag_reset(UHFTag* uhf_tag) {
uhf_tag->epc->crc = 0;
uhf_tag->epc->pc = 0;
uhf_tag->epc->size = 0;
uhf_tag->tid->size = 0;
uhf_tag->user->size = 0;
}
void uhf_tag_free(UHFTag* uhf_tag) {
if(uhf_tag == NULL) return;
free(uhf_tag->reserved);
free(uhf_tag->epc);
free(uhf_tag->tid);
free(uhf_tag->user);
free(uhf_tag);
}
void uhf_tag_set_epc_pc(UHFTag* uhf_tag, uint16_t pc) {
uhf_tag->epc->pc = pc;
}
void uhf_tag_set_epc_crc(UHFTag* uhf_tag, uint16_t crc) {
uhf_tag->epc->crc = crc;
}
void uhf_tag_set_epc(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
memcpy(uhf_tag->epc->data, data_in, size);
uhf_tag->epc->size = size;
}
void uhf_tag_set_epc_size(UHFTag* uhf_tag, size_t size) {
uhf_tag->epc->size = size;
}
void uhf_tag_set_tid(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
memcpy(uhf_tag->tid->data, data_in, size);
uhf_tag->tid->size = size;
}
void uhf_tag_set_tid_size(UHFTag* uhf_tag, size_t size) {
uhf_tag->tid->size = size;
}
void uhf_tag_set_user(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
memcpy(uhf_tag->user->data, data_in, size);
uhf_tag->user->size = size;
}
void uhf_tag_set_user_size(UHFTag* uhf_tag, size_t size) {
uhf_tag->user->size = size;
}
// getters
uint8_t* uhf_tag_get_epc(UHFTag* uhf_tag) {
return uhf_tag->epc->data;
}
size_t uhf_tag_get_epc_size(UHFTag* uhf_tag) {
return uhf_tag->epc->size;
}
uint16_t uhf_tag_get_epc_pc(UHFTag* uhf_tag) {
return uhf_tag->epc->pc;
}
uint16_t uhf_tag_get_epc_crc(UHFTag* uhf_tag) {
return uhf_tag->epc->crc;
}
uint8_t* uhf_tag_get_tid(UHFTag* uhf_tag) {
return uhf_tag->tid->data;
}
size_t uhf_tag_get_tid_size(UHFTag* uhf_tag) {
return uhf_tag->tid->size;
}
uint8_t* uhf_tag_get_user(UHFTag* uhf_tag) {
return uhf_tag->user->data;
}
size_t uhf_tag_get_user_size(UHFTag* uhf_tag) {
return uhf_tag->user->size;
}

Some files were not shown because too many files have changed in this diff Show More