diff --git a/drivers/MinimalSerial.h b/drivers/MinimalSerial.h new file mode 100644 index 00000000000..71e6e47326a --- /dev/null +++ b/drivers/MinimalSerial.h @@ -0,0 +1,99 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_MINIMAL_SERIAL_H +#define MBED_MINIMAL_SERIAL_H + +#include "platform/platform.h" + +#if DEVICE_SERIAL || defined(DOXYGEN_ONLY) +#include "hal/serial_api.h" +#include "platform/NonCopyable.h" +#include "PinNames.h" + +namespace mbed { + +/** + * \defgroup drivers_MinimalSerial MinimalSerial class + * \ingroup drivers-public-api-uart + * @{ + */ + +/** A abstract class for serial port implementations + */ +class MinimalSerial : private NonCopyable { + +public: + + enum Flow { + Disabled = 0, + RTS, + CTS, + RTSCTS + }; + +#if DEVICE_SERIAL_FC + /** Set the flow control type on the serial port + * + * @param type the flow control type (Disabled, RTS, CTS, RTSCTS) + * @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS) + * @param flow2 the second flow control pin (CTS for RTSCTS) + */ + void set_flow_control(Flow type, PinName flow1 = NC, PinName flow2 = NC); +#endif // DEVICE_SERIAL_FC + + /** Set the baud rate of the serial port + * + * @param baudrate The baudrate of the serial port. + */ + void baud(int baudrate); + +protected: + MinimalSerial( + PinName tx, + PinName rx, + int baud + ); + + MinimalSerial( + serial_t &serial_ref, + bool serial_inited, + PinName tx, + PinName rx, + int baud + ); + + virtual ~MinimalSerial(); + + int _base_getc(); + + int _base_putc(int c); + + int _baud; + + serial_t _serial; + +private: + void init(PinName tx, PinName rx); +}; + +/** @}*/ + +} // namespace mbed + +#endif // DEVICE_SERIAL || defined(DOXYGEN_ONLY) + +#endif // MBED_MINIMAL_SERIAL_H diff --git a/drivers/SerialBase.h b/drivers/SerialBase.h index 5213f325fd6..39508b8df36 100644 --- a/drivers/SerialBase.h +++ b/drivers/SerialBase.h @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited + * Copyright (c) 2006-2019 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ #include "hal/serial_api.h" #include "platform/mbed_toolchain.h" #include "platform/NonCopyable.h" +#include "drivers/MinimalSerial.h" #if DEVICE_SERIAL_ASYNCH #include "platform/CThunk.h" @@ -43,15 +44,9 @@ namespace mbed { * * @note Synchronization level: Set by subclass */ -class SerialBase : private NonCopyable { +class SerialBase : public MinimalSerial, private NonCopyable { public: - /** Set the baud rate of the serial port - * - * @param baudrate The baudrate of the serial port (default = 9600). - */ - void baud(int baudrate); - enum Parity { None = 0, Odd, @@ -67,13 +62,6 @@ class SerialBase : private NonCopyable { IrqCnt }; - enum Flow { - Disabled = 0, - RTS, - CTS, - RTSCTS - }; - /** Set the transmission format used by the serial port * * @param bits The number of bits in a word (5-8; default = 8) @@ -168,16 +156,6 @@ class SerialBase : private NonCopyable { #endif public: -#if DEVICE_SERIAL_FC - /** Set the flow control type on the serial port - * - * @param type the flow control type (Disabled, RTS, CTS, RTSCTS) - * @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS) - * @param flow2 the second flow control pin (CTS for RTSCTS) - */ - void set_flow_control(Flow type, PinName flow1 = NC, PinName flow2 = NC); -#endif - static void _irq_handler(uint32_t id, SerialIrq irq_type); #if DEVICE_SERIAL_ASYNCH @@ -291,10 +269,6 @@ class SerialBase : private NonCopyable { SerialBase(PinName tx, PinName rx, int baud); virtual ~SerialBase(); - int _base_getc(); - - int _base_putc(int c); - #if DEVICE_SERIAL_ASYNCH CThunk _thunk_irq; DMAUsage _tx_usage; @@ -304,10 +278,7 @@ class SerialBase : private NonCopyable { bool _tx_asynch_set; bool _rx_asynch_set; #endif - - serial_t _serial; Callback _irq[IrqCnt]; - int _baud; #endif }; diff --git a/drivers/UnbufferedSerial.h b/drivers/UnbufferedSerial.h new file mode 100644 index 00000000000..63c1e925b2a --- /dev/null +++ b/drivers/UnbufferedSerial.h @@ -0,0 +1,182 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_UNBUFFERED_SERIAL_H +#define MBED_UNBUFFERED_SERIAL_H + +#include "platform/platform.h" + +#if DEVICE_SERIAL || defined(DOXYGEN_ONLY) + +#include "drivers/SerialBase.h" +#include "platform/FileHandle.h" +#include "platform/NonCopyable.h" + +namespace mbed { + +/** + * \defgroup drivers_UnbufferedSerial UnbufferedSerial class + * \ingroup drivers-public-api-uart + * @{ + */ + +/** + * Class implementation for unbuffered I/O for an interrupt driven application + * or one that needs to have more control. + */ +class UnbufferedSerial: + public SerialBase, + public FileHandle, + private NonCopyable +{ +public: + /** + * Create a serial port instance connected to the specified transmit and + * receive pins, with the specified baud rate. + * + * @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 + */ + UnbufferedSerial( + PinName tx, + PinName rx, + int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE + ); + + /** Write a char to the serial port + * + * @param c The char to write + * + * @returns The written char or -1 if an error occurred + */ + int putc(int c); + + /** Read a char from the serial port + * + * @returns The char read from the serial port + */ + int getc(); + + /** Write a string to the serial port + * + * @param str The string to write + * + * @returns 0 if the write succeeds, EOF for error + */ + int puts(const char *str); + + /** Write the contents of a buffer to a file + * + * Follows POSIX semantics: + * + * * if blocking, block until all data is written + * * if no data can be written, and non-blocking set, return -EAGAIN + * * if some data can be written, and non-blocking set, write partial + * + * @param buffer The buffer to write from + * @param length The number of bytes to write + * @return The number of bytes written, negative error on failure + */ + virtual ssize_t write(const void *buffer, size_t size); + + /** Read the contents of a file into a buffer + * + * Follows POSIX semantics: + * + * * if no data is available, and non-blocking set return -EAGAIN + * * if no data is available, and blocking set, wait until data is available + * * If any data is available, call returns immediately + * + * @param buffer The buffer to read in to + * @param length The number of bytes to read + * @return The number of bytes read, 0 at end of file, negative error on failure + */ + virtual ssize_t read(void *buffer, size_t size); + + /** Move the file position to a given offset from from a given location + * + * Not valid for a device type FileHandle like UARTSerial. + * In case of UARTSerial, returns ESPIPE + * + * @param offset The offset from whence to move to + * @param whence The start of where to seek + * SEEK_SET to start from beginning of file, + * SEEK_CUR to start from current position in file, + * SEEK_END to start from end of file + * @return The new offset of the file, negative error code on failure + */ + virtual off_t seek(off_t offset, int whence = SEEK_SET) + { + return -ESPIPE; + } + + /** Get the size of the file + * + * @return Size of the file in bytes + */ + virtual off_t size() + { + return -EINVAL; + } + + /** Check if the file in an interactive terminal device + * + * @return True if the file is a terminal + * @return False if the file is not a terminal + * @return Negative error code on failure + */ + virtual int isatty() + { + return true; + } + + /** Close a file + * + * @return 0 on success, negative error code on failure + */ + virtual int close() + { + return 0; + } + + /** + * Equivalent to POSIX poll(). Derived from FileHandle. + * Provides a mechanism to multiplex input/output over a set of file + * handles. + */ + virtual short poll(short events) const; + +#if !(DOXYGEN_ONLY) +protected: + /* Acquire exclusive access to this serial port + */ + virtual void lock(void); + + /* Release exclusive access to this serial port + */ + virtual void unlock(void); +#endif // !(DOXYGEN_ONLY) +}; + +} // namespace mbed + +#endif // DEVICE_SERIAL || defined(DOXYGEN_ONLY) + +#endif // MBED_UNBUFFERED_SERIAL_H diff --git a/drivers/source/MinimalSerial.cpp b/drivers/source/MinimalSerial.cpp new file mode 100644 index 00000000000..e67068910a7 --- /dev/null +++ b/drivers/source/MinimalSerial.cpp @@ -0,0 +1,108 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "drivers/MinimalSerial.h" + +#if DEVICE_SERIAL + +namespace mbed { + +MinimalSerial::MinimalSerial( + PinName tx, + PinName rx, + int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE +) : _serial(), _baud(baud) +{ + + init(tx, rx); +} + +MinimalSerial::MinimalSerial( + serial_t &serial_ref, + bool serial_inited, + PinName tx, + PinName rx, + int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE +) : _serial(serial_ref), _baud(baud) +{ + if (serial_inited) { + return; + } + + init(tx, rx); +} + +MinimalSerial::~MinimalSerial() +{ +} + +void MinimalSerial::init(PinName tx, PinName rx) +{ + serial_init(&_serial, tx, rx); + serial_baud(&_serial, _baud); +} + +void MinimalSerial::baud(int baudrate) +{ + serial_baud(&_serial, baudrate); + _baud = baudrate; +} + +#if DEVICE_SERIAL_FC +void MinimalSerial::set_flow_control( + Flow type, + PinName flow1, + PinName flow2 +) +{ + FlowControl flow_type = (FlowControl)type; + switch (type) { + case RTS: + serial_set_flow_control(&_serial, flow_type, flow1, NC); + break; + + case CTS: + serial_set_flow_control(&_serial, flow_type, NC, flow1); + break; + + case RTSCTS: + case Disabled: + serial_set_flow_control(&_serial, flow_type, flow1, flow2); + break; + + default: + break; + } +} +#endif // DEVICE_SERIAL_FC + +int MinimalSerial::_base_getc() +{ + // Mutex is already held + return serial_getc(&_serial); +} + +int MinimalSerial::_base_putc(int c) +{ + // Mutex is already held + serial_putc(&_serial, c); + return c; +} + +} // namespace mbed + +#endif // DEVICE_SERIAL diff --git a/drivers/source/SerialBase.cpp b/drivers/source/SerialBase.cpp index 856944fd347..9da1e346f8a 100644 --- a/drivers/source/SerialBase.cpp +++ b/drivers/source/SerialBase.cpp @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited + * Copyright (c) 2006-2019 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,13 +24,13 @@ namespace mbed { SerialBase::SerialBase(PinName tx, PinName rx, int baud) : + MinimalSerial(tx, rx, baud), #if DEVICE_SERIAL_ASYNCH _thunk_irq(this), _tx_usage(DMA_USAGE_NEVER), _rx_usage(DMA_USAGE_NEVER), _tx_callback(NULL), _rx_callback(NULL), _tx_asynch_set(false), - _rx_asynch_set(false), + _rx_asynch_set(false) #endif - _serial(), _baud(baud) { // No lock needed in the constructor @@ -38,19 +38,9 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) : _irq[i] = NULL; } - serial_init(&_serial, tx, rx); - serial_baud(&_serial, _baud); serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this); } -void SerialBase::baud(int baudrate) -{ - lock(); - serial_baud(&_serial, baudrate); - _baud = baudrate; - unlock(); -} - void SerialBase::format(int bits, Parity parity, int stop_bits) { lock(); @@ -107,19 +97,6 @@ void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) } } -int SerialBase::_base_getc() -{ - // Mutex is already held - return serial_getc(&_serial); -} - -int SerialBase::_base_putc(int c) -{ - // Mutex is already held - serial_putc(&_serial, c); - return c; -} - void SerialBase::set_break() { lock(); @@ -171,31 +148,6 @@ SerialBase::~SerialBase() } } -#if DEVICE_SERIAL_FC -void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) -{ - lock(); - FlowControl flow_type = (FlowControl)type; - switch (type) { - case RTS: - serial_set_flow_control(&_serial, flow_type, flow1, NC); - break; - - case CTS: - serial_set_flow_control(&_serial, flow_type, NC, flow1); - break; - - case RTSCTS: - case Disabled: - serial_set_flow_control(&_serial, flow_type, flow1, flow2); - break; - - default: - break; - } - unlock(); -} -#endif #if DEVICE_SERIAL_ASYNCH diff --git a/drivers/source/UnbufferedSerial.cpp b/drivers/source/UnbufferedSerial.cpp new file mode 100644 index 00000000000..6fe244bfb03 --- /dev/null +++ b/drivers/source/UnbufferedSerial.cpp @@ -0,0 +1,108 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hal/serial_api.h" + +#include "drivers/UnbufferedSerial.h" + + +#if DEVICE_SERIAL + +namespace mbed { + +UnbufferedSerial::UnbufferedSerial( + PinName tx, + PinName rx, + int baud +) : SerialBase(tx, rx, baud) +{ +} + +int UnbufferedSerial::getc() +{ + lock(); + int ret = _base_getc(); + unlock(); + return ret; +} + +int UnbufferedSerial::putc(int c) +{ + lock(); + int ret = _base_putc(c); + unlock(); + return ret; +} + +int UnbufferedSerial::puts(const char *str) +{ + lock(); + while (*str) { + putc(*str ++); + } + unlock(); + return 0; +} + +ssize_t UnbufferedSerial::write(const void *buffer, size_t size) +{ + const unsigned char *buf = static_cast(buffer); + for (size_t i = 0; i < size; i++) { + serial_putc(&_serial, buf[i]); + } + return size; +} + +ssize_t UnbufferedSerial::read(void *buffer, size_t size) +{ + unsigned char *buf = static_cast(buffer); + if (size == 0) { + return 0; + } + buf[0] = serial_getc(&_serial); + return 1; +} + +short UnbufferedSerial::poll(short events) const +{ + short revents = 0; + if ((events & POLLIN) && serial_readable((serial_t*)&_serial)) { + revents |= POLLIN; + } + if ((events & POLLOUT) && serial_writable((serial_t*)&_serial)) { + revents |= POLLOUT; + } + return revents; +} + +/** Acquire exclusive access to this serial port + */ +void UnbufferedSerial::lock() +{ + // No lock used - external synchronization required +} + +/** Release exclusive access to this serial port + */ +void UnbufferedSerial::unlock() +{ + // No lock used - external synchronization required +} + +} // namespace mbed + +#endif // #if DEVICE_SERIAL diff --git a/platform/mbed_lib.json b/platform/mbed_lib.json index b571f3781ba..2a6396eba46 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.) Enable this instead of `stdio-buffered-serial` if filehandles are not required to access the serial interface as console only to print.", + "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 c5058280083..ba1bdac58d1 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 2038c1adad6..cb5bcd38e27 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) } } @@ -208,7 +214,79 @@ 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 MinimalSerial { +public: + MinimalConsole(int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE); + int putc(int c); + 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(int baud) : + MinimalSerial( + stdio_uart, + (bool)stdio_uart_inited, + STDIO_UART_TX, + STDIO_UART_RX, + baud + ) +{ + if (stdio_uart_inited) { + return; + } + +#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS + set_flow_control(MinimalSerial::RTS, STDIO_UART_RTS, NC); +#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS + set_flow_control(MinimalSerial::CTS, NC, STDIO_UART_CTS); +#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS + set_flow_control(MinimalSerial::RTSCTS, 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) +{ + return _base_putc(c); +} + +/** Read a char to the serial port + * + * @returns The char read from the serial port + */ +int MinimalConsole::getc() +{ + return _base_getc(); +} + + +/* Locate the default console */ +static MinimalConsole *get_minimal_console() +{ + static MinimalConsole console( + 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 +325,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 +469,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 +484,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 +499,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 +556,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 +604,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 +647,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 +676,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 +773,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 +787,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 +796,22 @@ 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(); + + 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 +891,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 +905,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 +914,22 @@ 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(); + + 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 +942,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 +956,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 +971,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 +985,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 +1031,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 +1051,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 +1073,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 +1150,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 +1227,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 +1508,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