mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Make stdin/stdout/stderr be FileHandles
Rework so that everything is a FileHandle, including stdin/stdout/stderr. Provide legacy functionality of calling serial_getc and serial_putc as an internal "DirectSerial" FileHandle. Add a JSON option to use UARTSerial instead. Add hooks for target and application to provide custom FileHandles. Allow for CRLF conversion to work on any FileHandle that isatty(), as stdin/stdout or any other FILE. Optimise the conversion so it doesn't force all write calls to be 1 byte. Limit the conversion to the stdio layer, so that read() and write() work the same as the FileHandle methods - this seems less confusing.pull/5571/head
							parent
							
								
									96c709fb35
								
							
						
					
					
						commit
						f79bfddcad
					
				| 
						 | 
				
			
			@ -2,7 +2,17 @@
 | 
			
		|||
    "name": "platform",
 | 
			
		||||
    "config": {
 | 
			
		||||
        "stdio-convert-newlines": {
 | 
			
		||||
            "help": "Enable conversion to standard newlines on stdin/stdout",
 | 
			
		||||
            "help": "Enable conversion to standard newlines on stdin/stdout/stderr",
 | 
			
		||||
            "value": false
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        "stdio-convert-tty-newlines": {
 | 
			
		||||
            "help": "Enable conversion to standard newlines on any tty FILE stream",
 | 
			
		||||
            "value": false
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        "stdio-buffered-serial": {
 | 
			
		||||
            "help": "Use UARTSerial driver to obtain buffered serial I/O on stdin/stdout/stderr. If false, unbuffered serial_getc and serial_putc are used directly.",
 | 
			
		||||
            "value": false
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,11 +28,15 @@
 | 
			
		|||
#include "platform/mbed_critical.h"
 | 
			
		||||
#include "platform/mbed_poll.h"
 | 
			
		||||
#include "platform/PlatformMutex.h"
 | 
			
		||||
#include "drivers/UARTSerial.h"
 | 
			
		||||
#include "us_ticker_api.h"
 | 
			
		||||
#include "lp_ticker_api.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#ifndef SSIZE_MAX
 | 
			
		||||
#define SSIZE_MAX INT_MAX
 | 
			
		||||
#endif
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include "platform/mbed_retarget.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +70,7 @@ static SingletonPtr<PlatformMutex> _mutex;
 | 
			
		|||
#   define PREFIX(x)    x
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define FILE_HANDLE_RESERVED    0xFFFFFFFF
 | 
			
		||||
#define FILE_HANDLE_RESERVED    ((FileHandle*)0xFFFFFFFF)
 | 
			
		||||
 | 
			
		||||
using namespace mbed;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +93,9 @@ uint32_t mbed_heap_size = 0;
 | 
			
		|||
 * 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];
 | 
			
		||||
static FileHandle *filehandles[OPEN_MAX] = { FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED };
 | 
			
		||||
static char stdio_in_prev[OPEN_MAX];
 | 
			
		||||
static char stdio_out_prev[OPEN_MAX];
 | 
			
		||||
static SingletonPtr<PlatformMutex> filehandle_mutex;
 | 
			
		||||
 | 
			
		||||
namespace mbed {
 | 
			
		||||
| 
						 | 
				
			
			@ -110,20 +116,138 @@ void remove_filehandle(FileHandle *file) {
 | 
			
		|||
#if DEVICE_SERIAL
 | 
			
		||||
extern int stdio_uart_inited;
 | 
			
		||||
extern serial_t stdio_uart;
 | 
			
		||||
#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
 | 
			
		||||
static char stdio_in_prev;
 | 
			
		||||
static char stdio_out_prev;
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void init_serial() {
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
/* 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
 | 
			
		||||
 * is why it's not public. People should be using UARTSerial.
 | 
			
		||||
 */
 | 
			
		||||
class DirectSerial : public FileHandle {
 | 
			
		||||
public:
 | 
			
		||||
    DirectSerial(PinName tx, PinName rx, int baud);
 | 
			
		||||
    virtual ssize_t write(const void *buffer, size_t size);
 | 
			
		||||
    virtual ssize_t read(void *buffer, size_t size);
 | 
			
		||||
    virtual off_t seek(off_t offset, int whence = SEEK_SET) {
 | 
			
		||||
        return -ESPIPE;
 | 
			
		||||
    }
 | 
			
		||||
    virtual off_t size() {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
    virtual int isatty() {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    virtual int close() {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    virtual short poll(short events) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DirectSerial::DirectSerial(PinName tx, PinName rx, int baud) {
 | 
			
		||||
    if (stdio_uart_inited) return;
 | 
			
		||||
    serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
 | 
			
		||||
#if MBED_CONF_PLATFORM_STDIO_BAUD_RATE
 | 
			
		||||
    serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE);
 | 
			
		||||
    serial_init(&stdio_uart, tx, rx);
 | 
			
		||||
    serial_baud(&stdio_uart, baud);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t DirectSerial::write(const void *buffer, size_t size) {
 | 
			
		||||
    const unsigned char *buf = static_cast<const unsigned char *>(buffer);
 | 
			
		||||
    for (size_t i = 0; i < size; i++) {
 | 
			
		||||
        serial_putc(&stdio_uart, buf[i]);
 | 
			
		||||
    }
 | 
			
		||||
    return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t DirectSerial::read(void *buffer, size_t size) {
 | 
			
		||||
    unsigned char *buf = static_cast<unsigned char *>(buffer);
 | 
			
		||||
    if (size == 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    buf[0] = serial_getc(&stdio_uart);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
short DirectSerial::poll(short events) const {
 | 
			
		||||
    short revents = 0;
 | 
			
		||||
    if ((events & POLLIN) && serial_readable(&stdio_uart)) {
 | 
			
		||||
        revents |= POLLIN;
 | 
			
		||||
    }
 | 
			
		||||
    if ((events & POLLOUT) && serial_writable(&stdio_uart)) {
 | 
			
		||||
        revents |= POLLOUT;
 | 
			
		||||
    }
 | 
			
		||||
    return revents;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Sink : public FileHandle {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ssize_t write(const void *buffer, size_t size);
 | 
			
		||||
    virtual ssize_t read(void *buffer, size_t size);
 | 
			
		||||
    virtual off_t seek(off_t offset, int whence = SEEK_SET) { return ESPIPE; }
 | 
			
		||||
    virtual off_t size() { return -EINVAL; }
 | 
			
		||||
    virtual int isatty() { return true; }
 | 
			
		||||
    virtual int close() { return 0; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ssize_t Sink::write(const void *buffer, size_t size) {
 | 
			
		||||
    // Just swallow the data - this is historical non-DEVICE_SERIAL behaviour
 | 
			
		||||
    return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t Sink::read(void *buffer, size_t size) {
 | 
			
		||||
    // Produce 1 zero byte - historical behaviour returned 1 without touching
 | 
			
		||||
    // the buffer
 | 
			
		||||
    unsigned char *buf = static_cast<unsigned char *>(buffer);
 | 
			
		||||
    buf[0] = 0;
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MBED_WEAK FileHandle* mbed::mbed_target_override_console(int fd)
 | 
			
		||||
{
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MBED_WEAK FileHandle* mbed::mbed_override_console(int fd)
 | 
			
		||||
{
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static FileHandle* default_console()
 | 
			
		||||
{
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
#  if MBED_CONF_PLATFORM_STDIO_BUFFERED_SERIAL
 | 
			
		||||
    static UARTSerial console(STDIO_UART_TX, STDIO_UART_RX, MBED_CONF_PLATFORM_STDIO_BAUD_RATE);
 | 
			
		||||
#  else
 | 
			
		||||
    static DirectSerial console(STDIO_UART_TX, STDIO_UART_RX, MBED_CONF_PLATFORM_STDIO_BAUD_RATE);
 | 
			
		||||
#  endif
 | 
			
		||||
#else // DEVICE_SERIAL
 | 
			
		||||
    static Sink console;
 | 
			
		||||
#endif
 | 
			
		||||
    return &console;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Locate the default console for stdout, stdin, stderr */
 | 
			
		||||
static FileHandle* get_console(int fd) {
 | 
			
		||||
    FileHandle *fh = mbed_override_console(fd);
 | 
			
		||||
    if (fh) {
 | 
			
		||||
        return fh;
 | 
			
		||||
    }
 | 
			
		||||
    fh = mbed_target_override_console(fd);
 | 
			
		||||
    if (fh) {
 | 
			
		||||
        return fh;
 | 
			
		||||
    }
 | 
			
		||||
    return default_console();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Deal with the fact C library may not _open descriptors 0, 1, 2 - auto bind */
 | 
			
		||||
static FileHandle* get_fhc(int fd) {
 | 
			
		||||
    if (fd >= OPEN_MAX) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    FileHandle *fh = filehandles[fd];
 | 
			
		||||
    if (fh == FILE_HANDLE_RESERVED && fd < 3) {
 | 
			
		||||
        filehandles[fd] = fh = get_console(fd);
 | 
			
		||||
    }
 | 
			
		||||
    return fh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -189,7 +313,7 @@ static int reserve_filehandle() {
 | 
			
		|||
        filehandle_mutex->unlock();
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED;
 | 
			
		||||
    filehandles[fh_i] = FILE_HANDLE_RESERVED;
 | 
			
		||||
    filehandle_mutex->unlock();
 | 
			
		||||
 | 
			
		||||
    return fh_i;
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +326,8 @@ int mbed::bind_to_fd(FileHandle *fh) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    filehandles[fh_i] = fh;
 | 
			
		||||
    stdio_in_prev[fh_i] = 0;
 | 
			
		||||
    stdio_out_prev[fh_i] = 0;
 | 
			
		||||
 | 
			
		||||
    return fh_i;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -285,19 +411,21 @@ extern "C" FILEHANDLE PREFIX(_open)(const char *name, int openflags) {
 | 
			
		|||
    // Before version 5.03, we were using a patched version of microlib with proper names
 | 
			
		||||
    // This is the workaround that the microlib author suggested us
 | 
			
		||||
    static int n = 0;
 | 
			
		||||
    if (!std::strcmp(name, ":tt")) return n++;
 | 
			
		||||
    if (std::strcmp(name, ":tt") == 0 && n < 3) {
 | 
			
		||||
        return n++;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /* Use the posix convention that stdin,out,err are filehandles 0,1,2.
 | 
			
		||||
     */
 | 
			
		||||
    if (std::strcmp(name, __stdin_name) == 0) {
 | 
			
		||||
        init_serial();
 | 
			
		||||
        return 0;
 | 
			
		||||
        get_fhc(STDIN_FILENO);
 | 
			
		||||
        return STDIN_FILENO;
 | 
			
		||||
    } else if (std::strcmp(name, __stdout_name) == 0) {
 | 
			
		||||
        init_serial();
 | 
			
		||||
        return 1;
 | 
			
		||||
        get_fhc(STDOUT_FILENO);
 | 
			
		||||
        return STDOUT_FILENO;
 | 
			
		||||
    } else if (std::strcmp(name, __stderr_name) == 0) {
 | 
			
		||||
        init_serial();
 | 
			
		||||
        return 2;
 | 
			
		||||
        get_fhc(STDERR_FILENO);
 | 
			
		||||
        return STDERR_FILENO;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef __IAR_SYSTEMS_ICC__
 | 
			
		||||
| 
						 | 
				
			
			@ -341,6 +469,8 @@ extern "C" int open(const char *name, int oflag, ...) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    filehandles[fh_i] = res;
 | 
			
		||||
    stdio_in_prev[fh_i] = 0;
 | 
			
		||||
    stdio_out_prev[fh_i] = 0;
 | 
			
		||||
 | 
			
		||||
    return fh_i;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -350,7 +480,7 @@ extern "C" int PREFIX(_close)(FILEHANDLE fh) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
extern "C" int close(int fh) {
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    filehandles[fh] = NULL;
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
| 
						 | 
				
			
			@ -366,15 +496,88 @@ extern "C" int close(int fh) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool convert_crlf(int fd) {
 | 
			
		||||
#if MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES
 | 
			
		||||
    return isatty(fd);
 | 
			
		||||
#elif MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
 | 
			
		||||
    return fd < 3 && isatty(fd);
 | 
			
		||||
#else
 | 
			
		||||
    return false;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(__ICCARM__)
 | 
			
		||||
extern "C" size_t    __write (int        fh, const unsigned char *buffer, size_t length) {
 | 
			
		||||
#else
 | 
			
		||||
extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) {
 | 
			
		||||
#endif
 | 
			
		||||
    ssize_t written = write(fh, buffer, length);
 | 
			
		||||
 | 
			
		||||
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
 | 
			
		||||
    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
 | 
			
		||||
        error("Error - writing to a file in an ISR or critical section\r\n");
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (length > SSIZE_MAX) {
 | 
			
		||||
        errno = EINVAL;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ssize_t slength = length;
 | 
			
		||||
    ssize_t written = 0;
 | 
			
		||||
 | 
			
		||||
    if (convert_crlf(fh)) {
 | 
			
		||||
        // local prev is previous in buffer during seek
 | 
			
		||||
        // stdio_out_prev[fh] is last thing actually written
 | 
			
		||||
        char prev = stdio_out_prev[fh];
 | 
			
		||||
        // Seek for '\n' without preceding '\r'; if found flush
 | 
			
		||||
        // preceding and insert '\r'. Continue until end of input.
 | 
			
		||||
        for (ssize_t cur = 0; cur < slength; cur++) {
 | 
			
		||||
            if (buffer[cur] == '\n' && prev != '\r') {
 | 
			
		||||
                ssize_t r;
 | 
			
		||||
                // flush stuff preceding the \n
 | 
			
		||||
                if (cur > written) {
 | 
			
		||||
                    r = write(fh, buffer + written, cur - written);
 | 
			
		||||
                    if (r < 0) {
 | 
			
		||||
                        return -1;
 | 
			
		||||
                    }
 | 
			
		||||
                    written += r;
 | 
			
		||||
                    if (written < cur) {
 | 
			
		||||
                        // For some reason, didn't write all - give up now
 | 
			
		||||
                        goto finish;
 | 
			
		||||
                    }
 | 
			
		||||
                    stdio_out_prev[fh] = prev;
 | 
			
		||||
                }
 | 
			
		||||
                // insert a \r now, leaving the \n still to be written
 | 
			
		||||
                r = write(fh, "\r", 1);
 | 
			
		||||
                if (r < 0) {
 | 
			
		||||
                    return -1;
 | 
			
		||||
                }
 | 
			
		||||
                if (r < 1) {
 | 
			
		||||
                    goto finish;
 | 
			
		||||
                }
 | 
			
		||||
                stdio_out_prev[fh] = '\r';
 | 
			
		||||
            }
 | 
			
		||||
            prev = buffer[cur];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Flush remaining from conversion, or the whole thing if no conversion
 | 
			
		||||
    if (written < slength) {
 | 
			
		||||
        ssize_t r = write(fh, buffer + written, slength - written);
 | 
			
		||||
        if (r < 0) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        written += r;
 | 
			
		||||
        if (written > 0) {
 | 
			
		||||
            stdio_out_prev[fh] = buffer[written - 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
#ifdef __ARMCC_VERSION
 | 
			
		||||
    if (written >= 0) {
 | 
			
		||||
        return (ssize_t)length - written;
 | 
			
		||||
        return slength - written;
 | 
			
		||||
    } else {
 | 
			
		||||
        return written;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -384,47 +587,21 @@ extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsign
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
extern "C" ssize_t write(int fh, const void *buf, size_t length) {
 | 
			
		||||
    const unsigned char *buffer = static_cast<const unsigned char *>(buf);
 | 
			
		||||
    int n; // n is the number of bytes written
 | 
			
		||||
 | 
			
		||||
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
 | 
			
		||||
    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
 | 
			
		||||
        error("Error - writing to a file in an ISR or critical section\r\n");
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    if (fhc == NULL && fh < 3) {
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
        if (!stdio_uart_inited) init_serial();
 | 
			
		||||
#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
 | 
			
		||||
        for (unsigned int i = 0; i < length; i++) {
 | 
			
		||||
            if (buffer[i] == '\n' && stdio_out_prev != '\r') {
 | 
			
		||||
                 serial_putc(&stdio_uart, '\r');
 | 
			
		||||
            }
 | 
			
		||||
            serial_putc(&stdio_uart, buffer[i]);
 | 
			
		||||
            stdio_out_prev = buffer[i];
 | 
			
		||||
        }
 | 
			
		||||
#else
 | 
			
		||||
        for (unsigned int i = 0; i < length; i++) {
 | 
			
		||||
            serial_putc(&stdio_uart, buffer[i]);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
        n = length;
 | 
			
		||||
    } else {
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        n = fhc->write(buffer, length);
 | 
			
		||||
        if (n < 0) {
 | 
			
		||||
            errno = -n;
 | 
			
		||||
    ssize_t ret = fhc->write(buf, length);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        errno = -ret;
 | 
			
		||||
        return -1;
 | 
			
		||||
    } else {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
 | 
			
		||||
extern "C" void PREFIX(_exit)(int return_code) {
 | 
			
		||||
| 
						 | 
				
			
			@ -432,9 +609,8 @@ extern "C" void PREFIX(_exit)(int return_code) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
extern "C" void _ttywrch(int ch) {
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
    serial_putc(&stdio_uart, ch);
 | 
			
		||||
#endif
 | 
			
		||||
    char c = ch;
 | 
			
		||||
    write(STDOUT_FILENO, &c, 1);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -443,7 +619,50 @@ extern "C" size_t    __read (int        fh, unsigned char *buffer, size_t
 | 
			
		|||
#else
 | 
			
		||||
extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) {
 | 
			
		||||
#endif
 | 
			
		||||
    ssize_t bytes_read = read(fh, buffer, length);
 | 
			
		||||
 | 
			
		||||
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
 | 
			
		||||
    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
 | 
			
		||||
        error("Error - reading from a file in an ISR or critical section\r\n");
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (length > SSIZE_MAX) {
 | 
			
		||||
        errno = EINVAL;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ssize_t bytes_read = 0;
 | 
			
		||||
 | 
			
		||||
    if (convert_crlf(fh)) {
 | 
			
		||||
        while (true) {
 | 
			
		||||
            char c;
 | 
			
		||||
            ssize_t r = read(fh, &c, 1);
 | 
			
		||||
            if (r < 0) {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            if (r == 0) {
 | 
			
		||||
                return bytes_read;
 | 
			
		||||
            }
 | 
			
		||||
            if ((c == '\r' && stdio_in_prev[fh] != '\n') ||
 | 
			
		||||
                (c == '\n' && stdio_in_prev[fh] != '\r')) {
 | 
			
		||||
                stdio_in_prev[fh] = c;
 | 
			
		||||
                *buffer = '\n';
 | 
			
		||||
                break;
 | 
			
		||||
            } else if ((c == '\r' && stdio_in_prev[fh] == '\n') ||
 | 
			
		||||
                       (c == '\n' && stdio_in_prev[fh] == '\r')) {
 | 
			
		||||
                stdio_in_prev[fh] = c;
 | 
			
		||||
                continue;
 | 
			
		||||
            } else {
 | 
			
		||||
                stdio_in_prev[fh] = c;
 | 
			
		||||
                *buffer = c;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        bytes_read = 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        bytes_read = read(fh, buffer, length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef __ARMCC_VERSION
 | 
			
		||||
    if (bytes_read < 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -458,57 +677,22 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
extern "C" ssize_t read(int fh, void *buf, size_t length) {
 | 
			
		||||
    unsigned char *buffer = static_cast<unsigned char *>(buf);
 | 
			
		||||
    int n; // n is the number of bytes read
 | 
			
		||||
 | 
			
		||||
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
 | 
			
		||||
    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
 | 
			
		||||
        error("Error - reading from a file in an ISR or critical section\r\n");
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    if (fhc == NULL && fh < 3) {
 | 
			
		||||
        // only read a character at a time from stdin
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
        if (!stdio_uart_inited) init_serial();
 | 
			
		||||
#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
 | 
			
		||||
        while (true) {
 | 
			
		||||
            char c = serial_getc(&stdio_uart);
 | 
			
		||||
            if ((c == '\r' && stdio_in_prev != '\n') ||
 | 
			
		||||
                (c == '\n' && stdio_in_prev != '\r')) {
 | 
			
		||||
                stdio_in_prev = c;
 | 
			
		||||
                *buffer = '\n';
 | 
			
		||||
                break;
 | 
			
		||||
            } else if ((c == '\r' && stdio_in_prev == '\n') ||
 | 
			
		||||
                       (c == '\n' && stdio_in_prev == '\r')) {
 | 
			
		||||
                stdio_in_prev = c;
 | 
			
		||||
                // onto next character
 | 
			
		||||
                continue;
 | 
			
		||||
            } else {
 | 
			
		||||
                stdio_in_prev = c;
 | 
			
		||||
                *buffer = c;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
#else
 | 
			
		||||
        *buffer = serial_getc(&stdio_uart);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
        n = 1;
 | 
			
		||||
    } else {
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        n = fhc->read(buffer, length);
 | 
			
		||||
        if (n < 0) {
 | 
			
		||||
            errno = -n;
 | 
			
		||||
    ssize_t ret = fhc->read(buf, length);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        errno = -ret;
 | 
			
		||||
        return -1;
 | 
			
		||||
    } else {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __ARMCC_VERSION
 | 
			
		||||
extern "C" int PREFIX(_istty)(FILEHANDLE fh)
 | 
			
		||||
| 
						 | 
				
			
			@ -520,11 +704,8 @@ extern "C" int _isatty(FILEHANDLE fh)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
extern "C" int isatty(int fh) {
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        /* stdin, stdout and stderr should be tty */
 | 
			
		||||
        if (fh < 3) return 1;
 | 
			
		||||
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -561,12 +742,7 @@ int _lseek(FILEHANDLE fh, int offset, int whence)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
extern "C" off_t lseek(int fh, off_t offset, int whence) {
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    if (fhc == NULL && fh < 3) {
 | 
			
		||||
        errno = ESPIPE;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -587,7 +763,7 @@ extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
extern "C" int fsync(int fh) {
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -604,12 +780,7 @@ extern "C" int fsync(int fh) {
 | 
			
		|||
 | 
			
		||||
#ifdef __ARMCC_VERSION
 | 
			
		||||
extern "C" long PREFIX(_flen)(FILEHANDLE fh) {
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    if (fhc == NULL && fh < 3) {
 | 
			
		||||
        errno = EINVAL;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -656,12 +827,7 @@ extern "C" int _fstat(int fh, struct stat *st) {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
extern "C" int fstat(int fh, struct stat *st) {
 | 
			
		||||
    FileHandle* fhc = filehandles[fh];
 | 
			
		||||
    if (fhc == NULL && fh < 3) {
 | 
			
		||||
        st->st_mode = S_IFCHR;
 | 
			
		||||
        return  0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FileHandle* fhc = get_fhc(fh);
 | 
			
		||||
    if (fhc == NULL) {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -683,7 +849,7 @@ extern "C" int poll(struct pollfd fds[], nfds_t nfds, int timeout)
 | 
			
		|||
    for (nfds_t n = 0; n < nfds; n++) {
 | 
			
		||||
        // Underlying FileHandle poll returns POLLNVAL if given NULL, so
 | 
			
		||||
        // we don't need to take special action.
 | 
			
		||||
        fhs[n].fh = filehandles[fds[n].fd];
 | 
			
		||||
        fhs[n].fh = get_fhc(fds[n].fd);
 | 
			
		||||
        fhs[n].events = fds[n].events;
 | 
			
		||||
    }
 | 
			
		||||
    int ret = poll(fhs, nfds, timeout);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,10 @@ typedef unsigned int  gid_t;    ///< Group ID
 | 
			
		|||
 | 
			
		||||
#define NAME_MAX 255    ///< Maximum size of a name in a file path
 | 
			
		||||
 | 
			
		||||
#define STDIN_FILENO  0
 | 
			
		||||
#define STDOUT_FILENO 1
 | 
			
		||||
#define STDERR_FILENO 2
 | 
			
		||||
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
/** \addtogroup platform */
 | 
			
		||||
| 
						 | 
				
			
			@ -70,6 +74,46 @@ namespace mbed {
 | 
			
		|||
class FileHandle;
 | 
			
		||||
class DirHandle;
 | 
			
		||||
 | 
			
		||||
/** Targets may implement this to change stdin, stdout, stderr.
 | 
			
		||||
 *
 | 
			
		||||
 * If the application hasn't provided mbed_override_console, this is called
 | 
			
		||||
 * to give the target a chance to specify a FileHandle for the console.
 | 
			
		||||
 *
 | 
			
		||||
 * If this is not provided or returns NULL, the console will be:
 | 
			
		||||
 *   - UARTSerial if configuration option "platform.stdio-buffered-serial" is
 | 
			
		||||
 *     true and the target has DEVICE_SERIAL;
 | 
			
		||||
 *   - Raw HAL serial via serial_getc and serial_putc if
 | 
			
		||||
 *     "platform.stdio-buffered-serial" is false and the target has DEVICE_SERIAL;
 | 
			
		||||
 *   - stdout/stderr will be a sink and stdin will input a stream of 0s if the
 | 
			
		||||
 *     target does not have DEVICE_SERIAL.
 | 
			
		||||
 *
 | 
			
		||||
 * @param fd file descriptor - STDIN_FILENO, STDOUT_FILENO or STDERR_FILENO
 | 
			
		||||
 * @return  pointer to FileHandle to override normal stream otherwise NULL
 | 
			
		||||
 */
 | 
			
		||||
FileHandle* mbed_target_override_console(int fd);
 | 
			
		||||
 | 
			
		||||
/** Applications may implement this to change stdin, stdout, stderr.
 | 
			
		||||
 *
 | 
			
		||||
 * This hook gives the application a chance to specify a custom FileHandle
 | 
			
		||||
 * for the console.
 | 
			
		||||
 *
 | 
			
		||||
 * If this is not provided or returns NULL, the console will be specified
 | 
			
		||||
 * by mbed_target_override_console, else will default to serial - see
 | 
			
		||||
 * mbed_target_override_console for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * Example:
 | 
			
		||||
 * @code
 | 
			
		||||
 * FileHandle* mbed::mbed_override_console(int) {
 | 
			
		||||
 *     static UARTSerial my_serial(D0, D1);
 | 
			
		||||
 *     return &my_serial;
 | 
			
		||||
 * }
 | 
			
		||||
 * @endcode
 | 
			
		||||
 | 
			
		||||
 * @param fd file descriptor - STDIN_FILENO, STDOUT_FILENO or STDERR_FILENO
 | 
			
		||||
 * @return  pointer to FileHandle to override normal stream otherwise NULL
 | 
			
		||||
 */
 | 
			
		||||
FileHandle* mbed_override_console(int fd);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef mbed::DirHandle DIR;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue