291 lines
6.8 KiB
C
291 lines
6.8 KiB
C
![]() |
/*
|
|||
|
* c't-Sim - Robotersimulator fuer den c't-Bot
|
|||
|
*
|
|||
|
* This program is free software; you can redistribute it
|
|||
|
* and/or modify it under the terms of the GNU General
|
|||
|
* Public License as published by the Free Software
|
|||
|
* Foundation; either version 2 of the License, or (at your
|
|||
|
* option) any later version.
|
|||
|
* This program is distributed in the hope that it will be
|
|||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
|||
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|||
|
* PURPOSE. See the GNU General Public License for more details.
|
|||
|
* You should have received a copy of the GNU General Public
|
|||
|
* License along with this program; if not, write to the Free
|
|||
|
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|||
|
* MA 02111-1307, USA.
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
/*! @file log.c
|
|||
|
* @brief Routinen zum Loggen von Informationen. Es sollten ausschliesslich nur
|
|||
|
* die Log-Makros: LOG_DEBUG(), LOG_INFO(), LOG_WARN(), LOG_ERROR() und LOG_FATAL()
|
|||
|
* verwendet werden.
|
|||
|
* Eine Ausgabe kann wie folgt erzeugt werden:
|
|||
|
* LOG_DEBUG(("Hallo Welt!"));
|
|||
|
* LOG_INFO(("Wert x=%d", x));
|
|||
|
* Wichtig ist die doppelte Klammerung. Bei den Ausgaben kann auf ein Line Feed
|
|||
|
* '\n' am Ende des Strings verzichtet werden, da dies automatisch angeh<EFBFBD>ngt
|
|||
|
* hinzugefuegt wird.
|
|||
|
*
|
|||
|
* @author Andreas Merkle (mail@blue-andi.de)
|
|||
|
* @date 27.02.06
|
|||
|
*/
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <stdarg.h>
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
#include "log.h"
|
|||
|
#include "display.h"
|
|||
|
#include "command.h"
|
|||
|
#include "uart.h"
|
|||
|
|
|||
|
#ifdef LOG_AVAILABLE
|
|||
|
|
|||
|
#ifdef PC
|
|||
|
#include <pthread.h>
|
|||
|
#endif /* PC */
|
|||
|
|
|||
|
#ifdef LOG_DISPLAY_AVAILABLE
|
|||
|
/*! Nummer des Screens auf den Loggings ausgegeben werden sollen. */
|
|||
|
#define LOG_TO_SCREEN 4
|
|||
|
|
|||
|
/*! Groesse des Puffers fuer die Logausgaben bei Verwendung des LCD-Displays. */
|
|||
|
#define LOG_BUFFER_SIZE (DISPLAY_LENGTH + 1)
|
|||
|
#else
|
|||
|
/*! Groesse des Puffers fuer die Logausgaben ueber UART und ueber TCP/IP. */
|
|||
|
#define LOG_BUFFER_SIZE 200
|
|||
|
#endif /* LOG_DISPLAY_AVAILABLE */
|
|||
|
|
|||
|
|
|||
|
#ifdef PC
|
|||
|
/*! Schuetzt den Ausgabepuffer */
|
|||
|
#define LOCK() pthread_mutex_lock(&log_buffer_mutex);
|
|||
|
/*! Hebt den Schutz fuer den Ausgabepuffer wieder auf */
|
|||
|
#define UNLOCK() pthread_mutex_unlock(&log_buffer_mutex);
|
|||
|
#else
|
|||
|
/*! Schuetzt den Ausgabepuffer */
|
|||
|
#define LOCK() /* TODO */
|
|||
|
/*! Hebt den Schutz fuer den Ausgabepuffer wieder auf */
|
|||
|
#define UNLOCK() /* TODO */
|
|||
|
#endif /* PC */
|
|||
|
|
|||
|
/*!
|
|||
|
* Liefert den Log-Typ als String.
|
|||
|
* @param log_type Log-Typ
|
|||
|
* @return char*
|
|||
|
*/
|
|||
|
static char* log_get_type_str(LOG_TYPE log_type);
|
|||
|
|
|||
|
/*! Puffer fuer das Zusammenstellen einer Logausgabe */
|
|||
|
static char log_buffer[LOG_BUFFER_SIZE];
|
|||
|
|
|||
|
#ifdef PC
|
|||
|
/*! Schuetzt den Ausgabepuffer */
|
|||
|
static pthread_mutex_t log_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||
|
#endif /* PC */
|
|||
|
|
|||
|
#ifdef LOG_DISPLAY_AVAILABLE
|
|||
|
/*! Zeile in der die naechste Logausgabe erfolgt. */
|
|||
|
static uint16 log_line = 0;
|
|||
|
#endif /* LOG_DISPLAY_AVAILABLE */
|
|||
|
|
|||
|
/*!
|
|||
|
* Schreibt Angaben ueber Datei, Zeilennummer und den Log-Typ in den Puffer.
|
|||
|
* Achtung, Mutex wird gelockt und muss explizit durch log_end() wieder
|
|||
|
* freigegeben werden!
|
|||
|
* @param filename Dateiname
|
|||
|
* @param line Zeilennummer
|
|||
|
* @param log_type Log-Typ
|
|||
|
*/
|
|||
|
extern void log_begin(char *filename, unsigned int line, LOG_TYPE log_type) {
|
|||
|
|
|||
|
/* Ausgaben ueber das LCD-Display werden ohne Dateiname und Zeilennumer
|
|||
|
* gemacht. Der Log-Typ versteckt sich im ersten Buchstaben. Durch eine
|
|||
|
* die Markierung mit '>' erkennt man das letzte Logging.
|
|||
|
* Nur bei Ausgaben ueber UART und an ct-Sim werden Dateiname, Zeilennummer
|
|||
|
* und der Log-Typ vollstaendig ausgegeben.
|
|||
|
*/
|
|||
|
#ifdef LOG_DISPLAY_AVAILABLE
|
|||
|
|
|||
|
LOCK();
|
|||
|
|
|||
|
/* Nur auf einem bestimmten Screen werden Loggings ausgegeben. */
|
|||
|
if (display_screen != LOG_TO_SCREEN) {
|
|||
|
log_buffer[0] = '\0';
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* Zum ersten Mal aufgerufen? */
|
|||
|
if (log_line == 0) {
|
|||
|
log_line++;
|
|||
|
} else {
|
|||
|
/* Alte Markierung loeschen */
|
|||
|
if (log_line - 1 == 0) {
|
|||
|
display_cursor(4, 1);
|
|||
|
}
|
|||
|
else {
|
|||
|
display_cursor(log_line - 1, 1);
|
|||
|
}
|
|||
|
display_printf(" ");
|
|||
|
}
|
|||
|
display_cursor(log_line, 1);
|
|||
|
log_line++;
|
|||
|
if (log_line >= DISPLAY_SCREENS) {
|
|||
|
log_line = 1;
|
|||
|
}
|
|||
|
|
|||
|
snprintf(log_buffer, LOG_BUFFER_SIZE, ">%s:", log_get_type_str(log_type));
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
char *ptr = NULL;
|
|||
|
|
|||
|
/* Nur den Dateinamen loggen, ohne Verzeichnisangabe */
|
|||
|
ptr = strrchr(filename, '/');
|
|||
|
|
|||
|
if (ptr == NULL)
|
|||
|
ptr = filename;
|
|||
|
else
|
|||
|
ptr++;
|
|||
|
|
|||
|
LOCK();
|
|||
|
|
|||
|
snprintf(log_buffer, LOG_BUFFER_SIZE, "%s(%d)\t%s\t",
|
|||
|
ptr, line, log_get_type_str(log_type));
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*!
|
|||
|
* Schreibt die eigentliche Ausgabeinformation in den Puffer.
|
|||
|
* @param format Format
|
|||
|
*/
|
|||
|
extern void log_printf(char *format, ...) {
|
|||
|
|
|||
|
va_list args;
|
|||
|
unsigned int len = strlen(log_buffer);
|
|||
|
|
|||
|
#ifdef LOG_DISPLAY_AVAILABLE
|
|||
|
/* Nur auf einem bestimmten Screen werden Loggings ausgegeben. */
|
|||
|
if (display_screen != LOG_TO_SCREEN)
|
|||
|
return;
|
|||
|
#endif
|
|||
|
|
|||
|
va_start(args, format);
|
|||
|
vsnprintf(&log_buffer[len], LOG_BUFFER_SIZE - len, format, args);
|
|||
|
va_end(args);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*!
|
|||
|
* Gibt den Puffer entsprechend aus.
|
|||
|
*/
|
|||
|
extern void log_end(void) {
|
|||
|
|
|||
|
#ifdef LOG_UART_AVAILABLE
|
|||
|
/* String ueber UART senden, ohne '\0'-Terminierung */
|
|||
|
uart_write((uint8*)log_buffer, strlen(log_buffer));
|
|||
|
/* Line feed senden */
|
|||
|
uart_write((uint8*)LINE_FEED,strlen(LINE_FEED));
|
|||
|
#endif /* LOG_UART_AVAILABLE */
|
|||
|
|
|||
|
#ifdef LOG_CTSIM_AVAILABLE
|
|||
|
/* Kommando an ct-Sim senden, ohne Line feed am Ende. */
|
|||
|
command_write_data(CMD_LOG, SUB_CMD_NORM, NULL, NULL, log_buffer);
|
|||
|
#endif /* LOG_CTSIM_AVAILABLE */
|
|||
|
|
|||
|
#ifdef LOG_DISPLAY_AVAILABLE
|
|||
|
/* Nur auf einem bestimmten Screen werden Loggings ausgegeben. */
|
|||
|
if (display_screen == LOG_TO_SCREEN) {
|
|||
|
/* String aufs LCD-Display schreiben */
|
|||
|
display_printf("%s", log_buffer);
|
|||
|
}
|
|||
|
#endif /* LOG_DISPLAY_AVAILABLE */
|
|||
|
|
|||
|
/* Wenn das Logging aktiviert und keine Ausgabeschnittstelle
|
|||
|
* definiert ist, dann wird auf dem PC auf die Konsole geschrieben.
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef LOG_STDOUT_AVAILABLE
|
|||
|
printf("%s\n", log_buffer);
|
|||
|
#endif /* LOG_STDOUT_AVAILABLE */
|
|||
|
|
|||
|
UNLOCK();
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef LOG_DISPLAY_AVAILABLE
|
|||
|
|
|||
|
/*!
|
|||
|
* Liefert den Log-Typ als String.
|
|||
|
* @param log_type Log-Typ
|
|||
|
* @return char*
|
|||
|
*/
|
|||
|
static char* log_get_type_str(LOG_TYPE log_type) {
|
|||
|
|
|||
|
switch(log_type) {
|
|||
|
case LOG_TYPE_DEBUG:
|
|||
|
return "D";
|
|||
|
|
|||
|
case LOG_TYPE_INFO:
|
|||
|
return "I";
|
|||
|
|
|||
|
case LOG_TYPE_WARN:
|
|||
|
return "W";
|
|||
|
|
|||
|
case LOG_TYPE_ERROR:
|
|||
|
return "E";
|
|||
|
|
|||
|
case LOG_TYPE_FATAL:
|
|||
|
return "F";
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return "";
|
|||
|
}
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
/*!
|
|||
|
* Liefert den Log-Typ als String.
|
|||
|
* @param log_type Log-Typ
|
|||
|
* @return char*
|
|||
|
*/
|
|||
|
static char* log_get_type_str(LOG_TYPE log_type) {
|
|||
|
|
|||
|
switch(log_type) {
|
|||
|
case LOG_TYPE_DEBUG:
|
|||
|
return "- DEBUG -";
|
|||
|
|
|||
|
case LOG_TYPE_INFO:
|
|||
|
return "- INFO -";
|
|||
|
|
|||
|
case LOG_TYPE_WARN:
|
|||
|
return "- WARNING -";
|
|||
|
|
|||
|
case LOG_TYPE_ERROR:
|
|||
|
return "- ERROR -";
|
|||
|
|
|||
|
case LOG_TYPE_FATAL:
|
|||
|
return "- FATAL -";
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return "";
|
|||
|
}
|
|||
|
|
|||
|
#endif /* LOG_DISPLAY_AVAILABLE */
|
|||
|
|
|||
|
#endif /* LOG_AVAILABLE */
|