mirror of
https://github.com/google/pebble.git
synced 2026-02-12 00:17:19 -05:00
198 lines
5.7 KiB
C
198 lines
5.7 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.
|
|
*/
|
|
|
|
#include "pulse_logging.h"
|
|
|
|
#include "pebble_tasks.h"
|
|
#include "logging_private.h"
|
|
#include "util/stack_info.h"
|
|
|
|
#include "console/console_internal.h"
|
|
#include "console/prompt.h"
|
|
#include "console/serial_console.h"
|
|
#include "debug/advanced_logging.h"
|
|
#include "drivers/rtc.h"
|
|
#include "system/logging.h"
|
|
|
|
#include "mcu/interrupts.h"
|
|
#include "mcu/privilege.h"
|
|
|
|
#include "util/math.h"
|
|
#include "util/net.h"
|
|
#include "util/string.h"
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#ifndef PBL_LOG_LEVEL
|
|
#define PBL_LOG_LEVEL LOG_LEVEL_DEBUG
|
|
#endif
|
|
|
|
int g_pbl_log_level = PBL_LOG_LEVEL;
|
|
bool g_pbl_log_enabled = true;
|
|
|
|
static bool prv_check_serial_log_enabled(int level) {
|
|
return (g_pbl_log_enabled) &&
|
|
(level == LOG_LEVEL_ALWAYS ||
|
|
(level <= g_pbl_log_level));
|
|
}
|
|
|
|
#if !PULSE_EVERYWHERE
|
|
#define TIMESTAMP_BUFFER_SIZE 14
|
|
static void prv_log_timestamp(void) {
|
|
// Enough stack space to use sprintfs?
|
|
uint32_t stack_space = stack_free_bytes();
|
|
if (stack_space < LOGGING_MIN_STACK_FOR_SPRINTF) {
|
|
serial_console_write_log_message(LOGGING_STACK_FULL_MSG);
|
|
serial_console_write_log_message(" ");
|
|
return;
|
|
}
|
|
|
|
char buffer[TIMESTAMP_BUFFER_SIZE];
|
|
|
|
time_t time_seconds;
|
|
uint16_t time_ms;
|
|
rtc_get_time_ms(&time_seconds, &time_ms);
|
|
struct tm time_seconds_calendar;
|
|
gmtime_r(&time_seconds, &time_seconds_calendar);
|
|
|
|
sniprintf(buffer, TIMESTAMP_BUFFER_SIZE, "%02u:%02u:%02u.%03u ",
|
|
time_seconds_calendar.tm_hour, time_seconds_calendar.tm_min, time_seconds_calendar.tm_sec, time_ms);
|
|
|
|
serial_console_write_log_message(buffer);
|
|
}
|
|
|
|
static void prv_log_serial(
|
|
uint8_t log_level, const char* src_filename, int src_line_number, const char* message) {
|
|
if (!serial_console_is_logging_enabled() && log_level != LOG_LEVEL_ALWAYS) {
|
|
return;
|
|
}
|
|
|
|
// Log the log level and the current task+privilege level
|
|
{
|
|
unsigned char task_char = pebble_task_get_char(pebble_task_get_current());
|
|
if (mcu_state_is_privileged()) {
|
|
task_char = toupper(task_char);
|
|
}
|
|
|
|
char buffer[] = { pbl_log_get_level_char(log_level), ' ', task_char, ' ', 0 };
|
|
serial_console_write_log_message(buffer);
|
|
}
|
|
|
|
// Start out with the timestamp
|
|
prv_log_timestamp();
|
|
|
|
// Write out the filename
|
|
src_filename = GET_FILE_NAME(src_filename);
|
|
serial_console_write_log_message(src_filename);
|
|
|
|
// Write out the line number
|
|
{
|
|
char line_number_buffer[12];
|
|
itoa_int(src_line_number, line_number_buffer, 10);
|
|
serial_console_write_log_message(":");
|
|
serial_console_write_log_message(line_number_buffer);
|
|
serial_console_write_log_message("> ");
|
|
}
|
|
|
|
// Write the actual log message.
|
|
serial_console_write_log_message(message);
|
|
|
|
// Append our newlines and our trailing null
|
|
serial_console_write_log_message("\r\n");
|
|
}
|
|
#endif // PULSE_EVERYWHERE
|
|
|
|
void kernel_pbl_log_serial(LogBinaryMessage *log_message, bool async) {
|
|
if (!prv_check_serial_log_enabled(log_message->log_level)) {
|
|
return;
|
|
}
|
|
|
|
#if PULSE_EVERYWHERE
|
|
if (async) {
|
|
pulse_logging_log(log_message->log_level, log_message->filename,
|
|
htons(log_message->line_number), log_message->message);
|
|
} else {
|
|
pulse_logging_log_sync(
|
|
log_message->log_level, log_message->filename,
|
|
htons(log_message->line_number), log_message->message);
|
|
}
|
|
#else
|
|
prv_log_serial(log_message->log_level, log_message->filename,
|
|
htons(log_message->line_number), log_message->message);
|
|
#endif
|
|
}
|
|
|
|
void kernel_pbl_log_flash(LogBinaryMessage *log_message, bool async) {
|
|
int length = sizeof(*log_message) + log_message->message_length;
|
|
|
|
static const uint8_t FLASH_LOG_LEVEL = LOG_LEVEL_INFO;
|
|
if (g_pbl_log_enabled &&
|
|
(log_message->log_level == LOG_LEVEL_ALWAYS ||
|
|
(log_message->log_level <= FLASH_LOG_LEVEL))) {
|
|
pbl_log_advanced((const char*) log_message, length, async);
|
|
}
|
|
}
|
|
|
|
void kernel_pbl_log(LogBinaryMessage* log_message, bool async) {
|
|
kernel_pbl_log_serial(log_message, async);
|
|
|
|
if (!portIN_CRITICAL() && !mcu_state_is_isr() &&
|
|
xTaskGetSchedulerState() != taskSCHEDULER_SUSPENDED) {
|
|
kernel_pbl_log_flash(log_message, async);
|
|
}
|
|
}
|
|
|
|
void kernel_pbl_log_from_fault_handler(
|
|
const char *src_filename, uint16_t src_line_number, const char *message) {
|
|
#if PULSE_EVERYWHERE
|
|
pulse_logging_log_sync(LOG_LEVEL_ALWAYS, src_filename,
|
|
src_line_number, message);
|
|
#else
|
|
serial_console_write_log_message(message);
|
|
serial_console_write_log_message("\r\n");
|
|
#endif
|
|
}
|
|
|
|
void kernel_pbl_log_from_fault_handler_fmt(
|
|
const char *src_filename, uint16_t src_line_number, char *buffer,
|
|
unsigned int buffer_size, const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsniprintf(buffer, buffer_size, fmt, ap);
|
|
va_end(ap);
|
|
|
|
kernel_pbl_log_from_fault_handler(src_filename, src_line_number, buffer);
|
|
}
|
|
|
|
// Serial Commands
|
|
///////////////////////////////////////////////////////////
|
|
void command_log_level_set(const char* level) {
|
|
char buffer[32];
|
|
g_pbl_log_level = atoi(level);
|
|
prompt_send_response_fmt(buffer, 32, "Log level set to: %i", g_pbl_log_level);
|
|
}
|
|
|
|
void command_log_level_get(void) {
|
|
char buffer[32];
|
|
prompt_send_response_fmt(buffer, 32, "Log level: %i", g_pbl_log_level);
|
|
}
|
|
|