Skip to content

Commit d3db0a8

Browse files
author
Cruz Monrreal
authored
Merge pull request #9476 from lrusinowicz/asynch_serial_api
Asynchronous Serial API fixes and refactoring
2 parents 6443e43 + 8586528 commit d3db0a8

File tree

2 files changed

+109
-47
lines changed

2 files changed

+109
-47
lines changed

drivers/SerialBase.cpp

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
2727
#if DEVICE_SERIAL_ASYNCH
2828
_thunk_irq(this), _tx_usage(DMA_USAGE_NEVER),
2929
_rx_usage(DMA_USAGE_NEVER), _tx_callback(NULL),
30-
_rx_callback(NULL),
30+
_rx_callback(NULL), _tx_asynch_set(false),
31+
_rx_asynch_set(false),
3132
#endif
3233
_serial(), _baud(baud)
3334
{
@@ -200,24 +201,33 @@ void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2)
200201

201202
int SerialBase::write(const uint8_t *buffer, int length, const event_callback_t &callback, int event)
202203
{
203-
if (serial_tx_active(&_serial)) {
204-
return -1; // transaction ongoing
204+
int result = 0;
205+
lock();
206+
if (!serial_tx_active(&_serial) && !_tx_asynch_set) {
207+
start_write((void *)buffer, length, 8, callback, event);
208+
} else {
209+
result = -1; // transaction ongoing
205210
}
206-
start_write((void *)buffer, length, 8, callback, event);
207-
return 0;
211+
unlock();
212+
return result;
208213
}
209214

210215
int SerialBase::write(const uint16_t *buffer, int length, const event_callback_t &callback, int event)
211216
{
212-
if (serial_tx_active(&_serial)) {
213-
return -1; // transaction ongoing
217+
int result = 0;
218+
lock();
219+
if (!serial_tx_active(&_serial) && !_tx_asynch_set) {
220+
start_write((void *)buffer, length, 16, callback, event);
221+
} else {
222+
result = -1; // transaction ongoing
214223
}
215-
start_write((void *)buffer, length, 16, callback, event);
216-
return 0;
224+
unlock();
225+
return result;
217226
}
218227

219228
void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_width, const event_callback_t &callback, int event)
220229
{
230+
_tx_asynch_set = true;
221231
_tx_callback = callback;
222232

223233
_thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
@@ -227,22 +237,30 @@ void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_wi
227237

228238
void SerialBase::abort_write(void)
229239
{
230-
// rx might still be active
231-
if (_rx_callback) {
240+
lock();
241+
core_util_critical_section_enter();
242+
if (_tx_asynch_set) {
243+
_tx_callback = NULL;
244+
_tx_asynch_set = false;
245+
serial_tx_abort_asynch(&_serial);
232246
sleep_manager_unlock_deep_sleep();
233247
}
234-
_tx_callback = NULL;
235-
serial_tx_abort_asynch(&_serial);
248+
core_util_critical_section_exit();
249+
unlock();
236250
}
237251

238252
void SerialBase::abort_read(void)
239253
{
240-
// tx might still be active
241-
if (_tx_callback) {
254+
lock();
255+
core_util_critical_section_enter();
256+
if (_rx_asynch_set) {
257+
_rx_callback = NULL;
258+
_rx_asynch_set = false;
259+
serial_rx_abort_asynch(&_serial);
242260
sleep_manager_unlock_deep_sleep();
243261
}
244-
_rx_callback = NULL;
245-
serial_rx_abort_asynch(&_serial);
262+
core_util_critical_section_exit();
263+
unlock();
246264
}
247265

248266
int SerialBase::set_dma_usage_tx(DMAUsage usage)
@@ -265,26 +283,35 @@ int SerialBase::set_dma_usage_rx(DMAUsage usage)
265283

266284
int SerialBase::read(uint8_t *buffer, int length, const event_callback_t &callback, int event, unsigned char char_match)
267285
{
268-
if (serial_rx_active(&_serial)) {
269-
return -1; // transaction ongoing
286+
int result = 0;
287+
lock();
288+
if (!serial_rx_active(&_serial) && !_rx_asynch_set) {
289+
start_read((void *)buffer, length, 8, callback, event, char_match);
290+
} else {
291+
result = -1; // transaction ongoing
270292
}
271-
start_read((void *)buffer, length, 8, callback, event, char_match);
272-
return 0;
293+
unlock();
294+
return result;
273295
}
274296

275297

276298
int SerialBase::read(uint16_t *buffer, int length, const event_callback_t &callback, int event, unsigned char char_match)
277299
{
278-
if (serial_rx_active(&_serial)) {
279-
return -1; // transaction ongoing
300+
int result = 0;
301+
lock();
302+
if (!serial_rx_active(&_serial) && !_rx_asynch_set) {
303+
start_read((void *)buffer, length, 16, callback, event, char_match);
304+
} else {
305+
result = -1; // transaction ongoing
280306
}
281-
start_read((void *)buffer, length, 16, callback, event, char_match);
282-
return 0;
307+
unlock();
308+
return result;
283309
}
284310

285311

286312
void SerialBase::start_read(void *buffer, int buffer_size, char buffer_width, const event_callback_t &callback, int event, unsigned char char_match)
287313
{
314+
_rx_asynch_set = true;
288315
_rx_callback = callback;
289316
_thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
290317
sleep_manager_lock_deep_sleep();
@@ -295,20 +322,25 @@ void SerialBase::interrupt_handler_asynch(void)
295322
{
296323
int event = serial_irq_handler_asynch(&_serial);
297324
int rx_event = event & SERIAL_EVENT_RX_MASK;
298-
bool unlock_deepsleep = false;
299325

300-
if (_rx_callback && rx_event) {
301-
unlock_deepsleep = true;
302-
_rx_callback.call(rx_event);
326+
if (_rx_asynch_set && rx_event) {
327+
event_callback_t cb = _rx_callback;
328+
_rx_asynch_set = false;
329+
_rx_callback = NULL;
330+
if (cb) {
331+
cb.call(rx_event);
332+
}
333+
sleep_manager_unlock_deep_sleep();
303334
}
304335

305336
int tx_event = event & SERIAL_EVENT_TX_MASK;
306-
if (_tx_callback && tx_event) {
307-
unlock_deepsleep = true;
308-
_tx_callback.call(tx_event);
309-
}
310-
// unlock if tx or rx events are generated
311-
if (unlock_deepsleep) {
337+
if (_tx_asynch_set && tx_event) {
338+
event_callback_t cb = _tx_callback;
339+
_tx_asynch_set = false;
340+
_tx_callback = NULL;
341+
if (cb) {
342+
cb.call(tx_event);
343+
}
312344
sleep_manager_unlock_deep_sleep();
313345
}
314346
}

drivers/SerialBase.h

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -179,57 +179,85 @@ class SerialBase : private NonCopyable<SerialBase> {
179179

180180
#if DEVICE_SERIAL_ASYNCH
181181

182-
/** Begin asynchronous write using 8bit buffer. The completion invokes registered TX event callback
182+
/** Begin asynchronous write using 8bit buffer.
183183
*
184-
* This function locks the deep sleep until any event has occurred
184+
* The write operation ends with any of the enabled events and invokes
185+
* registered callback function (which can be NULL to not receive callback at all).
186+
* Events that are not enabled by event argument are simply ignored.
187+
* Operation has to be ended explicitly by calling abort_write() when
188+
* no events are enabled.
189+
* This function locks the deep sleep until any event has occurred.
185190
*
186191
* @param buffer The buffer where received data will be stored
187192
* @param length The buffer length in bytes
188193
* @param callback The event callback function
189-
* @param event The logical OR of TX events
194+
* @param event The logical OR of TX events that should end operation
195+
* @return Zero if new transaction was started, -1 if transaction is already on-going
190196
*/
191197
int write(const uint8_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_TX_COMPLETE);
192198

193-
/** Begin asynchronous write using 16bit buffer. The completion invokes registered TX event callback
199+
/** Begin asynchronous write using 16bit buffer.
194200
*
195-
* This function locks the deep sleep until any event has occurred
201+
* The write operation ends with any of the enabled events and invokes
202+
* registered callback function (which can be NULL to not receive callback at all).
203+
* Events that are not enabled by event argument are simply ignored.
204+
* Operation has to be ended explicitly by calling abort_write() when
205+
* no events are enabled.
206+
* This function locks the deep sleep until any event has occurred.
196207
*
197208
* @param buffer The buffer where received data will be stored
198209
* @param length The buffer length in bytes
199210
* @param callback The event callback function
200-
* @param event The logical OR of TX events
211+
* @param event The logical OR of TX events that should end operation
212+
* @return Zero if new transaction was started, -1 if transaction is already on-going
201213
*/
202214
int write(const uint16_t *buffer, int length, const event_callback_t &callback, int event = SERIAL_EVENT_TX_COMPLETE);
203215

204216
/** Abort the on-going write transfer
217+
*
218+
* It is safe to call abort_write() when there is no on-going transaction.
205219
*/
206220
void abort_write();
207221

208-
/** Begin asynchronous reading using 8bit buffer. The completion invokes registered RX event callback.
222+
/** Begin asynchronous reading using 8bit buffer.
209223
*
210-
* This function locks the deep sleep until any event has occurred
224+
* The read operation ends with any of the enabled events and invokes registered
225+
* callback function (which can be NULL to not receive callback at all).
226+
* Events that are not enabled by event argument are simply ignored.
227+
* Operation has to be ended explicitly by calling abort_read() when
228+
* no events are enabled.
229+
* This function locks the deep sleep until any event has occurred.
211230
*
212231
* @param buffer The buffer where received data will be stored
213232
* @param length The buffer length in bytes
214233
* @param callback The event callback function
215-
* @param event The logical OR of RX events
234+
* @param event The logical OR of RX events that should end operation
216235
* @param char_match The matching character
236+
* @return Zero if new transaction was started, -1 if transaction is already on-going
217237
*/
218238
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);
219239

220-
/** Begin asynchronous reading using 16bit buffer. The completion invokes registered RX event callback.
240+
/** Begin asynchronous reading using 16bit buffer.
221241
*
222-
* This function locks the deep sleep until any event has occurred
242+
* The read operation ends with any of the enabled events and invokes registered
243+
* callback function (which can be NULL to not receive callback at all).
244+
* Events that are not enabled by event argument are simply ignored.
245+
* Operation has to be ended explicitly by calling abort_read() when
246+
* no events are enabled.
247+
* This function locks the deep sleep until any event has occurred.
223248
*
224249
* @param buffer The buffer where received data will be stored
225250
* @param length The buffer length in bytes
226251
* @param callback The event callback function
227-
* @param event The logical OR of RX events
252+
* @param event The logical OR of RX events that should end operation
228253
* @param char_match The matching character
254+
* @return Zero if new transaction was started, -1 if transaction is already on-going
229255
*/
230256
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);
231257

232258
/** Abort the on-going read transfer
259+
*
260+
* It is safe to call abort_read() when there is no on-going transaction.
233261
*/
234262
void abort_read();
235263

@@ -269,6 +297,8 @@ class SerialBase : private NonCopyable<SerialBase> {
269297
DMAUsage _rx_usage;
270298
event_callback_t _tx_callback;
271299
event_callback_t _rx_callback;
300+
bool _tx_asynch_set;
301+
bool _rx_asynch_set;
272302
#endif
273303

274304
serial_t _serial;

0 commit comments

Comments
 (0)