diff --git a/Core/Inc/FreeRTOSConfig.h b/Core/Inc/FreeRTOSConfig.h index 2b0dda2..1d62fa6 100644 --- a/Core/Inc/FreeRTOSConfig.h +++ b/Core/Inc/FreeRTOSConfig.h @@ -137,8 +137,8 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ /* Normal assert() semantics without relying on the provision of an assert.h header file. */ /* USER CODE BEGIN 1 */ -#include -#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); printf("configASSERT "__FILE__":%d\r\n",__LINE__); for( ;; );} +#include "snprintf.h" +#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); PRINTF("configASSERT "__FILE__":%d\r\n",__LINE__); for( ;; );} /* USER CODE END 1 */ /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS diff --git a/Core/Src/app_heater.c b/Core/Src/app_heater.c index e98ebc3..21ab3f9 100644 --- a/Core/Src/app_heater.c +++ b/Core/Src/app_heater.c @@ -66,14 +66,14 @@ void app_heater_set_tuning(float p, float i, float d) { } void app_heater_enable(bool enable) { - printf("Set heater enabled = %d\r\n", (int) enable); + PRINTF("Set heater enabled = %d\r\n", (int) enable); heaterEnterCritical(); PID_SetCtlMode(&state.pid, enable ? PID_AUTOMATIC : PID_MANUAL); heaterExitCritical(); } void app_heater_set_target(float target) { - printf("Set heater target = %d\r\n", (int) target); + PRINTF("Set heater target = %d\r\n", (int) target); heaterEnterCritical(); PID_SetSetpoint(&state.pid, target); heaterExitCritical(); @@ -99,7 +99,7 @@ void app_task_heater(void *argument) heaterEnterCritical(); PID_Compute(&state.pid, state.oven_temp); if (state.pid.ctlMode == PID_AUTOMATIC) { - printf("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output); + PRINTF("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output); heater_pwm_set_perc(state.pid.Output); } else { // turn it off diff --git a/Core/Src/app_main.c b/Core/Src/app_main.c index d825a32..73786af 100644 --- a/Core/Src/app_main.c +++ b/Core/Src/app_main.c @@ -33,13 +33,13 @@ static void redraw_display() { char tmp[100]; - sprintf(tmp, "T=%d°C", (int) s_app.oven_temp); + PRINTF(tmp, "T=%d°C", (int) s_app.oven_temp); fb_text(3, 3, tmp, FONT_5X7, 1); - sprintf(tmp, "Cil=%d°C", s_app.set_temp); + PRINTF(tmp, "Cil=%d°C", s_app.set_temp); fb_text(3, 11, tmp, FONT_5X7, 1); - sprintf(tmp, "Stav=%s", s_app.run ? "ZAP" : "VYP"); + PRINTF(tmp, "Stav=%s", s_app.run ? "ZAP" : "VYP"); fb_text(3, 19, tmp, FONT_5X7, 1); if (s_app.run) { @@ -83,7 +83,7 @@ static void redraw_display() { void app_task_main(void *argument) { - printf("Main task\r\n"); + PUTS("Main task\r\n"); app_analog_init(); app_buzzer_init(); app_knob_init(); @@ -98,7 +98,7 @@ void app_task_main(void *argument) bool any_change = true; uint32_t last_redraw = osKernelGetTickCount(); - printf("Loop\r\n"); + PUTS("Loop\r\n"); for (;;) { // sampling is done in the heater loop diff --git a/Core/Src/app_pid.c b/Core/Src/app_pid.c index fe1ae0f..6d1af5e 100644 --- a/Core/Src/app_pid.c +++ b/Core/Src/app_pid.c @@ -25,7 +25,7 @@ void PID_Compute(struct PID *self, float input) uint32_t now = xTaskGetTickCount(); int32_t timeChange = (now - self->lastTime); if (timeChange >= self->SampleTimeTicks) { - printf("compute\r\n"); + PUTS("compute\r\n"); /*Compute all the working error variables*/ float error = self->Setpoint - input; self->ITerm += (self->ki * error); @@ -35,7 +35,7 @@ void PID_Compute(struct PID *self, float input) float dInput = (input - self->lastInput); - printf("calc x100 %d + %d - %d\r\n", + PRINTF("calc x100 %d + %d - %d\r\n", (int) (100 * (self->kp * error)), (int) (100 * (self->ITerm)), (int) (100 * (self->kd * dInput)) diff --git a/Core/Src/app_temp.c b/Core/Src/app_temp.c index 510fa59..382557e 100644 --- a/Core/Src/app_temp.c +++ b/Core/Src/app_temp.c @@ -9,6 +9,7 @@ #include #include "app_temp.h" #include "adc.h" +#include "snprintf.h" /* DMA dest */ static volatile uint16_t adc_values[4]; @@ -247,5 +248,5 @@ void app_temp_adc_eos() void app_temp_show_buf() { - printf("%d,%d,%d,%d\r\n", adc_values[0], adc_values[1], adc_values[2], adc_values[3]); + PRINTF("%d,%d,%d,%d\r\n", adc_values[0], adc_values[1], adc_values[2], adc_values[3]); } diff --git a/Core/Src/freertos.c b/Core/Src/freertos.c index 2dab5ef..84b748c 100644 --- a/Core/Src/freertos.c +++ b/Core/Src/freertos.c @@ -25,7 +25,7 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ -#include +#include "snprintf.h" /* USER CODE END Includes */ @@ -135,7 +135,7 @@ void vApplicationMallocFailedHook(void); /* USER CODE BEGIN 4 */ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { - printf("vApplicationStackOverflowHook: %s\r\n", pcTaskName); + PRINTF("vApplicationStackOverflowHook: %s\r\n", pcTaskName); /* Run time stack overflow checking is performed if configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is called if a stack overflow is detected. */ @@ -145,7 +145,7 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) /* USER CODE BEGIN 5 */ void vApplicationMallocFailedHook(void) { - printf("vApplicationMallocFailedHook\r\n"); + PUTS("vApplicationMallocFailedHook\r\n"); /* vApplicationMallocFailedHook() will only be called if configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook function that will get called if a call to pvPortMalloc() fails. diff --git a/Core/Src/main.c b/Core/Src/main.c index 94e72ec..ceff3fd 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -120,7 +120,7 @@ int main(void) MX_SPI2_Init(); /* USER CODE BEGIN 2 */ - printf("Start.\r\n"); + PUTS("Start.\r\n"); /* USER CODE END 2 */ /* Init scheduler */ @@ -203,7 +203,7 @@ void Error_Handler(void) /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); - printf("Error_Handler\r\n"); + PUTS("Error_Handler\r\n"); while (1) { } @@ -221,6 +221,7 @@ void Error_Handler(void) void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ + PRINTF("assert_failed %s:%d", (const char *) file, (int) line); /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ diff --git a/Core/Src/stm32f1xx_it.c b/Core/Src/stm32f1xx_it.c index efcd890..6355db2 100644 --- a/Core/Src/stm32f1xx_it.c +++ b/Core/Src/stm32f1xx_it.c @@ -88,7 +88,7 @@ void NMI_Handler(void) void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ - printf("HardFault_Handler\r\n"); + PUTS("HardFault_Handler\r\n"); /* USER CODE END HardFault_IRQn 0 */ while (1) @@ -104,7 +104,7 @@ void HardFault_Handler(void) void MemManage_Handler(void) { /* USER CODE BEGIN MemoryManagement_IRQn 0 */ - printf("MemManage_Handler\r\n"); + PUTS("MemManage_Handler\r\n"); /* USER CODE END MemoryManagement_IRQn 0 */ while (1) @@ -120,7 +120,7 @@ void MemManage_Handler(void) void BusFault_Handler(void) { /* USER CODE BEGIN BusFault_IRQn 0 */ - printf("BusFault_Handler\r\n"); + PUTS("BusFault_Handler\r\n"); /* USER CODE END BusFault_IRQn 0 */ while (1) @@ -136,7 +136,7 @@ void BusFault_Handler(void) void UsageFault_Handler(void) { /* USER CODE BEGIN UsageFault_IRQn 0 */ - printf("UsageFault_Handler\r\n"); + PUTS("UsageFault_Handler\r\n"); /* USER CODE END UsageFault_IRQn 0 */ while (1) diff --git a/Core/Src/usart.c b/Core/Src/usart.c index 547bdba..3194fea 100644 --- a/Core/Src/usart.c +++ b/Core/Src/usart.c @@ -21,6 +21,8 @@ #include "usart.h" /* USER CODE BEGIN 0 */ +#include +#include #include "main.h" /* USER CODE END 0 */ @@ -75,17 +77,30 @@ void MX_USART1_UART_Init(void) } /* USER CODE BEGIN 1 */ +void stdout_write(const char *pcBuffer, const size_t iLength) { + int cnt = (int) iLength; + while (cnt-- > 0) { + while (!LL_USART_IsActiveFlag_TXE(USART_DEBUG)) {} + LL_USART_TransmitData8(USART_DEBUG, *pcBuffer++); + } +} + +void stdout_puts(const char *pcBuffer) { + stdout_write(pcBuffer, strlen(pcBuffer)); +} + +void stdout_putchar(char c) { + while (!LL_USART_IsActiveFlag_TXE(USART_DEBUG)) {} + LL_USART_TransmitData8(USART_DEBUG, c); +} + /** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */ int _write(int fd, const char *pcBuffer, const int iLength) { - int cnt = iLength; - while (cnt-- > 0) { - while (!LL_USART_IsActiveFlag_TXE(USART_DEBUG)) {} - LL_USART_TransmitData8(USART_DEBUG, *pcBuffer++); - } + stdout_write(pcBuffer, iLength); return iLength; } diff --git a/Lib/snprintf/snprintf.c b/Lib/snprintf/snprintf.c new file mode 100644 index 0000000..d924fc5 --- /dev/null +++ b/Lib/snprintf/snprintf.c @@ -0,0 +1,1040 @@ +// +// Created by MightyPork on 2017/11/09. +// + +#include "snprintf.h" + +/* + * snprintf.c + * ripped from rsync sources by pts@inf.bme.hu at Thu Mar 7 18:16:00 CET 2002 + * ripped from reTCP sources by pts@fazekas.hu at Tue Jun 11 14:47:01 CEST 2002 + * ripped from sam2p (ftp://ftp.dante.de/tex-archive/graphics/sam2p/snprintf.c) by MightyPork, 9 Nov 2017 + * + * Why does this .c file rock? + * + * -- minimal dependencies: only is included + * -- minimal dependencies: not even -lm is required + * -- can print floating point numbers + * -- can print `long long' and `long double' + * -- C99 semantics (NULL arg for vsnprintf OK, always returns the length + * that would have been printed) + * -- provides all vsnprintf(), snprintf(), vasprintf(), asprintf() + */ + +#include "snprintf.h" + +// malloc/free +#include "FreeRTOS.h" + +#define my_malloc(len) pvPortMalloc((len)) +#define my_free(p) vPortFree((p)) + +// Toggle features +#define size_t size_t /* normally: int, unsigned */ +#undef HAVE_LONG_DOUBLE +#undef HAVE_LONG_LONG +#undef TEST_SNPRINTF +#undef DEBUG_SNPRINTF +#define SUPPORT_FLOAT 1 + + + +// defines for use within this file +#define vsnprintf fixup_vsnprintf +#define snprintf fixup_snprintf +#define vasprintf fixup_vasprintf +#define asprintf fixup_asprintf +#define sprintf fixup_sprintf +#define printf fixup_printf +#define vprintf fixup_vprintf + + +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions + */ + +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formated the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * Andrew Tridgell (tridge@samba.org) Oct 1998 + * fixed handling of %.0f + * added test for HAVE_LONG_DOUBLE + * + * tridge@samba.org, idra@samba.org, April 2001 + * got rid of fcvt code (twas buggy and made testing harder) + * added C99 semantics + * + **************************************************************/ + + +#if HAVE_LONG_DOUBLE && NEED_LONG_DOUBLE +#define LDOUBLE long double +#else +#define LDOUBLE double +#endif + +#if HAVE_LONG_LONG && NEED_LONG_LONG +#define LLONG long long +#else +#define LLONG long +#endif + +static size_t dopr(char *buffer, size_t maxlen, const char *format, + va_list args); + +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); + +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags); + +static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags); + +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 +#define DP_C_LLONG 4 + +#define char_to_int(p) ((p) - '0') +#ifndef MAX +#define MAX(p, q) (((p) >= (q)) ? (p) : (q)) +#endif + +/**** pts ****/ +#undef isdigit +#define isdigit(c) ((unsigned char)((c)-'0')<=(unsigned char)('9'-'0')) + +static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args) +{ + char ch; + LLONG value; + LDOUBLE fvalue = 0; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + size_t currlen; + + state = DP_S_DEFAULT; + currlen = flags = cflags = min = 0; + max = -1; + ch = *format++; + + while (state != DP_S_DONE) { + if (ch == '\0') { + state = DP_S_DONE; + } + + switch (state) { + case DP_S_DEFAULT: + if (ch == '%') { + state = DP_S_FLAGS; + } else { + dopr_outch(buffer, &currlen, maxlen, ch); + } + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char) ch)) { + min = 10 * min + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } else { + state = DP_S_DOT; + } + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MAX: + if (isdigit((unsigned char) ch)) { + if (max < 0) { + max = 0; + } + max = 10 * max + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + if (ch == 'l') { /* It's a long long */ + cflags = DP_C_LLONG; + ch = *format++; + } + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) { + value = va_arg (args, int); + } else if (cflags == DP_C_LONG) { + value = va_arg (args, long int); + } else if (cflags == DP_C_LLONG) { + value = va_arg (args, LLONG); + } else { + value = va_arg (args, int); + } + fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); + break; +// case 'o': +// flags |= DP_F_UNSIGNED; +// if (cflags == DP_C_SHORT) +// value = va_arg (args, unsigned int); +// else if (cflags == DP_C_LONG) +// value = (long)va_arg (args, unsigned long int); +// else if (cflags == DP_C_LLONG) +// value = (long)va_arg (args, unsigned LLONG); +// else +// value = (long)va_arg (args, unsigned int); +// fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); +// break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) { + value = va_arg (args, unsigned int); + } else if (cflags == DP_C_LONG) { + value = (long) va_arg (args, unsigned long int); + } else if (cflags == DP_C_LLONG) { + value = (LLONG) va_arg (args, unsigned LLONG); + } else { + value = (long) va_arg (args, unsigned int); + } + fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) { + value = va_arg (args, unsigned int); + } else if (cflags == DP_C_LONG) { + value = (long) va_arg (args, unsigned long int); + } else if (cflags == DP_C_LLONG) { + value = (LLONG) va_arg (args, unsigned LLONG); + } else { + value = (long) va_arg (args, unsigned int); + } + fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); + break; +#if SUPPORT_FLOAT + case 'f': + if (cflags == DP_C_LDOUBLE) { + fvalue = va_arg (args, LDOUBLE); + } else { + fvalue = va_arg (args, double); + } + /* um, floating point? */ + fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) { + fvalue = va_arg (args, LDOUBLE); + } else { + fvalue = va_arg (args, double); + } + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) { + fvalue = va_arg (args, LDOUBLE); + } else { + fvalue = va_arg (args, double); + } + break; +#endif + case 'c': + dopr_outch(buffer, &currlen, maxlen, (char) va_arg (args, int)); + break; + case 's': + strvalue = va_arg (args, char *); + if (max == -1) { + /**** pts ****/ + for (max = 0; strvalue[max]; ++max) {} /* strlen */ + } + if (min > 0 && max >= 0 && min > max) { max = min; } + fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = (char *) (va_arg (args, void *)); + fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + break; +// case 'n': +// if (cflags == DP_C_SHORT) { +// short int *num; +// num = va_arg (args, short int *); +// *num = currlen; +// } else if (cflags == DP_C_LONG) { +// long int *num; +// num = va_arg (args, long int *); +// *num = (long int)currlen; +// } else if (cflags == DP_C_LLONG) { +// LLONG *num; +// num = va_arg (args, LLONG *); +// *num = (LLONG)currlen; +// } else { +// int *num; +// num = va_arg (args, int *); +// *num = currlen; +// } +// break; + case '%': + dopr_outch(buffer, &currlen, maxlen, ch); + break; +// case 'w': +// /* not supported yet, treat as next char */ +// ch = *format++; +// break; + default: + /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (maxlen != 0) { + if (currlen < maxlen - 1) { + buffer[currlen] = '\0'; + } else if (maxlen > 0) { + buffer[maxlen - 1] = '\0'; + } + } + + (void) fvalue; // mark as used + + return currlen; +} + +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int padlen, strln; /* amount to pad */ + int cnt = 0; + +#ifdef DEBUG_SNPRINTF + printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); +#endif + if (value == 0) { + value = ""; + } + + for (strln = 0; value[strln]; ++strln) {} /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while ((padlen > 0) && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, ' '); + --padlen; + ++cnt; + } + while (*value && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, *value++); + ++cnt; + } + while ((padlen < 0) && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, ' '); + ++padlen; + ++cnt; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags) +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + int caps = 0; + + if (max < 0) { + max = 0; + } + + uvalue = value; + + if (!(flags & DP_F_UNSIGNED)) { + if (value < 0) { + signvalue = '-'; + uvalue = -value; + } else { + if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ + signvalue = '+'; + } else if (flags & DP_F_SPACE) { + signvalue = ' '; + } + } + } + + if (flags & DP_F_UP) { caps = 1; } /* Should characters be upper case? */ + + do { + convert[place++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned) base]; + uvalue = (uvalue / (unsigned) base); + } while (uvalue && (place < 20)); + if (place == 20) place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) zpadlen = 0; + if (spadlen < 0) spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + +#ifdef DEBUG_SNPRINTF + printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", + zpadlen, spadlen, min, max, place); +#endif + + /* Spaces */ + while (spadlen > 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch(buffer, currlen, maxlen, (char) signvalue); /* pacify VC6.0 */ + + /* Zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch(buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static LDOUBLE __attribute__((const)) abs_val(LDOUBLE value) +{ + LDOUBLE result = value; + + if (value < 0) { + result = -value; + } + + return result; +} + +static LDOUBLE __attribute__((const)) POW10(int exp) +{ + LDOUBLE result = 1; + + while (exp) { + result *= 10; + exp--; + } + + return result; +} + +static LLONG __attribute__((const)) ROUND(LDOUBLE value) +{ + LLONG intpart; + + intpart = (LLONG) value; + value = value - intpart; + if (value >= 0.5) { intpart++; } + + return intpart; +} + +///* a replacement for modf that doesn't need the math library. Should +// be portable, but slow */ +//static double my_modf(double x0, double *iptr) +//{ +// int i; +// long l=0; +// double x = x0; +// double f = 1.0; +// +// for (i=0;i<100;i++) { +// l = (long)x; +// if (l <= (x+1) && l >= (x-1)) break; +// x *= 0.1; +// f *= 10.0; +// } +// +// if (i == 100) { +// /* yikes! the number is beyond what we can handle. What do we do? */ +// (*iptr) = 0; +// return 0; +// } +// +// if (i != 0) { +// double i2; +// double ret; +// +// ret = my_modf(x0-l*f, &i2); +// (*iptr) = l*f + i2; +// return ret; +// } +// +// (*iptr) = l; +// return x - (*iptr); +//} + +#include + +#define my_modf(x0, iptr) modf(x0, iptr) + +#if SUPPORT_FLOAT + +static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags) +{ + int signvalue = 0; + double ufvalue; + char iconvert[311]; + char fconvert[311]; + int iplace = 0; + int fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0; + int caps = 0; + int index; + double intpart; + double fracpart; + double temp; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) { + max = 6; + } + + ufvalue = abs_val(fvalue); + + if (fvalue < 0) { + signvalue = '-'; + } else { + if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ + signvalue = '+'; + } else { + if (flags & DP_F_SPACE) { + signvalue = ' '; + } + } + } + +#if 0 + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ +#endif + +#if 0 + if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ +#endif + + /* + * Sorry, we only support 16 digits past the decimal because of our + * conversion method + */ + if (max > 16) { + max = 16; + } + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + + temp = ufvalue; + my_modf(temp, &intpart); + + fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); + + if (fracpart >= POW10(max)) { + intpart++; + fracpart -= POW10(max); + } + + + /* Convert integer part */ + do { + temp = intpart; + my_modf(intpart * 0.1, &intpart); + temp = temp * 0.1; + index = (int) ((temp - intpart + 0.05) * 10.0); + /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ + /* printf ("%llf, %f, %x\n", temp, intpart, index); */ + iconvert[iplace++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef")[index]; + } while (intpart && (iplace < 311)); + if (iplace == 311) { iplace--; } + iconvert[iplace] = 0; + + /* Convert fractional part */ + if (fracpart) { + do { + temp = fracpart; + my_modf(fracpart * 0.1, &fracpart); + temp = temp * 0.1; + index = (int) ((temp - fracpart + 0.05) * 10.0); + /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */ + /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */ + fconvert[fplace++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef")[index]; + } while (fracpart && (fplace < 311)); + if (fplace == 311) { fplace--; } + } + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) { zpadlen = 0; } + if (padlen < 0) { + padlen = 0; + } + if (flags & DP_F_MINUS) { + padlen = -padlen; + } /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + dopr_outch(buffer, currlen, maxlen, (char) signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch(buffer, currlen, maxlen, (char) signvalue); + + while (iplace > 0) + dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); + +#ifdef DEBUG_SNPRINTF + printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); +#endif + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + if (max > 0) { + dopr_outch(buffer, currlen, maxlen, '.'); + + while (fplace > 0) + dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); + } + + while (zpadlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (padlen < 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +#endif /* SUPPORT_FLOAT */ + +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) { + buffer[(*currlen)] = c; + } + (*currlen)++; +} + +int vsnprintf(char *str, size_t count, const char *fmt, va_list args) +{ + return dopr(str, count, fmt, args); +} + +int snprintf(char *str, size_t count, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vsnprintf(str, count, fmt, ap); + va_end(ap); + return ret; +} + + +int vasprintf(char **ptr, const char *format, va_list ap) +{ + int ret; + + ret = vsnprintf((char *) NULL, 0, format, ap); + if (ret + 1 <= 1) { return ret; } /* pts: bit of old unsigned trick... */ + + if (NULL == (*ptr = (char *) my_malloc(ret + 1))) { return -1; } + ret = vsnprintf(*ptr, ret + 1, format, ap); + + return ret; +} + +int asprintf(char **ptr, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = vasprintf(ptr, format, ap); + va_end(ap); + + return ret; +} + +/**** pts ****/ +int sprintf(char *ptr, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = vsnprintf(ptr, (size_t) -1, format, ap); + va_end(ap); + + return ret; +} + +int printf(const char *format, ...) +{ + va_list ap; + int ret; + + char *ptr = NULL; + + va_start(ap, format); + ret = vasprintf(&ptr, format, ap); + va_end(ap); + + if (!ptr) { + return 0; + } + + WRITE(ptr, ret); + my_free(ptr); + + return ret; +} + +int vprintf(const char *format, va_list ap) +{ + int ret; + char *ptr = NULL; + + ret = vasprintf(&ptr, format, ap); + + if (!ptr) { + return 0; + } + + WRITE(ptr, ret); + my_free(ptr); + + return ret; +} + + +#ifdef TEST_SNPRINTF + +size_t sprintf(char *str,const char *fmt,...); + + int main (void) +{ + char buf1[1024]; + char buf2[1024]; + char *fp_fmt[] = { + "%1.1f", + "%-1.5f", + "%1.5f", + "%123.9f", + "%10.5f", + "% 10.5f", + "%+22.9f", + "%+4.9f", + "%01.3f", + "%4f", + "%3.1f", + "%3.2f", + "%.0f", + "%f", + "-16.16f", + NULL + }; + double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, + 0.9996, 1.996, 4.136, 0}; + char *int_fmt[] = { + "%-1.5d", + "%1.5d", + "%123.9d", + "%5.5d", + "%10.5d", + "% 10.5d", + "%+22.33d", + "%01.3d", + "%4d", + "%d", + NULL + }; + long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; + char *str_fmt[] = { + "10.5s", + "5.10s", + "10.1s", + "0.10s", + "10.0s", + "1.10s", + "%s", + "%.1s", + "%.10s", + "%10s", + NULL + }; + char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; + int x, y; + int fail = 0; + int num = 0; + + printf ("Testing snprintf format codes against system sprintf...\n"); + + for (x = 0; fp_fmt[x] ; x++) { + for (y = 0; fp_nums[y] != 0 ; y++) { + int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]); + int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); + sprintf (buf2, fp_fmt[x], fp_nums[y]); + if (strcmp (buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", + fp_fmt[x], buf1, buf2); + fail++; + } + if (l1 != l2) { + printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]); + fail++; + } + num++; + } + } + + for (x = 0; int_fmt[x] ; x++) { + for (y = 0; int_nums[y] != 0 ; y++) { + int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]); + int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); + sprintf (buf2, int_fmt[x], int_nums[y]); + if (strcmp (buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", + int_fmt[x], buf1, buf2); + fail++; + } + if (l1 != l2) { + printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]); + fail++; + } + num++; + } + } + + for (x = 0; str_fmt[x] ; x++) { + for (y = 0; str_vals[y] != 0 ; y++) { + int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]); + int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); + sprintf (buf2, str_fmt[x], str_vals[y]); + if (strcmp (buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", + str_fmt[x], buf1, buf2); + fail++; + } + if (l1 != l2) { + printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]); + fail++; + } + num++; + } + } + + printf ("%d tests failed out of %d.\n", fail, num); + + printf("seeing how many digits we support\n"); + { + double v0 = 0.12345678901234567890123456789012345678901; + for (x=0; x<100; x++) { + snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x)); + sprintf(buf2, "%1.1f", v0*pow(10, x)); + if (strcmp(buf1, buf2)) { + printf("we seem to support %d digits\n", x-1); + break; + } + } + } + + return 0; +} +#endif /* SNPRINTF_TEST */ diff --git a/Lib/snprintf/snprintf.h b/Lib/snprintf/snprintf.h new file mode 100644 index 0000000..365df00 --- /dev/null +++ b/Lib/snprintf/snprintf.h @@ -0,0 +1,39 @@ +// +// Created by MightyPork on 2017/11/09. +// +// Small sprintf/snprintf implementation, used instead of the newlib one. +// + +#ifndef GEX_SNPRINTF_H +#define GEX_SNPRINTF_H + +#include +#include + +int fixup_vsnprintf(char *str, size_t count, const char *fmt, va_list args); +int fixup_snprintf(char *str, size_t count,const char *fmt,...); +int fixup_vasprintf(char **ptr, const char *format, va_list ap); +int fixup_asprintf(char **ptr, const char *format, ...); +int fixup_sprintf(char *ptr, const char *format, ...); +int fixup_printf(const char *format, ...); +int fixup_vprintf(const char *format, va_list ap); + +#define VSNPRINTF(...) fixup_vsnprintf(__VA_ARGS__) +#define SNPRINTF(...) fixup_snprintf(__VA_ARGS__) +#define VASPRINTF(...) fixup_vasprintf(__VA_ARGS__) +#define ASPRINTF(...) fixup_asprintf(__VA_ARGS__) +#define SPRINTF(...) fixup_sprintf(__VA_ARGS__) +#define PRINTF(...) fixup_printf(__VA_ARGS__) +#define VPRINTF(...) fixup_vprintf(__VA_ARGS__) + +// extern + +extern void stdout_puts(const char *s); +extern void stdout_putchar(char c); +extern void stdout_write(const char *s, size_t len); + +#define PUTS(s) stdout_puts((s)) +#define PUTCHAR(c) stdout_putchar((c)) +#define WRITE(s, n) stdout_write((s), (n)) + +#endif //GEX_SNPRINTF_H diff --git a/Makefile b/Makefile index 019ad76..05e738f 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ ########################################################################################################################## -# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Sun Mar 12 14:42:27 CET 2023] +# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Sun Mar 12 14:42:27 CET 2023] ########################################################################################################################## # ------------------------------------------------ @@ -64,7 +64,12 @@ Middlewares/Third_Party/FreeRTOS/Source/timers.c \ Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \ Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c \ -Lib/ufb/Src/framebuffer.c Lib/ufb/Src/utf8.c Lib/ufb/Src/font.c Lib/ufb/Src/fb_7seg.c Lib/ufb/Src/fb_text.c \ +Lib/ufb/Src/framebuffer.c \ +Lib/ufb/Src/utf8.c \ +Lib/ufb/Src/font.c \ +Lib/ufb/Src/fb_7seg.c \ +Lib/ufb/Src/fb_text.c \ +Lib/snprintf/snprintf.c \ Core/Src/dma.c \ Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_gpio.c \ Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_adc.c \ @@ -149,7 +154,8 @@ C_INCLUDES = \ -IMiddlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3 \ -IDrivers/CMSIS/Device/ST/STM32F1xx/Include \ -IDrivers/CMSIS/Include \ --ILib/ufb/Inc +-ILib/ufb/Inc \ +-ILib/snprintf # compile gcc flags @@ -211,7 +217,7 @@ $(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR) $(BUILD_DIR): mkdir -p $@ -.PHONY: all build flash clean flash flash-stlink analyze +.PHONY: all flash clean flash-stlink analyze size ####################################### # clean up @@ -228,6 +234,9 @@ clean: build: all +size: $(BUILD_DIR)/$(TARGET).elf + $(SZ) $< + flash-stlink: $(BUILD_DIR)/$(TARGET).bin st-flash write $< 0x8000000 diff --git a/Middlewares/Third_Party/FreeRTOS/Source/tasks.c b/Middlewares/Third_Party/FreeRTOS/Source/tasks.c index e41d9d1..203ea22 100644 --- a/Middlewares/Third_Party/FreeRTOS/Source/tasks.c +++ b/Middlewares/Third_Party/FreeRTOS/Source/tasks.c @@ -53,7 +53,8 @@ functions but without including stdio.h here. */ to generate human readable text from the raw data generated by the uxTaskGetSystemState() function. Note the formatting functions are provided for convenience only, and are NOT considered part of the kernel. */ - #include + //#include +#include "snprintf.h" #endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ #if( configUSE_PREEMPTION == 0 ) @@ -4229,7 +4230,7 @@ TCB_t *pxTCB; pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); /* Write the rest of the string. */ - sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); + SPRINTF( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); pcWriteBuffer += strlen( pcWriteBuffer ); } @@ -4325,13 +4326,13 @@ TCB_t *pxTCB; { #ifdef portLU_PRINTF_SPECIFIER_REQUIRED { - sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); + SPRINTF( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); } #else { /* sizeof( int ) == sizeof( long ) so a smaller printf() library can be used. */ - sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); + SPRINTF( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); } #endif } @@ -4341,13 +4342,13 @@ TCB_t *pxTCB; consumed less than 1% of the total run time. */ #ifdef portLU_PRINTF_SPECIFIER_REQUIRED { - sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter ); + SPRINTF( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter ); } #else { /* sizeof( int ) == sizeof( long ) so a smaller printf() library can be used. */ - sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); + SPRINTF( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); } #endif }