Merge pull request #9476 from lrusinowicz/asynch_serial_api

Asynchronous Serial API fixes and refactoring
pull/10267/head
Cruz Monrreal 2019-03-28 17:09:22 -05:00 committed by GitHub
commit d3db0a8c2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 109 additions and 47 deletions

View File

@ -27,7 +27,8 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
#if DEVICE_SERIAL_ASYNCH #if DEVICE_SERIAL_ASYNCH
_thunk_irq(this), _tx_usage(DMA_USAGE_NEVER), _thunk_irq(this), _tx_usage(DMA_USAGE_NEVER),
_rx_usage(DMA_USAGE_NEVER), _tx_callback(NULL), _rx_usage(DMA_USAGE_NEVER), _tx_callback(NULL),
_rx_callback(NULL), _rx_callback(NULL), _tx_asynch_set(false),
_rx_asynch_set(false),
#endif #endif
_serial(), _baud(baud) _serial(), _baud(baud)
{ {
@ -200,24 +201,33 @@ void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2)
int SerialBase::write(const uint8_t *buffer, int length, const event_callback_t &callback, int event) int SerialBase::write(const uint8_t *buffer, int length, const event_callback_t &callback, int event)
{ {
if (serial_tx_active(&_serial)) { int result = 0;
return -1; // transaction ongoing lock();
if (!serial_tx_active(&_serial) && !_tx_asynch_set) {
start_write((void *)buffer, length, 8, callback, event);
} else {
result = -1; // transaction ongoing
} }
start_write((void *)buffer, length, 8, callback, event); unlock();
return 0; return result;
} }
int SerialBase::write(const uint16_t *buffer, int length, const event_callback_t &callback, int event) int SerialBase::write(const uint16_t *buffer, int length, const event_callback_t &callback, int event)
{ {
if (serial_tx_active(&_serial)) { int result = 0;
return -1; // transaction ongoing lock();
if (!serial_tx_active(&_serial) && !_tx_asynch_set) {
start_write((void *)buffer, length, 16, callback, event);
} else {
result = -1; // transaction ongoing
} }
start_write((void *)buffer, length, 16, callback, event); unlock();
return 0; return result;
} }
void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_width, const event_callback_t &callback, int event) void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_width, const event_callback_t &callback, int event)
{ {
_tx_asynch_set = true;
_tx_callback = callback; _tx_callback = callback;
_thunk_irq.callback(&SerialBase::interrupt_handler_asynch); _thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
@ -227,22 +237,30 @@ void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_wi
void SerialBase::abort_write(void) void SerialBase::abort_write(void)
{ {
// rx might still be active lock();
if (_rx_callback) { core_util_critical_section_enter();
if (_tx_asynch_set) {
_tx_callback = NULL;
_tx_asynch_set = false;
serial_tx_abort_asynch(&_serial);
sleep_manager_unlock_deep_sleep(); sleep_manager_unlock_deep_sleep();
} }
_tx_callback = NULL; core_util_critical_section_exit();
serial_tx_abort_asynch(&_serial); unlock();
} }
void SerialBase::abort_read(void) void SerialBase::abort_read(void)
{ {
// tx might still be active lock();
if (_tx_callback) { core_util_critical_section_enter();
if (_rx_asynch_set) {
_rx_callback = NULL;
_rx_asynch_set = false;
serial_rx_abort_asynch(&_serial);
sleep_manager_unlock_deep_sleep(); sleep_manager_unlock_deep_sleep();
} }
_rx_callback = NULL; core_util_critical_section_exit();
serial_rx_abort_asynch(&_serial); unlock();
} }
int SerialBase::set_dma_usage_tx(DMAUsage usage) int SerialBase::set_dma_usage_tx(DMAUsage usage)
@ -265,26 +283,35 @@ int SerialBase::set_dma_usage_rx(DMAUsage usage)
int SerialBase::read(uint8_t *buffer, int length, const event_callback_t &callback, int event, unsigned char char_match) int SerialBase::read(uint8_t *buffer, int length, const event_callback_t &callback, int event, unsigned char char_match)
{ {
if (serial_rx_active(&_serial)) { int result = 0;
return -1; // transaction ongoing lock();
if (!serial_rx_active(&_serial) && !_rx_asynch_set) {
start_read((void *)buffer, length, 8, callback, event, char_match);
} else {
result = -1; // transaction ongoing
} }
start_read((void *)buffer, length, 8, callback, event, char_match); unlock();
return 0; return result;
} }
int SerialBase::read(uint16_t *buffer, int length, const event_callback_t &callback, int event, unsigned char char_match) int SerialBase::read(uint16_t *buffer, int length, const event_callback_t &callback, int event, unsigned char char_match)
{ {
if (serial_rx_active(&_serial)) { int result = 0;
return -1; // transaction ongoing lock();
if (!serial_rx_active(&_serial) && !_rx_asynch_set) {
start_read((void *)buffer, length, 16, callback, event, char_match);
} else {
result = -1; // transaction ongoing
} }
start_read((void *)buffer, length, 16, callback, event, char_match); unlock();
return 0; return result;
} }
void SerialBase::start_read(void *buffer, int buffer_size, char buffer_width, const event_callback_t &callback, int event, unsigned char char_match) void SerialBase::start_read(void *buffer, int buffer_size, char buffer_width, const event_callback_t &callback, int event, unsigned char char_match)
{ {
_rx_asynch_set = true;
_rx_callback = callback; _rx_callback = callback;
_thunk_irq.callback(&SerialBase::interrupt_handler_asynch); _thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
sleep_manager_lock_deep_sleep(); sleep_manager_lock_deep_sleep();
@ -295,20 +322,25 @@ void SerialBase::interrupt_handler_asynch(void)
{ {
int event = serial_irq_handler_asynch(&_serial); int event = serial_irq_handler_asynch(&_serial);
int rx_event = event & SERIAL_EVENT_RX_MASK; int rx_event = event & SERIAL_EVENT_RX_MASK;
bool unlock_deepsleep = false;
if (_rx_callback && rx_event) { if (_rx_asynch_set && rx_event) {
unlock_deepsleep = true; event_callback_t cb = _rx_callback;
_rx_callback.call(rx_event); _rx_asynch_set = false;
_rx_callback = NULL;
if (cb) {
cb.call(rx_event);
}
sleep_manager_unlock_deep_sleep();
} }
int tx_event = event & SERIAL_EVENT_TX_MASK; int tx_event = event & SERIAL_EVENT_TX_MASK;
if (_tx_callback && tx_event) { if (_tx_asynch_set && tx_event) {
unlock_deepsleep = true; event_callback_t cb = _tx_callback;
_tx_callback.call(tx_event); _tx_asynch_set = false;
} _tx_callback = NULL;
// unlock if tx or rx events are generated if (cb) {
if (unlock_deepsleep) { cb.call(tx_event);
}
sleep_manager_unlock_deep_sleep(); sleep_manager_unlock_deep_sleep();
} }
} }

View File

@ -179,57 +179,85 @@ public:
#if DEVICE_SERIAL_ASYNCH #if DEVICE_SERIAL_ASYNCH
/** Begin asynchronous write using 8bit buffer. The completion invokes registered TX event callback /** Begin asynchronous write using 8bit buffer.
* *
* This function locks the deep sleep until any event has occurred * The write operation ends with any of the enabled events and invokes
* registered callback function (which can be NULL to not receive callback at all).
* Events that are not enabled by event argument are simply ignored.
* Operation has to be ended explicitly by calling abort_write() when
* no events are enabled.
* This function locks the deep sleep until any event has occurred.
* *
* @param buffer The buffer where received data will be stored * @param buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
* @param event The logical OR of TX events * @param event The logical OR of TX events that should end operation
* @return Zero if new transaction was started, -1 if transaction is already on-going
*/ */
int write(const uint8_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_TX_COMPLETE); int write(const uint8_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_TX_COMPLETE);
/** Begin asynchronous write using 16bit buffer. The completion invokes registered TX event callback /** Begin asynchronous write using 16bit buffer.
* *
* This function locks the deep sleep until any event has occurred * The write operation ends with any of the enabled events and invokes
* registered callback function (which can be NULL to not receive callback at all).
* Events that are not enabled by event argument are simply ignored.
* Operation has to be ended explicitly by calling abort_write() when
* no events are enabled.
* This function locks the deep sleep until any event has occurred.
* *
* @param buffer The buffer where received data will be stored * @param buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
* @param event The logical OR of TX events * @param event The logical OR of TX events that should end operation
* @return Zero if new transaction was started, -1 if transaction is already on-going
*/ */
int write(const uint16_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_TX_COMPLETE); int write(const uint16_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_TX_COMPLETE);
/** Abort the on-going write transfer /** Abort the on-going write transfer
*
* It is safe to call abort_write() when there is no on-going transaction.
*/ */
void abort_write(); void abort_write();
/** Begin asynchronous reading using 8bit buffer. The completion invokes registered RX event callback. /** Begin asynchronous reading using 8bit buffer.
* *
* This function locks the deep sleep until any event has occurred * The read operation ends with any of the enabled events and invokes registered
* callback function (which can be NULL to not receive callback at all).
* Events that are not enabled by event argument are simply ignored.
* Operation has to be ended explicitly by calling abort_read() when
* no events are enabled.
* This function locks the deep sleep until any event has occurred.
* *
* @param buffer The buffer where received data will be stored * @param buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
* @param event The logical OR of RX events * @param event The logical OR of RX events that should end operation
* @param char_match The matching character * @param char_match The matching character
* @return Zero if new transaction was started, -1 if transaction is already on-going
*/ */
int read(uint8_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_RX_COMPLETE, unsigned char char_match = SERIAL_RESERVED_CHAR_MATCH); int read(uint8_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_RX_COMPLETE, unsigned char char_match = SERIAL_RESERVED_CHAR_MATCH);
/** Begin asynchronous reading using 16bit buffer. The completion invokes registered RX event callback. /** Begin asynchronous reading using 16bit buffer.
* *
* This function locks the deep sleep until any event has occurred * The read operation ends with any of the enabled events and invokes registered
* callback function (which can be NULL to not receive callback at all).
* Events that are not enabled by event argument are simply ignored.
* Operation has to be ended explicitly by calling abort_read() when
* no events are enabled.
* This function locks the deep sleep until any event has occurred.
* *
* @param buffer The buffer where received data will be stored * @param buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
* @param event The logical OR of RX events * @param event The logical OR of RX events that should end operation
* @param char_match The matching character * @param char_match The matching character
* @return Zero if new transaction was started, -1 if transaction is already on-going
*/ */
int read(uint16_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_RX_COMPLETE, unsigned char char_match = SERIAL_RESERVED_CHAR_MATCH); int read(uint16_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_RX_COMPLETE, unsigned char char_match = SERIAL_RESERVED_CHAR_MATCH);
/** Abort the on-going read transfer /** Abort the on-going read transfer
*
* It is safe to call abort_read() when there is no on-going transaction.
*/ */
void abort_read(); void abort_read();
@ -269,6 +297,8 @@ protected:
DMAUsage _rx_usage; DMAUsage _rx_usage;
event_callback_t _tx_callback; event_callback_t _tx_callback;
event_callback_t _rx_callback; event_callback_t _rx_callback;
bool _tx_asynch_set;
bool _rx_asynch_set;
#endif #endif
serial_t _serial; serial_t _serial;