From 8f5d49de812d2686c854ec37be5422f6b793603f Mon Sep 17 00:00:00 2001 From: otopetrik Date: Mon, 19 Dec 2016 16:55:26 +0100 Subject: [PATCH] Allow changing write function of stdout (#304) * Allow changing write function of stdout. Required for stdout redirection. Works on blocks, not chars - does _not_ use sdk_os_putc ! Should work even when linking with SPIFFS. --- core/include/stdout_redirect.h | 45 +++++++++++++++++++++++++++++++ core/newlib_syscalls.c | 48 +++++++++++++++++++++++++++++----- extras/spiffs/esp_spiffs.c | 25 +++--------------- 3 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 core/include/stdout_redirect.h diff --git a/core/include/stdout_redirect.h b/core/include/stdout_redirect.h new file mode 100644 index 0000000..8cc06ed --- /dev/null +++ b/core/include/stdout_redirect.h @@ -0,0 +1,45 @@ +/* + * Part of esp-open-rtos + * Copyright (C) 2016 Oto Petrik + * BSD Licensed as described in the file LICENSE + */ + +#ifndef _STDOUT_REDIRECT_H_ +#define _STDOUT_REDIRECT_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef long _WriteFunction(struct _reent *r, int fd, const char *ptr, int len ); + +/** Set implementation of write syscall for stdout. + * + * Use this function to redirect stdout for further processing (save to file, send over network). + * It may be good idea to save result of `get_write_stdout()` beforehand and call + * it at the end of the supplied function. + * + * NOTE: use NULL to reset to default implementation. + * + * @param[in] f New code to handle stdout output + * + */ +void set_write_stdout(_WriteFunction *f); + +/** Get current implementation of write syscall for stdout. + * + * Save returned value before calling `set_write_stdout`, it allows for chaining + * multiple independent handlers. + * + * @returns current stdout handler + */ +_WriteFunction *get_write_stdout(); + +#ifdef __cplusplus +} +#endif + +#endif /* _STDOUT_REDIRECT_H_ */ diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c index f526bea..146a010 100644 --- a/core/newlib_syscalls.c +++ b/core/newlib_syscalls.c @@ -12,6 +12,7 @@ #include #include #include +#include extern void *xPortSupervisorStackPointer; @@ -41,12 +42,8 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr) } /* syscall implementation for stdio write to UART */ -__attribute__((weak)) long _write_r(struct _reent *r, int fd, const char *ptr, int len ) +__attribute__((weak)) long _write_stdout_r(struct _reent *r, int fd, const char *ptr, int len ) { - if(fd != r->_stdout->_file) { - r->_errno = EBADF; - return -1; - } for(int i = 0; i < len; i++) { /* Auto convert CR to CRLF, ignore other LFs (compatible with Espressif SDK behaviour) */ if(ptr[i] == '\r') @@ -58,6 +55,37 @@ __attribute__((weak)) long _write_r(struct _reent *r, int fd, const char *ptr, i return len; } +static _WriteFunction *current_stdout_write_r = &_write_stdout_r; + +void set_write_stdout(_WriteFunction *f) +{ + if (f != NULL) { + current_stdout_write_r = f; + } else { + current_stdout_write_r = &_write_stdout_r; + } +} + +_WriteFunction *get_write_stdout() +{ + return current_stdout_write_r; +} + +/* default implementation, replace in a filesystem */ +__attribute__((weak)) long _write_filesystem_r(struct _reent *r, int fd, const char *ptr, int len ) +{ + r->_errno = EBADF; + return -1; +} + +__attribute__((weak)) long _write_r(struct _reent *r, int fd, const char *ptr, int len ) +{ + if(fd != r->_stdout->_file) { + return _write_filesystem_r(r, fd, ptr, len); + } + return current_stdout_write_r(r, fd, ptr, len); +} + /* syscall implementation for stdio read from UART */ __attribute__((weak)) long _read_stdin_r(struct _reent *r, int fd, char *ptr, int len) { @@ -71,11 +99,17 @@ __attribute__((weak)) long _read_stdin_r(struct _reent *r, int fd, char *ptr, in return i; } +/* default implementation, replace in a filesystem */ +__attribute__((weak)) long _read_filesystem_r( struct _reent *r, int fd, char *ptr, int len ) +{ + r->_errno = EBADF; + return -1; +} + __attribute__((weak)) long _read_r( struct _reent *r, int fd, char *ptr, int len ) { if(fd != r->_stdin->_file) { - r->_errno = EBADF; - return -1; + return _read_filesystem_r(r, fd, ptr, len); } return _read_stdin_r(r, fd, ptr, len); } diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index 96ec743..3d81218 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -125,32 +125,15 @@ int32_t esp_spiffs_mount() } // This implementation replaces implementation in core/newlib_syscals.c -long _write_r(struct _reent *r, int fd, const char *ptr, int len ) +long _write_filesystem_r(struct _reent *r, int fd, const char *ptr, int len ) { - if(fd != r->_stdout->_file) { - return SPIFFS_write(&fs, (spiffs_file)fd, (char*)ptr, len); - } - for(int i = 0; i < len; i++) { - /* Auto convert CR to CRLF, ignore other LFs (compatible with Espressif SDK behaviour) */ - if(ptr[i] == '\r') - continue; - if(ptr[i] == '\n') - uart_putc(0, '\r'); - uart_putc(0, ptr[i]); - } - return len; + return SPIFFS_write(&fs, (spiffs_file)fd, (char*)ptr, len); } -// This function is weakly defined in core/newlib_syscalls.c -long _read_stdin_r(struct _reent *r, int fd, char *ptr, int len); - // This implementation replaces implementation in core/newlib_syscals.c -long _read_r( struct _reent *r, int fd, char *ptr, int len ) +long _read_filesystem_r( struct _reent *r, int fd, char *ptr, int len ) { - if(fd != r->_stdin->_file) { - return SPIFFS_read(&fs, (spiffs_file)fd, ptr, len); - } - return _read_stdin_r(r, fd, ptr, len); + return SPIFFS_read(&fs, (spiffs_file)fd, ptr, len); } int _open_r(struct _reent *r, const char *pathname, int flags, int mode)