OVMS3-idf/components/esp32/include/xtensa/xos_syslog.h
2018-05-29 20:07:45 +08:00

330 lines
10 KiB
C

/** @file */
// xos_syslog.h - XOS Event logging module.
// Copyright (c) 2003-2015 Cadence Design Systems, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// NOTE: Do not include this file directly in your application. Including
// xos.h will automatically include this file.
#ifndef __XOS_SYSLOG_H__
#define __XOS_SYSLOG_H__
#include "xos_types.h"
#ifdef __cplusplus
extern "C" {
#endif
//-----------------------------------------------------------------------------
// The XOS system log is an array of fixed size entries. The size of the log
// is determined by the application, and memory for the log must be provided
// at init time. Every time the log function is called, an entry is made in
// the log and the next pointer advanced. When the log is full, it will wrap
// around and start overwriting the oldest entries.
// Logging can be done from C/C++ code as well as assembly code, and at any
// interrupt level, even from high level interrupt handlers.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Defines.
//-----------------------------------------------------------------------------
#define XOS_SYSLOG_ENABLED 0x0001
///----------------------------------------------------------------------------
///
/// Use this macro to compute how much memory to allocate for the syslog.
///
///----------------------------------------------------------------------------
#define XOS_SYSLOG_SIZE(num_entries) \
( sizeof(XosSysLog) + ((num_entries - 1) * sizeof(XosSysLogEntry)) )
///----------------------------------------------------------------------------
///
/// System log entry structure.
///
///----------------------------------------------------------------------------
typedef struct XosSysLogEntry {
uint32_t timestamp; ///< Timestamp in clock cycles
uint32_t param1; ///< User defined value
uint32_t param2; ///< User defined value
struct XosSysLogEntry * next; ///< Link to next entry
} XosSysLogEntry;
///----------------------------------------------------------------------------
///
/// System log structure.
///
///----------------------------------------------------------------------------
typedef struct XosSysLog {
uint16_t flags; ///< Flags
uint16_t size; ///< Number of entries
XosSysLogEntry * next; ///< Next write position
XosSysLogEntry entries[1]; ///< First entry
} XosSysLog;
//-----------------------------------------------------------------------------
// Pointer to syslog area.
//-----------------------------------------------------------------------------
extern XosSysLog * xos_syslog;
//----------------------------------------------------------------------------
///
/// Initialize the syslog. Initializing the log also enables it. The system
/// log always wraps around when full and overwrites the oldest entries.
///
/// \param log_mem Pointer to allocated memory for the log.
///
/// \param num_entries The number of entries that the log can contain.
///
/// \return Returns nothing.
///
//----------------------------------------------------------------------------
static inline void
xos_syslog_init(void * log_mem, uint16_t num_entries)
{
uint16_t i;
xos_syslog = (XosSysLog *) log_mem;
xos_syslog->size = num_entries;
xos_syslog->next = xos_syslog->entries;
for (i = 0; i < num_entries - 1; i++) {
xos_syslog->entries[i].next = &(xos_syslog->entries[i+1]);
xos_syslog->entries[i].timestamp = 0;
}
xos_syslog->entries[i].next = xos_syslog->entries;
xos_syslog->entries[i].timestamp = 0;
xos_syslog->flags = XOS_SYSLOG_ENABLED;
}
///----------------------------------------------------------------------------
///
/// Reset the syslog. All entries made up to now are abandoned and the write
/// pointer is set to the first entry location.
///
/// No parameters.
///
/// \return Returns nothing.
///
///----------------------------------------------------------------------------
static inline void
xos_syslog_clear()
{
#if XCHAL_HAVE_INTERRUPTS
uint32_t ps = XT_RSIL(XCHAL_NUM_INTLEVELS);
#endif
xos_syslog_init(xos_syslog, xos_syslog->size);
#if XCHAL_HAVE_INTERRUPTS
xos_restore_int_pri_level(ps);
#endif
}
///----------------------------------------------------------------------------
///
/// Enable logging to the syslog. This function needs to be called only if
/// logging had been previously disabled via xos_syslog_disable(), since
/// initializing the syslog automatically enables it.
///
/// No parameters.
///
/// \return Returns nothing.
///
///----------------------------------------------------------------------------
static inline void
xos_syslog_enable()
{
#if XCHAL_HAVE_INTERRUPTS
uint32_t ps = XT_RSIL(XCHAL_NUM_INTLEVELS);
#endif
xos_syslog->flags |= XOS_SYSLOG_ENABLED;
#if XCHAL_HAVE_INTERRUPTS
xos_restore_int_pri_level(ps);
#endif
}
///----------------------------------------------------------------------------
///
/// Disable logging to the syslog. It is sometimes useful to disable logging
/// while the log is being examined or dumped.
///
/// No parameters.
///
/// \return Returns nothing.
///
///----------------------------------------------------------------------------
static inline void
xos_syslog_disable()
{
#if XCHAL_HAVE_INTERRUPTS
uint32_t ps = XT_RSIL(XCHAL_NUM_INTLEVELS);
#endif
xos_syslog->flags &= ~XOS_SYSLOG_ENABLED;
#if XCHAL_HAVE_INTERRUPTS
xos_restore_int_pri_level(ps);
#endif
}
///----------------------------------------------------------------------------
///
/// Write an entry into the syslog. This function does disable all interrupts
/// since logging can be done from interrupt handlers as well. It will write
/// into the log only if the log exists and is enabled.
///
/// \param param1 User defined value.
///
/// \param param2 User defined value.
///
/// \return Returns nothing.
///
///----------------------------------------------------------------------------
static inline void
xos_syslog_write(uint32_t param1, uint32_t param2)
{
if (xos_syslog != XOS_NULL) {
#if XCHAL_HAVE_INTERRUPTS
uint32_t ps = XT_RSIL(XCHAL_NUM_INTLEVELS);
#endif
if ((xos_syslog->flags & XOS_SYSLOG_ENABLED) != 0) {
XosSysLogEntry * next = xos_syslog->next;
next->timestamp = xos_get_ccount();
next->param1 = param1;
next->param2 = param2;
xos_syslog->next = next->next;
}
#if XCHAL_HAVE_INTERRUPTS
xos_restore_int_pri_level(ps);
#endif
}
}
///----------------------------------------------------------------------------
///
/// Read the first (oldest) entry in the syslog. Will return an error if the
/// log has not been created or is empty. Storage to copy the entry must be
/// provided by the caller.
///
/// \param entry Pointer to storage where the entry data will be
/// copied. This pointer must be passed to
/// xos_syslog_get_next().
///
/// \return Returns XOS_OK on success, else error code.
///
///----------------------------------------------------------------------------
static inline int32_t
xos_syslog_get_first(XosSysLogEntry * entry)
{
if (xos_syslog == XOS_NULL) {
return XOS_ERR_NOT_FOUND;
}
if (entry != XOS_NULL) {
#if XCHAL_HAVE_INTERRUPTS
uint32_t ps = XT_RSIL(XCHAL_NUM_INTLEVELS);
#endif
XosSysLogEntry * next = xos_syslog->next;
// 'next' should be pointing to the next entry to be overwritten, if we
// have wrapped. This means it is the oldest entry. However if this entry
// has a zero timestamp then we have not wrapped, in which case we must
// look at the first entry in the list.
if (next->timestamp == 0) {
next = xos_syslog->entries;
}
*entry = *next;
#if XCHAL_HAVE_INTERRUPTS
xos_restore_int_pri_level(ps);
#endif
return entry->timestamp ? XOS_OK : XOS_ERR_NOT_FOUND;
}
return XOS_ERR_INVALID_PARAMETER;
}
///----------------------------------------------------------------------------
///
/// Get the next sequential entry from the syslog. This function must be called
/// only after xos_syslog_get_first() has been called.
///
/// \param entry Pointer to storage where entry data will be copied.
/// Must be the same pointer that was passed in the call
/// to xos_syslog_get_first(), as it is used to keep track
/// of the current position.
///
/// \return Returns XOS_OK on success, else error code.
///
///----------------------------------------------------------------------------
static inline int32_t
xos_syslog_get_next(XosSysLogEntry * entry)
{
if (entry != XOS_NULL) {
#if XCHAL_HAVE_INTERRUPTS
uint32_t ps = XT_RSIL(XCHAL_NUM_INTLEVELS);
#endif
XosSysLogEntry * next = entry->next;
int32_t ret = XOS_OK;
// Make sure we're not pointing past the last entry.
if ((next != XOS_NULL) && (next != xos_syslog->next) && (next->timestamp != 0)) {
*entry = *next;
}
else {
ret = XOS_ERR_NOT_FOUND;
}
#if XCHAL_HAVE_INTERRUPTS
xos_restore_int_pri_level(ps);
#endif
return ret;
}
return XOS_ERR_INVALID_PARAMETER;
}
#ifdef __cplusplus
}
#endif
#endif // __XOS_SYSLOG_H__