From ed8f05d3671a48361a64129595e44d8d360e6ea7 Mon Sep 17 00:00:00 2001 From: jief Date: Mon, 24 Feb 2020 17:51:58 +0300 Subject: [PATCH] Commit the real files instead of symlinks. --- rEFIt_UEFI/cpp_foundation/printf_lite.cpp | 1253 +++++++++++++++++++++ rEFIt_UEFI/cpp_foundation/printf_lite.h | 181 +++ 2 files changed, 1434 insertions(+) create mode 100644 rEFIt_UEFI/cpp_foundation/printf_lite.cpp create mode 100644 rEFIt_UEFI/cpp_foundation/printf_lite.h diff --git a/rEFIt_UEFI/cpp_foundation/printf_lite.cpp b/rEFIt_UEFI/cpp_foundation/printf_lite.cpp new file mode 100644 index 000000000..ec3bbff0e --- /dev/null +++ b/rEFIt_UEFI/cpp_foundation/printf_lite.cpp @@ -0,0 +1,1253 @@ +// +// printf_lite.hpp +// +// Created by jief the 04 Apr 2019. +// Imported in CLover the 24 Feb 2020 +// +/* + This code should be pasted within the files where this function is needed. + This function will not create any code conflicts. + + The function call is similar to printf: ardprintf("Test %d %s", 25, "string"); + + To print the '%' character, use '%%' + + This code was first posted on http://arduino.stackexchange.com/a/201 +*/ + +#include "printf_lite.h" // need to include that before testing #if PRINTF_LITE_USB_SUPPORT == 1 + +#ifdef USE_HAL_DRIVER + #include "stm32f1xx_hal.h" + #if PRINTF_LITE_USB_SUPPORT == 1 + #include "usb_device.h" + #include "usbd_cdc_if.h" + #include "printf_lite.h" // need to re-include that after included usbd_cdc_if.h to get definition under defined(__USBD_CDC_IF_H) + #endif +#endif + +#ifdef ARDUINO + #include +// #include +#endif + +#ifdef NRF51 + #include + #include +#endif + +#if defined(OS_USE_TRACE_ITM) || defined(OS_USE_TRACE_SEMIHOSTING_DEBUG) || defined(OS_USE_TRACE_SEMIHOSTING_STDOUT) +#include +#endif + +#include +#include +#include +#include + +#ifdef __STM32F1xx_HAL_UART_H +extern UART_HandleTypeDef huart1; +#endif + + + + + +// using int because this is what generate less code. It's a bit more on the stack but it's temporary. +typedef struct { + #if PRINTF_LITE_BUF_SIZE > 1 + printf_char_type buf[PRINTF_LITE_BUF_SIZE]; + uint8_t bufIdx; + #endif + transmitBufCallBackType transmitBufCallBack; + int inDirective; + int l_modifier; + #if PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + int z_modifier; + #endif + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + int inWidthField; + int width_specifier; + #endif + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 || (PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 && PRINTF_LITE_FIELDWIDTH_SUPPORT == 1) // in that case, we need the inPrecisionField to know we are currently ignoring precision field + int inPrecisionField; + #endif + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + int precision_specifier; + #endif + #if PRINTF_LITE_PADCHAR_SUPPORT == 1 + char pad_char; + #endif + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + int *newlinePtr; + int timestamp; // not using bool in case of C compilation + #endif + #if PRINTF_LITE_XSPECIFIER_SUPPORT == 1 + int uppercase; + #endif +} PrintfParams; + +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 +static void print_timestamp(PrintfParams* printfParams); +#endif + +static void print_char(printf_char_type c, PrintfParams* printfParams) +{ + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + if ( printfParams->newlinePtr ) + { + if ( *printfParams->newlinePtr ) + { + *printfParams->newlinePtr = 0; // to do BEFORE call to printTimeStamp + if ( printfParams->timestamp ) print_timestamp(printfParams); + } + #if PRINTF_LITE_BUF_SIZE > 1 + printfParams->buf[(printfParams->bufIdx)++] = c; + #else + printfParams->transmitBufCallBack(&c, 1); + #endif + if ( c == '\n' ) { + *printfParams->newlinePtr = 1; + } + }else{ + #if PRINTF_LITE_BUF_SIZE > 1 + printfParams->buf[(printfParams->bufIdx)++] = c; + #else + printfParams->transmitBufCallBack(&c, 1); + #endif + } + #else + { + #if PRINTF_LITE_BUF_SIZE > 1 + printfParams->buf[(printfParams->bufIdx)++] = c; + #else + printfParams->transmitBufCallBack(&c, 1); + #endif + } + #endif + #if PRINTF_LITE_BUF_SIZE > 1 + if ( printfParams->bufIdx == PRINTF_LITE_BUF_SIZE ) { + printfParams->transmitBufCallBack(printfParams->buf, printfParams->bufIdx); + printfParams->bufIdx = 0; + } + #endif +} + + + +#if PRINTF_OUTPUT_FORMAT_UNICODE == 1 && PRINTF_UTF8_SUPPORT == 1 + +#define halfBase 0x0010000UL +#define halfMask 0x3FFUL +#define halfShift 10 /* used for shifting by 10 bits */ +#define UNI_SUR_HIGH_START 0xD800u +#define UNI_SUR_LOW_START 0xDC00u + +static void print_string(const unsigned char* s, PrintfParams* printfParams) +{ + while ( *s ) { + char32_t c; + if (*s & 0x80) { + if (*(s+1) == 0) { + // Finished in the middle of an utf8 multibyte char + return; + } + if ((*(s+1) & 0xc0) != 0x80) { + s += 1; + continue; + } + if ((*s & 0xe0) == 0xe0) { + if (*(s+2) == 0) { + // Finished in the middle of an utf8 multibyte char + return; + } + if ((*(s+2) & 0xc0) != 0x80) { + s += 2; + continue; + } + if ((*s & 0xf0) == 0xf0) { + if (*(s+3) == 0) { + // Finished in the middle of an utf8 multibyte char + return; + } + if ((*s & 0xf8) != 0xf0 || (*(s+3) & 0xc0) != 0x80) { + s += 3; + continue; + } + /* 4-byte code */ + c = (*s & 0x7) << 18; + c |= (*(s+1) & 0x3f) << 12; + c |= (*(s+2) & 0x3f) << 6; + c |= *(s+3) & 0x3f; + s += 4; + } else { + /* 3-byte code */ + c = (*s & 0xf) << 12; + c |= (*(s+1) & 0x3f) << 6; + c |= *(s+2) & 0x3f; + s += 3; + } + } else { + /* 2-byte code */ + c = (*s & 0x1f) << 6; + c |= *(s+1) & 0x3f; + s += 2; + } + } else { + /* 1-byte code */ + c = *s; + s += 1; + } +#if __WCHAR_MAX__ > 0xFFFFu + print_char(c, printfParams); +#else + if ( c <= 0xFFFF) { + print_char(c, printfParams); + } else { + c -= halfBase; + print_char((wchar_t)((c >> halfShift) + UNI_SUR_HIGH_START), printfParams); + print_char((wchar_t)((c & halfMask) + UNI_SUR_LOW_START), printfParams); + } +#endif + } +} +#endif + +static void print_string(const printf_char_type* s, PrintfParams* printfParams) +{ + while ( *s ) print_char(*s++, printfParams); +} + +#if defined(ARDUINO) && PRINTF_LITE_FLASHSTRING_SUPPORT == 1 + +static void print_Fstring(const char* s, PrintfParams* printfParams) +{ + PGM_P p_to_print = reinterpret_cast(s); + unsigned char c_to_print = pgm_read_byte(p_to_print++); + while ( c_to_print != 0 ) { + print_char(c_to_print, printfParams); + c_to_print = pgm_read_byte(p_to_print++); + } +} + +#endif + +#if PRINTF_LITE_LONGLONGINT_SUPPORT == 1 && PRINTF_LITE_LONGINT_SUPPORT == 1 + #define INT_BIGGEST_TYPE long long int +#else + #if PRINTF_LITE_LONGINT_SUPPORT == 1 + #define INT_BIGGEST_TYPE long int + #else + #define INT_BIGGEST_TYPE int + #endif +#endif + +/* Jief : I found this here : https://github.com/cjlano/tinyprintf/blob/master/tinyprintf.c. Thanks CJlano */ +static void print_ulonglong(unsigned INT_BIGGEST_TYPE v, unsigned int base, PrintfParams* printfParams, int printfSign) +{ + int n = 0; + unsigned INT_BIGGEST_TYPE d = 1; + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + int nbDigits = 1 + printfSign; + #endif + while (v / d >= base) { + d *= base; + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + nbDigits += 1; + #endif + } + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 && PRINTF_LITE_PADCHAR_SUPPORT == 1 + if ( printfSign && printfParams->pad_char != ' ' ) print_char('-', printfParams); + #endif + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + while ( printfParams->width_specifier > nbDigits ) { + #if PRINTF_LITE_PADCHAR_SUPPORT == 1 + print_char(printfParams->pad_char, printfParams); + #else + print_char(' ', printfParams); + #endif + nbDigits += 1; + } + #endif + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 && PRINTF_LITE_PADCHAR_SUPPORT == 1 + if ( printfSign && printfParams->pad_char == ' ' ) print_char('-', printfParams); + #else + if ( printfSign ) print_char('-', printfParams); + #endif + while (d != 0) { + unsigned int dgt = (unsigned int)(v / d); // cast is safe as v/d < 10 + v %= d; + d /= base; + #if PRINTF_LITE_XSPECIFIER_SUPPORT == 1 + print_char( (char)(dgt + (dgt < 10 ? '0' : (printfParams->uppercase ? 'A' : 'a') - 10)), printfParams); + #else + print_char( (char)(dgt + '0'), printfParams); + #endif + n += 1; + } +} + +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + +#if defined(EFIAPI) + +#error TODO + +#elif defined(__APPLE__) + +#include + +uint32_t getUptimeInMilliseconds() +{ + static mach_timebase_info_data_t s_timebase_info; + + kern_return_t result = mach_timebase_info(&s_timebase_info); + (void(result)); +// assert(result == 0); + + // multiply to get value in the nano seconds + double multiply = (double)s_timebase_info.numer / (double)s_timebase_info.denom; + // divide to get value in the seconds + multiply /= 1000; + + return mach_absolute_time() * multiply; +} +#endif +#endif //PRINTF_LITE_TIMESTAMP_SUPPORT + + +static void print_longlong(INT_BIGGEST_TYPE v, int base, PrintfParams* printfParams) +{ + if ( v >= 0 ) return print_ulonglong(v, base, printfParams, 0); + print_ulonglong(-v, base, printfParams, 1); // -v doesn't work for INT64_MIN +} + +#define PRINTF_LITE_REENTRANT 1 +#if PRINTF_LITE_REENTRANT == 1 && PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + +void printf_with_callback(const char* format, transmitBufCallBackType transmitBufCallBack, +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + int* newline, int timestamp, +#endif // PRINTF_LITE_TIMESTAMP_SUPPORT + ...); + +#ifdef ARDUINO +void printf_with_callback(const __FlashStringHelper* format, transmitBufCallBackType transmitBufCallBack +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , int* newline, int timestamp, +#endif // PRINTF_LITE_TIMESTAMP_SUPPORT + ...); +#endif // ARDUINO + +#include // for PRIu32 + +#endif // PRINTF_LITE_REENTRANT + + +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 +static void print_timestamp(PrintfParams* printfParams) +{ + #ifdef USE_HAL_DRIVER + uint32_t ms = HAL_GetTick(); + #endif + #ifdef ARDUINO + uint32_t ms = millis(); + #endif + #ifdef NRF51 + uint32_t p_ticks; + uint32_t error_code = app_timer_cnt_get(&p_ticks); + APP_ERROR_CHECK(error_code); + uint32_t ms = p_ticks * ( ( NRF_RTC1->PRESCALER + 1 ) * 1000 ) / APP_TIMER_CLOCK_FREQ; + #endif + #ifdef __APPLE__ + uint32_t ms = getUptimeInMilliseconds(); + #endif + uint32_t s = ms/1000; + uint32_t m = s/60; + uint32_t h = m/60; + m %= 60; + s %= 60; + ms %= 1000; +#if PRINTF_LITE_REENTRANT == 1 + #ifdef ARDUINO + printf_with_callback(F("%03" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%03" PRIu32 " - "), printfParams->transmitBufCallBack, NULL, 0, h, m, s, ms); + #else + printf_with_callback("%03" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%03" PRIu32 " - ", printfParams->transmitBufCallBack, NULL, 0, h, m, s, ms); + #endif +#else + // non reentrant version take a bit more code size + #if PRINTF_LITE_PADCHAR_SUPPORT == 1 + char pad_char = printfParams->pad_char; + printfParams->pad_char = '0'; + #endif + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + int width_specifier = printfParams->width_specifier; + printfParams->width_specifier = 3; + #endif + print_longlong(h, 10, printfParams); + print_char(':', printfParams); + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + printfParams->width_specifier = 2; + #endif + print_longlong(m, 10, printfParams); + print_char(':', printfParams); + print_longlong(s, 10, printfParams); + print_char('.', printfParams); + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + printfParams->width_specifier = 3; + #endif + print_longlong(ms, 10, printfParams); + // version 1 + // for (int i=0 ; i<3 ; i++) print_char('-', printfParams); + // version 2 + // print_char(' ', printfParams); + // print_char('-', printfParams); + // print_char(' ', printfParams); + // version 3 + // print_Fstring(PSTR(" - "), printfParams); + // version 4 + print_string(" - ", printfParams); // this one seems to use less space in flash, but 4 bytes in memory, on my Arduino UNO + + #if PRINTF_LITE_PADCHAR_SUPPORT == 1 + printfParams->pad_char = pad_char; + #endif + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + printfParams->width_specifier = width_specifier; + #endif +#endif +} +#endif + +#if PRINTF_LITE_FLOAT_SUPPORT == 1 +/* Jief : I found this in Arduino code */ + +/* According to snprintf(), + * + * nextafter((double)numeric_limits::max(), 0.0) ~= 9.22337e+18 + * + * This slightly smaller value was picked semi-arbitrarily. */ +#define LARGE_DOUBLE_TRESHOLD (9.1e18) + +/* THIS FUNCTION SHOULDN'T BE USED IF YOU NEED ACCURATE RESULTS. + * + * This implementation is meant to be simple and not occupy too much + * code size. However, printing floating point values accurately is a + * subtle task, best left to a well-tested library function. + * + * See Steele and White 2003 for more details: + * + * http://kurtstephens.com/files/p372-steele.pdf + */ +static void print_double(double number, PrintfParams* printfParams) +{ + // Hackish fail-fast behavior for large-magnitude doubles + if (number >= LARGE_DOUBLE_TRESHOLD || number <= -LARGE_DOUBLE_TRESHOLD) { + if (number < 0.0) { + print_char('-', printfParams); + } +#if PRINTF_OUTPUT_FORMAT_UNICODE == 1 && PRINTF_UTF8_SUPPORT == 0 + print_string(L"", printfParams); +#else + print_string((unsigned char*)"", printfParams); +#endif + } + + int negative = 0; + if (number < 0.0) { + negative = 1; + number = -number; + } + + // Simplistic rounding strategy so that e.g. print(1.999, 2) + // prints as "2.00" + double rounding = 0.5; + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + for (uint8_t i = 0; i < printfParams->precision_specifier; i++) { + rounding /= 10.0; + } + #else + for (uint8_t i = 0; i < 6; i++) { + rounding /= 10.0; + } + #endif + number += rounding; + + // Extract the integer part of the number and print it + unsigned INT_BIGGEST_TYPE int_part = (unsigned INT_BIGGEST_TYPE)number; // we're sure it's positive number here. + double remainder = number - (double)int_part; +#if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + int width_specifier = printfParams->width_specifier; + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + printfParams->width_specifier -= printfParams->precision_specifier + (printfParams->precision_specifier ? 1 : 0); // doesn't matter if width_specifier is negative. + #else + printfParams->width_specifier -= 7; // doesn't matter if width_specifier is negative. + #endif +#endif + print_ulonglong(int_part, 10, printfParams, negative); +#if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + printfParams->width_specifier = width_specifier; +#endif + + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + // Print the decimal point, but only if there are digits beyond + if (printfParams->precision_specifier > 0) { + print_char('.', printfParams); + } + #else + // if no precision support, it's always 6, so always a decimal point. + print_char('.', printfParams); + #endif + + // Extract digits from the remainder one at a time + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + while (printfParams->precision_specifier-- > 0) { + #else + for ( int i=0 ; i<6 ; i++) { + #endif + remainder *= 10.0; + int to_print = (int)remainder; + print_char((char)(to_print + '0'), printfParams); + remainder -= to_print; + } +} +#endif + +#ifdef __APPLE__ + #define VALIST_PARAM_TYPE va_list + #define VALIST_PARAM(valist) valist + #define VALIST_ACCESS(valist) valist +#else + #define VALIST_PARAM_TYPE va_list* + #define VALIST_PARAM(valist) &valist + #define VALIST_ACCESS(valist) (*valist) +#endif +static void printf_handle_format_char(char c, VALIST_PARAM_TYPE valist, PrintfParams* printfParams) +{ + if ( printfParams->inDirective ) + { + switch(c) + { +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 || PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 || PRINTF_LITE_PADCHAR_SUPPORT == 1 + case '0': + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + if ( printfParams->inWidthField ) { + printfParams->width_specifier *= 10; + }else + #endif + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + if ( printfParams->inPrecisionField ) { + printfParams->precision_specifier *= 10; + } + else + #endif + #if PRINTF_LITE_PADCHAR_SUPPORT == 1 + printfParams->pad_char = '0'; + #else + #if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 0 + printfParams->inDirective = 0; + #endif + #endif + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 || (PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 && PRINTF_LITE_FIELDWIDTH_SUPPORT == 1) + if ( printfParams->inPrecisionField ) + { + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 // just ignore if we don't support precision field + printfParams->precision_specifier *= 10; + printfParams->precision_specifier += ( c - '0'); + #endif + } + else + #endif + { + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + printfParams->inWidthField = 1; + printfParams->width_specifier *= 10; + printfParams->width_specifier += ( c - '0'); + #else + #if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 + // We just have to ignore field width + #else + // It's considered a mistake. Get out directive. Nothing will be printed. Harder to debug the format string for the user, but save sapce. + printfParams->inDirective = 0; + #endif + #endif + } + break; + +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + case '.': + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + printfParams->inWidthField = 0; + #endif + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 || (PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 && PRINTF_LITE_FIELDWIDTH_SUPPORT == 1) + printfParams->inPrecisionField = 1; + #endif + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + printfParams->precision_specifier = 0; + #endif + break; +#endif +#endif // PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 || PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + case 'z': + #if PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + printfParams->z_modifier = 1; + #else + printfParams->l_modifier = 2; + #endif + break; +#endif // PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_XSPECIFIER_SUPPORT == 1 + case 'x': + case 'X': + #if PRINTF_LITE_XSPECIFIER_SUPPORT == 1 + printfParams->uppercase = c == 'X'; + #if PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + if ( printfParams->z_modifier ) print_ulonglong(va_arg(VALIST_ACCESS(valist), size_t), 16, printfParams, 0); + else + #endif + #if PRINTF_LITE_LONGLONGINT_SUPPORT == 1 && PRINTF_LITE_LONGINT_SUPPORT == 1 + if ( printfParams->l_modifier == 2 ) print_ulonglong(va_arg(VALIST_ACCESS(valist), unsigned long long int), 16, printfParams, 0); + else + #endif + #if PRINTF_LITE_LONGINT_SUPPORT == 1 + if ( printfParams->l_modifier != 0 ) print_ulonglong(va_arg(VALIST_ACCESS(valist), unsigned long int), 16, printfParams, 0); + else + #endif + print_ulonglong(va_arg(VALIST_ACCESS(valist), unsigned int), 16, printfParams, 0); + printfParams->inDirective = 0; + break; + #endif +#endif // PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_XSPECIFIER_SUPPORT == 1 + +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_USPECIFIER_SUPPORT == 1 + case 'u': + #if PRINTF_LITE_USPECIFIER_SUPPORT == 1 + #if PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + if ( printfParams->z_modifier ) print_ulonglong(va_arg(VALIST_ACCESS(valist), size_t), 10, printfParams, 0); + else + #endif + #if PRINTF_LITE_LONGLONGINT_SUPPORT == 1 && PRINTF_LITE_LONGINT_SUPPORT == 1 + if ( printfParams->l_modifier == 2 ) print_ulonglong(va_arg(VALIST_ACCESS(valist), unsigned long long int), 10, printfParams, 0); + else + #endif // PRINTF_LITE_LONGLONGINT_SUPPORT == 1 && PRINTF_LITE_LONGINT_SUPPORT == 1 + #if PRINTF_LITE_LONGINT_SUPPORT == 1 + if ( printfParams->l_modifier != 0 ) print_ulonglong(va_arg(VALIST_ACCESS(valist), unsigned long int), 10, printfParams, 0); + else + #endif // PRINTF_LITE_LONGINT_SUPPORT == 1 + print_ulonglong(va_arg(VALIST_ACCESS(valist), unsigned int), 10, printfParams, 0); + printfParams->inDirective = 0; + break; + #endif // PRINTF_LITE_USPECIFIER_SUPPORT +#endif // PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_USPECIFIER_SUPPORT == 1 + + case 'd': + #if PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + if ( printfParams->z_modifier ) print_longlong(va_arg(VALIST_ACCESS(valist), size_t), 10, printfParams); // we are using longlong version for every int to save code size. + else + #endif + #if PRINTF_LITE_LONGLONGINT_SUPPORT == 1 && PRINTF_LITE_LONGINT_SUPPORT == 1 + if ( printfParams->l_modifier == 2 ) print_longlong(va_arg(VALIST_ACCESS(valist), long long int), 10, printfParams); // we are using longlong version for every int to save code size. + else + #endif + #if PRINTF_LITE_LONGINT_SUPPORT == 1 + if ( printfParams->l_modifier != 0 ) print_longlong(va_arg(VALIST_ACCESS(valist), long int), 10, printfParams); // we are using longlong version for every int to save code size. + else + #endif + print_longlong(va_arg(VALIST_ACCESS(valist), int), 10, printfParams); + printfParams->inDirective = 0; + break; + +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FLOAT_SUPPORT == 1 + case 'f': + #if PRINTF_LITE_FLOAT_SUPPORT == 1 + print_double(va_arg(VALIST_ACCESS(valist), double), printfParams); // 'float' is promoted to 'double' when passed through '...' + #elif PRINTF_LITE_FLOAT_AS_INT_SUPPORT == 1 + print_longlong((INT_BIGGEST_TYPE)va_arg(VALIST_ACCESS(valist), double), 10, printfParams); // Cost 144 byte on Arduino + #else + va_arg(VALIST_ACCESS(valist), double); // this cost 16 bytes on stm32, 8 bytes on Arduino + #endif + printfParams->inDirective = 0; + break; +#endif // PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FLOAT_SUPPORT == 1 + +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_LONGINT_SUPPORT == 1 || PRINTF_LITE_FLOAT_SUPPORT == 1 + case 'l': + #if PRINTF_LITE_LONGINT_SUPPORT == 1 + printfParams->l_modifier += 1; + #endif + break; +#endif + case 'c': +#if PRINTF_OUTPUT_FORMAT_UNICODE == 1 && PRINTF_UTF8_SUPPORT == 1 + if ( printfParams->l_modifier == 0 ) { + char c = (char)va_arg(VALIST_ACCESS(valist), int); + print_char(c, printfParams); // 'char' is promoted to 'int' when passed through '...' + printfParams->inDirective = 0; + }else +#endif + { +// wchar_t tmp2 = L'a'; +// int tmp1 = va_arg(VALIST_ACCESS(valist), int); +// int tmp3 = va_arg(VALIST_ACCESS(valist), wchar_t); + print_char((printf_char_type)va_arg(VALIST_ACCESS(valist), int), printfParams); // 'char' is promoted to 'int' when passed through '...' + printfParams->inDirective = 0; + } + break; +//#ifdef ARDUINO +//#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FLASHSTRING_SUPPORT == 1 +// case 'F': +// #if PRINTF_LITE_FLASHSTRING_SUPPORT == 1 +// print_Fstring(va_arg(VALIST_ACCESS(valist), char *), printfParams); +// #endif +// printfParams->inDirective = 0; +// break; +//#endif //PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FLASHSTRING_SUPPORT == 1 +//#else //ARDUINO +//#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FLASHSTRING_SUPPORT == 0 +// case 'F': +//#endif +//#endif + +#if PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 || PRINTF_LITE_FLASHSTRING_SUPPORT == 1 + case 'F': +#endif +#if defined(ARDUINO) && PRINTF_LITE_FLASHSTRING_SUPPORT == 1 + print_Fstring(va_arg(VALIST_ACCESS(valist), char *), printfParams); + printfParams->inDirective = 0; + break; +#endif //defined(ARDUINO) && PRINTF_LITE_FLASHSTRING_SUPPORT == 1 + case 's': +#if PRINTF_OUTPUT_FORMAT_UNICODE == 1 +#endif +#if PRINTF_OUTPUT_FORMAT_UNICODE == 1 && PRINTF_UTF8_SUPPORT == 1 + if ( printfParams->l_modifier == 0 ) { + print_string(va_arg(VALIST_ACCESS(valist), unsigned char *), printfParams); + printfParams->inDirective = 0; + }else +#endif + { + print_string(va_arg(VALIST_ACCESS(valist), printf_char_type *), printfParams); + printfParams->inDirective = 0; + } + break; + default: { + print_char('%', printfParams); + if ( c != '%' ) print_char(c, printfParams); + printfParams->inDirective = 0; + } + } + } + else + { + if ( c == '%' ) + { + printfParams->inDirective = 1; + printfParams->l_modifier = 0; + #if PRINTF_LITE_ZSPECIFIER_SUPPORT == 1 + printfParams->z_modifier = 0; + #endif + #if PRINTF_LITE_FIELDWIDTH_SUPPORT == 1 + printfParams->inWidthField = 0; + printfParams->width_specifier = 0; + #endif + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 || (PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED == 1 && PRINTF_LITE_FIELDWIDTH_SUPPORT == 1) + printfParams->inPrecisionField = 0; + #endif + #if PRINTF_LITE_FIELDPRECISION_SUPPORT == 1 + printfParams->precision_specifier = 6; // 6 digits for float, as specified by ANSI, if I remeber well + #endif + #if PRINTF_LITE_PADCHAR_SUPPORT == 1 + printfParams->pad_char = ' '; + #endif + } + else + { + print_char(c, printfParams); + } + } +} + +void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , int* newline, int timestamp +#endif + ) +{ + PrintfParams printfParams; + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + printfParams.newlinePtr = newline; + printfParams.timestamp = timestamp; + #endif + #if PRINTF_LITE_BUF_SIZE > 1 + printfParams.bufIdx = 0; + #endif + printfParams.inDirective = 0; + printfParams.transmitBufCallBack = transmitBufCallBack; + + while ( 1 ) //Iterate over formatting string + { + char c = *format++; + if (c == 0) break; + printf_handle_format_char(c, VALIST_PARAM(valist), &printfParams); + } + #if PRINTF_LITE_BUF_SIZE > 1 + if ( printfParams.bufIdx > 0 ) printfParams.transmitBufCallBack(printfParams.buf, printfParams.bufIdx); + #endif + + va_end(valist); +} + +void printf_with_callback(const char* format, transmitBufCallBackType transmitBufCallBack, +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + int* newline, int timestamp, +#endif + ...) +{ + va_list valist; + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + va_start(valist, timestamp); + #else + va_start(valist, transmitBufCallBack); + #endif + vprintf_with_callback(format, valist,transmitBufCallBack + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , NULL, 0 + #endif + ); + va_end(valist); +} + + +#if defined(ARDUINO) && PRINTF_LITE_FLASHSTRING_SUPPORT == 1 + +void vprintf_with_callback(const __FlashStringHelper *format, va_list valist, transmitBufCallBackType transmitBufCallBack +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , int* newline, int timestamp +#endif + ) +{ + PrintfParams printfParams; + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + printfParams.newlinePtr = newline; + printfParams.timestamp = timestamp; + #endif + #if PRINTF_LITE_BUF_SIZE > 1 + printfParams.bufIdx = 0; + #endif + printfParams.inDirective = 0; + printfParams.transmitBufCallBack = transmitBufCallBack; + + PGM_P p = reinterpret_cast(format); + while (1) + { + char c = pgm_read_byte(p++); + if (c == 0) break; + printf_handle_format_char(c, &valist, &printfParams); + } + #if PRINTF_LITE_BUF_SIZE > 1 + if ( printfParams.bufIdx > 0 ) printfParams.transmitBufCallBack(printfParams.buf, printfParams.bufIdx); + #endif + + va_end(valist); +} + +void printf_with_callback(const __FlashStringHelper* format, transmitBufCallBackType transmitBufCallBack, +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + int* newline, int timestamp, +#endif + ...) +{ + va_list valist; + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + va_start(valist, timestamp); + #else + va_start(valist, transmitBufCallBack); + #endif + vprintf_with_callback(format, valist, transmitBufCallBack + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , NULL, 0 + #endif + ); + va_end(valist); +} + +#endif // defined(ARDUINO) && PRINTF_LITE_FLASHSTRING_SUPPORT == 1 + +/* ------------------------ SPRINTF ------------------------ */ + +#if PRINTF_LITE_SNPRINTF_SUPPORT == 1 + +char* sprintfBuf; +size_t sprintfBufLen; + +void transmitSprintf(const char* buf, size_t nbyte) +{ + size_t i=0; + for ( ; sprintfBufLen>0 && i 1 ) { + __asm volatile ("bkpt 0"); + } + #else + if ( nbyte > PRINTF_LITE_BUF_SIZE ) { + __asm volatile ("bkpt 0"); + } + #endif + #endif +// uint32_t ms = HAL_GetTick() + 3000; +// while ( HAL_GetTick() < ms && CDC_Transmit_FS((char*)buf, nbyte) == USBD_BUSY ) {}; // If data isn't consumed by the host in 1 ms, it probaly won't be so we give up to not block. + + + uint32_t t0 = HAL_GetTick(); + uint8_t ret = CDC_Transmit_FS((uint8_t*)buf, (uint16_t)nbyte); // nbbyte is < BUF_MAX so it's safe to assume we can cast it to uint16_t. + if ( ret != USBD_OK ) + { + uint32_t now = HAL_GetTick(); + while ( now - t0 < 300 && ret != USBD_OK ) { // What to do if can't send ? With uart, there no flow control so char can get lost. + ret = CDC_Transmit_FS((uint8_t*)buf, (uint16_t)nbyte); + now = HAL_GetTick(); + } + } +} + +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 +static int usb_newline = 1; +#endif + +void printf_usb(const char* format, ...) +{ + va_list valist; + va_start(valist, format); + vprintf_with_callback(format, valist, transmitBufUsb + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , &usb_newline, 0 + #endif + ); + va_end(valist); +} + +void vlogf_usb(const char* format, va_list valist) +{ + vprintf_with_callback(format, valist, transmitBufUsb + #if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , &usb_newline, 1 + #endif + ); +} + +void logf_usb(const char* format, ...) +{ + va_list valist; + va_start(valist, format); + vlogf_usb(format, valist); + va_end(valist); +} +#endif + +#endif // PRINTF_LITE_USB_SUPPORT + +/* ------------------------ SERIAL ------------------------ */ +#if PRINTF_LITE_UART_SUPPORT == 1 + +#ifdef __STM32F1xx_HAL_UART_H // STM32 + + static void transmitBufUart(const char* buf, size_t nbyte) + { + int ret = HAL_UART_Transmit(&huart1, (uint8_t*)buf, (uint16_t)nbyte, 1000); // nbbyte is < BUF_MAX so it's safe to assume we can cast it to uint16_t. + + if ( ret != HAL_OK ) // this is only to be able to put a breakpoint in case the first HAL_UART_Transmit return !HAL_OK + { + while ( ret != HAL_OK ) + { + ssize_t nbByteNotTransmitted = huart1.TxXferCount + (ret == HAL_TIMEOUT ? 1 : 0); // size to transmit. + if ( nbByteNotTransmitted <= 0 ) { + #ifdef DEBUG + __asm volatile ("bkpt 0"); + #endif + } + buf += nbyte - nbByteNotTransmitted; + nbyte = nbByteNotTransmitted; + ret = HAL_UART_Transmit(&huart1, (uint8_t*)buf, (uint16_t)nbyte, 1000); + } + } + } + +#endif + +#ifdef ARDUINO + + static void transmitBufUart(const char* buf, size_t nbyte) + { + for (size_t i=0 ; i + static void transmitBufUart(const char* buf, size_t nbyte) + { + for (size_t i=0 ; i 0) { +// // Transfer the buffer to the device +// ret = trace_write(buf, (size_t) ret); +// } +// +} + +void printf_semih(const char* format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + vprintf_semih(format, ap); + va_end(ap); +} + +#endif + + + +/* ---------------------- LCD --------------------------- */ +#ifdef LiquidCrystal_h + +extern LiquidCrystal lcd; +static int lcd_newline = 1; // newline is static avoid being reinitialized at each call + +static void transmitBufLcd(const char* buf, size_t nbyte) +{ +// lcd.write(buf, nbyte); + for (size_t i=0 ; i +#include +#ifdef ARDUINO + #include + #ifdef HAS_LIQUID_CRYSTAL + #include + #endif +#endif + +#define PRINTF_OUTPUT_FORMAT_UNICODE 1 +#if PRINTF_OUTPUT_FORMAT_UNICODE == 1 +# define PRINTF_UTF8_SUPPORT 1 +#endif + +/* + * A buffer is not needed. On some case it could be faster. For example when using semihosting + * It's 255 max, because of bufIdx of type uint8_t. It's possible to change it to int if bigger buffer needed. + * This buffer isn't statically allocated so it won't use permanent RAM. + * Not more than int because of cast in transmitBufXXX functions. + * 2017/08/31 : Save 22 bytes + bufsize of my STM32F103 + */ +#ifndef PRINTF_LITE_BUF_SIZE +#define PRINTF_LITE_BUF_SIZE 0 +#endif +/* + * Fallback on something close if specifier is'nt supported. + * Unsupported specifier are ignored. + * if 0, any unsupported modifier or specifier will be seen as unknown. + */ +#ifndef PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED +#define PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED 1 +#endif +#ifndef PRINTF_LITE_FLOAT_SUPPORT +#define PRINTF_LITE_FLOAT_SUPPORT 1 +#endif +/* + * The int part of the float (or double) will be printed if PRINTF_LITE_FLOAT_SUPPORT is enabled + * June 2017, avr-gcc 4.9.2-atmel3.5.4-arduino2 : + * Float support increase 828 bytes of text and 16 bytes of data + */ +#ifndef PRINTF_LITE_FLOAT_AS_INT_SUPPORT +#define PRINTF_LITE_FLOAT_AS_INT_SUPPORT 1 // if float not supported, an int will be print instead. +#endif +/* + * Disabling LONG LONG support has an effect on printing double. If long int is disabled, the int part of the double has to be < ULONG_MAX + */ +#ifndef PRINTF_LITE_LONGLONGINT_SUPPORT +#define PRINTF_LITE_LONGLONGINT_SUPPORT 1 // 1712 bytes +#endif +/* + * Disabling LONG support automatically disable LONG LONG support whatever the value of PRINTF_LITE_LONGLONGINT_SUPPORT. + * Disabling LONG support has an effect on printing double. The int part of the double has to be < UINT_MAX max + */ +#ifndef PRINTF_LITE_LONGINT_SUPPORT +#define PRINTF_LITE_LONGINT_SUPPORT 1 // 1712 bytes +#endif +#ifndef PRINTF_LITE_TIMESTAMP_SUPPORT +#define PRINTF_LITE_TIMESTAMP_SUPPORT 0 // 240 bytes +#endif +#ifndef PRINTF_LITE_FIELDWIDTH_SUPPORT +#define PRINTF_LITE_FIELDWIDTH_SUPPORT 1 // 107 bytes +#endif +#ifndef PRINTF_LITE_FIELDPRECISION_SUPPORT +#define PRINTF_LITE_FIELDPRECISION_SUPPORT 1 // bytes +#endif +#ifndef PRINTF_LITE_PADCHAR_SUPPORT +#define PRINTF_LITE_PADCHAR_SUPPORT 1 // bytes +#endif +#ifndef PRINTF_LITE_ZSPECIFIER_SUPPORT +#define PRINTF_LITE_ZSPECIFIER_SUPPORT 1 // 230 bytes. If not supported, z modifier become llu +#endif +#ifndef PRINTF_LITE_XSPECIFIER_SUPPORT +#define PRINTF_LITE_XSPECIFIER_SUPPORT 1 // 96 bytes. If not supported, x specifier become u +#endif +#ifndef PRINTF_LITE_USPECIFIER_SUPPORT +#define PRINTF_LITE_USPECIFIER_SUPPORT 1 // 96 bytes. If not supported, u specifier become d +#endif + +#ifndef PRINTF_LITE_UART_SUPPORT +#define PRINTF_LITE_UART_SUPPORT 0 // +#endif +#ifndef PRINTF_LITE_USB_SUPPORT +#define PRINTF_LITE_USB_SUPPORT 0 // +#endif +#ifndef PRINTF_LITE_SNPRINTF_SUPPORT +#define PRINTF_LITE_SNPRINTF_SUPPORT 0 // +#endif +#ifndef PRINTF_LITE_FLASHSTRING_SUPPORT +#define PRINTF_LITE_FLASHSTRING_SUPPORT 0 // +#endif + + +#if PRINTF_OUTPUT_FORMAT_UNICODE == 1 +# define printf_char_type wchar_t +#else +# define printf_char_type char +#endif + +typedef void (*transmitBufCallBackType)(const printf_char_type* buf, size_t nbyte); +void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack +#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1 + , int* newline, int timestamp +#endif + ); + +#if defined(__cplusplus) +extern "C" +{ +#endif + #if PRINTF_LITE_SNPRINTF_SUPPORT == 1 + int vsnprintf(char *__restrict, size_t, const char *__restrict, va_list valist) __attribute__ ((__format__ (__printf__, 3, 0))); // have to return int to conform stdio.h. Always return 1; + + // gcc-4.9.2-atmel3.5.4-arduino2 report snprintf to undefined. Change the name and it'll work. String isn't it ? + int snprintf(char *__restrict buf, size_t len, const char *__restrict format, ...) __attribute__((__format__ (__printf__, 3, 4))); // have to return int to conform stdio.h. Always return 1; + #endif + + #if PRINTF_LITE_UART_SUPPORT == 1 + void vprintf_uart(const char* str, va_list valist); + void printf_uart(const char *str, ...) __attribute__((format(printf, 1, 2))); + void vlogf_uart(const char* str, va_list valist); + void logf_uart(const char *str, ...) __attribute__((format(printf, 1, 2))); // same as printf_uart but print a timestamp at beginning of line. + #endif + + #ifdef LiquidCrystal_h + void printf_lcd(int row, int col, const char *str, ...) __attribute__((format(printf, 3, 4))); + #endif + #if PRINTF_LITE_USB_SUPPORT == 1 && defined(__USBD_CDC_IF_H) + void transmitBufUsb(const char* buf, size_t nbyte); + void printf_usb(const char *str, ...) __attribute__((format(printf, 1, 2))); + void vlogf_usb(const char* str, va_list valist); + void logf_usb(const char *str, ...) __attribute__((format(printf, 1, 2))); + #endif + + #if defined(OS_USE_TRACE_ITM) || defined(OS_USE_TRACE_SEMIHOSTING_DEBUG) || defined(OS_USE_TRACE_SEMIHOSTING_STDOUT) + void vprintf_semih(const char* str, va_list valist); + void printf_semih(const char* format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); + #endif +#if defined(__cplusplus) +} +#endif + + +#if defined(__cplusplus) + + #if defined(ARDUINO) && PRINTF_LITE_FLASHSTRING_SUPPORT == 1 + int vsnprintf(char *__restrict, size_t, const __FlashStringHelper *__restrict, va_list valist); // have to return int to conform stdio.h. Always return 1; + // gcc-4.9.2-atmel3.5.4-arduino2 report snprintf to undefined. Change the name and it'll work. String isn't it ? + int snprintf(char *__restrict buf, size_t len, const __FlashStringHelper * format, ...); // have to return int to conform stdio.h. Always return 1; + + // C code can't access this because __FlashStringHelper is a class + void vlogf_uart(const __FlashStringHelper* str, va_list valist); + + #ifdef __JIEF_FLASHSTRING_PRINTFWARNING_HACK__ + void printf_uart(const __FlashStringHelper *str, ...) __attribute__((format(printf, 1, 2))); + void logf_uart(const __FlashStringHelper *str, ...) __attribute__((format(printf, 1, 2))); // same as printf_uart but print a timestamp at beginning of line. + #ifdef LiquidCrystal_h + void printf_lcd(int row, int col, const __FlashStringHelper *str, ...) __attribute__((format(printf, 3, 4))); + #endif + #else + // if __JIEF_FLASHSTRING_PRINTFWARNING_HACK isn't defined, it means you don't use my hacked version of GCC. "Normal" version can't handle const __FlashStringHelper* as format for warning + void printf_uart(const __FlashStringHelper *str, ...); + void logf_uart(const __FlashStringHelper *str, ...); // same as printf_uart but print a timestamp at beginning of line. + #ifdef LiquidCrystal_h + void printf_lcd(int row, int col, const __FlashStringHelper *str, ...); + #endif + #endif + #endif + +#endif + + +#endif // __PRINTF_LITE_H__