file/log_file/main.c

/*
* EVALUATION AND USE OF THIS SOFTWARE IS SUBJECT TO THE TERMS AND
* CONDITIONS OF THE CONTROLLING LICENSE AGREEMENT FOUND AT LICENSE.md
* IN THIS SDK. IF YOU DO NOT AGREE TO THE LICENSE TERMS AND CONDITIONS,
* PLEASE RETURN ALL SOURCE FILES TO SILICON LABORATORIES.
* (c) Copyright 2018, Silicon Laboratories Inc. All rights reserved.
*/
/* 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 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);
// 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);;
}