Asynchronous Serial API fixes and refactoring, part 2

Aborting of asynchronous operation is necessarily hazardous, as
operation can end in interrupt anywhere from the point of decision
until it is actually aborted down the abort_...() method.
Proper deep sleep unlocking requires then use of the critical
section and should be contained completely within API implementation.
pull/9476/head
Leszek Rusinowicz 2019-02-12 17:09:48 +01:00
parent 6d648092e1
commit cbb84d8ad3
1 changed files with 40 additions and 16 deletions

View File

@ -201,20 +201,28 @@ 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)
@ -229,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)
{ {
lock();
core_util_critical_section_enter();
if (_tx_asynch_set) { if (_tx_asynch_set) {
_tx_callback = NULL; _tx_callback = NULL;
_tx_asynch_set = false; _tx_asynch_set = false;
serial_tx_abort_asynch(&_serial); serial_tx_abort_asynch(&_serial);
sleep_manager_unlock_deep_sleep(); sleep_manager_unlock_deep_sleep();
} }
core_util_critical_section_exit();
unlock();
} }
void SerialBase::abort_read(void) void SerialBase::abort_read(void)
{ {
lock();
core_util_critical_section_enter();
if (_rx_asynch_set) { if (_rx_asynch_set) {
_rx_callback = NULL; _rx_callback = NULL;
_rx_asynch_set = false; _rx_asynch_set = false;
serial_rx_abort_asynch(&_serial); serial_rx_abort_asynch(&_serial);
sleep_manager_unlock_deep_sleep(); sleep_manager_unlock_deep_sleep();
} }
core_util_critical_section_exit();
unlock();
} }
int SerialBase::set_dma_usage_tx(DMAUsage usage) int SerialBase::set_dma_usage_tx(DMAUsage usage)
@ -267,21 +283,29 @@ 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;
} }