mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #12207 from hugueskamba/hk-add-buffered_serial
Add BufferedSerial class to replace UARTSerialpull/12213/head
commit
18c941cc84
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Arm Limited and affiliates.
|
||||
* 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.
|
||||
*/
|
||||
#if !DEVICE_SERIAL
|
||||
#error [NOT_SUPPORTED] serial communication not supported for this target
|
||||
#else
|
||||
|
||||
#include "mbed.h"
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "platform/FileHandle.h"
|
||||
#include "drivers/BufferedSerial.h"
|
||||
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
|
||||
/**
|
||||
* Macros for setting console flow control.
|
||||
*/
|
||||
#define CONSOLE_FLOWCONTROL_RTS 1
|
||||
#define CONSOLE_FLOWCONTROL_CTS 2
|
||||
#define CONSOLE_FLOWCONTROL_RTSCTS 3
|
||||
#define mbed_console_concat_(x) CONSOLE_FLOWCONTROL_##x
|
||||
#define mbed_console_concat(x) mbed_console_concat_(x)
|
||||
#define CONSOLE_FLOWCONTROL mbed_console_concat(MBED_CONF_TARGET_CONSOLE_UART_FLOW_CONTROL)
|
||||
|
||||
|
||||
#define MSG_KEY_ECHO_MESSAGE "echo_message"
|
||||
#define MSG_VALUE_HELLO_WORLD "Hello, world!"
|
||||
|
||||
#define EXPECTED_ECHOED_STRING "{{" MSG_KEY_ECHO_MESSAGE ";" MSG_VALUE_HELLO_WORLD "}}"
|
||||
// The target is expected to transmit Greentea messages with \n (or \r\n) or they are not detected by the host
|
||||
#define STRING_TO_SEND EXPECTED_ECHOED_STRING "\n"
|
||||
|
||||
|
||||
static BufferedSerial buffered_serial_obj(
|
||||
USBTX, USBRX, MBED_CONF_PLATFORM_STDIO_BAUD_RATE
|
||||
);
|
||||
|
||||
|
||||
FileHandle *mbed::mbed_override_console(int fd)
|
||||
{
|
||||
return &buffered_serial_obj;
|
||||
}
|
||||
|
||||
static ssize_t buffered_serial_read(void *buffer, ssize_t length)
|
||||
{
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ignore the `\n` character previously sent to the host in the previous
|
||||
// key-value pair that may not have been removed from the FIFO.
|
||||
unsigned char *buf = static_cast<unsigned char *>(buffer);
|
||||
buffered_serial_obj.read(buf, 1);
|
||||
ssize_t i = (buf[0] == '{') ? 1 : 0;
|
||||
|
||||
// Get the message sent by the host
|
||||
for (; i < length; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT(1, buffered_serial_obj.read(buf + i, 1));
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
// Test that data sent using an UnbufferedSerial object is correctly sent.
|
||||
// The test case sends a Greentea key-value pair message from the target to the
|
||||
// host using an UnbufferedSerial object and expects the message
|
||||
// to be echoed back by the host. The host response is received via the Greentea
|
||||
// framework usual route using greentea_parse_kv(). Success is determined upon
|
||||
// reception of the echoed message which indicates that the message was received
|
||||
// by the host as it was sent by the target.
|
||||
static void test_serial_write()
|
||||
{
|
||||
char tx_msg[] = STRING_TO_SEND;
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT(
|
||||
strlen(tx_msg) + 1,
|
||||
buffered_serial_obj.write(tx_msg, strlen(tx_msg) + 1)
|
||||
);
|
||||
|
||||
char rx_key[30] = {0};
|
||||
char rx_value[30] = {0};
|
||||
greentea_parse_kv(rx_key, rx_value, sizeof(rx_key), sizeof(rx_value));
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(MSG_KEY_ECHO_MESSAGE, rx_key);
|
||||
TEST_ASSERT_EQUAL_STRING(MSG_VALUE_HELLO_WORLD, rx_value);
|
||||
}
|
||||
|
||||
|
||||
// Test that data received using an UnbufferedSerial object is correctly received.
|
||||
// The test case sends a Greentea key-value pair message from the target to the
|
||||
// host via the Greentea framework usual route using greentea_send_kv().
|
||||
// It expects the message to be echoed back to the target. An UnbufferedSerial
|
||||
// object is used to handle the received message. Succes is determined upon
|
||||
// reception of a key-value pair matching the key-value pair sent by the target.
|
||||
static void test_serial_read()
|
||||
{
|
||||
greentea_send_kv(MSG_KEY_ECHO_MESSAGE, MSG_VALUE_HELLO_WORLD);
|
||||
|
||||
char rx_msg[sizeof(EXPECTED_ECHOED_STRING)] = {0};
|
||||
// Exclude the null terminator which is not read
|
||||
ssize_t expected_rx_msg_length = sizeof(EXPECTED_ECHOED_STRING) - 1;
|
||||
|
||||
buffered_serial_read(rx_msg, expected_rx_msg_length);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(EXPECTED_ECHOED_STRING, rx_msg);
|
||||
}
|
||||
|
||||
|
||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(12, "serial_comms");
|
||||
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
|
||||
utest::v1::status_t greentea_failure_handler(
|
||||
const Case *const source, const failure_t reason
|
||||
)
|
||||
{
|
||||
greentea_case_failure_abort_handler(source, reason);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
Case cases[] = {
|
||||
Case(
|
||||
"Bytes are correctly sent",
|
||||
test_serial_write, greentea_failure_handler
|
||||
),
|
||||
Case(
|
||||
"Bytes are correctly received",
|
||||
test_serial_read, greentea_failure_handler
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
Specification specification(
|
||||
greentea_setup, cases, greentea_test_teardown_handler
|
||||
);
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS
|
||||
buffered_serial_obj.set_flow_control(
|
||||
SerialBase::RTS, STDIO_UART_RTS, NC
|
||||
);
|
||||
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS
|
||||
buffered_serial_obj.set_flow_control(
|
||||
SerialBase::CTS, NC, STDIO_UART_CTS
|
||||
);
|
||||
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS
|
||||
buffered_serial_obj.set_flow_control(
|
||||
SerialBase::RTSCTS, STDIO_UART_RTS, STDIO_UART_CTS
|
||||
);
|
||||
#endif
|
||||
return !Harness::run(specification);
|
||||
}
|
||||
|
||||
#endif // !DEVICE_SERIAL
|
|
@ -56,7 +56,7 @@ int main()
|
|||
|
||||
FileHandle *mbed::mbed_override_console(int)
|
||||
{
|
||||
static UARTSerial console(STDIO_UART_TX, STDIO_UART_RX, SERIAL_CONSOLE_BAUD_RATE);
|
||||
static BufferedSerial console(STDIO_UART_TX, STDIO_UART_RX, SERIAL_CONSOLE_BAUD_RATE);
|
||||
#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS
|
||||
console.set_flow_control(SerialBase::RTS, STDIO_UART_RTS, NC);
|
||||
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "platform/FileHandle.h"
|
||||
#include "drivers/UARTSerial.h"
|
||||
#include "drivers/BufferedSerial.h"
|
||||
|
||||
/**
|
||||
* Macros for setting console flow control.
|
||||
|
@ -32,8 +32,9 @@
|
|||
|
||||
mbed::FileHandle *mbed::mbed_override_console(int)
|
||||
{
|
||||
static mbed::UARTSerial console(STDIO_UART_TX, STDIO_UART_RX,
|
||||
SERIAL_CONSOLE_BAUD_RATE);
|
||||
static mbed::BufferedSerial console(
|
||||
STDIO_UART_TX, STDIO_UART_RX, SERIAL_CONSOLE_BAUD_RATE
|
||||
);
|
||||
#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS
|
||||
mbed::console.set_flow_control(SerialBase::RTS, STDIO_UART_RTS, NC);
|
||||
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS
|
||||
|
|
|
@ -57,7 +57,7 @@ int main()
|
|||
|
||||
FileHandle *mbed::mbed_override_console(int)
|
||||
{
|
||||
static UARTSerial console(STDIO_UART_TX, STDIO_UART_RX, SERIAL_CONSOLE_BAUD_RATE);
|
||||
static BufferedSerial console(STDIO_UART_TX, STDIO_UART_RX, SERIAL_CONSOLE_BAUD_RATE);
|
||||
#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS
|
||||
console.set_flow_control(SerialBase::RTS, STDIO_UART_RTS, NC);
|
||||
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
/* 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_BUFFEREDSERIAL_H
|
||||
#define MBED_BUFFEREDSERIAL_H
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) || defined(DOXYGEN_ONLY)
|
||||
|
||||
#include "platform/FileHandle.h"
|
||||
#include "drivers/SerialBase.h"
|
||||
#include "drivers/InterruptIn.h"
|
||||
#include "platform/PlatformMutex.h"
|
||||
#include "platform/CircularBuffer.h"
|
||||
#include "platform/NonCopyable.h"
|
||||
|
||||
#ifndef MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE
|
||||
#define MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE 256
|
||||
#endif
|
||||
|
||||
#ifndef MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE
|
||||
#define MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE 256
|
||||
#endif
|
||||
|
||||
namespace mbed {
|
||||
/**
|
||||
* \defgroup drivers_BufferedSerial BufferedSerial class
|
||||
* \ingroup drivers-public-api-uart
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Class providing buffered UART communication functionality using separate
|
||||
* circular buffer for send and receive channels
|
||||
*
|
||||
*/
|
||||
|
||||
class BufferedSerial:
|
||||
private SerialBase,
|
||||
public FileHandle,
|
||||
private NonCopyable<BufferedSerial> {
|
||||
|
||||
public:
|
||||
|
||||
/** Create a BufferedSerial port, connected to the specified transmit and
|
||||
* receive pins, with a particular 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)
|
||||
*/
|
||||
BufferedSerial(
|
||||
PinName tx,
|
||||
PinName rx,
|
||||
int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE
|
||||
);
|
||||
|
||||
/** Create a BufferedSerial port, connected to the specified transmit and
|
||||
* receive pins, with a particular baud rate.
|
||||
* @param static_pinmap reference to structure which holds static pinmap
|
||||
* @param baud The baud rate of the serial port (optional, defaults to
|
||||
* MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE)
|
||||
*/
|
||||
BufferedSerial(
|
||||
const serial_pinmap_t &static_pinmap,
|
||||
int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE
|
||||
);
|
||||
|
||||
virtual ~BufferedSerial();
|
||||
|
||||
/** Equivalent to POSIX poll(). Derived from FileHandle.
|
||||
* Provides a mechanism to multiplex input/output over a set of file
|
||||
* handles.
|
||||
* The events that can be reported are POLLIN, POLLOUT, POLLHUP.
|
||||
*/
|
||||
virtual short poll(short events) const;
|
||||
|
||||
/* Resolve ambiguities versus our private SerialBase
|
||||
* (for writable, spelling differs, but just in case)
|
||||
*/
|
||||
using FileHandle::readable;
|
||||
using FileHandle::writable;
|
||||
|
||||
/** 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 length);
|
||||
|
||||
/** 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 length);
|
||||
|
||||
/** Close a file
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int close();
|
||||
|
||||
/** 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();
|
||||
|
||||
/** Move the file position to a given offset from from a given location
|
||||
*
|
||||
* Not valid for a device type FileHandle like BufferedSerial.
|
||||
* In case of BufferedSerial, 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);
|
||||
|
||||
/** Flush any buffers associated with the file
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int sync();
|
||||
|
||||
/** Set blocking or non-blocking mode
|
||||
* The default is blocking.
|
||||
*
|
||||
* @param blocking true for blocking mode, false for non-blocking mode.
|
||||
*/
|
||||
virtual int set_blocking(bool blocking)
|
||||
{
|
||||
_blocking = blocking;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Check current blocking or non-blocking mode for file operations.
|
||||
*
|
||||
* @return true for blocking mode, false for non-blocking mode.
|
||||
*/
|
||||
virtual bool is_blocking() const
|
||||
{
|
||||
return _blocking;
|
||||
}
|
||||
|
||||
/** Enable or disable input
|
||||
*
|
||||
* Control enabling of device for input. This is primarily intended
|
||||
* for temporary power-saving; the overall ability of the device to operate
|
||||
* for input and/or output may be fixed at creation time, but this call can
|
||||
* allow input to be temporarily disabled to permit power saving without
|
||||
* losing device state.
|
||||
*
|
||||
* @param enabled true to enable input, false to disable.
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return Negative error code on failure
|
||||
*/
|
||||
virtual int enable_input(bool enabled);
|
||||
|
||||
/** Enable or disable output
|
||||
*
|
||||
* Control enabling of device for output. This is primarily intended
|
||||
* for temporary power-saving; the overall ability of the device to operate
|
||||
* for input and/or output may be fixed at creation time, but this call can
|
||||
* allow output to be temporarily disabled to permit power saving without
|
||||
* losing device state.
|
||||
*
|
||||
* @param enabled true to enable output, false to disable.
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return Negative error code on failure
|
||||
*/
|
||||
virtual int enable_output(bool enabled);
|
||||
|
||||
/** Register a callback on state change of the file.
|
||||
*
|
||||
* The specified callback will be called on state changes such as when
|
||||
* the file can be written to or read from.
|
||||
*
|
||||
* The callback may be called in an interrupt context and should not
|
||||
* perform expensive operations.
|
||||
*
|
||||
* Note! This is not intended as an attach-like asynchronous api, but
|
||||
* rather as a building block for constructing such functionality.
|
||||
*
|
||||
* The exact timing of when the registered function
|
||||
* is called is not guaranteed and susceptible to change. It should be
|
||||
* used as a cue to make read/write/poll calls to find the current state.
|
||||
*
|
||||
* @param func Function to call on state change
|
||||
*/
|
||||
virtual void sigio(Callback<void()> func);
|
||||
|
||||
/** Setup interrupt handler for DCD line
|
||||
*
|
||||
* If DCD line is connected, an IRQ handler will be setup.
|
||||
* Does nothing if DCD is NC, i.e., not connected.
|
||||
*
|
||||
* @param dcd_pin Pin-name for DCD
|
||||
* @param active_high a boolean set to true if DCD polarity is active
|
||||
* low
|
||||
*/
|
||||
void set_data_carrier_detect(PinName dcd_pin, bool active_high = false);
|
||||
|
||||
/** Set the baud rate
|
||||
*
|
||||
* @param baud The baud rate
|
||||
*/
|
||||
void set_baud(int baud);
|
||||
|
||||
// Expose private SerialBase::Parity as BufferedSerial::Parity
|
||||
using SerialBase::Parity;
|
||||
|
||||
/** Set the transmission format used by the serial port
|
||||
*
|
||||
* @param bits The number of bits in a word (5-8; default = 8)
|
||||
* @param parity The parity used (None, Odd, Even, Forced1, Forced0;
|
||||
* default = None)
|
||||
* @param stop_bits The number of stop bits (1 or 2; default = 1)
|
||||
*/
|
||||
void set_format(
|
||||
int bits = 8, Parity parity = BufferedSerial::None, int stop_bits = 1
|
||||
);
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
// For now use the base enum - but in future we may have extra options
|
||||
// such as XON/XOFF or manual GPIO RTSCTS.
|
||||
using SerialBase::Flow;
|
||||
|
||||
/** 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
|
||||
|
||||
private:
|
||||
|
||||
/** Acquire mutex
|
||||
*/
|
||||
virtual void api_lock(void);
|
||||
|
||||
/** Release mutex
|
||||
*/
|
||||
virtual void api_unlock(void);
|
||||
|
||||
/** Unbuffered write - invoked when write called from critical section
|
||||
* @param buf_ptr The buffer to write from
|
||||
* @param length The number of bytes to write
|
||||
* @return The number of bytes written, negative error on failure
|
||||
*/
|
||||
ssize_t write_unbuffered(const char *buf_ptr, size_t length);
|
||||
|
||||
/** Enable processing of byte reception IRQs and register a callback to
|
||||
* process them.
|
||||
*/
|
||||
void enable_rx_irq();
|
||||
|
||||
/** Disable processing of byte reception IRQs and de-register callback to
|
||||
* process them.
|
||||
*/
|
||||
void disable_rx_irq();
|
||||
|
||||
/** Enable processing of byte transmission IRQs and register a callback to
|
||||
* process them.
|
||||
*/
|
||||
void enable_tx_irq();
|
||||
|
||||
/** Disable processing of byte transmission IRQs and de-register callback to
|
||||
* process them.
|
||||
*/
|
||||
void disable_tx_irq();
|
||||
|
||||
/** Software serial buffers
|
||||
* By default buffer size is 256 for TX and 256 for RX. Configurable
|
||||
* through mbed_app.json
|
||||
*/
|
||||
CircularBuffer<char, MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE> _rxbuf;
|
||||
CircularBuffer<char, MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE> _txbuf;
|
||||
|
||||
PlatformMutex _mutex;
|
||||
|
||||
Callback<void()> _sigio_cb;
|
||||
|
||||
bool _blocking = true;
|
||||
bool _tx_irq_enabled = false;
|
||||
bool _rx_irq_enabled = false;
|
||||
bool _tx_enabled = true;
|
||||
bool _rx_enabled = true;
|
||||
InterruptIn *_dcd_irq = nullptr;
|
||||
|
||||
/** Device Hanged up
|
||||
* Determines if the device hanged up on us.
|
||||
*
|
||||
* @return True, if hanged up
|
||||
*/
|
||||
bool hup() const;
|
||||
|
||||
/** ISRs for serial
|
||||
* Routines to handle interrupts on serial pins.
|
||||
* Copies data into Circular Buffer.
|
||||
* Reports the state change to File handle.
|
||||
*/
|
||||
void tx_irq(void);
|
||||
void rx_irq(void);
|
||||
|
||||
/** Execute a callback previously registered for state change of the file.
|
||||
*/
|
||||
void wake(void);
|
||||
|
||||
/** Wake on data carrier detected.
|
||||
*/
|
||||
void dcd_irq(void);
|
||||
};
|
||||
|
||||
/** @}*/
|
||||
|
||||
} //namespace mbed
|
||||
|
||||
#endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN) || defined(DOXYGEN_ONLY)
|
||||
#endif //MBED_BUFFEREDSERIAL_H
|
|
@ -39,7 +39,7 @@ namespace mbed {
|
|||
*/
|
||||
|
||||
/** A base class for serial port implementations
|
||||
* Can't be instantiated directly (use UnbufferedSerial or UARTSerial)
|
||||
* Can't be instantiated directly (use UnbufferedSerial or BufferedSerial)
|
||||
*
|
||||
* @note Synchronization level: Set by subclass
|
||||
*/
|
||||
|
|
|
@ -48,28 +48,39 @@ namespace mbed {
|
|||
*
|
||||
*/
|
||||
|
||||
class UARTSerial : private SerialBase, public FileHandle, private NonCopyable<UARTSerial> {
|
||||
class
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-6.0.0",
|
||||
"Use BufferedSerial instead."
|
||||
) UARTSerial : private SerialBase, public FileHandle, private NonCopyable<UARTSerial> {
|
||||
|
||||
public:
|
||||
|
||||
/** Create a UARTSerial port, connected to the specified transmit and receive pins, with a particular baud rate.
|
||||
/** @deprecated
|
||||
* Create a UARTSerial port, connected to the specified transmit and receive pins, with a particular 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)
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
UARTSerial(PinName tx, PinName rx, int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
|
||||
|
||||
/** Create a UARTSerial port, connected to the specified transmit and receive pins, with a particular baud rate.
|
||||
/** @deprecated
|
||||
* Create a UARTSerial port, connected to the specified transmit and receive pins, with a particular baud rate.
|
||||
* @param static_pinmap reference to structure which holds static pinmap
|
||||
* @param baud The baud rate of the serial port (optional, defaults to MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE)
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
UARTSerial(const serial_pinmap_t &static_pinmap, int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
|
||||
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual ~UARTSerial();
|
||||
|
||||
/** Equivalent to POSIX poll(). Derived from FileHandle.
|
||||
/** @deprecated
|
||||
* Equivalent to POSIX poll(). Derived from FileHandle.
|
||||
* Provides a mechanism to multiplex input/output over a set of file handles.
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual short poll(short events) const;
|
||||
|
||||
/* Resolve ambiguities versus our private SerialBase
|
||||
|
@ -78,7 +89,8 @@ public:
|
|||
using FileHandle::readable;
|
||||
using FileHandle::writable;
|
||||
|
||||
/** Write the contents of a buffer to a file
|
||||
/** @deprecated
|
||||
* Write the contents of a buffer to a file
|
||||
*
|
||||
* Follows POSIX semantics:
|
||||
*
|
||||
|
@ -90,9 +102,11 @@ public:
|
|||
* @param length The number of bytes to write
|
||||
* @return The number of bytes written, negative error on failure
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual ssize_t write(const void *buffer, size_t length);
|
||||
|
||||
/** Read the contents of a file into a buffer
|
||||
/** @deprecated
|
||||
* Read the contents of a file into a buffer
|
||||
*
|
||||
* Follows POSIX semantics:
|
||||
*
|
||||
|
@ -104,23 +118,29 @@ public:
|
|||
* @param length The number of bytes to read
|
||||
* @return The number of bytes read, 0 at end of file, negative error on failure
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual ssize_t read(void *buffer, size_t length);
|
||||
|
||||
/** Close a file
|
||||
/** @deprecated
|
||||
* Close a file
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual int close();
|
||||
|
||||
/** Check if the file in an interactive terminal device
|
||||
/** @deprecated
|
||||
* 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
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual int isatty();
|
||||
|
||||
/** Move the file position to a given offset from from a given location
|
||||
/** @deprecated
|
||||
* 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
|
||||
|
@ -132,35 +152,43 @@ public:
|
|||
* SEEK_END to start from end of file
|
||||
* @return The new offset of the file, negative error code on failure
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual off_t seek(off_t offset, int whence);
|
||||
|
||||
/** Flush any buffers associated with the file
|
||||
/** @deprecated
|
||||
* Flush any buffers associated with the file
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual int sync();
|
||||
|
||||
/** Set blocking or non-blocking mode
|
||||
/** @deprecated
|
||||
* Set blocking or non-blocking mode
|
||||
* The default is blocking.
|
||||
*
|
||||
* @param blocking true for blocking mode, false for non-blocking mode.
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual int set_blocking(bool blocking)
|
||||
{
|
||||
_blocking = blocking;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Check current blocking or non-blocking mode for file operations.
|
||||
/** @deprecated
|
||||
* Check current blocking or non-blocking mode for file operations.
|
||||
*
|
||||
* @return true for blocking mode, false for non-blocking mode.
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual bool is_blocking() const
|
||||
{
|
||||
return _blocking;
|
||||
}
|
||||
|
||||
/** Enable or disable input
|
||||
/** @deprecated
|
||||
* Enable or disable input
|
||||
*
|
||||
* Control enabling of device for input. This is primarily intended
|
||||
* for temporary power-saving; the overall ability of the device to operate for
|
||||
|
@ -173,9 +201,11 @@ public:
|
|||
* @return 0 on success
|
||||
* @return Negative error code on failure
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual int enable_input(bool enabled);
|
||||
|
||||
/** Enable or disable output
|
||||
/** @deprecated
|
||||
* Enable or disable output
|
||||
*
|
||||
* Control enabling of device for output. This is primarily intended
|
||||
* for temporary power-saving; the overall ability of the device to operate for
|
||||
|
@ -188,9 +218,11 @@ public:
|
|||
* @return 0 on success
|
||||
* @return Negative error code on failure
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual int enable_output(bool enabled);
|
||||
|
||||
/** Register a callback on state change of the file.
|
||||
/** @deprecated
|
||||
* Register a callback on state change of the file.
|
||||
*
|
||||
* The specified callback will be called on state changes such as when
|
||||
* the file can be written to or read from.
|
||||
|
@ -207,9 +239,11 @@ public:
|
|||
*
|
||||
* @param func Function to call on state change
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
virtual void sigio(Callback<void()> func);
|
||||
|
||||
/** Setup interrupt handler for DCD line
|
||||
/** @deprecated
|
||||
* Setup interrupt handler for DCD line
|
||||
*
|
||||
* If DCD line is connected, an IRQ handler will be setup.
|
||||
* Does nothing if DCD is NC, i.e., not connected.
|
||||
|
@ -217,12 +251,15 @@ public:
|
|||
* @param dcd_pin Pin-name for DCD
|
||||
* @param active_high a boolean set to true if DCD polarity is active low
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
void set_data_carrier_detect(PinName dcd_pin, bool active_high = false);
|
||||
|
||||
/** Set the baud rate
|
||||
/** @deprecated
|
||||
* Set the baud rate
|
||||
*
|
||||
* @param baud The baud rate
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
void set_baud(int baud);
|
||||
|
||||
// Expose private SerialBase::Parity as UARTSerial::Parity
|
||||
|
@ -234,12 +271,14 @@ public:
|
|||
using SerialBase::Forced1;
|
||||
using SerialBase::Forced0;
|
||||
|
||||
/** Set the transmission format used by the serial port
|
||||
/** @deprecated
|
||||
* Set the transmission format used by the serial port
|
||||
*
|
||||
* @param bits The number of bits in a word (5-8; default = 8)
|
||||
* @param parity The parity used (None, Odd, Even, Forced1, Forced0; default = None)
|
||||
* @param stop_bits The number of stop bits (1 or 2; default = 1)
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
void set_format(int bits = 8, Parity parity = UARTSerial::None, int stop_bits = 1);
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
|
@ -252,30 +291,42 @@ public:
|
|||
using SerialBase::CTS;
|
||||
using SerialBase::RTSCTS;
|
||||
|
||||
/** Set the flow control type on the serial port
|
||||
/** @deprecated
|
||||
* 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)
|
||||
*/
|
||||
MBED_DEPRECATED("The class has been deprecated and will be removed in the future.")
|
||||
void set_flow_control(Flow type, PinName flow1 = NC, PinName flow2 = NC);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
/** SerialBase lock override */
|
||||
/** @deprecated
|
||||
* SerialBase lock override
|
||||
*/
|
||||
virtual void lock(void);
|
||||
|
||||
/** SerialBase unlock override */
|
||||
/** @deprecated
|
||||
* SerialBase unlock override
|
||||
*/
|
||||
virtual void unlock(void);
|
||||
|
||||
/** Acquire mutex */
|
||||
/** @deprecated
|
||||
* Acquire mutex
|
||||
*/
|
||||
virtual void api_lock(void);
|
||||
|
||||
/** Release mutex */
|
||||
/** @deprecated
|
||||
* Release mutex
|
||||
*/
|
||||
virtual void api_unlock(void);
|
||||
|
||||
/** Unbuffered write - invoked when write called from critical section */
|
||||
/** @deprecated
|
||||
* Unbuffered write - invoked when write called from critical section
|
||||
*/
|
||||
ssize_t write_unbuffered(const char *buf_ptr, size_t length);
|
||||
|
||||
void enable_rx_irq();
|
||||
|
@ -283,7 +334,8 @@ private:
|
|||
void enable_tx_irq();
|
||||
void disable_tx_irq();
|
||||
|
||||
/** Software serial buffers
|
||||
/** @deprecated
|
||||
* Software serial buffers
|
||||
* By default buffer size is 256 for TX and 256 for RX. Configurable through mbed_app.json
|
||||
*/
|
||||
CircularBuffer<char, MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE> _rxbuf;
|
||||
|
@ -300,14 +352,16 @@ private:
|
|||
bool _rx_enabled;
|
||||
InterruptIn *_dcd_irq;
|
||||
|
||||
/** Device Hanged up
|
||||
/** @deprecated
|
||||
* Device Hanged up
|
||||
* Determines if the device hanged up on us.
|
||||
*
|
||||
* @return True, if hanged up
|
||||
*/
|
||||
bool hup() const;
|
||||
|
||||
/** ISRs for serial
|
||||
/** @deprecated
|
||||
* ISRs for serial
|
||||
* Routines to handle interrupts on serial pins.
|
||||
* Copies data into Circular Buffer.
|
||||
* Reports the state change to File handle.
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"name": "drivers",
|
||||
"config": {
|
||||
"uart-serial-txbuf-size": {
|
||||
"help": "Default TX buffer size for a UARTSerial instance (unit Bytes))",
|
||||
"help": "Default TX buffer size for a BufferedSerial instance (unit Bytes))",
|
||||
"value": 256
|
||||
},
|
||||
"uart-serial-rxbuf-size": {
|
||||
"help": "Default RX buffer size for a UARTSerial instance (unit Bytes))",
|
||||
"help": "Default RX buffer size for a BufferedSerial instance (unit Bytes))",
|
||||
"value": 256
|
||||
},
|
||||
"crc-table-size": {
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
/* 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 "drivers/BufferedSerial.h"
|
||||
|
||||
#if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)
|
||||
|
||||
#include "platform/mbed_poll.h"
|
||||
#include "platform/mbed_thread.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
BufferedSerial::BufferedSerial(PinName tx, PinName rx, int baud):
|
||||
SerialBase(tx, rx, baud)
|
||||
{
|
||||
enable_rx_irq();
|
||||
}
|
||||
|
||||
BufferedSerial::BufferedSerial(const serial_pinmap_t &static_pinmap, int baud):
|
||||
SerialBase(static_pinmap, baud)
|
||||
{
|
||||
enable_rx_irq();
|
||||
}
|
||||
|
||||
BufferedSerial::~BufferedSerial()
|
||||
{
|
||||
delete _dcd_irq;
|
||||
}
|
||||
|
||||
void BufferedSerial::dcd_irq()
|
||||
{
|
||||
wake();
|
||||
}
|
||||
|
||||
void BufferedSerial::set_baud(int baud)
|
||||
{
|
||||
SerialBase::baud(baud);
|
||||
}
|
||||
|
||||
void BufferedSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
|
||||
{
|
||||
delete _dcd_irq;
|
||||
_dcd_irq = NULL;
|
||||
|
||||
if (dcd_pin != NC) {
|
||||
_dcd_irq = new InterruptIn(dcd_pin);
|
||||
if (active_high) {
|
||||
_dcd_irq->fall(callback(this, &BufferedSerial::dcd_irq));
|
||||
} else {
|
||||
_dcd_irq->rise(callback(this, &BufferedSerial::dcd_irq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BufferedSerial::set_format(int bits, Parity parity, int stop_bits)
|
||||
{
|
||||
api_lock();
|
||||
SerialBase::format(bits, parity, stop_bits);
|
||||
api_unlock();
|
||||
}
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
void BufferedSerial::set_flow_control(Flow type, PinName flow1, PinName flow2)
|
||||
{
|
||||
api_lock();
|
||||
SerialBase::set_flow_control(type, flow1, flow2);
|
||||
api_unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
int BufferedSerial::close()
|
||||
{
|
||||
// Does not let us pass a file descriptor. So how to close ?
|
||||
// Also, does it make sense to close a device type file descriptor?
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferedSerial::isatty()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
off_t BufferedSerial::seek(off_t offset, int whence)
|
||||
{
|
||||
// lseek can be done theoratically, but is it sane to mark positions on
|
||||
// a dynamically growing/shrinking buffer system (from an interrupt
|
||||
// context)
|
||||
return -ESPIPE;
|
||||
}
|
||||
|
||||
int BufferedSerial::sync()
|
||||
{
|
||||
api_lock();
|
||||
|
||||
while (!_txbuf.empty()) {
|
||||
api_unlock();
|
||||
// Doing better than wait would require TxIRQ to also do wake() when
|
||||
// becoming empty. Worth it?
|
||||
thread_sleep_for(1);
|
||||
api_lock();
|
||||
}
|
||||
|
||||
api_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BufferedSerial::sigio(Callback<void()> func)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
_sigio_cb = func;
|
||||
if (_sigio_cb) {
|
||||
short current_events = poll(0x7FFF);
|
||||
if (current_events) {
|
||||
_sigio_cb();
|
||||
}
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/* Special synchronous write designed to work from critical section, such
|
||||
* as in mbed_error_vprintf.
|
||||
*/
|
||||
ssize_t BufferedSerial::write_unbuffered(const char *buf_ptr, size_t length)
|
||||
{
|
||||
while (!_txbuf.empty()) {
|
||||
tx_irq();
|
||||
}
|
||||
|
||||
for (size_t data_written = 0; data_written < length; data_written++) {
|
||||
SerialBase::_base_putc(*buf_ptr++);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
ssize_t BufferedSerial::write(const void *buffer, size_t length)
|
||||
{
|
||||
size_t data_written = 0;
|
||||
const char *buf_ptr = static_cast<const char *>(buffer);
|
||||
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (core_util_in_critical_section()) {
|
||||
return write_unbuffered(buf_ptr, length);
|
||||
}
|
||||
|
||||
api_lock();
|
||||
|
||||
// Unlike read, we should write the whole thing if blocking. POSIX only
|
||||
// allows partial as a side-effect of signal handling; it normally tries to
|
||||
// write everything if blocking. Without signals we can always write all.
|
||||
while (data_written < length) {
|
||||
|
||||
if (_txbuf.full()) {
|
||||
if (!_blocking) {
|
||||
break;
|
||||
}
|
||||
do {
|
||||
api_unlock();
|
||||
// Should we have a proper wait?
|
||||
thread_sleep_for(1);
|
||||
api_lock();
|
||||
} while (_txbuf.full());
|
||||
}
|
||||
|
||||
while (data_written < length && !_txbuf.full()) {
|
||||
_txbuf.push(*buf_ptr++);
|
||||
data_written++;
|
||||
}
|
||||
|
||||
core_util_critical_section_enter();
|
||||
if (_tx_enabled && !_tx_irq_enabled) {
|
||||
// only write to hardware in one place
|
||||
BufferedSerial::tx_irq();
|
||||
if (!_txbuf.empty()) {
|
||||
enable_tx_irq();
|
||||
}
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
api_unlock();
|
||||
|
||||
return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
|
||||
}
|
||||
|
||||
ssize_t BufferedSerial::read(void *buffer, size_t length)
|
||||
{
|
||||
size_t data_read = 0;
|
||||
|
||||
char *ptr = static_cast<char *>(buffer);
|
||||
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
api_lock();
|
||||
|
||||
while (_rxbuf.empty()) {
|
||||
if (!_blocking) {
|
||||
api_unlock();
|
||||
return -EAGAIN;
|
||||
}
|
||||
api_unlock();
|
||||
// Do we need a proper wait?
|
||||
thread_sleep_for(1);
|
||||
api_lock();
|
||||
}
|
||||
|
||||
while (data_read < length && !_rxbuf.empty()) {
|
||||
_rxbuf.pop(*ptr++);
|
||||
data_read++;
|
||||
}
|
||||
|
||||
core_util_critical_section_enter();
|
||||
if (_rx_enabled && !_rx_irq_enabled) {
|
||||
// only read from hardware in one place
|
||||
BufferedSerial::rx_irq();
|
||||
if (!_rxbuf.full()) {
|
||||
enable_rx_irq();
|
||||
}
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
|
||||
api_unlock();
|
||||
|
||||
return data_read;
|
||||
}
|
||||
|
||||
bool BufferedSerial::hup() const
|
||||
{
|
||||
return _dcd_irq && _dcd_irq->read() != 0;
|
||||
}
|
||||
|
||||
void BufferedSerial::wake()
|
||||
{
|
||||
if (_sigio_cb) {
|
||||
_sigio_cb();
|
||||
}
|
||||
}
|
||||
|
||||
short BufferedSerial::poll(short events) const
|
||||
{
|
||||
|
||||
short revents = 0;
|
||||
// Check the Circular Buffer if space available for writing out
|
||||
|
||||
|
||||
if (!_rxbuf.empty()) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
|
||||
// POLLHUP and POLLOUT are mutually exclusive
|
||||
if (hup()) {
|
||||
revents |= POLLHUP;
|
||||
} else if (!_txbuf.full()) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
void BufferedSerial::api_lock(void)
|
||||
{
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void BufferedSerial::api_unlock(void)
|
||||
{
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
void BufferedSerial::rx_irq(void)
|
||||
{
|
||||
bool was_empty = _rxbuf.empty();
|
||||
|
||||
// Fill in the receive buffer if the peripheral is readable
|
||||
// and receive buffer is not full.
|
||||
while (!_rxbuf.full() && SerialBase::readable()) {
|
||||
char data = SerialBase::_base_getc();
|
||||
_rxbuf.push(data);
|
||||
}
|
||||
|
||||
if (_rx_irq_enabled && _rxbuf.full()) {
|
||||
disable_rx_irq();
|
||||
}
|
||||
|
||||
// Report the File handler that data is ready to be read from the buffer.
|
||||
if (was_empty && !_rxbuf.empty()) {
|
||||
wake();
|
||||
}
|
||||
}
|
||||
|
||||
// Also called from write to start transfer
|
||||
void BufferedSerial::tx_irq(void)
|
||||
{
|
||||
bool was_full = _txbuf.full();
|
||||
char data;
|
||||
|
||||
// Write to the peripheral if there is something to write
|
||||
// and if the peripheral is available to write.
|
||||
while (SerialBase::writeable() && _txbuf.pop(data)) {
|
||||
SerialBase::_base_putc(data);
|
||||
}
|
||||
|
||||
if (_tx_irq_enabled && _txbuf.empty()) {
|
||||
disable_tx_irq();
|
||||
}
|
||||
|
||||
// Report the File handler that data can be written to peripheral.
|
||||
if (was_full && !_txbuf.full() && !hup()) {
|
||||
wake();
|
||||
}
|
||||
}
|
||||
|
||||
/* These are all called from critical section
|
||||
* Attatch IRQ routines to the serial device.
|
||||
*/
|
||||
void BufferedSerial::enable_rx_irq()
|
||||
{
|
||||
SerialBase::attach(callback(this, &BufferedSerial::rx_irq), RxIrq);
|
||||
_rx_irq_enabled = true;
|
||||
}
|
||||
|
||||
void BufferedSerial::disable_rx_irq()
|
||||
{
|
||||
SerialBase::attach(NULL, RxIrq);
|
||||
_rx_irq_enabled = false;
|
||||
}
|
||||
|
||||
void BufferedSerial::enable_tx_irq()
|
||||
{
|
||||
SerialBase::attach(callback(this, &BufferedSerial::tx_irq), TxIrq);
|
||||
_tx_irq_enabled = true;
|
||||
}
|
||||
|
||||
void BufferedSerial::disable_tx_irq()
|
||||
{
|
||||
SerialBase::attach(NULL, TxIrq);
|
||||
_tx_irq_enabled = false;
|
||||
}
|
||||
|
||||
int BufferedSerial::enable_input(bool enabled)
|
||||
{
|
||||
api_lock();
|
||||
SerialBase::enable_input(enabled);
|
||||
api_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferedSerial::enable_output(bool enabled)
|
||||
{
|
||||
api_lock();
|
||||
SerialBase::enable_output(enabled);
|
||||
api_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
|
1
mbed.h
1
mbed.h
|
@ -72,6 +72,7 @@
|
|||
#include "drivers/RawSerial.h"
|
||||
#include "drivers/UnbufferedSerial.h"
|
||||
#include "drivers/UARTSerial.h"
|
||||
#include "drivers/BufferedSerial.h"
|
||||
#include "drivers/FlashIAP.h"
|
||||
#include "drivers/MbedCRC.h"
|
||||
#include "drivers/QSPI.h"
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace mbed {
|
|||
*
|
||||
* Here are some examples:
|
||||
* @code
|
||||
* UARTSerial serial = UARTSerial(D1, D0);
|
||||
* BufferedSerial serial = BufferedSerial(D1, D0);
|
||||
* ATCmdParser at = ATCmdParser(&serial, "\r\n");
|
||||
* int value;
|
||||
* char buffer[100];
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
|
||||
"stdio-buffered-serial": {
|
||||
"help": "(Applies if target.console-uart is true and stdio-minimal-console-only is false.) Use UARTSerial driver to obtain buffered serial I/O on stdin/stdout/stderr. If false, unbuffered serial_getc and serial_putc are used directly.",
|
||||
"help": "(Applies if target.console-uart is true and stdio-minimal-console-only is false.) Use BufferedSerial driver to obtain buffered serial I/O on stdin/stdout/stderr. If false, unbuffered serial_getc and serial_putc are used directly.",
|
||||
"value": false
|
||||
},
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ class DirHandle;
|
|||
* 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
|
||||
* - BufferedSerial 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;
|
||||
|
@ -121,10 +121,10 @@ FileHandle *mbed_target_override_console(int fd);
|
|||
* by mbed_target_override_console, else will default to serial - see
|
||||
* mbed_target_override_console for more details.
|
||||
*
|
||||
* Example using UARTSerial:
|
||||
* Example using BufferedSerial:
|
||||
* @code
|
||||
* FileHandle *mbed::mbed_override_console(int) {
|
||||
* static UARTSerial my_serial(D0, D1);
|
||||
* static BufferedSerial my_serial(D0, D1);
|
||||
* return &my_serial;
|
||||
* }
|
||||
* @endcode
|
||||
|
|
|
@ -75,7 +75,7 @@ void mbed_error_vprintf(const char *format, va_list arg)
|
|||
void mbed_error_puts(const char *str)
|
||||
{
|
||||
// Writing the string to the console in a critical section is
|
||||
// potentially beneficial - for example in UARTSerial it
|
||||
// potentially beneficial - for example in BufferedSerial it
|
||||
// forces the "unbuffered" mode that makes sure all characters
|
||||
// go out now. If we made the call not in a critical section,
|
||||
// it would go to the software buffer and we would be reliant
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "platform/mbed_atomic.h"
|
||||
#include "platform/mbed_critical.h"
|
||||
#include "platform/mbed_poll.h"
|
||||
#include "drivers/UARTSerial.h"
|
||||
#include "drivers/BufferedSerial.h"
|
||||
#include "hal/us_ticker_api.h"
|
||||
#include "hal/lp_ticker_api.h"
|
||||
#include "hal/static_pinmap.h"
|
||||
|
@ -150,7 +150,7 @@ extern serial_t stdio_uart;
|
|||
/* 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.
|
||||
* is why it's not public. People should be using BufferedSerial.
|
||||
*/
|
||||
class DirectSerial : public FileHandle {
|
||||
public:
|
||||
|
@ -337,7 +337,7 @@ static FileHandle *default_console()
|
|||
|
||||
# if MBED_CONF_PLATFORM_STDIO_BUFFERED_SERIAL
|
||||
static const serial_pinmap_t console_pinmap = get_uart_pinmap(STDIO_UART_TX, STDIO_UART_RX);
|
||||
static UARTSerial console(console_pinmap, MBED_CONF_PLATFORM_STDIO_BAUD_RATE);
|
||||
static BufferedSerial console(console_pinmap, MBED_CONF_PLATFORM_STDIO_BAUD_RATE);
|
||||
# if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS
|
||||
static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, NC);
|
||||
console.serial_set_flow_control(SerialBase::RTS, fc_pinmap);
|
||||
|
|
Loading…
Reference in New Issue