diff --git a/drivers/UARTSerial.cpp b/drivers/UARTSerial.cpp index 2f317b5310..f118e7d53b 100644 --- a/drivers/UARTSerial.cpp +++ b/drivers/UARTSerial.cpp @@ -32,11 +32,13 @@ UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) : SerialBase(tx, rx, baud), _blocking(true), _tx_irq_enabled(false), - _rx_irq_enabled(true), + _rx_irq_enabled(false), + _tx_enabled(true), + _rx_enabled(true), _dcd_irq(NULL) { /* Attatch IRQ routines to the serial device. */ - SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq); + enable_rx_irq(); } UARTSerial::~UARTSerial() @@ -188,11 +190,10 @@ ssize_t UARTSerial::write(const void *buffer, size_t length) } core_util_critical_section_enter(); - if (!_tx_irq_enabled) { + if (_tx_enabled && !_tx_irq_enabled) { UARTSerial::tx_irq(); // only write to hardware in one place if (!_txbuf.empty()) { - SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq); - _tx_irq_enabled = true; + enable_tx_irq(); } } core_util_critical_section_exit(); @@ -231,11 +232,10 @@ ssize_t UARTSerial::read(void *buffer, size_t length) } core_util_critical_section_enter(); - if (!_rx_irq_enabled) { + if (_rx_enabled && !_rx_irq_enabled) { UARTSerial::rx_irq(); // only read from hardware in one place if (!_rxbuf.full()) { - SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq); - _rx_irq_enabled = true; + enable_rx_irq(); } } core_util_critical_section_exit(); @@ -314,8 +314,7 @@ void UARTSerial::rx_irq(void) } if (_rx_irq_enabled && _rxbuf.full()) { - SerialBase::attach(NULL, RxIrq); - _rx_irq_enabled = false; + disable_rx_irq(); } /* Report the File handler that data is ready to be read from the buffer. */ @@ -337,8 +336,7 @@ void UARTSerial::tx_irq(void) } if (_tx_irq_enabled && _txbuf.empty()) { - SerialBase::attach(NULL, TxIrq); - _tx_irq_enabled = false; + disable_tx_irq(); } /* Report the File handler that data can be written to peripheral. */ @@ -347,6 +345,69 @@ void UARTSerial::tx_irq(void) } } +/* These are all called from critical section */ +void UARTSerial::enable_rx_irq() +{ + SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq); + _rx_irq_enabled = true; +} + +void UARTSerial::disable_rx_irq() +{ + SerialBase::attach(NULL, RxIrq); + _rx_irq_enabled = false; +} + +void UARTSerial::enable_tx_irq() +{ + SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq); + _tx_irq_enabled = true; +} + +void UARTSerial::disable_tx_irq() +{ + SerialBase::attach(NULL, TxIrq); + _tx_irq_enabled = false; +} + +int UARTSerial::enable_input(bool enabled) +{ + core_util_critical_section_enter(); + if (_rx_enabled != enabled) { + if (enabled) { + UARTSerial::rx_irq(); + if (!_rxbuf.full()) { + enable_rx_irq(); + } + } else { + disable_rx_irq(); + } + _rx_enabled = enabled; + } + core_util_critical_section_exit(); + + return 0; +} + +int UARTSerial::enable_output(bool enabled) +{ + core_util_critical_section_enter(); + if (_tx_enabled != enabled) { + if (enabled) { + UARTSerial::tx_irq(); + if (!_txbuf.empty()) { + enable_tx_irq(); + } + } else { + disable_tx_irq(); + } + _tx_enabled = enabled; + } + core_util_critical_section_exit(); + + return 0; +} + void UARTSerial::wait_ms(uint32_t millisec) { /* wait_ms implementation for RTOS spins until exact microseconds - we diff --git a/drivers/UARTSerial.h b/drivers/UARTSerial.h index 2a47da1a38..2959ce77e2 100644 --- a/drivers/UARTSerial.h +++ b/drivers/UARTSerial.h @@ -152,6 +152,36 @@ public: 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 @@ -242,6 +272,11 @@ private: /** Unbuffered write - invoked when write called from critical section */ ssize_t write_unbuffered(const char *buf_ptr, size_t length); + void enable_rx_irq(); + void disable_rx_irq(); + void enable_tx_irq(); + void disable_tx_irq(); + /** Software serial buffers * By default buffer size is 256 for TX and 256 for RX. Configurable through mbed_app.json */ @@ -255,6 +290,8 @@ private: bool _blocking; bool _tx_irq_enabled; bool _rx_irq_enabled; + bool _tx_enabled; + bool _rx_enabled; InterruptIn *_dcd_irq; /** Device Hanged up