-
-
Notifications
You must be signed in to change notification settings - Fork 213
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a17efe7
commit 13fe7b3
Showing
14 changed files
with
736 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
App( | ||
appid="findmy", | ||
name="FindMy Flipper", | ||
apptype=FlipperAppType.EXTERNAL, | ||
entry_point="findmy_main", | ||
requires=["gui"], | ||
stack_size=1 * 1024, | ||
order=35, | ||
fap_icon="location_icon.png", | ||
fap_category="Bluetooth", | ||
fap_author="@MatthewKuKanich", | ||
fap_version="1.0", | ||
fap_description="BLE FindMy Location Beacon", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
#include "findmy_i.h" | ||
|
||
static bool findmy_custom_event_callback(void* context, uint32_t event) { | ||
furi_assert(context); | ||
FindMy* app = context; | ||
return scene_manager_handle_custom_event(app->scene_manager, event); | ||
} | ||
|
||
static bool findmy_back_event_callback(void* context) { | ||
furi_assert(context); | ||
FindMy* app = context; | ||
return scene_manager_handle_back_event(app->scene_manager); | ||
} | ||
|
||
static FindMy* findmy_app_alloc() { | ||
FindMy* app = malloc(sizeof(FindMy)); | ||
|
||
app->gui = furi_record_open(RECORD_GUI); | ||
|
||
app->view_dispatcher = view_dispatcher_alloc(); | ||
view_dispatcher_enable_queue(app->view_dispatcher); | ||
|
||
app->scene_manager = scene_manager_alloc(&findmy_scene_handlers, app); | ||
|
||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app); | ||
view_dispatcher_set_custom_event_callback(app->view_dispatcher, findmy_custom_event_callback); | ||
view_dispatcher_set_navigation_event_callback( | ||
app->view_dispatcher, findmy_back_event_callback); | ||
|
||
app->findmy_main = findmy_main_alloc(app); | ||
view_dispatcher_add_view( | ||
app->view_dispatcher, FindMyViewMain, findmy_main_get_view(app->findmy_main)); | ||
|
||
app->byte_input = byte_input_alloc(); | ||
view_dispatcher_add_view( | ||
app->view_dispatcher, FindMyViewByteInput, byte_input_get_view(app->byte_input)); | ||
|
||
app->var_item_list = variable_item_list_alloc(); | ||
view_dispatcher_add_view( | ||
app->view_dispatcher, | ||
FindMyViewVarItemList, | ||
variable_item_list_get_view(app->var_item_list)); | ||
|
||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||
|
||
app->beacon_active = false; | ||
findmy_main_update_active(app->findmy_main, app->beacon_active); | ||
app->broadcast_interval = 5; | ||
findmy_main_update_interval(app->findmy_main, app->broadcast_interval); | ||
app->transmit_power = 6; | ||
app->apple = true; | ||
findmy_main_update_apple(app->findmy_main, app->apple); | ||
|
||
return app; | ||
} | ||
|
||
static void findmy_app_free(FindMy* app) { | ||
furi_assert(app); | ||
|
||
view_dispatcher_remove_view(app->view_dispatcher, FindMyViewVarItemList); | ||
variable_item_list_free(app->var_item_list); | ||
|
||
view_dispatcher_remove_view(app->view_dispatcher, FindMyViewByteInput); | ||
byte_input_free(app->byte_input); | ||
|
||
view_dispatcher_remove_view(app->view_dispatcher, FindMyViewMain); | ||
findmy_main_free(app->findmy_main); | ||
|
||
view_dispatcher_free(app->view_dispatcher); | ||
scene_manager_free(app->scene_manager); | ||
|
||
furi_record_close(RECORD_GUI); | ||
|
||
free(app); | ||
} | ||
|
||
static void findmy_start(FindMy* app) { | ||
furi_hal_bt_extra_beacon_stop(); // Stop any running beacon | ||
|
||
app->config.min_adv_interval_ms = app->broadcast_interval * 1000; // Converting s to ms | ||
app->config.max_adv_interval_ms = (app->broadcast_interval * 1000) + 150; | ||
app->config.adv_channel_map = GapAdvChannelMapAll; | ||
app->config.adv_power_level = GapAdvPowerLevel_0dBm + app->transmit_power; | ||
app->config.address_type = GapAddressTypePublic; | ||
|
||
uint8_t mac[EXTRA_BEACON_MAC_ADDR_SIZE] = {0x4D, 0x61, 0x74, 0x4B, 0x75, 0x4B}; | ||
furi_hal_bt_reverse_mac_addr(mac); | ||
memcpy(&app->config.address, mac, sizeof(app->config.address)); | ||
furi_check(furi_hal_bt_extra_beacon_set_config(&app->config)); | ||
|
||
uint8_t data[EXTRA_BEACON_MAX_DATA_SIZE]; | ||
uint8_t* it = data; | ||
|
||
// For Apple AirTags | ||
*it++ = 0x1E; // Length | ||
*it++ = 0xFF; // Manufacturer Specific Data | ||
*it++ = 0x4C; // Company ID (Apple, Inc.) | ||
*it++ = 0x00; // State | ||
*it++ = 0x12; // Data - Public Key without the MAC address | ||
*it++ = 0x81; // ... | ||
*it++ = 0xB9; // ... | ||
*it++ = 0x02; // First 2 bits are the version, the rest is the battery level | ||
*it++ = 0x7E; // Hint (0x00) | ||
|
||
furi_check(furi_hal_bt_extra_beacon_set_data(data, it - data)); | ||
} | ||
|
||
int32_t findmy_main(void* p) { | ||
UNUSED(p); | ||
FindMy* app = findmy_app_alloc(); | ||
|
||
findmy_start(app); | ||
|
||
scene_manager_next_scene(app->scene_manager, FindMySceneMain); | ||
|
||
view_dispatcher_run(app->view_dispatcher); | ||
|
||
findmy_app_free(app); | ||
return 0; | ||
} | ||
|
||
void findmy_change_broadcast_interval(FindMy* app, uint8_t value) { | ||
if(value > 10 || value < 1) { | ||
return; | ||
} | ||
app->broadcast_interval = value; | ||
findmy_main_update_interval(app->findmy_main, app->broadcast_interval); | ||
if(app->beacon_active) { | ||
// Always check if beacon is active before changing config | ||
furi_check(furi_hal_bt_extra_beacon_stop()); | ||
} | ||
app->config.min_adv_interval_ms = app->broadcast_interval * 1000; | ||
app->config.max_adv_interval_ms = app->config.min_adv_interval_ms + 150; | ||
furi_check(furi_hal_bt_extra_beacon_set_config(&app->config)); | ||
if(app->beacon_active) { | ||
furi_check(furi_hal_bt_extra_beacon_start()); | ||
} | ||
} | ||
|
||
void findmy_change_transmit_power(FindMy* app, uint8_t value) { | ||
if(value > 6) { | ||
return; | ||
} | ||
app->transmit_power = value; | ||
if(app->beacon_active) { | ||
furi_check(furi_hal_bt_extra_beacon_stop()); | ||
} | ||
app->config.adv_power_level = GapAdvPowerLevel_0dBm + app->transmit_power; | ||
furi_check(furi_hal_bt_extra_beacon_set_config(&app->config)); | ||
if(app->beacon_active) { | ||
furi_check(furi_hal_bt_extra_beacon_start()); | ||
} | ||
} | ||
|
||
void findmy_toggle_beacon(FindMy* app) { | ||
app->beacon_active = !app->beacon_active; | ||
findmy_main_update_active(app->findmy_main, app->beacon_active); | ||
findmy_main_update_apple(app->findmy_main, app->apple); | ||
if(app->beacon_active) { | ||
furi_hal_bt_extra_beacon_start(); | ||
} else { | ||
furi_hal_bt_extra_beacon_stop(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#pragma once | ||
|
||
typedef struct FindMy FindMy; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#pragma once | ||
|
||
#include "findmy.h" | ||
#include <furi_hal_bt.h> | ||
#include <extra_beacon.h> | ||
#include <assets_icons.h> | ||
#include <gui/gui.h> | ||
#include <gui/scene_manager.h> | ||
#include <gui/view_dispatcher.h> | ||
#include "views/findmy_main.h" | ||
#include <gui/modules/byte_input.h> | ||
#include <gui/modules/variable_item_list.h> | ||
#include "scenes/findmy_scene.h" | ||
|
||
struct FindMy { | ||
Gui* gui; | ||
SceneManager* scene_manager; | ||
ViewDispatcher* view_dispatcher; | ||
|
||
FindMyMain* findmy_main; | ||
ByteInput* byte_input; | ||
VariableItemList* var_item_list; | ||
|
||
uint8_t mac_buf[EXTRA_BEACON_MAC_ADDR_SIZE]; | ||
uint8_t packet_buf[EXTRA_BEACON_MAX_DATA_SIZE]; | ||
|
||
GapExtraBeaconConfig config; | ||
bool apple; | ||
bool beacon_active; | ||
uint8_t broadcast_interval; | ||
uint8_t transmit_power; | ||
}; | ||
|
||
typedef enum { | ||
FindMyViewMain, | ||
FindMyViewByteInput, | ||
FindMyViewVarItemList, | ||
} FindMyView; | ||
|
||
void findmy_change_broadcast_interval(FindMy* app, uint8_t value); | ||
void findmy_change_transmit_power(FindMy* app, uint8_t value); | ||
void findmy_toggle_beacon(FindMy* app); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#include "findmy_scene.h" | ||
#include "findmy.h" | ||
|
||
// Generate scene on_enter handlers array | ||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, | ||
void (*const findmy_on_enter_handlers[])(void*) = { | ||
#include "findmy_scenes.h" | ||
}; | ||
#undef ADD_SCENE | ||
|
||
// Generate scene on_event handlers array | ||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, | ||
bool (*const findmy_on_event_handlers[])(void* context, SceneManagerEvent event) = { | ||
#include "findmy_scenes.h" | ||
}; | ||
#undef ADD_SCENE | ||
|
||
// Generate scene on_exit handlers array | ||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, | ||
void (*const findmy_on_exit_handlers[])(void* context) = { | ||
#include "findmy_scenes.h" | ||
}; | ||
#undef ADD_SCENE | ||
|
||
// Initialize scene handlers configuration structure | ||
const SceneManagerHandlers findmy_scene_handlers = { | ||
.on_enter_handlers = findmy_on_enter_handlers, | ||
.on_event_handlers = findmy_on_event_handlers, | ||
.on_exit_handlers = findmy_on_exit_handlers, | ||
.scene_num = FindMySceneNum, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#pragma once | ||
|
||
#include <gui/scene_manager.h> | ||
#include "findmy.h" | ||
|
||
// Generate scene id and total number | ||
#define ADD_SCENE(prefix, name, id) FindMyScene##id, | ||
typedef enum { | ||
#include "findmy_scenes.h" | ||
FindMySceneNum, | ||
} FindMyScene; | ||
#undef ADD_SCENE | ||
|
||
extern const SceneManagerHandlers findmy_scene_handlers; | ||
|
||
// Generate scene on_enter handlers declaration | ||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); | ||
#include "findmy_scenes.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 "findmy_scenes.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 "findmy_scenes.h" | ||
#undef ADD_SCENE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
#include "../findmy_i.h" | ||
|
||
enum VarItemListIndex { | ||
VarItemListIndexBroadcastInterval, | ||
VarItemListIndexTransmitPower, | ||
VarItemListIndexRegisterTag, | ||
VarItemListIndexAbout, | ||
}; | ||
|
||
void findmy_scene_config_broadcast_interval_changed(VariableItem* item) { | ||
FindMy* app = variable_item_get_context(item); | ||
uint8_t index = variable_item_get_current_value_index(item); | ||
findmy_change_broadcast_interval(app, index + 1); | ||
char str[5]; | ||
snprintf(str, sizeof(str), "%ds", app->broadcast_interval); | ||
variable_item_set_current_value_text(item, str); | ||
variable_item_set_current_value_index(item, app->broadcast_interval - 1); | ||
} | ||
|
||
void findmy_scene_config_transmit_power_changed(VariableItem* item) { | ||
FindMy* app = variable_item_get_context(item); | ||
uint8_t index = variable_item_get_current_value_index(item); | ||
findmy_change_transmit_power(app, index); | ||
char str[7]; | ||
snprintf(str, sizeof(str), "%ddBm", app->transmit_power); | ||
variable_item_set_current_value_text(item, str); | ||
variable_item_set_current_value_index(item, app->transmit_power); | ||
} | ||
|
||
void findmy_scene_config_callback(void* context, uint32_t index) { | ||
furi_assert(context); | ||
FindMy* app = context; | ||
view_dispatcher_send_custom_event(app->view_dispatcher, index); | ||
} | ||
|
||
void findmy_scene_config_on_enter(void* context) { | ||
FindMy* app = context; | ||
VariableItemList* var_item_list = app->var_item_list; | ||
VariableItem* item; | ||
|
||
item = variable_item_list_add( | ||
var_item_list, | ||
"Broadcast Interval", | ||
10, | ||
findmy_scene_config_broadcast_interval_changed, | ||
app); | ||
// Broadcast Interval is 1-10, so use 0-9 and offset indexes by 1 | ||
variable_item_set_current_value_index(item, app->broadcast_interval - 1); | ||
char broadcast_interval_s[5]; | ||
snprintf(broadcast_interval_s, sizeof(broadcast_interval_s), "%ds", app->broadcast_interval); | ||
variable_item_set_current_value_text(item, broadcast_interval_s); | ||
|
||
item = variable_item_list_add( | ||
var_item_list, "Transmit Power", 7, findmy_scene_config_transmit_power_changed, app); | ||
variable_item_set_current_value_index(item, app->transmit_power); | ||
char transmit_power_s[7]; | ||
snprintf(transmit_power_s, sizeof(transmit_power_s), "%ddBm", app->transmit_power); | ||
variable_item_set_current_value_text(item, transmit_power_s); | ||
|
||
item = variable_item_list_add(var_item_list, "Register Tag", 0, NULL, NULL); | ||
item = variable_item_list_add(var_item_list, "Matthew KuKanich, Thanks to Chapoly1305, WillyJL, OpenHaystack, Testers", 1, NULL, NULL); | ||
variable_item_set_current_value_text(item, "Credits"); | ||
|
||
variable_item_list_set_enter_callback(var_item_list, findmy_scene_config_callback, app); | ||
|
||
variable_item_list_set_selected_item( | ||
var_item_list, scene_manager_get_scene_state(app->scene_manager, FindMySceneConfig)); | ||
|
||
view_dispatcher_switch_to_view(app->view_dispatcher, FindMyViewVarItemList); | ||
} | ||
|
||
bool findmy_scene_config_on_event(void* context, SceneManagerEvent event) { | ||
FindMy* app = context; | ||
bool consumed = false; | ||
|
||
if(event.type == SceneManagerEventTypeCustom) { | ||
scene_manager_set_scene_state(app->scene_manager, FindMySceneConfig, event.event); | ||
consumed = true; | ||
switch(event.event) { | ||
case VarItemListIndexRegisterTag: | ||
scene_manager_next_scene(app->scene_manager, FindMySceneConfigMac); | ||
break; | ||
case VarItemListIndexAbout: | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
return consumed; | ||
} | ||
|
||
void findmy_scene_config_on_exit(void* context) { | ||
FindMy* app = context; | ||
VariableItemList* var_item_list = app->var_item_list; | ||
|
||
variable_item_list_reset(var_item_list); | ||
} |
Oops, something went wrong.