Skip to content

Commit

Permalink
FindMy: Save and load state from file
Browse files Browse the repository at this point in the history
  • Loading branch information
Willy-JL committed Mar 8, 2024
1 parent 7c48c61 commit 5d45d6a
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 29 deletions.
3 changes: 3 additions & 0 deletions applications/system/findmy/findmy.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ void findmy_change_broadcast_interval(FindMy* app, uint8_t value) {
return;
}
app->state.broadcast_interval = value;
findmy_state_save(&app->state);
findmy_main_update_interval(app->findmy_main, app->state.broadcast_interval);
if(furi_hal_bt_extra_beacon_is_active()) {
// Always check if beacon is active before changing config
Expand All @@ -108,6 +109,7 @@ void findmy_change_transmit_power(FindMy* app, uint8_t value) {
return;
}
app->state.transmit_power = value;
findmy_state_save(&app->state);
if(furi_hal_bt_extra_beacon_is_active()) {
furi_check(furi_hal_bt_extra_beacon_stop());
}
Expand All @@ -120,6 +122,7 @@ void findmy_change_transmit_power(FindMy* app, uint8_t value) {

void findmy_toggle_beacon(FindMy* app) {
app->state.beacon_active = !app->state.beacon_active;
findmy_state_save(&app->state);
if(furi_hal_bt_extra_beacon_is_active()) {
furi_check(furi_hal_bt_extra_beacon_stop());
}
Expand Down
113 changes: 88 additions & 25 deletions applications/system/findmy/findmy_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,76 @@
#include <string.h>
#include <stddef.h>
#include <furi_hal_bt.h>
#include <flipper_format/flipper_format.h>

bool findmy_state_load(FindMyState* out_state) {
FindMyState state;

// Set default values
state.beacon_active = false;
state.broadcast_interval = 5;
state.transmit_power = 6;
// Try to load from file
bool loaded_from_file = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_file_exists(storage, FINDMY_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, FINDMY_STATE_PATH)) break;
if(!flipper_format_read_header(file, str, &tmp)) break;
if(furi_string_cmp_str(str, FINDMY_STATE_HEADER)) break;
if(tmp != FINDMY_STATE_VER) break;

if(!flipper_format_read_bool(file, "beacon_active", &state.beacon_active, 1)) break;

if(!flipper_format_read_uint32(file, "broadcast_interval", &tmp, 1)) break;
state.broadcast_interval = tmp;

if(!flipper_format_read_uint32(file, "transmit_power", &tmp, 1)) break;
state.transmit_power = tmp;

if(!flipper_format_read_hex(file, "mac", state.mac, sizeof(state.mac))) break;

if(!flipper_format_read_hex(file, "data", state.data, sizeof(state.data))) break;

loaded_from_file = true;
} while(0);
flipper_format_free(file);
}
furi_record_close(RECORD_STORAGE);

// Otherwise set default values
if(!loaded_from_file) {
state.beacon_active = false;
state.broadcast_interval = 5;
state.transmit_power = 6;

// Set default mac
uint8_t default_mac[EXTRA_BEACON_MAC_ADDR_SIZE] = {0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
memcpy(state.mac, default_mac, sizeof(state.mac));

// Set default empty AirTag data
uint8_t* data = state.data;
*data++ = 0x1E; // Length
*data++ = 0xFF; // Manufacturer Specific Data
*data++ = 0x4C; // Company ID (Apple, Inc.)
*data++ = 0x00; // ...
*data++ = 0x12; // Type (FindMy)
*data++ = 0x19; // Length
*data++ = 0x00; // Status
// Placeholder Empty Public Key without the MAC address
for(size_t i = 0; i < 22; ++i) {
*data++ = 0x00;
}
*data++ = 0x00; // First 2 bits are the version, the rest is the battery level
*data++ = 0x00; // Hint (0x00)
}

// Sync values to config
state.config.min_adv_interval_ms = state.broadcast_interval * 1000; // Converting s to ms
state.config.max_adv_interval_ms = (state.broadcast_interval * 1000) + 150;
state.config.adv_channel_map = GapAdvChannelMapAll;
state.config.adv_power_level = GapAdvPowerLevel_0dBm + state.transmit_power;
state.config.address_type = GapAddressTypePublic;

// Set default mac
uint8_t default_mac[EXTRA_BEACON_MAC_ADDR_SIZE] = {0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
memcpy(state.mac, default_mac, sizeof(state.mac));
memcpy(state.config.address, default_mac, sizeof(state.config.address));

// Set default empty AirTag data
uint8_t* data = state.data;
*data++ = 0x1E; // Length
*data++ = 0xFF; // Manufacturer Specific Data
*data++ = 0x4C; // Company ID (Apple, Inc.)
*data++ = 0x00; // ...
*data++ = 0x12; // Type (FindMy)
*data++ = 0x19; // Length
*data++ = 0x00; // Status
// Placeholder Empty Public Key without the MAC address
for(size_t i = 0; i < 22; ++i) {
*data++ = 0x00;
}
*data++ = 0x00; // First 2 bits are the version, the rest is the battery level
*data++ = 0x00; // Hint (0x00)
memcpy(state.config.address, state.mac, sizeof(state.config.address));

// Copy to caller state before popping stack
memcpy(out_state, &state, sizeof(state));
Expand All @@ -59,3 +95,30 @@ void findmy_state_apply(FindMyState* state) {
furi_check(furi_hal_bt_extra_beacon_start());
}
}

void findmy_state_save(FindMyState* state) {
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_simply_mkdir(storage, FINDMY_STATE_DIR);
FlipperFormat* file = flipper_format_file_alloc(storage);

do {
uint32_t tmp;
if(!flipper_format_file_open_always(file, FINDMY_STATE_PATH)) break;
if(!flipper_format_write_header_cstr(file, FINDMY_STATE_HEADER, FINDMY_STATE_VER)) break;

if(!flipper_format_write_bool(file, "beacon_active", &state->beacon_active, 1)) break;

tmp = state->broadcast_interval;
if(!flipper_format_write_uint32(file, "broadcast_interval", &tmp, 1)) break;

tmp = state->transmit_power;
if(!flipper_format_write_uint32(file, "transmit_power", &tmp, 1)) break;

if(!flipper_format_write_hex(file, "mac", state->mac, sizeof(state->mac))) break;

if(!flipper_format_write_hex(file, "data", state->data, sizeof(state->data))) break;
} while(0);

flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
}
17 changes: 13 additions & 4 deletions applications/system/findmy/findmy_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@

#include <extra_beacon.h>

typedef struct {
uint8_t mac[EXTRA_BEACON_MAC_ADDR_SIZE];
uint8_t data[EXTRA_BEACON_MAX_DATA_SIZE];
GapExtraBeaconConfig config;
#define FINDMY_STATE_HEADER "FindMy Flipper State"
#define FINDMY_STATE_VER 1
#define FINDMY_STATE_DIR EXT_PATH("apps_data/findmy")
#define FINDMY_STATE_PATH FINDMY_STATE_DIR "/findmy_state.txt"

typedef struct {
bool beacon_active;
uint8_t broadcast_interval;
uint8_t transmit_power;

uint8_t mac[EXTRA_BEACON_MAC_ADDR_SIZE];
uint8_t data[EXTRA_BEACON_MAX_DATA_SIZE];

// Generated from the other state values
GapExtraBeaconConfig config;
} FindMyState;

bool findmy_state_load(FindMyState* out_state);

void findmy_state_apply(FindMyState* state);

void findmy_state_save(FindMyState* state);
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ bool findmy_scene_config_mac_on_event(void* context, SceneManagerEvent event) {
case ByteInputResultOk:
furi_hal_bt_reverse_mac_addr(app->mac_buf);
memcpy(&app->state.mac, app->mac_buf, sizeof(app->state.mac));
findmy_state_save(&app->state);
memcpy(&app->state.config.address, app->mac_buf, sizeof(app->state.config.address));
if(furi_hal_bt_extra_beacon_is_active()) {
furi_check(furi_hal_bt_extra_beacon_stop());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ bool findmy_scene_config_packet_on_event(void* context, SceneManagerEvent event)
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, FindMySceneConfig);
memcpy(app->state.data, app->packet_buf, sizeof(app->state.data));
findmy_state_save(&app->state);
furi_check(
furi_hal_bt_extra_beacon_set_data(app->state.data, sizeof(app->state.data)));
findmy_main_update_type(app->findmy_main, findmy_data_get_type(app->state.data));
Expand Down
4 changes: 4 additions & 0 deletions applications/system/findmy/scenes/findmy_scene_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ bool findmy_scene_main_on_event(void* context, SceneManagerEvent event) {
findmy_toggle_beacon(app);
break;
case FindMyMainEventBackground:
app->state.beacon_active = true;
findmy_state_save(&app->state);
if(!furi_hal_bt_extra_beacon_is_active()) {
furi_check(furi_hal_bt_extra_beacon_start());
}
Expand All @@ -40,6 +42,8 @@ bool findmy_scene_main_on_event(void* context, SceneManagerEvent event) {
findmy_change_broadcast_interval(app, app->state.broadcast_interval - 1);
break;
case FindMyMainEventQuit:
app->state.beacon_active = false;
findmy_state_save(&app->state);
if(furi_hal_bt_extra_beacon_is_active()) {
furi_check(furi_hal_bt_extra_beacon_stop());
}
Expand Down

0 comments on commit 5d45d6a

Please sign in to comment.