diff --git a/platform/mbed_lib.json b/platform/mbed_lib.json index b571f3781ba2..aeb786951a45 100644 --- a/platform/mbed_lib.json +++ b/platform/mbed_lib.json @@ -16,6 +16,11 @@ "value": false }, + "stdio-minimal-console-only": { + "help": "(Applies if target.console-uart is true. Ignores stdio-buffered-serial) Creates a console for basic unbuffered I/O operations. Enable if your application does not require file handles to access the serial interface.", + "value": true + }, + "stdio-baud-rate": { "help": "(Applies if target.console-uart is true.) Baud rate for stdio", "value": 9600 diff --git a/platform/mbed_retarget.h b/platform/mbed_retarget.h index c5058280083c..ba1bdac58d1c 100644 --- a/platform/mbed_retarget.h +++ b/platform/mbed_retarget.h @@ -94,6 +94,7 @@ namespace mbed { class FileHandle; class DirHandle; +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) /** Targets may implement this to change stdin, stdout, stderr. * * If the application hasn't provided mbed_override_console, this is called @@ -179,6 +180,7 @@ FileHandle *mbed_override_console(int fd); * possible if it's not open with current implementation). */ FileHandle *mbed_file_handle(int fd); +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } typedef mbed::DirHandle DIR; @@ -559,7 +561,9 @@ struct pollfd { #if __cplusplus extern "C" { #endif +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) int open(const char *path, int oflag, ...); +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) #ifndef __IAR_SYSTEMS_ICC__ /* IAR provides fdopen itself */ #if __cplusplus std::FILE *fdopen(int fildes, const char *mode); @@ -576,7 +580,9 @@ extern "C" { int fstat(int fildes, struct stat *st); int fcntl(int fildes, int cmd, ...); int poll(struct pollfd fds[], nfds_t nfds, int timeout); +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) int close(int fildes); +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) int stat(const char *path, struct stat *st); int statvfs(const char *path, struct statvfs *buf); DIR *opendir(const char *); @@ -586,6 +592,12 @@ extern "C" { long telldir(DIR *); void seekdir(DIR *, long); int mkdir(const char *name, mode_t n); + +#if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY + ssize_t minimal_console_write(const void *buffer, size_t length); + ssize_t minimal_console_read(void *buffer, size_t length); +#endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY + #if __cplusplus }; // extern "C" diff --git a/platform/source/mbed_retarget.cpp b/platform/source/mbed_retarget.cpp index 2038c1adad68..71e1b9c5cee5 100644 --- a/platform/source/mbed_retarget.cpp +++ b/platform/source/mbed_retarget.cpp @@ -104,11 +104,15 @@ extern const char __stderr_name[] = "/stderr"; unsigned char *mbed_heap_start = 0; uint32_t mbed_heap_size = 0; +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) + /* newlib has the filehandle field in the FILE struct as a short, so * we can't just return a Filehandle* from _open and instead have to * put it in a filehandles array and return the index into that array */ static FileHandle *filehandles[OPEN_MAX] = { FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED }; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) + static char stdio_in_prev[OPEN_MAX]; static char stdio_out_prev[OPEN_MAX]; static SingletonPtr filehandle_mutex; @@ -118,6 +122,7 @@ void mbed_set_unbuffered_stream(std::FILE *_file); void remove_filehandle(FileHandle *file) { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) filehandle_mutex->lock(); /* Remove all open filehandles for this */ for (unsigned int fh_i = 0; fh_i < sizeof(filehandles) / sizeof(*filehandles); fh_i++) { @@ -126,6 +131,7 @@ void remove_filehandle(FileHandle *file) } } filehandle_mutex->unlock(); +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } } @@ -133,6 +139,7 @@ void remove_filehandle(FileHandle *file) extern int stdio_uart_inited; extern serial_t stdio_uart; +// #if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) /* Private FileHandle to implement backwards-compatible functionality of * direct HAL serial access for default stdin/stdout/stderr. * This is not a particularly well-behaved FileHandle for a stream, which @@ -208,7 +215,81 @@ short DirectSerial::poll(short events) const } return revents; } +#if (MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) +/** Class providing minimal UART communication functionalities + */ +class MinimalConsole { +public: + MinimalConsole(PinName tx, PinName rx, int baud); + virtual int putc(int c); + virtual int getc(); +}; + +/** Create a MinimalConsole port, connected to the specified transmit and receive pins, with the specified baud. + * + * @param tx Transmit pin + * @param rx Receive pin + * @param baud The baud rate of the serial port (optional, defaults to MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE) + * + * @note + * Either tx or rx may be specified as NC if unused + */ +MinimalConsole::MinimalConsole( + PinName tx, + PinName rx, + int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE +) +{ + if (stdio_uart_inited) { + return; + } + + serial_init(&stdio_uart, tx, rx); + serial_baud(&stdio_uart, baud); +#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS + serial_set_flow_control(&stdio_uart, FlowControlRTS, STDIO_UART_RTS, NC); +#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS + serial_set_flow_control(&stdio_uart, FlowControlCTS, NC, STDIO_UART_CTS); +#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS + serial_set_flow_control(&stdio_uart, FlowControlRTSCTS, STDIO_UART_RTS, STDIO_UART_CTS); #endif +} + +/** Write a char to the serial port + * + * @param c The char to write + * + * @returns The written char + */ +int MinimalConsole::putc(int c) +{ + serial_putc(&stdio_uart, c); + return c; +} + +/** Read a char to the serial port + * + * @returns The char read from the serial port + */ +int MinimalConsole::getc() +{ + return serial_getc(&stdio_uart); +} + + +/* Locate the default console */ +static MinimalConsole *get_minimal_console() +{ + static MinimalConsole console( + STDIO_UART_TX, + STDIO_UART_RX, + MBED_CONF_PLATFORM_STDIO_BAUD_RATE + ); + + return &console; +} +#endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY +#endif // DEVICE_SERIAL class Sink : public FileHandle { public: @@ -247,7 +328,7 @@ ssize_t Sink::read(void *buffer, size_t size) return 1; } - +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) MBED_WEAK FileHandle *mbed::mbed_target_override_console(int fd) { return NULL; @@ -391,9 +472,11 @@ static int reserve_filehandle() return fh_i; } +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) int mbed::bind_to_fd(FileHandle *fh) { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) int fildes = reserve_filehandle(); if (fildes < 0) { return fildes; @@ -404,10 +487,14 @@ int mbed::bind_to_fd(FileHandle *fh) stdio_out_prev[fildes] = 0; return fildes; +#else + return -1; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } static int unbind_from_fd(int fd, FileHandle *fh) { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) if (filehandles[fd] == fh) { filehandles[fd] = NULL; return 0; @@ -415,6 +502,9 @@ static int unbind_from_fd(int fd, FileHandle *fh) errno = EBADF; return -1; } +#else + return -1; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } #ifndef __IAR_SYSTEMS_ICC__ @@ -469,6 +559,7 @@ std::FILE *fdopen(FileHandle *fh, const char *mode) * */ extern "C" FILEHANDLE PREFIX(_open)(const char *name, int openflags) { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) #if !defined(MBED_CONF_RTOS_PRESENT) // valid only for mbed 2 @@ -516,8 +607,13 @@ extern "C" FILEHANDLE PREFIX(_open)(const char *name, int openflags) } #endif return open(name, openflags_to_posix(openflags)); +#else + // Everything goes to the same output + return STDOUT_FILENO; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) extern "C" int open(const char *name, int oflag, ...) { int fildes = reserve_filehandle(); @@ -554,12 +650,18 @@ extern "C" int open(const char *name, int oflag, ...) return fildes; } +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) extern "C" int PREFIX(_close)(FILEHANDLE fh) { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) return close(fh); +#else + return 0; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) extern "C" int close(int fildes) { FileHandle *fhc = mbed_file_handle(fildes); @@ -577,6 +679,7 @@ extern "C" int close(int fildes) return 0; } } +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) static bool convert_crlf(int fd) { @@ -673,7 +776,13 @@ extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsign extern "C" ssize_t write(int fildes, const void *buf, size_t length) { +#if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL + if (fildes != STDOUT_FILENO && fildes != STDERR_FILENO){ + return EBADF; + } + ssize_t ret = minimal_console_write(buf, length); +#else FileHandle *fhc = mbed_file_handle(fildes); if (fhc == NULL) { errno = EBADF; @@ -681,6 +790,7 @@ extern "C" ssize_t write(int fildes, const void *buf, size_t length) } ssize_t ret = fhc->write(buf, length); +#endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL if (ret < 0) { errno = -ret; return -1; @@ -689,6 +799,26 @@ extern "C" ssize_t write(int fildes, const void *buf, size_t length) } } +#if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL +/* Write the contents of a buffer to a serial interface */ +MBED_WEAK ssize_t minimal_console_write(const void *buffer, size_t length) +{ + MinimalConsole *mc = get_minimal_console(); + if (mc == nullptr) { + errno = EBADF; + return -1; + } + + const unsigned char *buf = static_cast(buffer); + + for (size_t i = 0; i < length; i++) { + mc->putc(buf[i]); + } + + return length; +} +#endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL + #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) extern "C" void PREFIX(_exit)(int return_code) { @@ -768,6 +898,13 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int extern "C" ssize_t read(int fildes, void *buf, size_t length) { +#if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL + if (fildes != STDOUT_FILENO && fildes != STDERR_FILENO){ + return EBADF; + } + + ssize_t ret = minimal_console_read(buf, length); +#else FileHandle *fhc = mbed_file_handle(fildes); if (fhc == NULL) { errno = EBADF; @@ -775,6 +912,7 @@ extern "C" ssize_t read(int fildes, void *buf, size_t length) } ssize_t ret = fhc->read(buf, length); +#endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL if (ret < 0) { errno = -ret; return -1; @@ -783,6 +921,26 @@ extern "C" ssize_t read(int fildes, void *buf, size_t length) } } +#if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL +/* Read the serial interface and store the content to a buffer */ +MBED_WEAK ssize_t minimal_console_read(void *buffer, size_t length) +{ + if (length == 0 || buffer == nullptr) { + return 0; + } + + MinimalConsole *mc = get_minimal_console(); + if (mc == nullptr) { + errno = EBADF; + return -1; + } + + unsigned char *buf = static_cast(buffer); + buf[0] = mc->getc(); + return 1; +} +#endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY && DEVICE_SERIAL + #ifdef __ARMCC_VERSION extern "C" int PREFIX(_istty)(FILEHANDLE fh) @@ -795,6 +953,7 @@ extern "C" int _isatty(FILEHANDLE fh) extern "C" int isatty(int fildes) { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) FileHandle *fhc = mbed_file_handle(fildes); if (fhc == NULL) { errno = EBADF; @@ -808,6 +967,10 @@ extern "C" int isatty(int fildes) } else { return tty; } +#else + // Is not attached to an interactive device + return 1; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } extern "C" @@ -819,6 +982,7 @@ long __lseek(int fh, long offset, int whence) int _lseek(FILEHANDLE fh, int offset, int whence) #endif { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) #if defined(__ARMCC_VERSION) int whence = SEEK_SET; #endif @@ -832,8 +996,13 @@ int _lseek(FILEHANDLE fh, int offset, int whence) return -1; } return off; +#else + // Not supported + return -1; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) extern "C" off_t lseek(int fildes, off_t offset, int whence) { FileHandle *fhc = mbed_file_handle(fildes); @@ -873,9 +1042,12 @@ extern "C" int PREFIX(_ensure)(FILEHANDLE fh) return fsync(fh); } #endif +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) extern "C" int fsync(int fildes) { + FileHandle *fhc = mbed_file_handle(fildes); if (fhc == NULL) { errno = EBADF; @@ -890,10 +1062,12 @@ extern "C" int fsync(int fildes) return 0; } } +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) #ifdef __ARMCC_VERSION extern "C" long PREFIX(_flen)(FILEHANDLE fh) { +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) FileHandle *fhc = mbed_file_handle(fh); if (fhc == NULL) { errno = EBADF; @@ -910,6 +1084,10 @@ extern "C" long PREFIX(_flen)(FILEHANDLE fh) return -1; } return size; +#else + // Not supported + return -1; +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) } // Do not compile this code for TFM secure target @@ -983,7 +1161,7 @@ extern "C" __value_in_regs struct __initial_stackheap __user_setup_stackheap(uin #endif - +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__) extern "C" int _fstat(int fh, struct stat *st) { @@ -1060,6 +1238,7 @@ extern "C" int poll(struct pollfd fds[], nfds_t nfds, int timeout) } return ret; } +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) namespace std { extern "C" int remove(const char *path) @@ -1340,8 +1519,10 @@ extern "C" void exit(int return_code) #if MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT fflush(stdout); fflush(stderr); +#if !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) fsync(STDOUT_FILENO); fsync(STDERR_FILENO); +#endif // !(MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY) #endif #endif