kopia lustrzana https://github.com/SP8EBC/ParaTNC
nvm event logger
rodzic
1e23ed3af8
commit
d444bad214
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"name": "PARAMETEO",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
|
@ -10,6 +10,17 @@
|
|||
"cStandard": "c17",
|
||||
"cppStandard": "gnu++17",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
},
|
||||
{
|
||||
"name": "UNIT_TESTS",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": ["UNIT_TEST"],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "gnu++17",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
"event_log.h": "c",
|
||||
"nvm_configuration.h": "c",
|
||||
"flash_stm32l4x.h": "c",
|
||||
"stm32f10x_flash.h": "c"
|
||||
"stm32f10x_flash.h": "c",
|
||||
"nvm_event.h": "c",
|
||||
"nvm_internals.h": "c"
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@
|
|||
#ifndef NVM_H_
|
||||
#define NVM_H_
|
||||
|
||||
#include "nvm_internals.h"
|
||||
#include <stdint.h>
|
||||
#include "nvm_t.h"
|
||||
|
||||
#define NVM_RECORD_SIZE 8 // in bytes!!
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef B9059D46_61C3_45A2_A688_7297F71FC356
|
||||
#define B9059D46_61C3_45A2_A688_7297F71FC356
|
||||
|
||||
#include "nvm_internals.h"
|
||||
#include "event_log.h"
|
||||
|
||||
#include "nvm_t.h"
|
||||
/**
|
||||
*
|
||||
* @param oldest
|
||||
|
@ -16,7 +15,7 @@ nvm_event_result_t nvm_event_log_find_first_oldest_newest(event_log_t** oldest,
|
|||
* @param oldest
|
||||
* @param newest
|
||||
*/
|
||||
nvm_event_result_t nvm_event_log_push_new_event(event_log_t* event, event_log_t** oldest, event_log_t** newest);
|
||||
nvm_event_result_t nvm_event_log_push_new_event(event_log_t* event);
|
||||
|
||||
|
||||
#endif /* B9059D46_61C3_45A2_A688_7297F71FC356 */
|
|
@ -0,0 +1,111 @@
|
|||
#ifndef E365347D_02F3_4DCB_A254_BF10A5E57B60
|
||||
#define E365347D_02F3_4DCB_A254_BF10A5E57B60
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_CREATE_POINTERS_FOR_TARGET(_name, _non_ptr_based_write_function, _area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity, pointer_based_access) \
|
||||
event_log_t* nvm_event_oldest##_name; \
|
||||
event_log_t* nvm_event_newest##_name; \
|
||||
\
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_PUSH_POINTERS_ARITM(_name, _area_start_addr, _area_end_addr, _erase_fn, _severity) \
|
||||
if (EVENT_LOG_GET_SEVERITY(event->severity_and_source) >= _severity ) { \
|
||||
nvm_event_log_perform_pointer_arithmetics(&nvm_event_oldest##_name, &nvm_event_newest##_name, _area_start_addr, _area_end_addr, _erase_fn); \
|
||||
} \
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_PUSH_POINTERS_FLASH_OPER(_name, _event_to_insert, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity) \
|
||||
if (EVENT_LOG_GET_SEVERITY(event->severity_and_source) >= _severity ) { \
|
||||
/* programming 32 bits at once */ \
|
||||
uint32_t * ptr_event_to_insert = (uint32_t*)_event_to_insert; \
|
||||
uint32_t * ptr_place_for_new_event = (uint32_t*)nvm_event_newest##_name; \
|
||||
\
|
||||
_enable_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)) = *ptr_event_to_insert; \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)+ 1) = *(ptr_event_to_insert + 1); \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)+ 2) = *(ptr_event_to_insert + 2); \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)+ 3) = *(ptr_event_to_insert + 3); \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
_disable_pgm_fn \
|
||||
\
|
||||
} \
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_PUSH_POINTERS_ARITM_SEC(_name, _area_start_addr, _area_end_addr) \
|
||||
/* rescan for oldest and newest event one more time */ \
|
||||
nvm_event_log_find_first_oldest_newest(&nvm_event_oldest##_name, &nvm_event_newest##_name, (void*)_area_start_addr, (void*)_area_end_addr); \
|
||||
\
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_EXPAND_POINTER_BASE_ACCESS_true(_name, _area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity) \
|
||||
NVM_EVENT_PUSH_POINTERS_ARITM(_name, _area_start_addr, _area_end_addr, _erase_fn, _severity); \
|
||||
NVM_EVENT_PUSH_POINTERS_FLASH_OPER(_name, event, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity); \
|
||||
NVM_EVENT_PUSH_POINTERS_ARITM_SEC(_name, _area_start_addr, _area_end_addr); \
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_EXPAND_POINTER_BASE_ACCESS(_name, _non_ptr_based_write_function, _area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity, pointer_based_access) \
|
||||
NVM_EVENT_EXPAND_POINTER_BASE_ACCESS_##pointer_based_access(_name, _area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity); \
|
||||
|
||||
#define NVM_EVENT_PERFORM_INIT_true(_name, _area_start_addr, _area_end_addr) \
|
||||
NVM_EVENT_PUSH_POINTERS_ARITM_SEC(_name, _area_start_addr, _area_end_addr) \
|
||||
|
||||
#define NVM_EVENT_PERFORM_INIT(_name, _area_start_addr, _area_end_addr, pointer_based_access) \
|
||||
NVM_EVENT_PERFORM_INIT_##pointer_based_access(_name, _area_start_addr, _area_end_addr) \
|
||||
|
||||
#ifdef STM32L471xx
|
||||
|
||||
//!< Size of single flash memory page
|
||||
#define NVM_PAGE_SIZE 2048
|
||||
|
||||
//!< How flash program operation are aligned, how many bytes must be programmed at once
|
||||
#define NVM_WRITE_BYTE_ALIGN 8
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef STM32F10X_MD_VL
|
||||
/*
|
||||
* NVM logger currently not implemented for this platform
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
#if (defined UNIT_TEST)
|
||||
//!< Size of single flash memory page
|
||||
#define NVM_PAGE_SIZE 2048
|
||||
|
||||
//!< How flash program operation are aligned, how many bytes must be programmed at once
|
||||
#define NVM_WRITE_BYTE_ALIGN 8
|
||||
|
||||
|
||||
// currently defined here for unit tests
|
||||
typedef enum
|
||||
{
|
||||
FLASH_BUSY = 1, /**< FLASH_BUSY */
|
||||
FLASH_ERROR_PG, /**< FLASH_ERROR_PG */
|
||||
FLASH_ERROR_WRP,/**< FLASH_ERROR_WRP */
|
||||
FLASH_COMPLETE, /**< FLASH_COMPLETE */
|
||||
FLASH_TIMEOUT /**< FLASH_TIMEOUT */
|
||||
}FLASH_Status;
|
||||
#endif
|
||||
|
||||
#endif /* E365347D_02F3_4DCB_A254_BF10A5E57B60 */
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef D693DD34_021C_482B_A532_AB5B31D18C64
|
||||
#define D693DD34_021C_482B_A532_AB5B31D18C64
|
||||
|
||||
typedef enum nvm_state_result_t {
|
||||
NVM_UNINITIALIZED,
|
||||
NVM_OK,
|
||||
NVM_NO_SPACE_LEFT,
|
||||
NVM_INIT_ERROR,
|
||||
NVM_PGM_ERROR
|
||||
}nvm_state_result_t;
|
||||
|
||||
typedef enum nvm_event_result_t {
|
||||
NVM_EVENT_OK,
|
||||
NVM_EVENT_OVERRUN_NO_TS,
|
||||
NVM_EVENT_OVERRUN,
|
||||
NVM_EVENT_SINGLE_TS,
|
||||
NVM_EVENT_EMPTY,
|
||||
NVM_EVENT_AREA_ERROR
|
||||
}nvm_event_result_t;
|
||||
|
||||
#endif /* D693DD34_021C_482B_A532_AB5B31D18C64 */
|
|
@ -1,50 +0,0 @@
|
|||
#ifndef E365347D_02F3_4DCB_A254_BF10A5E57B60
|
||||
#define E365347D_02F3_4DCB_A254_BF10A5E57B60
|
||||
|
||||
typedef enum nvm_state_result_t {
|
||||
NVM_UNINITIALIZED,
|
||||
NVM_OK,
|
||||
NVM_NO_SPACE_LEFT,
|
||||
NVM_INIT_ERROR,
|
||||
NVM_PGM_ERROR
|
||||
}nvm_state_result_t;
|
||||
|
||||
typedef enum nvm_event_result_t {
|
||||
NVM_EVENT_OK,
|
||||
NVM_EVENT_OVERRUN_NO_TS,
|
||||
NVM_EVENT_OVERRUN,
|
||||
NVM_EVENT_SINGLE_TS,
|
||||
NVM_EVENT_EMPTY,
|
||||
NVM_EVENT_AREA_ERROR
|
||||
}nvm_event_result_t;
|
||||
|
||||
#ifdef STM32L471xx
|
||||
|
||||
//!< Size of single flash memory page
|
||||
#define NVM_PAGE_SIZE 2048
|
||||
|
||||
//!< How flash program operation are aligned, how many bytes must be programmed at once
|
||||
#define NVM_WRITE_BYTE_ALIGN 8
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef STM32F10X_MD_VL
|
||||
/*
|
||||
* NVM logger currently not implemented for this platform
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
#if (defined UNIT_TEST)
|
||||
// currently defined here for unit tests
|
||||
typedef enum
|
||||
{
|
||||
FLASH_BUSY = 1, /**< FLASH_BUSY */
|
||||
FLASH_ERROR_PG, /**< FLASH_ERROR_PG */
|
||||
FLASH_ERROR_WRP,/**< FLASH_ERROR_WRP */
|
||||
FLASH_COMPLETE, /**< FLASH_COMPLETE */
|
||||
FLASH_TIMEOUT /**< FLASH_TIMEOUT */
|
||||
}FLASH_Status;
|
||||
#endif
|
||||
|
||||
#endif /* E365347D_02F3_4DCB_A254_BF10A5E57B60 */
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "nvm.h"
|
||||
#include "nvm_internals.h"
|
||||
#include "nvm_configuration.h"
|
||||
#include "memory_map.h"
|
||||
#include "backup_registers.h"
|
|
@ -0,0 +1,188 @@
|
|||
#include "nvm_event.h"
|
||||
#include "nvm_configuration.h"
|
||||
#include "memory_map.h"
|
||||
#include "backup_registers.h"
|
||||
#include "nvm_internals.h"
|
||||
|
||||
|
||||
|
||||
static nvm_state_result_t nvm_general_state = NVM_UNINITIALIZED;
|
||||
|
||||
|
||||
NVM_EVENT_LOGGING_TARGETS(NVM_EVENT_CREATE_POINTERS_FOR_TARGET);
|
||||
|
||||
static void nvm_event_log_perform_pointer_arithmetics(
|
||||
event_log_t** oldest,
|
||||
event_log_t** newest,
|
||||
void * area_start,
|
||||
void * area_end,
|
||||
FLASH_Status(*erase_fn)(uint32_t)) {
|
||||
|
||||
// pointers
|
||||
const event_log_t* oldest_init_ptr = *oldest;
|
||||
const event_log_t* next_newest_init_ptr = *newest + 1;
|
||||
|
||||
/* check if we reach boundary between two flash memory pages */
|
||||
/* and the newest entry is just before the oldest pne */
|
||||
if (next_newest_init_ptr == oldest_init_ptr) {
|
||||
/* erase next flash memory page to make a room for next events */
|
||||
const FLASH_Status flash_status = erase_fn (*oldest);
|
||||
|
||||
/* check operation result */
|
||||
if (flash_status != FLASH_COMPLETE) {
|
||||
nvm_general_state = NVM_PGM_ERROR;
|
||||
}
|
||||
|
||||
/* rescan for oldest and newest event one more time */
|
||||
nvm_event_log_find_first_oldest_newest(oldest, newest, (void*)area_start, (void*)area_end);
|
||||
|
||||
const uint8_t old_new_events_spacing = *oldest - *newest;
|
||||
|
||||
/* oldest - newest should be located NVM_PAGE_SIZE bytes apart */
|
||||
/* please note, that pointers points to the beginning of each */
|
||||
/* entry, hence this minus one */
|
||||
if ((old_new_events_spacing - 1) * sizeof(event_log_t) != NVM_PAGE_SIZE) {
|
||||
backup_assert(BACKUP_REG_ASSERT_ERASE_FAIL_WHILE_STORING_EVENT);
|
||||
}
|
||||
|
||||
/* move pointer to newest, to point to a place where */
|
||||
/* newly inserted event will be located */
|
||||
*newest = *(newest) + 1;
|
||||
}
|
||||
else if ((void*)next_newest_init_ptr >= (void*)area_end) {
|
||||
/* we have reached an end of the event area in flash */
|
||||
|
||||
/* erase first memory page */
|
||||
(void)erase_fn (area_start);
|
||||
|
||||
/* set pointers accordingly */
|
||||
event_log_t* new_newest = (event_log_t*)area_start;
|
||||
event_log_t* new_oldest = (event_log_t*)(area_end - sizeof(event_log_t));
|
||||
|
||||
*newest = new_newest;
|
||||
*oldest = new_oldest;
|
||||
}
|
||||
else {
|
||||
*newest = *(newest) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param oldest
|
||||
* @param newest
|
||||
*/
|
||||
nvm_event_result_t nvm_event_log_find_first_oldest_newest(event_log_t** oldest, event_log_t** newest, void * area_start, void * area_end) {
|
||||
|
||||
nvm_event_result_t res = NVM_EVENT_OK;
|
||||
|
||||
// pointer to last, non null and non TIMESYNC entry
|
||||
event_log_t* last_non_ts = NULL;
|
||||
|
||||
// pointer to the oldest non TIMESYNC event log entry
|
||||
event_log_t* oldest_non_ts = NULL;
|
||||
|
||||
// size of single log entry
|
||||
const uint8_t log_entry_size = sizeof(event_log_t);
|
||||
|
||||
// how any events could be stored in NVM flash memory
|
||||
const uint16_t log_entries = (area_end - area_start) / log_entry_size;
|
||||
|
||||
// lowest date found within events in NVM
|
||||
uint32_t lowest_date = 0xFFFFFFFFu;
|
||||
|
||||
uint32_t lowest_time = 0xFFFFFFFFu;
|
||||
|
||||
// sanity check if everything is set correctly
|
||||
if ((area_end - area_start) % log_entry_size != 0 ) {
|
||||
return NVM_EVENT_AREA_ERROR;
|
||||
}
|
||||
|
||||
last_non_ts = (event_log_t *)area_start;
|
||||
|
||||
// iterate through all event log flash area
|
||||
for (int i = 0; i < log_entries; i++) {
|
||||
|
||||
// set pointer to currently checked event
|
||||
const event_log_t* const current = (area_start + (log_entry_size) * i);
|
||||
|
||||
event_log_severity_t severity = (current->severity_and_source & 0xF0) >> 4;
|
||||
event_log_source_t source = (current->severity_and_source & 0xF);
|
||||
|
||||
// skip erased memory
|
||||
if (current->event_id == 0xFFU && current->event_master_time == 0xFFFFFFFFU) {
|
||||
oldest_non_ts = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// look for timesync event created at bootup
|
||||
if (current->event_id == EVENT_TIMESYNC && current->wparam == 0x77) {
|
||||
|
||||
// check if this timestamp is before the oldest found before
|
||||
if (lowest_date > current->lparam && lowest_time > current->lparam2) {
|
||||
|
||||
// set this as the oldest
|
||||
lowest_date = current->lparam;
|
||||
lowest_time = current->lparam2;
|
||||
|
||||
// timestamp are always created after the first one after power up, so that
|
||||
// with oldest RTC date and time will be the oldest in general
|
||||
*oldest = (event_log_t*)current;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (current->event_master_time > last_non_ts->event_master_time) {
|
||||
// store a pointer to last non-null and non-timesync event
|
||||
last_non_ts = (event_log_t*)current;
|
||||
|
||||
// updated output pointer with newest
|
||||
*newest = last_non_ts;
|
||||
}
|
||||
else {
|
||||
// this loop goes forward in memory. if consecutive non timesync event
|
||||
// has decreasing master_time value it means, that nvm events area
|
||||
// has overruned at least one time
|
||||
res = NVM_EVENT_OVERRUN;
|
||||
|
||||
if (oldest_non_ts == NULL) {
|
||||
oldest_non_ts = (event_log_t*)current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if any non-timesync event has been found at all
|
||||
if (last_non_ts == NULL) {
|
||||
// no, NVM log contains only single timesync event
|
||||
res = NVM_EVENT_SINGLE_TS;
|
||||
}
|
||||
|
||||
// check if any timesync event has been found
|
||||
if (lowest_date == 0xFFFFFFFFu && lowest_time == 0xFFFFFFFF) {
|
||||
if (last_non_ts == (event_log_t *)area_start) {
|
||||
res = NVM_EVENT_EMPTY; // nvm event area is empty
|
||||
}
|
||||
else {
|
||||
*oldest = oldest_non_ts;
|
||||
res = NVM_EVENT_OVERRUN_NO_TS;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event
|
||||
* @param oldest
|
||||
* @param newest
|
||||
*/
|
||||
nvm_event_result_t nvm_event_log_push_new_event(event_log_t* event) {
|
||||
nvm_event_result_t out = NVM_EVENT_OK;
|
||||
|
||||
|
||||
NVM_EVENT_LOGGING_TARGETS(NVM_EVENT_EXPAND_POINTER_BASE_ACCESS);
|
||||
|
||||
|
||||
return out;
|
||||
}
|
243
src/nvm_event.c
243
src/nvm_event.c
|
@ -1,243 +0,0 @@
|
|||
#include "nvm_event.h"
|
||||
#include "nvm_configuration.h"
|
||||
#include "memory_map.h"
|
||||
#include "backup_registers.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_CREATE_POINTERS_FOR_TARGET(_name, _non_ptr_based_write_function, _area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity, pointer_based_access) \
|
||||
event_log_t** nvm_event_oldest##_name; \
|
||||
event_log_t** nvm_event_newest##_name; \
|
||||
\
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_PUSH_POINTERS_ARITM(_area_start_addr, _area_end_addr, _erase_fn, _severity) \
|
||||
if (EVENT_LOG_GET_SEVERITY(event->severity_and_source) >= _severity ) { \
|
||||
/* check if we reach boundary between two flash memory pages */ \
|
||||
/* and the newest entry is just before the oldest pne */ \
|
||||
if (next_newest_init_ptr == oldest_init_ptr) { \
|
||||
/* erase next flash memory page to make a room for next events */ \
|
||||
flash_status = _erase_fn (*oldest); \
|
||||
\
|
||||
/* check operation result */ \
|
||||
if (flash_status != FLASH_COMPLETE) { \
|
||||
nvm_general_state = NVM_PGM_ERROR; \
|
||||
} \
|
||||
\
|
||||
/* rescan for oldest and newest event one more time */ \
|
||||
nvm_event_log_find_first_oldest_newest(oldest, newest, (void*)_area_start_addr, (void*)_area_end_addr); \
|
||||
\
|
||||
const uint8_t old_new_events_spacing = *oldest - *newest; \
|
||||
\
|
||||
/* oldest - newest should be located NVM_PAGE_SIZE bytes apart */ \
|
||||
/* please note, that pointers points to the beginning of each */ \
|
||||
/* entry, hence this minus one */ \
|
||||
if ((old_new_events_spacing - 1) * sizeof(event_log_t) != NVM_PAGE_SIZE) { \
|
||||
backup_assert(BACKUP_REG_ASSERT_ERASE_FAIL_WHILE_STORING_EVENT); \
|
||||
} \
|
||||
\
|
||||
/* move pointer to newest, to point to a place where */ \
|
||||
/* newly inserted event will be located */ \
|
||||
*newest = *(newest) + 1; \
|
||||
} \
|
||||
else if ((void*)next_newest_init_ptr >= (void*)_area_end_addr) { \
|
||||
/* we have reached an end of the event area in flash */ \
|
||||
\
|
||||
/* erase first memory page */ \
|
||||
flash_status = _erase_fn (_area_start_addr); \
|
||||
\
|
||||
/* set pointers accordingly */ \
|
||||
event_log_t* new_newest = (event_log_t*)_area_start_addr; \
|
||||
event_log_t* new_oldest = (event_log_t*)(_area_end_addr - sizeof(event_log_t)); \
|
||||
\
|
||||
*newest = new_newest; \
|
||||
*oldest = new_oldest; \
|
||||
} \
|
||||
else { \
|
||||
*newest = *(newest) + 1; \
|
||||
} \
|
||||
} \
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_PUSH_POINTERS_FLASH_OPER(_event_to_insert, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity) \
|
||||
if (EVENT_LOG_GET_SEVERITY(event->severity_and_source) >= _severity ) { \
|
||||
/* programming 32 bits at once */ \
|
||||
uint32_t * ptr_event_to_insert = (uint32_t*)_event_to_insert; \
|
||||
uint32_t * ptr_place_for_new_event = (uint32_t*)*newest; \
|
||||
\
|
||||
_enable_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)) = *ptr_event_to_insert; \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)+ 1) = *(ptr_event_to_insert + 1); \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)+ 2) = *(ptr_event_to_insert + 2); \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
*((uint32_t*)(ptr_place_for_new_event)+ 3) = *(ptr_event_to_insert + 3); \
|
||||
_wait_for_pgm_fn \
|
||||
\
|
||||
_disable_pgm_fn \
|
||||
\
|
||||
} \
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_PUSH_POINTERS_ARITM_SEC(_area_start_addr, _area_end_addr) \
|
||||
/* rescan for oldest and newest event one more time */ \
|
||||
nvm_event_log_find_first_oldest_newest(oldest, newest, (void*)_area_start_addr, (void*)_area_end_addr); \
|
||||
\
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_EXPAND_POINTER_BASE_ACCESS_true(_area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity) \
|
||||
NVM_EVENT_PUSH_POINTERS_ARITM(_area_start_addr, _area_end_addr, _erase_fn, _severity); \
|
||||
NVM_EVENT_PUSH_POINTERS_FLASH_OPER(event, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity); \
|
||||
NVM_EVENT_PUSH_POINTERS_ARITM_SEC(_area_start_addr, _area_end_addr); \
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define NVM_EVENT_EXPAND_POINTER_BASE_ACCESS(_name, _non_ptr_based_write_function, _area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity, pointer_based_access) \
|
||||
NVM_EVENT_EXPAND_POINTER_BASE_ACCESS_##pointer_based_access(_area_start_addr, _area_end_addr, _erase_fn, _enable_pgm_fn, _wait_for_pgm_fn, _disable_pgm_fn, _severity); \
|
||||
|
||||
|
||||
static nvm_state_result_t nvm_general_state = NVM_UNINITIALIZED;
|
||||
|
||||
|
||||
NVM_EVENT_LOGGING_TARGETS(NVM_EVENT_CREATE_POINTERS_FOR_TARGET);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param oldest
|
||||
* @param newest
|
||||
*/
|
||||
nvm_event_result_t nvm_event_log_find_first_oldest_newest(event_log_t** oldest, event_log_t** newest, void * area_start, void * area_end) {
|
||||
|
||||
nvm_event_result_t res = NVM_EVENT_OK;
|
||||
|
||||
// pointer to last, non null and non TIMESYNC entry
|
||||
event_log_t* last_non_ts = NULL;
|
||||
|
||||
// pointer to the oldest non TIMESYNC event log entry
|
||||
event_log_t* oldest_non_ts = NULL;
|
||||
|
||||
// size of single log entry
|
||||
const uint8_t log_entry_size = sizeof(event_log_t);
|
||||
|
||||
// how any events could be stored in NVM flash memory
|
||||
const uint16_t log_entries = (area_end - area_start) / log_entry_size;
|
||||
|
||||
// lowest date found within events in NVM
|
||||
uint32_t lowest_date = 0xFFFFFFFFu;
|
||||
|
||||
uint32_t lowest_time = 0xFFFFFFFFu;
|
||||
|
||||
// sanity check if everything is set correctly
|
||||
if ((area_end - area_start) % log_entry_size != 0 ) {
|
||||
return NVM_EVENT_AREA_ERROR;
|
||||
}
|
||||
|
||||
last_non_ts = (event_log_t *)area_start;
|
||||
|
||||
// iterate through all event log flash area
|
||||
for (int i = 0; i < log_entries; i++) {
|
||||
|
||||
// set pointer to currently checked event
|
||||
const event_log_t* const current = (area_start + (log_entry_size) * i);
|
||||
|
||||
event_log_severity_t severity = (current->severity_and_source & 0xF0) >> 4;
|
||||
event_log_source_t source = (current->severity_and_source & 0xF);
|
||||
|
||||
// skip erased memory
|
||||
if (current->event_id == 0xFFU && current->event_master_time == 0xFFFFFFFFU) {
|
||||
oldest_non_ts = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// look for timesync event created at bootup
|
||||
if (current->event_id == EVENT_TIMESYNC && current->wparam == 0x77) {
|
||||
|
||||
// check if this timestamp is before the oldest found before
|
||||
if (lowest_date > current->lparam && lowest_time > current->lparam2) {
|
||||
|
||||
// set this as the oldest
|
||||
lowest_date = current->lparam;
|
||||
lowest_time = current->lparam2;
|
||||
|
||||
// timestamp are always created after the first one after power up, so that
|
||||
// with oldest RTC date and time will be the oldest in general
|
||||
*oldest = (event_log_t*)current;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (current->event_master_time > last_non_ts->event_master_time) {
|
||||
// store a pointer to last non-null and non-timesync event
|
||||
last_non_ts = (event_log_t*)current;
|
||||
|
||||
// updated output pointer with newest
|
||||
*newest = last_non_ts;
|
||||
}
|
||||
else {
|
||||
// this loop goes forward in memory. if consecutive non timesync event
|
||||
// has decreasing master_time value it means, that nvm events area
|
||||
// has overruned at least one time
|
||||
res = NVM_EVENT_OVERRUN;
|
||||
|
||||
if (oldest_non_ts == NULL) {
|
||||
oldest_non_ts = (event_log_t*)current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if any non-timesync event has been found at all
|
||||
if (last_non_ts == NULL) {
|
||||
// no, NVM log contains only single timesync event
|
||||
res = NVM_EVENT_SINGLE_TS;
|
||||
}
|
||||
|
||||
// check if any timesync event has been found
|
||||
if (lowest_date == 0xFFFFFFFFu && lowest_time == 0xFFFFFFFF) {
|
||||
if (last_non_ts == (event_log_t *)area_start) {
|
||||
res = NVM_EVENT_EMPTY; // nvm event area is empty
|
||||
}
|
||||
else {
|
||||
*oldest = oldest_non_ts;
|
||||
res = NVM_EVENT_OVERRUN_NO_TS;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event
|
||||
* @param oldest
|
||||
* @param newest
|
||||
*/
|
||||
nvm_event_result_t nvm_event_log_push_new_event(event_log_t* event, event_log_t** oldest, event_log_t** newest) {
|
||||
nvm_event_result_t out = NVM_EVENT_OK;
|
||||
|
||||
// flash operation result
|
||||
FLASH_Status flash_status = 0;
|
||||
|
||||
// pointers
|
||||
const event_log_t* oldest_init_ptr = *oldest;
|
||||
const event_log_t* next_newest_init_ptr = *newest + 1;
|
||||
|
||||
NVM_EVENT_LOGGING_TARGETS(NVM_EVENT_EXPAND_POINTER_BASE_ACCESS);
|
||||
|
||||
|
||||
return out;
|
||||
}
|
Ładowanie…
Reference in New Issue