/** @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__