diff --git a/drivers/SerialBase.h b/drivers/SerialBase.h index 5213f325fd..64787b804c 100644 --- a/drivers/SerialBase.h +++ b/drivers/SerialBase.h @@ -295,6 +295,30 @@ protected: int _base_putc(int c); + /** Initialize serial port + */ + void _init(); + + /** Deinitialize serial port + */ + void _deinit(); + + /** Enable serial input + * + * If both serial input and serial output are disabled, the + * peripheral is freed. If either serial input or serial + * output is re-enabled, the peripheral is reinitialized. + */ + void _enable_input(bool enable = true); + + /** Enable serial output + * + * If both serial input and serial output are disabled, the + * peripheral is freed. If either serial input or serial + * output is re-enabled, the peripheral is reinitialized. + */ + void _enable_output(bool enable = true); + #if DEVICE_SERIAL_ASYNCH CThunk _thunk_irq; DMAUsage _tx_usage; @@ -308,6 +332,10 @@ protected: serial_t _serial; Callback _irq[IrqCnt]; int _baud; + bool _rx_enabled; + bool _tx_enabled; + const PinName _tx_pin; + const PinName _rx_pin; #endif }; diff --git a/drivers/source/SerialBase.cpp b/drivers/source/SerialBase.cpp index 856944fd34..d3b2bd4eed 100644 --- a/drivers/source/SerialBase.cpp +++ b/drivers/source/SerialBase.cpp @@ -30,7 +30,7 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) : _rx_callback(NULL), _tx_asynch_set(false), _rx_asynch_set(false), #endif - _serial(), _baud(baud) + _serial(), _baud(baud), _rx_enabled(true), _tx_enabled(true), _tx_pin(tx), _rx_pin(rx) { // No lock needed in the constructor @@ -38,9 +38,7 @@ 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); + _init(); } void SerialBase::baud(int baudrate) @@ -120,6 +118,74 @@ int SerialBase::_base_putc(int c) return c; } +void SerialBase::_init() +{ + serial_init(&_serial, _tx_pin, _rx_pin); + serial_baud(&_serial, _baud); + serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this); +} + +void SerialBase::_deinit() +{ + serial_free(&_serial); +} + +void SerialBase::_enable_input(bool enable) +{ + if (_rx_enabled != enable) { + if(enable && !_tx_enabled) { + _init(); + } + + core_util_critical_section_enter(); + if (enable) { + // Enable rx IRQ if attached (indicated by rx IRQ callback not NULL) + if(_irq[RxIrq]) { + _irq[RxIrq].call(); + serial_irq_set(&_serial, (SerialIrq)RxIrq, 1); + } + } else { + // Disable rx IRQ + serial_irq_set(&_serial, (SerialIrq)RxIrq, 0); + } + core_util_critical_section_exit(); + + _rx_enabled = enable; + + if (!enable && !_tx_enabled) { + _deinit(); + } + } +} + +void SerialBase::_enable_output(bool enable) +{ + if (_tx_enabled != enable) { + if(enable && !_rx_enabled) { + _init(); + } + + core_util_critical_section_enter(); + if (enable) { + // Enable tx IRQ if attached (indicated by tx IRQ callback not NULL) + if(_irq[TxIrq]) { + _irq[TxIrq].call(); + serial_irq_set(&_serial, (SerialIrq)TxIrq, 1); + } + } else { + // Disable tx IRQ + serial_irq_set(&_serial, (SerialIrq)TxIrq, 0); + } + core_util_critical_section_exit(); + + _tx_enabled = enable; + + if (!enable && !_rx_enabled) { + _deinit(); + } + } +} + void SerialBase::set_break() { lock(); diff --git a/drivers/source/UARTSerial.cpp b/drivers/source/UARTSerial.cpp index 0475bf820e..4c9fe6710b 100644 --- a/drivers/source/UARTSerial.cpp +++ b/drivers/source/UARTSerial.cpp @@ -366,38 +366,18 @@ void UARTSerial::disable_tx_irq() 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(); + api_lock(); + _enable_input(enabled); + api_unlock(); 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(); + api_lock(); + _enable_input(enabled); + api_unlock(); return 0; }