Просмотр исходного кода

Prelim state save/load, refactoring

Zachary Weiss 1 год назад
Родитель
Сommit
ae5ca16df3

+ 28 - 51
helpers/mag_helpers.c

@@ -19,31 +19,8 @@ const int sublen[] = {32, 48, 48};
 
 
 uint8_t last_value = 2;
 uint8_t last_value = 2;
 
 
-const GpioPin* mag_gpio_enum_to_pin(MagSettingPin pin) {
-    switch(pin) {
-    case MagSettingPinA7:
-        return &gpio_ext_pa7;
-    case MagSettingPinA6:
-        return &gpio_ext_pa6;
-    case MagSettingPinA4:
-        return &gpio_ext_pa4;
-    case MagSettingPinB3:
-        return &gpio_ext_pb3;
-    case MagSettingPinB2:
-        return &gpio_ext_pb2;
-    case MagSettingPinC3:
-        return &gpio_ext_pc3;
-    case MagSettingPinC1:
-        return &gpio_ext_pc1;
-    case MagSettingPinC0:
-        return &gpio_ext_pc0;
-    default:
-        return NULL;
-    }
-}
-
-void play_halfbit(bool value, MagSetting* setting) {
-    switch(setting->tx) {
+void play_halfbit(bool value, MagState* state) {
+    switch(state->tx) {
     case MagTxStateRFID:
     case MagTxStateRFID:
         furi_hal_gpio_write(RFID_PIN_OUT, value);
         furi_hal_gpio_write(RFID_PIN_OUT, value);
         /*furi_hal_gpio_write(RFID_PIN_OUT, !value);
         /*furi_hal_gpio_write(RFID_PIN_OUT, !value);
@@ -111,7 +88,7 @@ void play_halfbit(bool value, MagSetting* setting) {
     last_value = value;
     last_value = value;
 }
 }
 
 
-void play_track(uint8_t* bits_manchester, uint16_t n_bits, MagSetting* setting, bool reverse) {
+void play_track(uint8_t* bits_manchester, uint16_t n_bits, MagState* state, bool reverse) {
     for(uint16_t i = 0; i < n_bits; i++) {
     for(uint16_t i = 0; i < n_bits; i++) {
         uint16_t j = (reverse) ? (n_bits - i - 1) : i;
         uint16_t j = (reverse) ? (n_bits - i - 1) : i;
         uint8_t byte = j / 8;
         uint8_t byte = j / 8;
@@ -140,9 +117,9 @@ void play_track(uint8_t* bits_manchester, uint16_t n_bits, MagSetting* setting,
         // for DWT->CYCCNT. Note timer is aliased to 64us as per
         // for DWT->CYCCNT. Note timer is aliased to 64us as per
         // #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) | furi_hal_cortex.c
         // #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) | furi_hal_cortex.c
 
 
-        play_halfbit(bit, setting);
-        furi_delay_us(setting->us_clock);
-        // if (i % 2 == 1) furi_delay_us(setting->us_interpacket);
+        play_halfbit(bit, state);
+        furi_delay_us(state->us_clock);
+        // if (i % 2 == 1) furi_delay_us(state->us_interpacket);
     }
     }
 }
 }
 
 
@@ -154,7 +131,7 @@ void tx_init_rfid() {
     // furi_hal_ibutton_start_drive();
     // furi_hal_ibutton_start_drive();
     furi_hal_ibutton_pin_write(false);
     furi_hal_ibutton_pin_write(false);
 
 
-    // Initializing at GpioSpeedLow seems sufficient for our needs; no improvements seen by increasing speed setting
+    // Initializing at GpioSpeedLow seems sufficient for our needs; no improvements seen by increasing speed state
 
 
     // this doesn't seem to make a difference, leaving it in
     // this doesn't seem to make a difference, leaving it in
     furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@@ -202,9 +179,9 @@ void tx_deinit_piezo() {
     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 }
 }
 
 
-bool tx_init(MagSetting* setting) {
+bool tx_init(MagState* state) {
     // Initialize configured TX method
     // Initialize configured TX method
-    switch(setting->tx) {
+    switch(state->tx) {
     case MagTxStateRFID:
     case MagTxStateRFID:
         tx_init_rfid();
         tx_init_rfid();
         break;
         break;
@@ -242,9 +219,9 @@ bool tx_init(MagSetting* setting) {
     return true;
     return true;
 }
 }
 
 
-bool tx_deinit(MagSetting* setting) {
+bool tx_deinit(MagState* state) {
     // Reset configured TX method
     // Reset configured TX method
-    switch(setting->tx) {
+    switch(state->tx) {
     case MagTxStateRFID:
     case MagTxStateRFID:
         tx_deinit_rfid();
         tx_deinit_rfid();
         break;
         break;
@@ -285,7 +262,7 @@ bool tx_deinit(MagSetting* setting) {
 }
 }
 
 
 void mag_spoof(Mag* mag) {
 void mag_spoof(Mag* mag) {
-    MagSetting* setting = mag->setting;
+    MagState* state = &mag->state;
 
 
     // TODO: cleanup this section. Possibly move precompute + tx_init to emulate_on_enter?
     // TODO: cleanup this section. Possibly move precompute + tx_init to emulate_on_enter?
     FuriString* ft1 = mag->mag_dev->dev_data.track[0].str;
     FuriString* ft1 = mag->mag_dev->dev_data.track[0].str;
@@ -343,47 +320,47 @@ void mag_spoof(Mag* mag) {
     last_value = 2;
     last_value = 2;
     bool bit = false;
     bool bit = false;
 
 
-    if(!tx_init(setting)) return;
+    if(!tx_init(state)) return;
 
 
     FURI_CRITICAL_ENTER();
     FURI_CRITICAL_ENTER();
     for(uint16_t i = 0; i < (ZERO_PREFIX * 2); i++) {
     for(uint16_t i = 0; i < (ZERO_PREFIX * 2); i++) {
         // is this right?
         // is this right?
         if(!!(i % 2)) bit ^= 1;
         if(!!(i % 2)) bit ^= 1;
-        play_halfbit(bit, setting);
-        furi_delay_us(setting->us_clock);
+        play_halfbit(bit, state);
+        furi_delay_us(state->us_clock);
     }
     }
 
 
-    if((setting->track == MagTrackStateOneAndTwo) || (setting->track == MagTrackStateOne))
-        play_track((uint8_t*)bits_t1_manchester, bits_t1_count, setting, false);
+    if((state->track == MagTrackStateOneAndTwo) || (state->track == MagTrackStateOne))
+        play_track((uint8_t*)bits_t1_manchester, bits_t1_count, state, false);
 
 
-    if((setting->track == MagTrackStateOneAndTwo))
+    if((state->track == MagTrackStateOneAndTwo))
         for(uint16_t i = 0; i < (ZERO_BETWEEN * 2); i++) {
         for(uint16_t i = 0; i < (ZERO_BETWEEN * 2); i++) {
             if(!!(i % 2)) bit ^= 1;
             if(!!(i % 2)) bit ^= 1;
-            play_halfbit(bit, setting);
-            furi_delay_us(setting->us_clock);
+            play_halfbit(bit, state);
+            furi_delay_us(state->us_clock);
         }
         }
 
 
-    if((setting->track == MagTrackStateOneAndTwo) || (setting->track == MagTrackStateTwo))
+    if((state->track == MagTrackStateOneAndTwo) || (state->track == MagTrackStateTwo))
         play_track(
         play_track(
             (uint8_t*)bits_t2_manchester,
             (uint8_t*)bits_t2_manchester,
             bits_t2_count,
             bits_t2_count,
-            setting,
-            (setting->reverse == MagReverseStateOn));
+            state,
+            (state->reverse == MagReverseStateOn));
 
 
-    if((setting->track == MagTrackStateThree))
-        play_track((uint8_t*)bits_t3_manchester, bits_t3_count, setting, false);
+    if((state->track == MagTrackStateThree))
+        play_track((uint8_t*)bits_t3_manchester, bits_t3_count, state, false);
 
 
     for(uint16_t i = 0; i < (ZERO_SUFFIX * 2); i++) {
     for(uint16_t i = 0; i < (ZERO_SUFFIX * 2); i++) {
         if(!!(i % 2)) bit ^= 1;
         if(!!(i % 2)) bit ^= 1;
-        play_halfbit(bit, setting);
-        furi_delay_us(setting->us_clock);
+        play_halfbit(bit, state);
+        furi_delay_us(state->us_clock);
     }
     }
     FURI_CRITICAL_EXIT();
     FURI_CRITICAL_EXIT();
 
 
     free(data1);
     free(data1);
     free(data2);
     free(data2);
     free(data3);
     free(data3);
-    tx_deinit(setting);
+    tx_deinit(state);
 }
 }
 
 
 uint16_t add_bit(bool value, uint8_t* out, uint16_t count) {
 uint16_t add_bit(bool value, uint8_t* out, uint16_t count) {

+ 4 - 6
helpers/mag_helpers.h

@@ -2,18 +2,16 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <string.h>
 
 
-const GpioPin* mag_gpio_enum_to_pin(MagSettingPin pin);
-
-void play_halfbit(bool value, MagSetting* setting);
-void play_track(uint8_t* bits_manchester, uint16_t n_bits, MagSetting* setting, bool reverse);
+void play_halfbit(bool value, MagState* state);
+void play_track(uint8_t* bits_manchester, uint16_t n_bits, MagState* state, bool reverse);
 
 
 void tx_init_rf(int hz);
 void tx_init_rf(int hz);
 void tx_init_rfid();
 void tx_init_rfid();
 void tx_init_piezo();
 void tx_init_piezo();
-bool tx_init(MagSetting* setting);
+bool tx_init(MagState* state);
 void tx_deinit_piezo();
 void tx_deinit_piezo();
 void tx_deinit_rfid();
 void tx_deinit_rfid();
-bool tx_deinit(MagSetting* setting);
+bool tx_deinit(MagState* state);
 
 
 uint16_t add_bit(bool value, uint8_t* out, uint16_t count);
 uint16_t add_bit(bool value, uint8_t* out, uint16_t count);
 uint16_t add_bit_manchester(bool value, uint8_t* out, uint16_t count);
 uint16_t add_bit_manchester(bool value, uint8_t* out, uint16_t count);

+ 0 - 11
helpers/mag_types.h

@@ -14,17 +14,6 @@ typedef enum {
     MagViewTextInput,
     MagViewTextInput,
 } MagView;
 } MagView;
 
 
-typedef enum {
-    MagSettingPinA7,
-    MagSettingPinA6,
-    MagSettingPinA4,
-    MagSettingPinB3,
-    MagSettingPinB2,
-    MagSettingPinC3,
-    MagSettingPinC1,
-    MagSettingPinC0,
-} MagSettingPin;
-
 typedef enum {
 typedef enum {
     MagReverseStateOff,
     MagReverseStateOff,
     MagReverseStateOn,
     MagReverseStateOn,

+ 3 - 29
mag.c

@@ -14,24 +14,6 @@ static bool mag_debug_back_event_callback(void* context) {
     return scene_manager_handle_back_event(mag->scene_manager);
     return scene_manager_handle_back_event(mag->scene_manager);
 }
 }
 
 
-static MagSetting* mag_setting_alloc() {
-    // temp hardcoded defaults
-    MagSetting* setting = malloc(sizeof(MagSetting));
-    setting->reverse = SETTING_DEFAULT_REVERSE;
-    setting->track = SETTING_DEFAULT_TRACK;
-    setting->tx = SETTING_DEFAULT_TX;
-    setting->us_clock = SETTING_DEFAULT_US_CLOCK;
-    setting->us_interpacket = SETTING_DEFAULT_US_INTERPACKET;
-
-    setting->pin_input = SETTING_DEFAULT_PIN_INPUT;
-    setting->pin_output = SETTING_DEFAULT_PIN_OUTPUT;
-    setting->pin_enable = SETTING_DEFAULT_PIN_ENABLE;
-
-    setting->is_debug = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
-
-    return setting;
-}
-
 static Mag* mag_alloc() {
 static Mag* mag_alloc() {
     Mag* mag = malloc(sizeof(Mag));
     Mag* mag = malloc(sizeof(Mag));
 
 
@@ -52,7 +34,7 @@ static Mag* mag_alloc() {
         mag->view_dispatcher, mag_debug_back_event_callback);
         mag->view_dispatcher, mag_debug_back_event_callback);
 
 
     mag->mag_dev = mag_device_alloc();
     mag->mag_dev = mag_device_alloc();
-    mag->setting = mag_setting_alloc();
+    mag_state_load(&mag->state);
 
 
     // Open GUI record
     // Open GUI record
     mag->gui = furi_record_open(RECORD_GUI);
     mag->gui = furi_record_open(RECORD_GUI);
@@ -97,13 +79,9 @@ static Mag* mag_alloc() {
     mag->expansion = furi_record_open(RECORD_EXPANSION);
     mag->expansion = furi_record_open(RECORD_EXPANSION);
     expansion_disable(mag->expansion);
     expansion_disable(mag->expansion);
 
 
-    return mag;
-}
+    // Move UART here? conditional upon setting?
 
 
-static void mag_setting_free(MagSetting* setting) {
-    furi_assert(setting);
-
-    free(setting);
+    return mag;
 }
 }
 
 
 static void mag_free(Mag* mag) {
 static void mag_free(Mag* mag) {
@@ -117,10 +95,6 @@ static void mag_free(Mag* mag) {
     mag_device_free(mag->mag_dev);
     mag_device_free(mag->mag_dev);
     mag->mag_dev = NULL;
     mag->mag_dev = NULL;
 
 
-    // Mag setting
-    mag_setting_free(mag->setting);
-    mag->setting = NULL;
-
     // Submenu
     // Submenu
     view_dispatcher_remove_view(mag->view_dispatcher, MagViewSubmenu);
     view_dispatcher_remove_view(mag->view_dispatcher, MagViewSubmenu);
     submenu_free(mag->submenu);
     submenu_free(mag->submenu);

+ 2 - 22
mag_i.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "mag_device.h"
 #include "mag_device.h"
+#include "mag_state.h"
 //#include "helpers/mag_helpers.h"
 //#include "helpers/mag_helpers.h"
 #include "helpers/mag_types.h"
 #include "helpers/mag_types.h"
 
 
@@ -47,33 +48,12 @@
     }
     }
 #endif
 #endif
 
 
-#define SETTING_DEFAULT_REVERSE MagReverseStateOff
-#define SETTING_DEFAULT_TRACK MagTrackStateOneAndTwo
-#define SETTING_DEFAULT_TX MagTxStateGPIO
-#define SETTING_DEFAULT_US_CLOCK 240
-#define SETTING_DEFAULT_US_INTERPACKET 10
-#define SETTING_DEFAULT_PIN_INPUT MagSettingPinA7
-#define SETTING_DEFAULT_PIN_OUTPUT MagSettingPinA6
-#define SETTING_DEFAULT_PIN_ENABLE MagSettingPinA4
-
 enum MagCustomEvent {
 enum MagCustomEvent {
     MagEventNext = 100,
     MagEventNext = 100,
     MagEventExit,
     MagEventExit,
     MagEventPopupClosed,
     MagEventPopupClosed,
 };
 };
 
 
-typedef struct {
-    MagTxState tx;
-    MagTrackState track;
-    MagReverseState reverse;
-    uint32_t us_clock;
-    uint32_t us_interpacket;
-    MagSettingPin pin_input;
-    MagSettingPin pin_output;
-    MagSettingPin pin_enable;
-    bool is_debug;
-} MagSetting;
-
 typedef struct {
 typedef struct {
     ViewDispatcher* view_dispatcher;
     ViewDispatcher* view_dispatcher;
     Gui* gui;
     Gui* gui;
@@ -88,7 +68,7 @@ typedef struct {
     FuriString* file_name;
     FuriString* file_name;
     FuriString* args;
     FuriString* args;
 
 
-    MagSetting* setting;
+    MagState state;
 
 
     // Common views
     // Common views
     Submenu* submenu;
     Submenu* submenu;

+ 109 - 0
mag_state.c

@@ -0,0 +1,109 @@
+#include "mag_state.h"
+
+#define TAG "MagState"
+
+const GpioPin* mag_state_enum_to_pin(MagPin pin) {
+    switch(pin) {
+    case MagPinA7:
+        return &gpio_ext_pa7;
+    case MagPinA6:
+        return &gpio_ext_pa6;
+    case MagPinA4:
+        return &gpio_ext_pa4;
+    case MagPinB3:
+        return &gpio_ext_pb3;
+    case MagPinB2:
+        return &gpio_ext_pb2;
+    case MagPinC3:
+        return &gpio_ext_pc3;
+    case MagPinC1:
+        return &gpio_ext_pc1;
+    case MagPinC0:
+        return &gpio_ext_pc0;
+    default:
+        return NULL;
+    }
+}
+
+bool mag_state_gpio_is_valid(MagState* state) {
+    return (state->pin_input != state->pin_output) && (state->pin_input != state->pin_enable) &&
+           (state->pin_enable != state->pin_output);
+}
+
+void mag_state_gpio_reset(MagState* state) {
+    state->pin_input = MAG_STATE_DEFAULT_PIN_INPUT;
+    state->pin_output = MAG_STATE_DEFAULT_PIN_OUTPUT;
+    state->pin_enable = MAG_STATE_DEFAULT_PIN_ENABLE;
+}
+
+bool mag_state_load(MagState* out_state) {
+    MagState state;
+
+    // Try to load from file
+    bool loaded_from_file = false;
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    if(storage_file_exists(storage, MAG_STATE_PATH)) {
+        FlipperFormat* file = flipper_format_file_alloc(storage);
+        do {
+            uint32_t tmp;
+            FuriString* str = furi_string_alloc();
+            if(!flipper_format_file_open_existing(file, MAG_STATE_PATH)) break;
+            if(!flipper_format_read_header(file, str, &tmp)) break;
+            if(furi_string_cmp_str(str, MAG_STATE_HEADER)) break;
+            if(tmp != MAG_STATE_VER) break;
+
+            if(!flipper_format_read_uint32(file, "pin_input", &tmp, 1)) break;
+            state.pin_input = tmp;
+            if(!flipper_format_read_uint32(file, "pin_output", &tmp, 1)) break;
+            state.pin_output = tmp;
+            if(!flipper_format_read_uint32(file, "pin_enable", &tmp, 1)) break;
+            state.pin_enable = tmp;
+
+            loaded_from_file = true;
+        } while(0);
+        flipper_format_free(file);
+    }
+    furi_record_close(RECORD_STORAGE);
+
+    // If could not be read from file
+    // Or file GPIO config is invalid (pins overlap)
+    // Set defaults
+    if(!loaded_from_file || !mag_state_gpio_is_valid(&state)) {
+        mag_state_gpio_reset(&state);
+    }
+
+    // set defaults we don't save
+    state.tx = MAG_STATE_DEFAULT_TX;
+    state.track = MAG_STATE_DEFAULT_TRACK;
+    state.reverse = MAG_STATE_DEFAULT_REVERSE;
+    state.us_clock = MAG_STATE_DEFAULT_US_CLOCK;
+    state.us_interpacket = MAG_STATE_DEFAULT_US_INTERPACKET;
+    state.is_debug = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
+
+    // Copy to caller state before popping stack
+    memcpy(out_state, &state, sizeof(state));
+
+    return loaded_from_file;
+}
+
+void mag_state_save(MagState* state) {
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    storage_simply_mkdir(storage, MAG_STATE_DIR);
+    FlipperFormat* file = flipper_format_file_alloc(storage);
+
+    do {
+        uint32_t tmp;
+        if(!flipper_format_file_open_always(file, MAG_STATE_PATH)) break;
+        if(!flipper_format_write_header_cstr(file, MAG_STATE_HEADER, MAG_STATE_VER)) break;
+
+        tmp = state->pin_input;
+        if(!flipper_format_write_uint32(file, "pin_input", &tmp, 1)) break;
+        tmp = state->pin_output;
+        if(!flipper_format_write_uint32(file, "pin_output", &tmp, 1)) break;
+        tmp = state->pin_enable;
+        if(!flipper_format_write_uint32(file, "pin_enable", &tmp, 1)) break;
+
+    } while(0);
+    flipper_format_free(file);
+    furi_record_close(RECORD_STORAGE);
+}

+ 61 - 0
mag_state.h

@@ -0,0 +1,61 @@
+#pragma once
+
+#include <string.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <furi_hal_resources.h>
+#include <furi_hal_rtc.h>
+
+#include <storage/storage.h>
+#include <flipper_format/flipper_format.h>
+
+#include "helpers/mag_types.h"
+
+#define MAG_STATE_HEADER "Mag State"
+#define MAG_STATE_VER 1
+#define MAG_STATE_DIR STORAGE_APP_DATA_PATH_PREFIX
+#define MAG_STATE_PATH MAG_STATE_DIR "/mag_state.txt"
+
+typedef enum {
+    MagPinA7,
+    MagPinA6,
+    MagPinA4,
+    MagPinB3,
+    MagPinB2,
+    MagPinC3,
+    MagPinC1,
+    MagPinC0,
+} MagPin;
+
+#define MAG_STATE_DEFAULT_REVERSE MagReverseStateOff
+#define MAG_STATE_DEFAULT_TRACK MagTrackStateOneAndTwo
+#define MAG_STATE_DEFAULT_TX MagTxStateGPIO
+#define MAG_STATE_DEFAULT_US_CLOCK 240
+#define MAG_STATE_DEFAULT_US_INTERPACKET 10
+#define MAG_STATE_DEFAULT_PIN_INPUT MagPinA7
+#define MAG_STATE_DEFAULT_PIN_OUTPUT MagPinA6
+#define MAG_STATE_DEFAULT_PIN_ENABLE MagPinA4
+
+typedef struct {
+    MagTxState tx;
+    MagTrackState track;
+    MagReverseState reverse;
+    uint32_t us_clock;
+    uint32_t us_interpacket;
+    MagPin pin_input;
+    MagPin pin_output;
+    MagPin pin_enable;
+    bool is_debug;
+} MagState;
+
+const GpioPin* mag_state_enum_to_pin(MagPin pin);
+
+bool mag_state_gpio_is_valid(MagState* state);
+
+void mag_state_gpio_reset(MagState* state);
+
+bool mag_state_load(MagState* out_state);
+
+void mag_state_save(MagState* state);

+ 1 - 0
scenes/mag_scene_config.h

@@ -2,6 +2,7 @@ ADD_SCENE(mag, start, Start)
 ADD_SCENE(mag, about, About)
 ADD_SCENE(mag, about, About)
 ADD_SCENE(mag, read, Read)
 ADD_SCENE(mag, read, Read)
 ADD_SCENE(mag, settings, Settings)
 ADD_SCENE(mag, settings, Settings)
+ADD_SCENE(mag, settings_invalid, SettingsInvalid)
 ADD_SCENE(mag, emulate, Emulate)
 ADD_SCENE(mag, emulate, Emulate)
 ADD_SCENE(mag, emulate_config, EmulateConfig)
 ADD_SCENE(mag, emulate_config, EmulateConfig)
 ADD_SCENE(mag, file_select, FileSelect)
 ADD_SCENE(mag, file_select, FileSelect)

+ 2 - 2
scenes/mag_scene_emulate.c

@@ -30,7 +30,7 @@ void mag_scene_emulate_on_enter(void* context) {
         widget, 13, 2, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(tmp_str));
         widget, 13, 2, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(tmp_str));
     furi_string_reset(tmp_str);
     furi_string_reset(tmp_str);
 
 
-    FURI_LOG_D(TAG, "%d", mag->setting->reverse);
+    FURI_LOG_D(TAG, "%d", mag->state.reverse);
 
 
     // print relevant data
     // print relevant data
     uint8_t cat_count = 0;
     uint8_t cat_count = 0;
@@ -39,7 +39,7 @@ void mag_scene_emulate_on_enter(void* context) {
 
 
         // still messy / dumb way to do this, but slightly cleaner than before.
         // still messy / dumb way to do this, but slightly cleaner than before.
         // will clean up more later
         // will clean up more later
-        switch(mag->setting->track) {
+        switch(mag->state.track) {
         case MagTrackStateOne:
         case MagTrackStateOne:
             if(i == 0) cat_trackstr(tmp_str, cat_count++, i, trackstr);
             if(i == 0) cat_trackstr(tmp_str, cat_count++, i, trackstr);
             break;
             break;

+ 14 - 14
scenes/mag_scene_emulate_config.c

@@ -128,17 +128,17 @@ static void mag_scene_emulate_config_set_tx(VariableItem* item) {
 
 
     variable_item_set_current_value_text(item, tx_text[index]);
     variable_item_set_current_value_text(item, tx_text[index]);
 
 
-    mag->setting->tx = tx_value[index];
+    mag->state.tx = tx_value[index];
 };
 };
 
 
 static void mag_scene_emulate_config_set_track(VariableItem* item) {
 static void mag_scene_emulate_config_set_track(VariableItem* item) {
     Mag* mag = variable_item_get_context(item);
     Mag* mag = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
     uint8_t index = variable_item_get_current_value_index(item);
 
 
-    if(mag->setting->reverse == MagReverseStateOff) {
+    if(mag->state.reverse == MagReverseStateOff) {
         variable_item_set_current_value_text(item, track_text[index]);
         variable_item_set_current_value_text(item, track_text[index]);
-        mag->setting->track = track_value[index];
-    } else if(mag->setting->reverse == MagReverseStateOn) {
+        mag->state.track = track_value[index];
+    } else if(mag->state.reverse == MagReverseStateOn) {
         variable_item_set_current_value_index(
         variable_item_set_current_value_index(
             item, value_index_uint32(MagTrackStateOneAndTwo, track_value, TRACK_COUNT));
             item, value_index_uint32(MagTrackStateOneAndTwo, track_value, TRACK_COUNT));
     }
     }
@@ -151,10 +151,10 @@ static void mag_scene_emulate_config_set_reverse(VariableItem* item) {
     Mag* mag = variable_item_get_context(item);
     Mag* mag = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
     uint8_t index = variable_item_get_current_value_index(item);
 
 
-    if(mag->setting->track == MagTrackStateOneAndTwo) {
+    if(mag->state.track == MagTrackStateOneAndTwo) {
         // only allow reverse track to be set when playing both 1 and 2
         // only allow reverse track to be set when playing both 1 and 2
         variable_item_set_current_value_text(item, reverse_text[index]);
         variable_item_set_current_value_text(item, reverse_text[index]);
-        mag->setting->reverse = reverse_value[index];
+        mag->state.reverse = reverse_value[index];
         //FURI_LOG_D(TAG, "%s", reverse_text[index]);
         //FURI_LOG_D(TAG, "%s", reverse_text[index]);
         //FURI_LOG_D(TAG, "%d", mag->setting->reverse);
         //FURI_LOG_D(TAG, "%d", mag->setting->reverse);
     } else {
     } else {
@@ -169,7 +169,7 @@ static void mag_scene_emulate_config_set_clock(VariableItem* item) {
 
 
     variable_item_set_current_value_text(item, clock_text[index]);
     variable_item_set_current_value_text(item, clock_text[index]);
 
 
-    mag->setting->us_clock = clock_value[index];
+    mag->state.us_clock = clock_value[index];
 };
 };
 
 
 static void mag_scene_emulate_config_set_interpacket(VariableItem* item) {
 static void mag_scene_emulate_config_set_interpacket(VariableItem* item) {
@@ -178,7 +178,7 @@ static void mag_scene_emulate_config_set_interpacket(VariableItem* item) {
 
 
     variable_item_set_current_value_text(item, interpacket_text[index]);
     variable_item_set_current_value_text(item, interpacket_text[index]);
 
 
-    mag->setting->us_interpacket = interpacket_value[index];
+    mag->state.us_interpacket = interpacket_value[index];
 };
 };
 
 
 void mag_scene_emulate_config_on_enter(void* context) {
 void mag_scene_emulate_config_on_enter(void* context) {
@@ -191,7 +191,7 @@ void mag_scene_emulate_config_on_enter(void* context) {
     // Clock
     // Clock
     item = variable_item_list_add(
     item = variable_item_list_add(
         mag->variable_item_list, "Clock:", CLOCK_COUNT, mag_scene_emulate_config_set_clock, mag);
         mag->variable_item_list, "Clock:", CLOCK_COUNT, mag_scene_emulate_config_set_clock, mag);
-    value_index = value_index_uint32(mag->setting->us_clock, clock_value, CLOCK_COUNT);
+    value_index = value_index_uint32(mag->state.us_clock, clock_value, CLOCK_COUNT);
     scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, clock_text[value_index]);
     variable_item_set_current_value_text(item, clock_text[value_index]);
@@ -199,7 +199,7 @@ void mag_scene_emulate_config_on_enter(void* context) {
     // Track
     // Track
     item = variable_item_list_add(
     item = variable_item_list_add(
         mag->variable_item_list, "Track:", TRACK_COUNT, mag_scene_emulate_config_set_track, mag);
         mag->variable_item_list, "Track:", TRACK_COUNT, mag_scene_emulate_config_set_track, mag);
-    value_index = value_index_uint32(mag->setting->track, track_value, TRACK_COUNT);
+    value_index = value_index_uint32(mag->state.track, track_value, TRACK_COUNT);
     scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, track_text[value_index]);
     variable_item_set_current_value_text(item, track_text[value_index]);
@@ -212,25 +212,25 @@ void mag_scene_emulate_config_on_enter(void* context) {
         REVERSE_COUNT,
         REVERSE_COUNT,
         mag_scene_emulate_config_set_reverse,
         mag_scene_emulate_config_set_reverse,
         mag);
         mag);
-    value_index = value_index_uint32(mag->setting->reverse, reverse_value, REVERSE_COUNT);
+    value_index = value_index_uint32(mag->state.reverse, reverse_value, REVERSE_COUNT);
     scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, reverse_text[value_index]);
     variable_item_set_current_value_text(item, reverse_text[value_index]);
 
 
     // TX
     // TX
 #ifdef FW_ORIGIN_Official
 #ifdef FW_ORIGIN_Official
-    if(mag->setting->is_debug) {
+    if(mag->state.is_debug) {
 #endif
 #endif
         item = variable_item_list_add(
         item = variable_item_list_add(
             mag->variable_item_list, "TX via:", TX_COUNT, mag_scene_emulate_config_set_tx, mag);
             mag->variable_item_list, "TX via:", TX_COUNT, mag_scene_emulate_config_set_tx, mag);
-        value_index = value_index_uint32(mag->setting->tx, tx_value, TX_COUNT);
+        value_index = value_index_uint32(mag->state.tx, tx_value, TX_COUNT);
         scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
         scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
         variable_item_set_current_value_index(item, value_index);
         variable_item_set_current_value_index(item, value_index);
         variable_item_set_current_value_text(item, tx_text[value_index]);
         variable_item_set_current_value_text(item, tx_text[value_index]);
 #ifdef FW_ORIGIN_Official
 #ifdef FW_ORIGIN_Official
     }
     }
 #else
 #else
-    variable_item_set_locked(item, !mag->setting->is_debug, "Enable Debug!");
+    variable_item_set_locked(item, !mag->state.is_debug, "Enable Debug!");
 #endif
 #endif
     // Interpacket
     // Interpacket
     /*
     /*

+ 4 - 4
scenes/mag_scene_saved_menu.c

@@ -24,13 +24,13 @@ void mag_scene_saved_menu_on_enter(void* context) {
     bool is_empty_t3 = furi_string_empty(mag->mag_dev->dev_data.track[2].str);
     bool is_empty_t3 = furi_string_empty(mag->mag_dev->dev_data.track[2].str);
 
 
     if(!is_empty_t1 && !is_empty_t2) {
     if(!is_empty_t1 && !is_empty_t2) {
-        mag->setting->track = MagTrackStateOneAndTwo;
+        mag->state.track = MagTrackStateOneAndTwo;
     } else if(!is_empty_t1) {
     } else if(!is_empty_t1) {
-        mag->setting->track = MagTrackStateOne;
+        mag->state.track = MagTrackStateOne;
     } else if(!is_empty_t2) {
     } else if(!is_empty_t2) {
-        mag->setting->track = MagTrackStateTwo;
+        mag->state.track = MagTrackStateTwo;
     } else if(!is_empty_t3) {
     } else if(!is_empty_t3) {
-        mag->setting->track = MagTrackStateThree;
+        mag->state.track = MagTrackStateThree;
     } // TODO: what happens if no track data present?
     } // TODO: what happens if no track data present?
 
 
     submenu_add_item(
     submenu_add_item(

+ 29 - 21
scenes/mag_scene_settings.c

@@ -1,44 +1,46 @@
 #include "../mag_i.h"
 #include "../mag_i.h"
+#include "../mag_state.h"
+#include "../helpers/mag_helpers.h"
 
 
 #define TAG "MagSceneEmulateConfig"
 #define TAG "MagSceneEmulateConfig"
 
 
-#define GPIO_COUNT 8
-static const char* gpio[GPIO_COUNT] = {
-    [MagSettingPinA7] = "2 (A7)",
-    [MagSettingPinA6] = "3 (A6)",
-    [MagSettingPinA4] = "4 (A4)",
-    [MagSettingPinB3] = "5 (B3)",
-    [MagSettingPinB2] = "6 (B2)",
-    [MagSettingPinC3] = "7 (C3)",
-    [MagSettingPinC1] = "15 (C1)",
-    [MagSettingPinC0] = "16 (C0)",
+static const char* gpio[] = {
+    [MagPinA7] = "2 (A7)",
+    [MagPinA6] = "3 (A6)",
+    [MagPinA4] = "4 (A4)",
+    [MagPinB3] = "5 (B3)",
+    [MagPinB2] = "6 (B2)",
+    [MagPinC3] = "7 (C3)",
+    [MagPinC1] = "15 (C1)",
+    [MagPinC0] = "16 (C0)",
 };
 };
+const uint8_t GPIO_COUNT = COUNT_OF(gpio);
 
 
-static void mag_scene_settings_set_gpio(VariableItem* item, MagSettingPin* pin_to_set) {
-    MagSettingPin pin = variable_item_get_current_value_index(item);
+static void mag_scene_settings_set_gpio(VariableItem* item, MagPin* pin_out) {
+    MagPin pin = variable_item_get_current_value_index(item);
     variable_item_set_current_value_text(item, gpio[pin]);
     variable_item_set_current_value_text(item, gpio[pin]);
-    *pin_to_set = pin;
+    *pin_out = pin;
 }
 }
 
 
 static void mag_scene_settings_set_gpio_input(VariableItem* item) {
 static void mag_scene_settings_set_gpio_input(VariableItem* item) {
     Mag* mag = variable_item_get_context(item);
     Mag* mag = variable_item_get_context(item);
-    mag_scene_settings_set_gpio(item, &mag->setting->pin_input);
+    mag_scene_settings_set_gpio(item, &mag->state.pin_input);
 };
 };
 
 
 static void mag_scene_settings_set_gpio_output(VariableItem* item) {
 static void mag_scene_settings_set_gpio_output(VariableItem* item) {
     Mag* mag = variable_item_get_context(item);
     Mag* mag = variable_item_get_context(item);
-    mag_scene_settings_set_gpio(item, &mag->setting->pin_output);
+    mag_scene_settings_set_gpio(item, &mag->state.pin_output);
 };
 };
 
 
 static void mag_scene_settings_set_gpio_enable(VariableItem* item) {
 static void mag_scene_settings_set_gpio_enable(VariableItem* item) {
     Mag* mag = variable_item_get_context(item);
     Mag* mag = variable_item_get_context(item);
-    mag_scene_settings_set_gpio(item, &mag->setting->pin_enable);
+    mag_scene_settings_set_gpio(item, &mag->state.pin_enable);
 };
 };
 
 
 static void mag_pin_variable_item_list_add(
 static void mag_pin_variable_item_list_add(
     Mag* mag,
     Mag* mag,
     const char* label,
     const char* label,
-    MagSettingPin pin,
+    MagPin pin,
     VariableItemChangeCallback change_callback) {
     VariableItemChangeCallback change_callback) {
     VariableItem* item =
     VariableItem* item =
         variable_item_list_add(mag->variable_item_list, label, GPIO_COUNT, change_callback, mag);
         variable_item_list_add(mag->variable_item_list, label, GPIO_COUNT, change_callback, mag);
@@ -52,11 +54,11 @@ void mag_scene_settings_on_enter(void* context) {
     Mag* mag = context;
     Mag* mag = context;
 
 
     mag_pin_variable_item_list_add(
     mag_pin_variable_item_list_add(
-        mag, "Input pin:", mag->setting->pin_input, mag_scene_settings_set_gpio_input);
+        mag, "Input pin:", mag->state.pin_input, mag_scene_settings_set_gpio_input);
     mag_pin_variable_item_list_add(
     mag_pin_variable_item_list_add(
-        mag, "Output pin:", mag->setting->pin_output, mag_scene_settings_set_gpio_output);
+        mag, "Output pin:", mag->state.pin_output, mag_scene_settings_set_gpio_output);
     mag_pin_variable_item_list_add(
     mag_pin_variable_item_list_add(
-        mag, "Enable pin:", mag->setting->pin_enable, mag_scene_settings_set_gpio_enable);
+        mag, "Enable pin:", mag->state.pin_enable, mag_scene_settings_set_gpio_enable);
 
 
     view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewVariableItemList);
     view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewVariableItemList);
 }
 }
@@ -75,6 +77,12 @@ bool mag_scene_settings_on_event(void* context, SceneManagerEvent event) {
 
 
 void mag_scene_settings_on_exit(void* context) {
 void mag_scene_settings_on_exit(void* context) {
     Mag* mag = context;
     Mag* mag = context;
-    variable_item_list_set_selected_item(mag->variable_item_list, 0);
+
     variable_item_list_reset(mag->variable_item_list);
     variable_item_list_reset(mag->variable_item_list);
+
+    if(!mag_state_gpio_is_valid(&mag->state)) {
+        scene_manager_next_scene(mag->scene_manager, MagSceneSettingsInvalid);
+    }
+
+    mag_state_save(&mag->state);
 }
 }

+ 50 - 0
scenes/mag_scene_settings_invalid.c

@@ -0,0 +1,50 @@
+#include "../mag_i.h"
+#include "../helpers/mag_helpers.h"
+
+void mag_scene_settings_invalid_on_enter(void* context) {
+    Mag* mag = context;
+    Widget* widget = mag->widget;
+
+    FuriString* tmp_str;
+    tmp_str = furi_string_alloc();
+
+    furi_string_printf(tmp_str, "\e#Invalid Pin Configuration!#\e");
+
+    //TODO: print concise summary of data on card? Would need to vary by card/track type
+
+    widget_add_text_box_element(
+        widget, 0, 0, 128, 27, AlignCenter, AlignCenter, furi_string_get_cstr(tmp_str), true);
+    widget_add_button_element(widget, GuiButtonTypeLeft, "Modify", mag_widget_callback, mag);
+    widget_add_button_element(widget, GuiButtonTypeRight, "Reset", mag_widget_callback, mag);
+
+    view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewWidget);
+
+    furi_string_free(tmp_str);
+}
+
+bool mag_scene_settings_invalid_on_event(void* context, SceneManagerEvent event) {
+    Mag* mag = context;
+    SceneManager* scene_manager = mag->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == GuiButtonTypeRight) {
+            consumed = true;
+            // reset to defaults here
+            // once impl'd saved settings, reset to last save? or still to defaults?
+            mag_state_gpio_reset(&mag->state);
+
+            scene_manager_search_and_switch_to_previous_scene(mag->scene_manager, MagSceneStart);
+        } else if(event.event == GuiButtonTypeLeft) {
+            consumed = true;
+            scene_manager_previous_scene(scene_manager);
+        }
+    }
+
+    return consumed;
+}
+
+void mag_scene_settings_invalid_on_exit(void* context) {
+    Mag* mag = context;
+    widget_reset(mag->widget);
+}

+ 1 - 1
scenes/mag_scene_start.c

@@ -25,7 +25,7 @@ void mag_scene_start_on_enter(void* context) {
         SubmenuIndexRead,
         SubmenuIndexRead,
         mag_scene_start_submenu_callback,
         mag_scene_start_submenu_callback,
         mag,
         mag,
-        !mag->setting->is_debug,
+        !mag->state.is_debug,
         "Enable Debug!");
         "Enable Debug!");
     //submenu_add_item(
     //submenu_add_item(
     //    submenu, "Add Manually", SubmenuIndexAddManually, mag_scene_start_submenu_callback, mag);
     //    submenu, "Add Manually", SubmenuIndexAddManually, mag_scene_start_submenu_callback, mag);