Commit a29f1591 authored by Michael Zehrer's avatar Michael Zehrer
Browse files

add new 'Printable' base class and remove previous printf implementation

parent 71ba6aa1
......@@ -9,7 +9,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <arctos/debug.h>
#include <arctos/debug.hpp>
#include <arctos/task.hpp>
#include <arctos/time.hpp>
......
......@@ -6,7 +6,7 @@
* @brief A Task is an active schedulable object with own context and stack
* @author Michael Zehrer
*/
#include <arctos/debug.h>
#include <arctos/debug.hpp>
#include <arctos/task.hpp>
#include <arctos/time.hpp>
......
......@@ -3,10 +3,11 @@ add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/src")
# Headers
target_sources(${UNIT} PUBLIC
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/memory/partitioning.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/debug.h"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/debug.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/fifo.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/list.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/mutex.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/printable.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/scheduler.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/task.hpp"
"${CMAKE_CURRENT_LIST_DIR}/api/arctos/time.hpp"
......
/**
* Copyright (c) 2018, Michael Zehrer
* All rights reserved.
*
* @licence BSD
* @brief Debug functions
* @author Michael Zehrer
*/
#ifndef ARCTOS_DEBUG_H
#define ARCTOS_DEBUG_H
#ifdef __cplusplus
extern "C" {
#endif
// TODO Comment!!
void PRINTF(const char* fmt, ...) __attribute__((__format__(__printf__,1,2)));
void SPRINTF(char* dest, const char* fmt, ...) __attribute__((__format__(__printf__,2,3)));
void PANIC(const char* error_msg, ...) __attribute__((__format__(__printf__,1,2)));
#ifdef __cplusplus
} // end extern "C"
#endif
#endif /* ARCTOS_DEBUG_H */
/**
* Copyright (c) 2018-2019, Michael Zehrer
* All rights reserved.
*
* @licence BSD
* @brief Debug functions (temporary interface)
* @author Michael Zehrer
*/
#ifndef ARCTOS_DEBUG_HPP
#define ARCTOS_DEBUG_HPP
#include <arctos/params.h>
#include <serial/all.hpp>
// TODO This is a temporary implementation -> delete ASAP
// IMPORTANT: 'RPI_DEBUG_SERIAL_IDX' isn't save to use here, because it is first defined in bare-metal!
#define PRINTF (modules::serial::get(modules::serial::RPI_DEBUG_SERIAL_IDX)->printf)
#define PANIC (modules::serial::get(modules::serial::RPI_DEBUG_SERIAL_IDX)->printf)
#endif /* ARCTOS_DEBUG_HPP */
/**
* Copyright (c) 2019, Michael Zehrer
* All rights reserved.
*
* @licence BSD
* @brief Printable base class
* @author Michael Zehrer
*/
#ifndef ARCTOS_PRINTABLE_HPP
#define ARCTOS_PRINTABLE_HPP
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
namespace arctos {
/**
* @brief Base for all those classes who need some print(f) extension
*/
class Printable {
public:
/**
* @brief Waits for all outgoing transmissions to complete
*/
virtual void flush(void) = 0;
/**
* @brief Print a character.
*
* @param[in] c The character to print.
* @return the value one
*/
virtual size_t print(char c) = 0;
/**
* @brief Print a string.
*
* @param[in] str The string to print
* @param[in] len The length of the input string
* @return Number of chars which were really printed
*/
virtual size_t print(const char *str, size_t len) = 0;
/**
* @brief Print a string.
*
* @param[in] str The string to print
* @return Number of chars which were really printed
*/
virtual size_t print(const char *str) { return this->print(str, strlen(str)); }
/**
* @brief Print a formatted string.
*
* @param[in] fmt The format string to display
* @param[in] ... Format parameters
* @return The length of the string
*/
__attribute__((__format__(__printf__, 2, 3))) size_t printf(const char *fmt, ...);
/**
* @brief Print a formatted string.
*
* @param[in] fmt The format string to display
* @param[in] vl Already initalized variadic list
* @return The length of the string
*/
size_t vprintf(const char *fmt, va_list vl);
};
} /* namespace arctos */
#endif /* ARCTOS_PRINTABLE_HPP */
......@@ -47,26 +47,6 @@ void _hwInit(void);
* // TODO comment
*/
/**
* @brief Prints the given character 'c' to a target specific
* debugging interface (normally some default UART)
* @note This interface function is optional.
* If you don't need the debug interface on your portation,
* you could leave this function unimplemented.
*/
void _debugPutChar(const char c);
/**
* @brief Prints the given string 'str' to a target specific
* debugging interface (normally some default UART)
* @param p_str Debug string
* @param len Length of the string. If 'len' is negativ: Print
* until you reach the terminating null character
* @note This interface function is optional.
* If you implement this function, you must also provide
* the corresponding '_debugPutChar(...)' function.
*/
void _debugPutString(const char *p_str, int32_t len);
#ifdef __cplusplus
} // end extern "C"
#endif
......
......@@ -3,9 +3,9 @@ add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/memory")
# Sources
target_sources(${UNIT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/debug.c"
"${CMAKE_CURRENT_LIST_DIR}/hw_interface.c"
"${CMAKE_CURRENT_LIST_DIR}/main.cpp"
"${CMAKE_CURRENT_LIST_DIR}/new.cpp"
"${CMAKE_CURRENT_LIST_DIR}/printable.cpp"
"${CMAKE_CURRENT_LIST_DIR}/time.cpp"
)
/**
* Copyright (c) 2018, Michael Zehrer
* Copyright (c) 2018-2019, Michael Zehrer
* All rights reserved.
*
* @licence BSD
......@@ -17,15 +17,6 @@ extern "C" {
__attribute__((weak))
void _hwInit(void) { }
__attribute__((weak))
void _debugPutChar(const char c) { }
__attribute__((weak))
void _debugPutString(const char *str, int32_t len) {
while ((*str != '\0') && (len-- != 0))
_debugPutChar(*str++);
}
#ifdef __cplusplus
} // end extern "C"
#endif
......@@ -9,7 +9,7 @@
#include <arctos/hw_interface.hpp>
#include <arctos/scheduler.hpp>
#include <arctos/debug.h>
#include <arctos/debug.hpp>
#include <arctos/task.hpp>
namespace arctos {
......
......@@ -9,7 +9,7 @@
#include <stddef.h>
#include <string.h>
#include <arctos/debug.h>
#include <arctos/debug.hpp>
#include <arctos/memory/partitioning.hpp>
#include <arctos/hw_interface.hpp>
......
/**
* Copyright (c) 2018, Michael Zehrer
* Copyright (c) 2019, Michael Zehrer
* All rights reserved.
*
* @licence BSD
* @brief Debug functions
* @brief Printable base class
* @author Michael Zehrer
*
* TODO Reimplement as Thread-Safe printable class
*/
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
#include <limits.h>
#include <arctos/printable.hpp>
#include <compiler.h>
#include <arctos/debug.h>
#include <arctos/hw_interface.h>
#ifdef __cplusplus
extern "C" {
#endif
namespace arctos {
typedef union {
uint16_t value;
struct {
uint16_t flags_hash:1;
uint16_t precision_set:1;
uint16_t length_l:1;
uint16_t length_ll:1;
uint16_t specifier_uppercase:1;
uint16_t base:5;
uint16_t is_signed:1;
uint16_t is_float:1;
} attr;
} Format;
static void printf_impl(const char *fmt, va_list *ap,
void (*putc)(const char c), void (*putstr)(const char *str, int32_t len)) {
size_t Printable::printf(const char *fmt, ...) {
va_list vl;
va_start(vl, fmt);
size_t counter = this->vprintf(fmt, vl);
va_end(vl);
return counter;
}
size_t Printable::vprintf(const char *fmt, va_list vl) {
size_t counter = 0;
Format format;
int16_t width;
uint16_t log2base, precision;
char fill;
const char *start = fmt;
char c = *fmt++;
while (c != '\0') {
if (*fmt != '%' || (*fmt == '%' && c == '\\')) {
if (c != '%') {
c = *fmt++;
continue;
}
putstr(start, fmt - start);
// skip '%'
++fmt;
counter += this->print(start, fmt - start - 1);
c = *fmt++;
// if the percent sign was the last character in the string
// (which is btw. no proper format string) processing will be canceled
if (c == '\0')
return;
format.value = 0;
width = 0;
log2base = precision = 0;
fill = ' ';
break;
Format format = { .value = 0 };
int16_t width = 0;
uint16_t log2base = 0;
uint16_t precision = 0;
char fill = ' ';
// FLAGS
if (c == '0') {
fill = c;
......@@ -84,13 +72,13 @@ static void printf_impl(const char *fmt, va_list *ap,
format.attr.flags_hash = 1;
c = *fmt++;
}
// WIDTH
for (size_t j = 1; c >= '0' && c <= '9'; j *= 10, c = *fmt++) {
width *= j;
width += (c - '0');
}
// PRECISION
if (c == '.') {
format.attr.precision_set = 1;
......@@ -101,7 +89,7 @@ static void printf_impl(const char *fmt, va_list *ap,
}
// another incorrect format string
if (c == '\0')
return;
return counter;
c = *fmt++;
}
......@@ -118,36 +106,36 @@ static void printf_impl(const char *fmt, va_list *ap,
switch(c) {
case '\0':
// another incorrect format string
return;
return counter;
case 'c':
c = va_arg(*ap, int);
c = va_arg(vl, int);
FALL_THROUGH;
default:
putc(c);
counter += this->print(c);
start = fmt;
c = *fmt++;
continue;
case 's':
if (format.attr.precision_set == 0)
putstr(va_arg(*ap, const char *), -1);
counter += this->print(va_arg(vl, const char *));
else
putstr(va_arg(*ap, const char *), (int)(precision));
counter += this->print(va_arg(vl, const char *), static_cast<size_t>(precision));
start = fmt;
c = *fmt++;
continue;
// Not in the standard, but it might be useful
case 'b':
format.attr.base = 2;
log2base = 1;
break;
case 'o':
format.attr.base = 8;
log2base = 3;
if (format.attr.flags_hash)
putc('0');
counter += this->print('0');
break;
case 'F':
......@@ -172,8 +160,8 @@ static void printf_impl(const char *fmt, va_list *ap,
FALL_THROUGH;
case 'x':
if (format.attr.flags_hash) {
putc('0');
putc(c);
counter += this->print('0');
counter += this->print(c);
}
format.attr.base = 16;
log2base = 4;
......@@ -186,8 +174,8 @@ static void printf_impl(const char *fmt, va_list *ap,
double val_f = 0.0;
if (format.attr.is_float) {
val_f = va_arg(*ap, double);
val_ll = (long long)(val_f);
val_f = va_arg(vl, double);
val_ll = static_cast<long long>(val_f);
// if the precision was explicitly set to zero...
if (precision == 0) {
// ...we pretend that the value 'val_ll' was
......@@ -198,48 +186,45 @@ static void printf_impl(const char *fmt, va_list *ap,
width = width - precision - 1;
}
else if (format.attr.length_ll)
val_ll = va_arg(*ap, long long);
val_ll = va_arg(vl, long long);
else if (format.attr.length_l)
val_ll = va_arg(*ap, long);
val_ll = va_arg(vl, long);
else
val_ll = va_arg(*ap, int);
val_ll = va_arg(vl, int);
if (format.attr.is_signed) {
if (val_ll < 0 || val_f < 0) {
val_ll = -val_ll;
val_f = -val_f;
putc('-');
counter += this->print('-');
--width;
}
}
if (format.attr.length_ll)
val_ull = (unsigned long long)(val_ll);
val_ull = static_cast<unsigned long long>(val_ll);
else if (format.attr.length_l)
val_ull = (unsigned long long)((unsigned long)(val_ll));
val_ull = static_cast<unsigned long long>(static_cast<unsigned long>(val_ll));
else
val_ull = (unsigned long long)((unsigned int)(val_ll));
val_ull = static_cast<unsigned long long>(static_cast<unsigned int>(val_ll));
if (format.attr.base == 10) {
#ifdef __cplusplus
constexpr
#endif
size_t size = __builtin_ceil(__builtin_log10(2) * sizeof(unsigned long long) * 8);
constexpr size_t size = __builtin_ceil(__builtin_log10(2)*sizeof(unsigned long long)*8);
char buffer[size];
char *const end = buffer + size - 1;
char *ptr = end;
do {
*ptr-- = (char)(val_ull % 10) + '0';
*ptr-- = static_cast<char>(val_ull % 10) + '0';
val_ull /= 10;
--width;
} while (val_ull);
while (width-- > 0)
putc(fill);
putstr(ptr + 1, end - ptr);
counter += this->print(fill);
counter += this->print(ptr + 1, end - ptr);
}
else {
// The base is a power of 2 and therefore some potential faster
......@@ -248,10 +233,10 @@ static void printf_impl(const char *fmt, va_list *ap,
char buffer[size];
char *const end = buffer + size - 1;
char *ptr = end;
uint8_t mod_mask = format.attr.base - 1;
do {
c = (char)((val_ull & mod_mask) + '0');
c = static_cast<char>((val_ull & mod_mask) + '0');
if (c > '9')
c += (format.attr.specifier_uppercase == 1 ? 'A' : 'a') - '9' - 1;
*ptr-- = c;
......@@ -260,78 +245,34 @@ static void printf_impl(const char *fmt, va_list *ap,
} while (val_ull);
while (width-- > 0)
putc(fill);
putstr(ptr + 1, end - ptr);
counter += this->print(fill);
counter += this->print(ptr + 1, end - ptr);
}
if (format.attr.is_float) {
// Print the digits after the decimal point
putc('.');
counter += this->print('.');
while (precision--) {
val_f = (val_f - val_ll) * 10;
val_ll = (long long)(val_f);
putc(val_ll + '0');
val_ll = static_cast<long long>(val_f);
counter += this->print(val_ll + '0');
}
}
}
start = fmt;
c = *fmt++;
}
// On loop exit 'fmt' is one char "behind" the terminating null
// character. We have to correct that...
--fmt;
if (fmt > start)
//...and print out the tail if necessary
putstr(start, fmt - start);
}
static char *g_p_dest = NULL;
static void appendChar(const char c) {
//assert(g_p_dest != NULL);
*g_p_dest++ = c;
*g_p_dest = '\0';
}
static void appendString(const char *str, int32_t len) {
//assert(g_p_dest != NULL);
if (len > 0)
strncat(g_p_dest, str, len);
else if (len < 0)
strcat(g_p_dest, str);
}
void PRINTF(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
printf_impl(fmt, &ap, &_debugPutChar, &_debugPutString);
va_end(ap);
}
void SPRINTF(char *dest, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
g_p_dest = dest;
printf_impl(fmt, &ap, &appendChar, &appendString);
g_p_dest = NULL;
va_end(ap);
}
counter += this->print(start, fmt - start);
void PANIC(const char *errorMsg, ...) {
va_list ap;
va_start(ap, errorMsg);
PRINTF("\n! KERNEL PANIC !\n");
printf_impl(errorMsg, &ap, &_debugPutChar, &_debugPutString);
PRINTF("\n! KERNEL PANIC !");
va_end(ap);
while (true) { }
return counter;
}
#ifdef __cplusplus
} // end extern "C"
#endif
} /* namespace arctos */
......@@ -11,6 +11,8 @@
#include <stddef.h>
#include <stdint.h>
#include <arctos/printable.hpp>