file/log_file/main.c

/*******************************************************************************
* # License
* Copyright 2019 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
******************************************************************************/
/* Documentation for this app is available online.
* See https://docs.silabs.com/gecko-os/4/standard/latest/sdk/examples/file/log-file
*/
#include "gos.h"
#define BUTTON_DEBOUNCE_TIME_MS 50
#define BUTTON_CLICK_TIME_MS 500
#define BUTTON_PRESS_TIME_MS 1000
#define MAX_LOG_FILE_SIZE (1024 * 5)
#define LOG_FILENAME "test.log"
#define LOG_PERIOD 50
#define LOG_COUNT 10
#define APPLICATION_START_LINE "'log_file' demo running ..."
// An individual log record will contain the following info ...
typedef struct
{
uint32_t log_id;
uint32_t gpio_mask;
} log_record_t;
static void log_event_logfile_handler(void *arg);
static void print_log_records(void);
static void partial_read_test(uint32_t log_to_read);
static gos_handle_t logfile_handle;
static uint32_t log_id;
static uint32_t end_id;
/*************************************************************************************************/
void gos_app_init(void)
{
gos_result_t result;
strcpy(file_info.name, LOG_FILENAME); // The name of the log file
file_info.size = MAX_LOG_FILE_SIZE; // The maximum size of the log file
logfile_handle = GOS_NULL_HANDLE;
GOS_LOG(APPLICATION_START_LINE);
if(GOS_FAILED(result, initialize_hardware()))
{
GOS_LOG("Failed to initialize hardware");
return;
}
// Create (or open) the log file
if (GOS_FAILED(result, gos_log_file_open(&file_info, &logfile_handle, false)))
{
GOS_LOG("Failed to create/open log file: %d", result);
return;
}
// Read stats of existing log file
gos_log_file_get_stats(logfile_handle, &stats);
log_id = stats.record_count; // ID of the last log already in the file
end_id = log_id + LOG_COUNT; // ID of the last log that will be appended to the file
// Display stats for existing logs (if any)
GOS_LOG("Log file statistics:");
GOS_LOG(" name: %s", file_info.name);
GOS_LOG(" record count: %d", stats.record_count);
GOS_LOG(" bytes used: %d", stats.bytes_used);
GOS_LOG(" bytes remaining: %d", stats.bytes_remaining);
GOS_LOG(" ");
print_log_records(); // Print all records in the logfile
partial_read_test(3); // Read and print log #3
// Setup a periodic event to start logging to file
GOS_LOG(" ");
GOS_LOG("Taking %d logs...", LOG_COUNT);
gos_event_register_periodic(log_event_logfile_handler, NULL, LOG_PERIOD, GOS_EVENT_FLAGS1(RUN_NOW));
}
/*************************************************************************************************/
void gos_app_deinit(void)
{
if (logfile_handle != GOS_NULL_HANDLE)
{
GOS_LOG("\r\n'log_file' demo shutting down, run the demo again to view saved logs.\r\n");
gos_file_close(logfile_handle);
}
}
/*************************************************************************************************
* Take a log sample and write it to the log file
*/
static void log_event_logfile_handler(void *arg)
{
gos_result_t result;
log_record_t record;
gos_time_get_current_utc_ms(&record.time, false);
record.log_id = log_id;
record.gpio_mask = gos_gpio_mask_get(UINT32_MAX);
if (GOS_FAILED(result, gos_log_file_append(logfile_handle, &record, sizeof(log_record_t))))
{
GOS_LOG("Failed to append new log: %d", result);
}
else
{
GOS_LOG("Saved log: %d", log_id);
++log_id;
}
// Unregister the event to stop logging once we reach the end
if ((log_id >= end_id) || (result != GOS_SUCCESS))
{
gos_event_unregister(log_event_logfile_handler, NULL);
}
}
/*************************************************************************************************
* Sequentially read the log records and print
*/
static void print_log_records(void)
{
log_record_t record;
gos_buffer_t buffer =
{
.data = (uint8_t*)&record,
.size = sizeof(log_record_t)
};
do
{
if (gos_log_file_read(logfile_handle, &buffer, GOS_LOG_FILE_GET_NEXT) != GOS_SUCCESS)
{
GOS_LOG("Empty log file, no records to display.");
break;
}
else
{
gos_time_utc_ms_to_iso8601_str(record.time, 0, &time_str);
GOS_LOG("Log %d:", record.log_id);
GOS_LOG(" Time: %s", (const char*)&time_str);
GOS_LOG(" GPIO mask: 0x%08X", record.gpio_mask);
}
} while(1);
}
/*************************************************************************************************
* Test reading a log record in chunks
*/
static void partial_read_test(uint32_t log_to_read)
{
log_record_t record;
uint8_t *ptr = (uint8_t*)&record;
gos_buffer_t buffer;
do
{
gos_result_t result;
buffer.data = ptr;
buffer.size = 5;
if (GOS_FAILED(result, gos_log_file_read(logfile_handle, &buffer, log_to_read)))
{
if(result != GOS_NOT_FOUND)
GOS_LOG("Failed to read log: %d", result);
return;
}
ptr += buffer.size;
// When the size is 0, there's no more log data to read
} while(buffer.size > 0);
gos_time_utc_ms_to_iso8601_str(record.time, 0, &time_str);
GOS_LOG(" ");
GOS_LOG("Partial read test, Log ID: %d", record.log_id);
GOS_LOG(" Time: %s", (const char*)&time_str);
GOS_LOG(" GPIO mask: 0x%08X", record.gpio_mask);;
}
/*************************************************************************************************
* Initialize the buttons.
*/
static gos_result_t initialize_hardware(void)
{
gos_result_t result;
const gos_button_config_t config =
{
.active_level = PLATFORM_BUTTON_ACTIVE_STATE,
.debounce = BUTTON_DEBOUNCE_TIME_MS,
.click_time = BUTTON_CLICK_TIME_MS,
.press_time = BUTTON_PRESS_TIME_MS,
.event_handler.press = NULL,
.event_handler.click = NULL,
.event_handler.toggle = NULL,
.execution_context = GOS_BUTTON_CONTEXT_DEFAULT
};
GOS_LOG("Initializing button 1 ...");
if(GOS_FAILED(result, gos_button_init(PLATFORM_BUTTON1, &config, (void*)1)))
{
GOS_LOG("Failed to init PLATFORM_BUTTON1, err:%d", result);
return result;
}
GOS_LOG("Initializing button 2 ...");
if(GOS_FAILED(result, gos_button_init(PLATFORM_BUTTON2, &config, (void*)2)))
{
GOS_LOG("Failed to init PLATFORM_BUTTON2, err:%d", result);
return result;
}
return GOS_SUCCESS;
}