1 /******************************************************************************
3 * Copyright (C) 2014 Google, Inc.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 ******************************************************************************/
19 #define LOG_TAG "bt_low_power_manager"
21 #include "low_power_manager.h"
26 #include "osi/include/alarm.h"
27 #include "osi/include/log.h"
28 #include "osi/include/osi.h"
29 #include "osi/include/thread.h"
37 } low_power_mode_state_t;
40 LPM_WAKE_DEASSERTED = 0,
46 // Our interface and modules we import
47 static const low_power_manager_t interface;
48 static const vendor_t *vendor;
50 static void vendor_enable_disable_callback(bool success);
52 static void event_disable(void *context);
53 static void event_enable(void *context);
54 static void event_wake_assert(void *context);
55 static void event_allow_device_sleep(void *context);
56 static void event_idle_timeout(void *context);
58 static void reset_state();
59 static void start_idle_timer();
60 static void stop_idle_timer();
62 static thread_fn event_functions[] = {
66 event_allow_device_sleep
69 static thread_t *thread;
70 static low_power_mode_state_t state;
71 static wake_state_t wake_state;
72 static uint32_t idle_timeout_ms;
73 static alarm_t *idle_alarm;
74 static bool transmit_is_done;
76 // Interface functions
78 static void init(thread_t *post_thread) {
79 assert(post_thread != NULL);
82 vendor->set_callback(VENDOR_SET_LPM_MODE, vendor_enable_disable_callback);
84 idle_alarm = alarm_new();
86 LOG_ERROR(LOG_TAG, "%s could not create idle alarm.", __func__);
92 static void cleanup() {
94 alarm_free(idle_alarm);
98 static void post_command(low_power_command_t command) {
99 if (command > LPM_WAKE_DEASSERT) {
100 LOG_ERROR(LOG_TAG, "%s unknown low power command %d", __func__, command);
104 thread_post(thread, event_functions[command], NULL);
107 static void wake_assert() {
108 if (state != LPM_DISABLED) {
111 uint8_t new_state = BT_VND_LPM_WAKE_ASSERT;
112 vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
113 wake_state = LPM_WAKE_ASSERTED;
116 // TODO(zachoverflow): investigate this interaction. If someone above
117 // HCI asserts wake, we'll wait until we transmit before deasserting.
118 // That doesn't seem quite right.
119 transmit_is_done = false;
122 static void transmit_done() {
123 transmit_is_done = true;
124 if (wake_state == LPM_WAKE_W4_TX_DONE || wake_state == LPM_WAKE_ASSERTED) {
125 wake_state = LPM_WAKE_W4_TIMEOUT;
130 // Internal functions
132 static void enable(bool enable) {
133 if (state == LPM_DISABLING) {
135 LOG_ERROR(LOG_TAG, "%s still processing prior disable request, cannot enable.", __func__);
137 LOG_WARN(LOG_TAG, "%s still processing prior disable request, ignoring new request to disable.", __func__);
138 } else if (state == LPM_ENABLING) {
140 LOG_ERROR(LOG_TAG, "%s still processing prior enable request, ignoring new request to enable.", __func__);
142 LOG_WARN(LOG_TAG, "%s still processing prior enable request, cannot disable.", __func__);
143 } else if (state == LPM_ENABLED && enable) {
144 LOG_INFO(LOG_TAG, "%s already enabled.", __func__);
145 } else if (state == LPM_DISABLED && !enable) {
146 LOG_INFO(LOG_TAG, "%s already disabled.", __func__);
148 uint8_t command = enable ? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE;
149 state = enable ? LPM_ENABLING : LPM_DISABLING;
150 if (state == LPM_ENABLING)
151 vendor->send_command(VENDOR_GET_LPM_IDLE_TIMEOUT, &idle_timeout_ms);
152 vendor->send_async_command(VENDOR_SET_LPM_MODE, &command);
156 static void allow_device_sleep() {
157 if (state == LPM_ENABLED && wake_state == LPM_WAKE_ASSERTED) {
158 if (transmit_is_done) {
159 wake_state = LPM_WAKE_W4_TIMEOUT;
162 wake_state = LPM_WAKE_W4_TX_DONE;
167 static void wake_deassert() {
168 if (state == LPM_ENABLED && transmit_is_done) {
169 uint8_t new_state = BT_VND_LPM_WAKE_DEASSERT;
170 vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
171 wake_state = LPM_WAKE_DEASSERTED;
175 static void reset_state() {
176 state = LPM_DISABLED;
177 wake_state = LPM_WAKE_DEASSERTED;
178 transmit_is_done = true;
182 static void idle_timer_expired(UNUSED_ATTR void *context) {
183 if (state == LPM_ENABLED && wake_state == LPM_WAKE_W4_TIMEOUT)
184 thread_post(thread, event_idle_timeout, NULL);
187 static void start_idle_timer() {
188 if (state == LPM_ENABLED) {
189 alarm_set(idle_alarm, idle_timeout_ms, idle_timer_expired, NULL);
193 static void stop_idle_timer() {
194 alarm_cancel(idle_alarm);
197 static void event_disable(UNUSED_ATTR void *context) {
201 static void event_enable(UNUSED_ATTR void *context) {
205 static void event_wake_assert(UNUSED_ATTR void *context) {
209 static void event_allow_device_sleep(UNUSED_ATTR void *context) {
210 allow_device_sleep();
213 static void event_idle_timeout(UNUSED_ATTR void *context) {
217 static void vendor_enable_disable_callback(bool success) {
219 state = (state == LPM_ENABLING) ? LPM_ENABLED : LPM_DISABLED;
221 state = (state == LPM_ENABLING) ? LPM_DISABLED : LPM_ENABLED;
223 if (state == LPM_DISABLED) {
228 static const low_power_manager_t interface = {
236 const low_power_manager_t *low_power_manager_get_interface() {
237 vendor = vendor_get_interface();
241 const low_power_manager_t *low_power_manager_get_test_interface(const vendor_t *vendor_interface) {
242 vendor = vendor_interface;