diff --git a/arduino/libretuya/port/printf/printf_config.h b/arduino/libretuya/port/printf/printf_config.h new file mode 100644 index 0000000..10757d0 --- /dev/null +++ b/arduino/libretuya/port/printf/printf_config.h @@ -0,0 +1,9 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */ + +// make printf.c define wrapper functions +#define printf_ __wrap_printf +#define sprintf_ __wrap_sprintf +#define vsprintf_ __wrap_vsprintf +#define snprintf_ __wrap_snprintf +#define vsnprintf_ __wrap_vsnprintf +#define vprintf_ __wrap_vprintf diff --git a/arduino/libretuya/port/printf/putchar.c b/arduino/libretuya/port/printf/putchar.c new file mode 100644 index 0000000..5c1499d --- /dev/null +++ b/arduino/libretuya/port/printf/putchar.c @@ -0,0 +1,9 @@ +// https://github.com/embeddedartistry/libc/blob/master/src/stdio/putchar.c + +#include +#include + +int __wrap_putchar(int c) { + putchar_((char)c); + return c; +} diff --git a/arduino/libretuya/port/printf/puts.c b/arduino/libretuya/port/printf/puts.c new file mode 100644 index 0000000..e04f050 --- /dev/null +++ b/arduino/libretuya/port/printf/puts.c @@ -0,0 +1,21 @@ +// https://github.com/embeddedartistry/libc/blob/master/src/stdio/puts.c + +#include +#include + +int __wrap_puts(const char *str) { + int r = 0; + + for (const char *c = str; *c != 0; c++) { + putchar_((int)*c); + r++; + } + + // puts adds a newline + if (r) { + putchar_('\n'); + r++; + } + + return r ? r : EOF; +} diff --git a/arduino/realtek-ambz/cores/arduino/sdk_extern.h b/arduino/realtek-ambz/cores/arduino/sdk_extern.h index da658dd..ae171a2 100644 --- a/arduino/realtek-ambz/cores/arduino/sdk_extern.h +++ b/arduino/realtek-ambz/cores/arduino/sdk_extern.h @@ -28,9 +28,14 @@ // remove previously defined workaround #undef boolean -// stdio.h -#define printf rtl_printf -#define sprintf rtl_sprintf +// undefine ROM stdio in favor of printf() library (wrappers) +#undef printf +#undef sprintf +#undef vsprintf +#undef snprintf +#undef vsnprintf +#undef vprintf +#include // moved from syscalls.h #define _close __rtl_close diff --git a/arduino/realtek-ambz/port/printf/printf.c b/arduino/realtek-ambz/port/printf/printf.c new file mode 100644 index 0000000..c5f285d --- /dev/null +++ b/arduino/realtek-ambz/port/printf/printf.c @@ -0,0 +1,30 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */ + +#include +#include +// include LOGUART_PutChar() +#include +// make sure to call the "real" vprintf instead of rtl_vprintf +#undef vprintf + +void putchar_(char c) { + LOGUART_PutChar(c); +} + +// stdio wrappers for Realtek SDK + +int __wrap_rtl_printf(const char *format, ...) { + va_list va; + va_start(va, format); + const int ret = vprintf(format, va); + va_end(va); + return ret; +} + +int __wrap_DiagPrintf(const char *format, ...) { + va_list va; + va_start(va, format); + const int ret = vprintf(format, va); + va_end(va); + return ret; +} diff --git a/builder/arduino-common.py b/builder/arduino-common.py index a039135..c969f4a 100644 --- a/builder/arduino-common.py +++ b/builder/arduino-common.py @@ -26,6 +26,9 @@ env.Append( "-Wl,--no-enum-size-warning", "-Wl,--no-undefined", "-Wl,--warn-common", + # wrappers from port/printf/ + "-Wl,-wrap,putchar", + "-Wl,-wrap,puts", ], ) # Arduino core uses __libc_init_array @@ -129,6 +132,7 @@ for code, base_dir in env["ARDUINO_DIRS"].items(): # Sources - external library ports env.AddLibraryFlashDB(version="03500fa") +env.AddLibraryPrintf(version="6.0.0") # Libs & linker config env.Append( diff --git a/builder/frameworks/realtek-ambz-arduino.py b/builder/frameworks/realtek-ambz-arduino.py index 023f9ea..5a8be3f 100644 --- a/builder/frameworks/realtek-ambz-arduino.py +++ b/builder/frameworks/realtek-ambz-arduino.py @@ -27,9 +27,27 @@ env.Append( # implemented features ("LT_ARD_HAS_WIFI", "1"), ("LT_ARD_HAS_MD5", "1"), + # not broken anymore with printf() library + ("LT_PRINTF_BROKEN", "0"), ], LINKFLAGS=[ "-Wl,--undefined=InfraStart", + # stdio wrappers (port/printf/printf.c) + "-Wl,-wrap,rtl_printf", + "-Wl,-wrap,rtl_sprintf", + "-Wl,-wrap,rtl_snprintf", + "-Wl,-wrap,rtl_vsnprintf", + "-Wl,-wrap,rtl_vsnprintf_r", + "-Wl,-wrap,rtl_vprintf", + "-Wl,-wrap,rtl_vfprintf", + "-Wl,-wrap,DiagPrintf", + "-Wl,-wrap,DiagSPrintf", + "-Wl,-wrap,DiagSnPrintf", + "-Wl,-wrap,prvDiagPrintf", + "-Wl,-wrap,prvDiagSPrintf", + "-Wl,-wrap,VSprintf", + "-Wl,-wrap,LOG_PRINTF", + "-Wl,-wrap,__rtl_vfprintf_r_v1_00", ], ) diff --git a/builder/libs/printf.py b/builder/libs/printf.py new file mode 100644 index 0000000..7c37d66 --- /dev/null +++ b/builder/libs/printf.py @@ -0,0 +1,39 @@ +# Copyright (c) Kuba Szczodrzyński 2022-06-19. + +from SCons.Script import DefaultEnvironment + +env = DefaultEnvironment() +platform = env.PioPlatform() + + +def env_add_printf( + env, + version: str, +): + package_dir = platform.get_package_dir(f"library-printf@{version}") + + env.AddLibrary( + name=f"printf{version}", + base_dir=package_dir, + srcs=[ + "+", + ], + includes=[ + "+", + ], + options=dict( + CFLAGS=["-Wno-maybe-uninitialized"], + CPPDEFINES=[("PRINTF_INCLUDE_CONFIG_H", "1")], + LINKFLAGS=[ + "-Wl,-wrap,printf", + "-Wl,-wrap,sprintf", + "-Wl,-wrap,vsprintf", + "-Wl,-wrap,snprintf", + "-Wl,-wrap,vsnprintf", + "-Wl,-wrap,vprintf", + ], + ), + ) + + +env.AddMethod(env_add_printf, "AddLibraryPrintf") diff --git a/builder/main.py b/builder/main.py index 4dcb3cb..8865d0a 100644 --- a/builder/main.py +++ b/builder/main.py @@ -18,8 +18,9 @@ env.SConscript("utils/flash.py", exports="env") env.SConscript("utils/libs.py", exports="env") env.SConscript("utils/uf2.py", exports="env") # Vendor-specific library ports -env.SConscript("libs/lwip.py", exports="env") env.SConscript("libs/flashdb.py", exports="env") +env.SConscript("libs/lwip.py", exports="env") +env.SConscript("libs/printf.py", exports="env") # Firmware name if env.get("PROGNAME", "program") == "program": diff --git a/platform.json b/platform.json index 2863814..7f6113f 100644 --- a/platform.json +++ b/platform.json @@ -62,6 +62,9 @@ "libraries": { "flashdb": [ "03500fa" + ], + "printf": [ + "v6.0.0" ] } }, @@ -81,6 +84,14 @@ "description": "An ultra-lightweight database that supports key-value and time series data" } }, + "library-printf": { + "type": "framework", + "optional": true, + "base_url": "https://github.com/eyalroz/printf", + "manifest": { + "description": "Tiny, fast(ish), self-contained and fully loaded printf, sprinf etc. implementation, mainly for embedded systems." + } + }, "toolchain-gccarmnoneeabi": { "type": "toolchain", "optionalVersions": [