blob: 12f6a2119812a747b0fe5428f656079ecc74411e [file] [log] [blame]
#pragma once
//! @file
//!
//! Copyright (c) Memfault, Inc.
//! See LICENSE for details
//!
//! @brief
//! Hooks for linking system assert infra with Memfault error collection
#include "memfault/core/compiler.h"
#include "memfault/core/reboot_reason_types.h"
#include "memfault/panics/fault_handling.h"
#ifdef __cplusplus
extern "C" {
#endif
//! The 'MEMFAULT_ASSERT*' hooks that should be called as part of the normal ASSERT flow in
//! the system. This will save the reboot info to persist across boots.
//!
//! - MEMFAULT_ASSERT : normal assert
//! - MEMFAULT_ASSERT_EXTRA : assert with a single arbitrary uint32_t context value included
//! - MEMFAULT_ASSERT_EXTRA_AND_REASON : assert with arbitrary uint32_t value and reason code
//! - MEMFAULT_ASSERT_WITH_REASON : assert with reason code
//! - MEMFAULT_SOFTWARE_WATCHDOG : assert with kMfltRebootReason_SoftwareWatchdog reason set
//!
//! NB: We may also want to think about whether we should save off something like __LINE__ (or use a
//! compiler flag) that blocks the compiler from coalescing asserts (since that could be confusing
//! to an end customer trying to figure out the exact assert hit)
#define MEMFAULT_ASSERT_EXTRA_AND_REASON(_extra, _reason) \
do { \
void *pc; \
MEMFAULT_GET_PC(pc); \
void *lr; \
MEMFAULT_GET_LR(lr); \
sMemfaultAssertInfo _assert_info = { \
.extra = (uint32_t)_extra, \
.assert_reason = _reason, \
}; \
memfault_fault_handling_assert_extra(pc, lr, &_assert_info); \
} while (0)
#define MEMFAULT_ASSERT_RECORD(_extra) \
MEMFAULT_ASSERT_EXTRA_AND_REASON(_extra, kMfltRebootReason_Assert)
#define MEMFAULT_ASSERT_EXTRA(exp, _extra) \
do { \
if (!(exp)) { \
MEMFAULT_ASSERT_RECORD(_extra); \
} \
} while (0)
#define MEMFAULT_ASSERT(exp) \
do { \
if (!(exp)) { \
void *pc; \
MEMFAULT_GET_PC(pc); \
void *lr; \
MEMFAULT_GET_LR(lr); \
memfault_fault_handling_assert(pc, lr); \
} \
} while (0)
#define MEMFAULT_ASSERT_WITH_REASON(exp, _reason) \
do { \
if (!(exp)) { \
MEMFAULT_ASSERT_EXTRA_AND_REASON(0, _reason); \
} \
} while (0)
//! Assert subclass to be used when a software watchdog trips.
#define MEMFAULT_SOFTWARE_WATCHDOG() \
MEMFAULT_ASSERT_WITH_REASON(0, kMfltRebootReason_SoftwareWatchdog)
//! Assert subclass to be used when a task watchdog trips.
#define MEMFAULT_TASK_WATCHDOG() MEMFAULT_ASSERT_WITH_REASON(0, kMfltRebootReason_TaskWatchdog)
#ifdef __cplusplus
}
#endif