155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
| MIT License
 | |
| 
 | |
| Copyright (c) 2019 R. Dunbar Poor <rdpoor@gmail.com>
 | |
| 
 | |
| 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.
 | |
| */
 | |
| 
 | |
| /**
 | |
|  * \file ulog.c
 | |
|  *
 | |
|  * \brief uLog: lightweight logging for embedded systems
 | |
|  *
 | |
|  * See ulog.h for sparse documentation.
 | |
|  */
 | |
| 
 | |
| #include "ulog.h"
 | |
| 
 | |
| #ifdef ULOG_ENABLED // whole file...
 | |
| 
 | |
| // #include <stdio.h>
 | |
| #include "printf.h"
 | |
| #include <string.h>
 | |
| #include <stdarg.h>
 | |
| 
 | |
| // =============================================================================
 | |
| // types and definitions
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|     ulog_function_t fn;
 | |
|     ulog_level_t threshold;
 | |
| } subscriber_t;
 | |
| 
 | |
| // =============================================================================
 | |
| // local storage
 | |
| 
 | |
| static subscriber_t s_subscribers[ULOG_MAX_SUBSCRIBERS];
 | |
| static char s_message[ULOG_MAX_MESSAGE_LENGTH];
 | |
| 
 | |
| // =============================================================================
 | |
| // user-visible code
 | |
| 
 | |
| void ulog_init()
 | |
| {
 | |
|     memset(s_subscribers, 0, sizeof(s_subscribers));
 | |
| }
 | |
| 
 | |
| // search the s_subscribers table to install or update fn
 | |
| ulog_err_t ulog_subscribe(ulog_function_t fn, ulog_level_t threshold)
 | |
| {
 | |
|     int available_slot = -1;
 | |
|     int i;
 | |
|     for (i = 0; i < ULOG_MAX_SUBSCRIBERS; i++)
 | |
|     {
 | |
|         if (s_subscribers[i].fn == fn)
 | |
|         {
 | |
|             // already subscribed: update threshold and return immediately.
 | |
|             s_subscribers[i].threshold = threshold;
 | |
|             return ULOG_ERR_NONE;
 | |
|         }
 | |
|         else if (s_subscribers[i].fn == NULL)
 | |
|         {
 | |
|             // found a free slot
 | |
|             available_slot = i;
 | |
|         }
 | |
|     }
 | |
|     // fn is not yet a subscriber.  assign if possible.
 | |
|     if (available_slot == -1)
 | |
|     {
 | |
|         return ULOG_ERR_SUBSCRIBERS_EXCEEDED;
 | |
|     }
 | |
|     s_subscribers[available_slot].fn = fn;
 | |
|     s_subscribers[available_slot].threshold = threshold;
 | |
|     return ULOG_ERR_NONE;
 | |
| }
 | |
| 
 | |
| // search the s_subscribers table to remove
 | |
| ulog_err_t ulog_unsubscribe(ulog_function_t fn)
 | |
| {
 | |
|     int i;
 | |
|     for (i = 0; i < ULOG_MAX_SUBSCRIBERS; i++)
 | |
|     {
 | |
|         if (s_subscribers[i].fn == fn)
 | |
|         {
 | |
|             s_subscribers[i].fn = NULL; // mark as empty
 | |
|             return ULOG_ERR_NONE;
 | |
|         }
 | |
|     }
 | |
|     return ULOG_ERR_NOT_SUBSCRIBED;
 | |
| }
 | |
| 
 | |
| const char *ulog_level_name(ulog_level_t severity)
 | |
| {
 | |
|     switch (severity)
 | |
|     {
 | |
|     case ULOG_TRACE_LEVEL:
 | |
|         return "TRACE";
 | |
|     case ULOG_DEBUG_LEVEL:
 | |
|         return "DEBUG";
 | |
|     case ULOG_INFO_LEVEL:
 | |
|         return "INFO";
 | |
|     case ULOG_WARNING_LEVEL:
 | |
|         return "WARNING";
 | |
|     case ULOG_ERROR_LEVEL:
 | |
|         return "ERROR";
 | |
|     case ULOG_CRITICAL_LEVEL:
 | |
|         return "CRITICAL";
 | |
|     case ULOG_ALWAYS_LEVEL:
 | |
|         return "ALWAYS";
 | |
|     default:
 | |
|         return "UNKNOWN";
 | |
|     }
 | |
| }
 | |
| 
 | |
| void ulog_message(ulog_level_t severity, const char *fmt, ...)
 | |
| {
 | |
|     va_list ap;
 | |
|     int i;
 | |
|     va_start(ap, fmt);
 | |
|     vsnprintf(s_message, ULOG_MAX_MESSAGE_LENGTH, fmt, ap);
 | |
|     va_end(ap);
 | |
| 
 | |
|     for (i = 0; i < ULOG_MAX_SUBSCRIBERS; i++)
 | |
|     {
 | |
|         if (s_subscribers[i].fn != NULL)
 | |
|         {
 | |
|             if (severity >= s_subscribers[i].threshold)
 | |
|             {
 | |
|                 s_subscribers[i].fn(severity, s_message);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // =============================================================================
 | |
| // private code
 | |
| 
 | |
| #endif // #ifdef ULOG_ENABLED
 |