Skip to content

Commit be79a9e

Browse files
committed
MagSpoof read PoC
1 parent a4df68c commit be79a9e

File tree

11 files changed

+314
-8
lines changed

11 files changed

+314
-8
lines changed

application.fam

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
App(
22
appid="mag",
3-
name="MagSpoof WIP",
3+
name="MagSpoof",
44
apptype=FlipperAppType.EXTERNAL,
55
entry_point="mag_app",
66
cdefines=["APP_MAG"],
@@ -11,10 +11,10 @@ App(
1111
"dialogs",
1212
],
1313
provides=[],
14-
stack_size=5 * 1024,
14+
stack_size=6 * 1024,
1515
order=64, # keep it at the bottom of the list while still WIP
1616
fap_icon="icons/mag_10px.png",
17-
fap_category="Tools",
17+
fap_category="GPIO",
1818
fap_icon_assets="icons",
1919
fap_version=(0, 5), # major, minor
2020
fap_description="WIP MagSpoof port using the RFID subsystem",

helpers/mag_helpers.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
#define TAG "MagHelpers"
44

5-
#define GPIO_PIN_A &gpio_ext_pa6
6-
#define GPIO_PIN_B &gpio_ext_pa7
5+
// Haviv Board - pins gpio_ext_pa7 & gpio_ext_pa6 was swapped.
6+
#define GPIO_PIN_A &gpio_ext_pa7
7+
#define GPIO_PIN_B &gpio_ext_pa6
78
#define GPIO_PIN_ENABLE &gpio_ext_pa4
89
#define RFID_PIN_OUT &gpio_rfid_carrier_out
910

@@ -126,10 +127,12 @@ void tx_init_rfid() {
126127
// initialize RFID system for TX
127128

128129
// OTG needed for RFID? Or just legacy from GPIO?
129-
furi_hal_power_enable_otg();
130+
// furi_hal_power_enable_otg();
131+
furi_hal_ibutton_pin_configure();
132+
133+
// furi_hal_ibutton_start_drive();
134+
furi_hal_ibutton_pin_write(false);
130135

131-
furi_hal_ibutton_start_drive();
132-
furi_hal_ibutton_pin_low();
133136

134137
// Initializing at GpioSpeedLow seems sufficient for our needs; no improvements seen by increasing speed setting
135138

helpers/mag_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,10 @@ typedef enum {
3636
MagTxCC1101_434,
3737
MagTxCC1101_868,
3838
} MagTxState;
39+
40+
41+
typedef enum {
42+
UART_TerminalEventRefreshConsoleOutput = 0,
43+
UART_TerminalEventStartConsole,
44+
UART_TerminalEventStartKeyboard,
45+
} UART_TerminalCustomEvent;

mag_device.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,77 @@ bool mag_device_delete(MagDevice* mag_dev, bool use_load_path) {
230230
return deleted;
231231
}
232232

233+
bool mag_device_parse_card_string(MagDevice* mag_dev, FuriString* f_card_str) {
234+
furi_assert(mag_dev);
235+
FURI_LOG_D(TAG, "mag_device_parse_card_string");
236+
237+
const char* card_str = furi_string_get_cstr(f_card_str);
238+
239+
FURI_LOG_D(TAG, "Parsing card string: %s", card_str);
240+
241+
// Track 1
242+
const char* track1_start = strchr(card_str, '%');
243+
if(!track1_start) {
244+
FURI_LOG_D(TAG, "Could not find track 1 start");
245+
return false;
246+
}
247+
track1_start++;
248+
const char* track1_end = strchr(track1_start, '?');
249+
if(!track1_end) {
250+
FURI_LOG_D(TAG, "Could not find track 1 end");
251+
return false;
252+
}
253+
size_t track1_len = track1_end - track1_start;
254+
255+
FURI_LOG_D(TAG, "Track 1: %.*s", track1_len, track1_start);
256+
257+
mag_dev->dev_data.track[0].len = track1_len;
258+
furi_string_printf(mag_dev->dev_data.track[0].str, "%%%.*s?", track1_len, track1_start);
259+
260+
// Track 2
261+
const char* track2_start = strchr(track1_end, ';');
262+
if (!track2_start) {
263+
FURI_LOG_D(TAG, "Could not find track 2 start");
264+
return true;
265+
}
266+
267+
track2_start++;
268+
const char* track2_end = strchr(track2_start, '?');
269+
if(!track2_end) {
270+
FURI_LOG_D(TAG, "Could not find track 2 end");
271+
return true;
272+
}
273+
size_t track2_len = track2_end - track2_start;
274+
275+
FURI_LOG_D(TAG, "Track 2: %.*s", track2_len, track2_start);
276+
277+
mag_dev->dev_data.track[1].len = track2_len;
278+
furi_string_printf(mag_dev->dev_data.track[1].str, "%%%.*s?", track2_len, track2_start);
279+
280+
// Track 3
281+
const char* track3_start = strchr(track2_end, ';');
282+
if (!track3_start) {
283+
FURI_LOG_D(TAG, "Could not find track 3 start");
284+
return true;
285+
}
286+
287+
track3_start++;
288+
const char* track3_end = strchr(track3_start, '?');
289+
if(!track3_end) {
290+
FURI_LOG_D(TAG, "Could not find track 3 end");
291+
return true;
292+
}
293+
size_t track3_len = track3_end - track3_start;
294+
295+
FURI_LOG_D(TAG, "Track 3: %.*s", track3_len, track3_start);
296+
297+
mag_dev->dev_data.track[2].len = track3_len;
298+
furi_string_printf(mag_dev->dev_data.track[2].str, "%%%.*s?", track3_len, track3_start);
299+
300+
return true;
301+
}
302+
303+
233304
void mag_device_set_loading_callback(
234305
MagDevice* mag_dev,
235306
MagLoadingCallback callback,

mag_device.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ typedef void (*MagLoadingCallback)(void* context, bool state);
1717

1818
typedef struct {
1919
FuriString* str;
20+
size_t len;
2021
} MagTrack;
2122

2223
typedef struct {
@@ -49,6 +50,8 @@ void mag_device_clear(MagDevice* mag_dev);
4950

5051
bool mag_device_delete(MagDevice* mag_dev, bool use_load_path);
5152

53+
bool mag_device_parse_card_string(MagDevice* mag_dev, FuriString* card_str);
54+
5255
void mag_device_set_loading_callback(
5356
MagDevice* mag_dev,
5457
MagLoadingCallback callback,

mag_i.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <toolbox/value_index.h>
3434

3535
#include "scenes/mag_scene.h"
36+
#include "scenes/mag_scene_read.h"
3637

3738
#define MAG_TEXT_STORE_SIZE 150
3839

@@ -50,6 +51,7 @@ typedef struct {
5051
uint32_t us_interpacket;
5152
} MagSetting;
5253

54+
5355
typedef struct {
5456
ViewDispatcher* view_dispatcher;
5557
Gui* gui;
@@ -76,6 +78,17 @@ typedef struct {
7678

7779
// Custom views
7880
Mag_TextInput* mag_text_input;
81+
82+
// UART
83+
FuriThread* uart_rx_thread;
84+
FuriStreamBuffer* uart_rx_stream;
85+
uint8_t uart_rx_buf[UART_RX_BUF_SIZE + 1];
86+
void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context);
87+
88+
char uart_text_input_store[UART_TERMINAL_TEXT_INPUT_STORE_SIZE + 1];
89+
FuriString* uart_text_box_store;
90+
size_t uart_text_box_store_strlen;
91+
// UART_TextInput* text_input;
7992
} Mag;
8093

8194
void mag_text_store_set(Mag* mag, const char* text, ...);

scenes/mag_scene_config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ ADD_SCENE(mag, delete_success, DeleteSuccess)
1212
ADD_SCENE(mag, delete_confirm, DeleteConfirm)
1313
ADD_SCENE(mag, exit_confirm, ExitConfirm)
1414
ADD_SCENE(mag, under_construction, UnderConstruction)
15+
ADD_SCENE(mag, read, Read)

scenes/mag_scene_read.c

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Creator: Hummus@FlipperGang
2+
3+
#include "../mag_i.h"
4+
#include "../helpers/mag_helpers.h"
5+
6+
#include "mag_scene_read.h"
7+
8+
#define TAG "MagSceneRead"
9+
10+
void uart_callback(UartIrqEvent event, uint8_t data, void *context) {
11+
Mag* mag = context;
12+
if(event == UartIrqEventRXNE) {
13+
furi_stream_buffer_send(mag->uart_rx_stream, &data, 1, 0);
14+
furi_thread_flags_set(furi_thread_get_id(mag->uart_rx_thread), WorkerEvtRxDone);
15+
}
16+
}
17+
18+
static int32_t uart_worker(void* context) {
19+
Mag* mag = context;
20+
mag->uart_rx_stream = furi_stream_buffer_alloc(UART_RX_BUF_SIZE, 1);
21+
mag->uart_text_box_store_strlen = 0;
22+
23+
while (1) {
24+
uint32_t events = furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
25+
// furi_check((events & FuriFlagError) == 0);
26+
27+
if(events & WorkerEvtStop) break;
28+
if(events & WorkerEvtRxDone) {
29+
FURI_LOG_D(TAG, "WorkerEvtRxDone");
30+
// notification_message(mag->notifications, &sequence_success);
31+
size_t len = furi_stream_buffer_receive(mag->uart_rx_stream, mag->uart_rx_buf, UART_RX_BUF_SIZE, 200);
32+
FURI_LOG_D(TAG, "UART RX len: %d", len);
33+
34+
if (len > 0) {
35+
// If text box store gets too big, then truncate it
36+
mag->uart_text_box_store_strlen += len;
37+
38+
if(mag->uart_text_box_store_strlen >= UART_TERMINAL_TEXT_BOX_STORE_SIZE - 1) {
39+
furi_string_right(mag->uart_text_box_store, mag->uart_text_box_store_strlen / 2);
40+
mag->uart_text_box_store_strlen = furi_string_size(mag->uart_text_box_store) + len;
41+
}
42+
43+
// Add '\0' to the end of the string, and then add the new data
44+
mag->uart_rx_buf[len] = '\0';
45+
furi_string_cat_printf(mag->uart_text_box_store, "%s", mag->uart_rx_buf);
46+
47+
FURI_LOG_D(TAG, "UART RX buf: %*.s", len, mag->uart_rx_buf);
48+
FURI_LOG_D(TAG, "UART RX store: %s", furi_string_get_cstr(mag->uart_text_box_store));
49+
50+
}
51+
52+
FURI_LOG_D(TAG, "UARTEventRxData");
53+
54+
view_dispatcher_send_custom_event(
55+
mag->view_dispatcher, UARTEventRxData);
56+
57+
}
58+
}
59+
60+
furi_stream_buffer_free(mag->uart_rx_stream);
61+
62+
return 0;
63+
}
64+
65+
void update_widgets(Mag* mag) {
66+
// Clear widget from all elements
67+
widget_reset(mag->widget);
68+
69+
// Titlebar
70+
widget_add_icon_element(mag->widget, 38, -1, &I_mag_file_10px);
71+
widget_add_string_element(mag->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "READ");
72+
widget_add_icon_element(mag->widget, 81, -1, &I_mag_file_10px);
73+
74+
// Text box
75+
widget_add_text_scroll_element(mag->widget, 0, 10, 128, 40, furi_string_get_cstr(mag->uart_text_box_store));
76+
77+
// Buttons
78+
widget_add_button_element(mag->widget, GuiButtonTypeLeft, "Clear", mag_widget_callback, mag);
79+
widget_add_button_element(mag->widget, GuiButtonTypeRight, "Parse", mag_widget_callback, mag);
80+
}
81+
82+
void mag_scene_read_on_enter(void* context) {
83+
Mag* mag = context;
84+
FuriString* message = furi_string_alloc();
85+
furi_string_printf(message, "Flipper Elite, swipe a card!\n");
86+
mag->uart_text_box_store = message;
87+
88+
view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewWidget);
89+
90+
update_widgets(mag);
91+
92+
93+
// Initialize UART
94+
// furi_hal_console_disable();
95+
furi_hal_uart_deinit(FuriHalUartIdUSART1);
96+
furi_hal_uart_init(FuriHalUartIdUSART1, 9600);
97+
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_callback, mag);
98+
FURI_LOG_D(TAG, "UART initialized");
99+
100+
mag->uart_rx_thread = furi_thread_alloc();
101+
furi_thread_set_name(mag->uart_rx_thread, "UartRx");
102+
furi_thread_set_stack_size(mag->uart_rx_thread, 1024);
103+
furi_thread_set_context(mag->uart_rx_thread, mag);
104+
furi_thread_set_callback(mag->uart_rx_thread, uart_worker);
105+
106+
furi_thread_start(mag->uart_rx_thread);
107+
FURI_LOG_D(TAG, "UART worker started");
108+
}
109+
110+
bool mag_scene_read_on_event(void* context, SceneManagerEvent event) {
111+
Mag* mag = context;
112+
113+
bool consumed = false;
114+
115+
if(event.type == SceneManagerEventTypeCustom) {
116+
FURI_LOG_D(TAG, "Custom event: %ld", event.event);
117+
118+
switch(event.event) {
119+
case GuiButtonTypeLeft: // Clear
120+
consumed = true;
121+
// Clear text box store
122+
furi_string_reset(mag->uart_text_box_store);
123+
mag->uart_text_box_store_strlen = 0;
124+
break;
125+
126+
case GuiButtonTypeRight: // Parse
127+
consumed = true;
128+
FURI_LOG_D(TAG, "Trying to parse");
129+
MagDevice* mag_dev = mag->mag_dev;
130+
131+
bool res = mag_device_parse_card_string(mag_dev, mag->uart_text_box_store);
132+
furi_string_reset(mag->uart_text_box_store);
133+
if(res) {
134+
notification_message(mag->notifications, &sequence_success);
135+
136+
furi_string_printf(mag->uart_text_box_store, "Track 1: %.*s\nTrack 2: %.*s\nTrack 3: %.*s",
137+
mag_dev->dev_data.track[0].len, furi_string_get_cstr(mag_dev->dev_data.track[0].str),
138+
mag_dev->dev_data.track[1].len, furi_string_get_cstr(mag_dev->dev_data.track[1].str),
139+
mag_dev->dev_data.track[2].len, furi_string_get_cstr(mag_dev->dev_data.track[2].str));
140+
141+
// Switch to saved menu scene
142+
scene_manager_next_scene(mag->scene_manager, MagSceneSavedMenu);
143+
144+
} else {
145+
furi_string_printf(mag->uart_text_box_store, "Failed to parse! Try again\n");
146+
notification_message(mag->notifications, &sequence_error);
147+
}
148+
149+
break;
150+
}
151+
152+
update_widgets(mag);
153+
}
154+
155+
return consumed;
156+
}
157+
158+
void mag_scene_read_on_exit(void* context) {
159+
Mag* mag = context;
160+
// notification_message(mag->notifications, &sequence_blink_stop);
161+
widget_reset(mag->widget);
162+
// view_dispatcher_remove_view(mag->view_dispatcher, MagViewWidget);
163+
164+
// Stop UART worker
165+
FURI_LOG_D(TAG, "Stopping UART worker");
166+
furi_thread_flags_set(furi_thread_get_id(mag->uart_rx_thread), WorkerEvtStop);
167+
furi_thread_join(mag->uart_rx_thread);
168+
furi_thread_free(mag->uart_rx_thread);
169+
FURI_LOG_D(TAG, "UART worker stopped");
170+
171+
furi_string_free(mag->uart_text_box_store);
172+
173+
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL, NULL);
174+
furi_hal_uart_deinit(FuriHalUartIdUSART1);
175+
// furi_hal_console_enable();
176+
177+
notification_message(mag->notifications, &sequence_blink_stop);
178+
}

scenes/mag_scene_read.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include <gui/modules/text_box.h>
4+
5+
#define UART_RX_BUF_SIZE (320)
6+
#define UART_TERMINAL_TEXT_BOX_STORE_SIZE (4096)
7+
#define UART_TERMINAL_TEXT_INPUT_STORE_SIZE (512)
8+
#define UART_CH (FuriHalUartIdUSART1)
9+
#define UART_BAUDRATE (9600)
10+
11+
typedef enum {
12+
WorkerEvtStop = (1 << 0),
13+
WorkerEvtRxDone = (1 << 1),
14+
} WorkerEvtFlags;
15+
16+
typedef enum {
17+
UARTEventRxData = 100,
18+
} UARTEvents;
19+
20+
21+
#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone)

0 commit comments

Comments
 (0)