Files
pebble/src/fw/services/common/bluetooth/pairability.c
2025-01-27 11:38:16 -08:00

156 lines
5.0 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define FILE_LOG_COLOR LOG_COLOR_BLUE
#include "system/logging.h"
#include "system/passert.h"
#include "comm/ble/gap_le_slave_discovery.h"
#include "kernel/pebble_tasks.h"
#include "services/common/bluetooth/bluetooth_ctl.h"
#include "services/common/bluetooth/bluetooth_persistent_storage.h"
#include "services/common/bluetooth/local_addr.h"
#include "services/common/bluetooth/pairability.h"
#include "services/common/regular_timer.h"
#include "services/common/system_task.h"
#include <bluetooth/connectability.h>
#include <bluetooth/features.h>
#include <bluetooth/pairability.h>
static void prv_pairability_timer_cb(void *unused);
static int s_allow_bt_pairing_refcount = 0;
static int s_allow_ble_pairing_refcount = 0;
static RegularTimerInfo s_pairability_timer_info = {
.cb = prv_pairability_timer_cb,
};
static void evaluate_pairing_refcount(void *data) {
PBL_ASSERT_TASK(PebbleTask_KernelBackground);
if (!bt_ctl_is_bluetooth_running()) {
return;
}
PBL_LOG(LOG_LEVEL_DEBUG, "Pairabilty state: LE=%u, Classic=%u",
s_allow_ble_pairing_refcount, s_allow_bt_pairing_refcount);
bool is_ble_pairable_and_discoverable = (s_allow_ble_pairing_refcount > 0);
bt_driver_le_pairability_set_enabled(is_ble_pairable_and_discoverable);
if (gap_le_slave_is_discoverable() != is_ble_pairable_and_discoverable) {
if (is_ble_pairable_and_discoverable) {
bt_local_addr_pause_cycling();
} else {
bt_local_addr_resume_cycling();
}
gap_le_slave_set_discoverable(is_ble_pairable_and_discoverable);
}
if (bt_driver_supports_bt_classic()) {
bt_driver_classic_pairability_set_enabled((s_allow_bt_pairing_refcount > 0));
bt_driver_classic_update_connectability();
}
}
static void prv_schedule_evaluation(void) {
// We used to sparingly schedule the evaluation and had a bug because of this:
// https://pebbletechnology.atlassian.net/browse/PBL-22884
// Because this pretty much only happens in response to user input, don't bother limiting this,
// and always evaluate, even though the state might not have changed:
system_task_add_callback(evaluate_pairing_refcount, NULL);
}
void bt_pairability_use(void) {
++s_allow_bt_pairing_refcount;
++s_allow_ble_pairing_refcount;
prv_schedule_evaluation();
}
void bt_pairability_use_bt(void) {
++s_allow_bt_pairing_refcount;
prv_schedule_evaluation();
}
void bt_pairability_use_ble(void) {
++s_allow_ble_pairing_refcount;
prv_schedule_evaluation();
}
static void prv_pairability_timer_cb(void *unused) {
regular_timer_remove_callback(&s_pairability_timer_info);
bt_pairability_release_ble();
}
void bt_pairability_use_ble_for_period(uint16_t duration_secs) {
if (!regular_timer_is_scheduled(&s_pairability_timer_info)) {
// If this function is called multiple times before the timer is unscheduled, limit to calling
// "use" only once:
bt_pairability_use_ble();
}
// Always reschedule, even if the duration is shorter than the one that might already be
// scheduled:
regular_timer_add_multisecond_callback(&s_pairability_timer_info, duration_secs);
}
void bt_pairability_release(void) {
PBL_ASSERT(s_allow_bt_pairing_refcount != 0 && s_allow_ble_pairing_refcount != 0, "");
--s_allow_bt_pairing_refcount;
--s_allow_ble_pairing_refcount;
prv_schedule_evaluation();
}
void bt_pairability_release_bt(void) {
PBL_ASSERT(s_allow_bt_pairing_refcount != 0, "");
--s_allow_bt_pairing_refcount;
prv_schedule_evaluation();
}
void bt_pairability_release_ble(void) {
PBL_ASSERT(s_allow_ble_pairing_refcount != 0, "");
--s_allow_ble_pairing_refcount;
prv_schedule_evaluation();
}
//! Call this whenever we modify the number of saved bondings we have.
void bt_pairability_update_due_to_bonding_change(void) {
static bool s_pairable_due_to_no_gateway_bondings = false;
const bool has_classic_bonding =
(bt_driver_supports_bt_classic() &&
bt_persistent_storage_has_active_bt_classic_gateway_bonding());
if (!has_classic_bonding &&
!bt_persistent_storage_has_active_ble_gateway_bonding() &&
!bt_persistent_storage_has_ble_ancs_bonding()) {
if (!s_pairable_due_to_no_gateway_bondings) {
bt_pairability_use();
s_pairable_due_to_no_gateway_bondings = true;
}
} else {
if (s_pairable_due_to_no_gateway_bondings) {
bt_pairability_release();
s_pairable_due_to_no_gateway_bondings = false;
}
}
}
void bt_pairability_init(void) {
bt_pairability_update_due_to_bonding_change();
prv_schedule_evaluation();
}