mirror of
https://github.com/google/pebble.git
synced 2025-05-31 23:43:11 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
173
src/fw/kernel/kernel_applib_state.c
Normal file
173
src/fw/kernel/kernel_applib_state.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "kernel_applib_state.h"
|
||||
|
||||
#include "applib/ui/layer.h"
|
||||
#include "mcu/interrupts.h"
|
||||
#include "os/mutex.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
static PebbleRecursiveMutex *s_log_state_mutex = INVALID_MUTEX_HANDLE;
|
||||
static bool s_log_state_task_entered[NumPebbleTask]; // which tasks have entered
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
CompassServiceConfig **kernel_applib_get_compass_config(void) {
|
||||
static CompassServiceConfig *s_compass_config;
|
||||
return &s_compass_config;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
AnimationState* kernel_applib_get_animation_state(void) {
|
||||
static AnimationState s_kernel_animation_state;
|
||||
return &s_kernel_animation_state;
|
||||
}
|
||||
|
||||
// Get the current task. If FreeRTOS has not been initialized yet, set to KernelMain
|
||||
static PebbleTask prv_get_current_task(void) {
|
||||
if (pebble_task_get_handle_for_task(PebbleTask_KernelMain) == NULL) {
|
||||
return PebbleTask_KernelMain;
|
||||
} else {
|
||||
return pebble_task_get_current();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Return a pointer to the LogState to use for kernel (non app task) code. The LogState contains
|
||||
// the buffers for formatting the log message.
|
||||
// Returns NULL if a kernel logging operation is already in progress
|
||||
LogState *kernel_applib_get_log_state(void) {
|
||||
static LogState sys_log_state;
|
||||
bool use_mutex;
|
||||
|
||||
// Return right away if we re-entered from the same task For example, if we hit an assert while
|
||||
// trying to grab the s_log_state_mutex mutex below and tried to log an error.
|
||||
PebbleTask task = prv_get_current_task();
|
||||
if (s_log_state_task_entered[task]) {
|
||||
return NULL;
|
||||
}
|
||||
s_log_state_task_entered[task] = true;
|
||||
|
||||
|
||||
// We have 3 possible phases of operation:
|
||||
// 1.) Before FreeRTOS has been initialized - only 1 "task", no mutexes available
|
||||
// 2.) After FreeRTOS, but before our mutex has been created (via kernel_applib_init())
|
||||
// 3.) After our mutex has been created.
|
||||
// In phase 1, we don't bother taking the mutex but still log
|
||||
// In phase 2, we just return without logging. It is too dangerous to have
|
||||
// possibly multiple tasks using logging without mutex support
|
||||
// In phase 3, we log after locking the mutex only.
|
||||
// Note, if we are in an ISR or critical section in any of these phases, we cannot use a mutex
|
||||
if ((pebble_task_get_handle_for_task(PebbleTask_KernelMain) == NULL) || mcu_state_is_isr()
|
||||
|| portIN_CRITICAL() || (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING)) {
|
||||
// phase 1 || in an ISR || in a critical section
|
||||
use_mutex = false;
|
||||
} else if (s_log_state_mutex == INVALID_MUTEX_HANDLE) {
|
||||
// phase 2
|
||||
dbgserial_putstr("LOGGING DISABLED");
|
||||
goto exit_fail;
|
||||
} else {
|
||||
// phase 3
|
||||
use_mutex = true;
|
||||
}
|
||||
|
||||
if (use_mutex) {
|
||||
// Logging operations shouldn't take long to complete. Use a timeout in case we run into
|
||||
// an unlikely deadlock situation (one task doing a synchronous log to flash and another task
|
||||
// trying to log from flash code)
|
||||
bool success = mutex_lock_recursive_with_timeout(s_log_state_mutex, 1000);
|
||||
if (!success) {
|
||||
dbgserial_putstr("kernel_applib_get_log_state timeout error");
|
||||
goto exit_fail;
|
||||
}
|
||||
}
|
||||
|
||||
// Return if re-entered (logging while logging). This can happen for example if one task
|
||||
// grabbed the context from an ISR or critical section and another grabbed it using the mutex
|
||||
if (sys_log_state.in_progress) {
|
||||
if (use_mutex) {
|
||||
mutex_unlock_recursive(s_log_state_mutex);
|
||||
}
|
||||
goto exit_fail;
|
||||
}
|
||||
|
||||
sys_log_state.in_progress = true;
|
||||
return &sys_log_state;
|
||||
|
||||
exit_fail:
|
||||
s_log_state_task_entered[task] = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Release the LogState buffer obtained by kernel_applib_get_log_state()
|
||||
void kernel_applib_release_log_state(LogState *state) {
|
||||
state->in_progress = false;
|
||||
|
||||
// For phase 1 & when in an ISR, there is no mutex available
|
||||
if (!portIN_CRITICAL() && !mcu_state_is_isr() &&
|
||||
(xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) &&
|
||||
(s_log_state_mutex != INVALID_MUTEX_HANDLE)) {
|
||||
mutex_unlock_recursive(s_log_state_mutex);
|
||||
}
|
||||
|
||||
// Clear the re-entrancy flag for this task
|
||||
PebbleTask task = prv_get_current_task();
|
||||
s_log_state_task_entered[task] = false;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
EventServiceInfo* kernel_applib_get_event_service_state(void) {
|
||||
static EventServiceInfo s_event_service_state;
|
||||
return &s_event_service_state;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
TickTimerServiceState* kernel_applib_get_tick_timer_service_state(void) {
|
||||
static TickTimerServiceState s_tick_timer_service_state;
|
||||
return &s_tick_timer_service_state;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
ConnectionServiceState* kernel_applib_get_connection_service_state(void) {
|
||||
static ConnectionServiceState s_connection_service_state;
|
||||
return &s_connection_service_state;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
BatteryStateServiceState* kernel_applib_get_battery_state_service_state(void) {
|
||||
static BatteryStateServiceState s_battery_state_service_state;
|
||||
return &s_battery_state_service_state;
|
||||
}
|
||||
|
||||
Layer** kernel_applib_get_layer_tree_stack(void) {
|
||||
static Layer* layer_tree_stack[LAYER_TREE_STACK_SIZE];
|
||||
return layer_tree_stack;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
void kernel_applib_init(void) {
|
||||
s_log_state_mutex = mutex_create_recursive();
|
||||
connection_service_state_init(kernel_applib_get_connection_service_state());
|
||||
battery_state_service_state_init(kernel_applib_get_battery_state_service_state());
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue