-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BufferedSerial is a FileHandle and using SerialBase. It keeps the SerialBase private however lets the user extend FileHandle by keeping it public. It is using CircularBuffer class for having circular buffers. There are some minor amendments in CircularBuffer too. Adding an entry for tx/rx buffer sizes in platform/mbed_lib.json. Default size is 256 bytes. For RTOS read(), write() calls yield for other threads to carry on with their stuff. For non-RTOS blovking read or write would mean a loop where 100 percent resources are consumed by this loop. Need to get a better implementation in. Currently no mechanism to wake the mcu up after WFE.
- Loading branch information
Hasnain Virk
committed
May 31, 2017
1 parent
09ae609
commit 2790d44
Showing
4 changed files
with
315 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
/* mbed Microcontroller Library | ||
* Copyright (c) 2006-2017 ARM Limited | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#if DEVICE_SERIAL | ||
|
||
#include <errno.h> | ||
#include "platform/BufferedSerial.h" | ||
#include "platform/mbed_poll.h" | ||
#include "platform/mbed_wait_api.h" | ||
|
||
namespace mbed { | ||
|
||
BufferedSerial::BufferedSerial(PinName tx, PinName rx, int baud) : | ||
SerialBase(tx, rx, baud), | ||
_blocking(true), | ||
_tx_irq_enabled(false) | ||
{ | ||
/* Attatch IRQ routines to the serial device. */ | ||
SerialBase::attach(callback(this, &BufferedSerial::rx_irq), RxIrq); | ||
} | ||
|
||
int BufferedSerial::close() | ||
{ | ||
/* Does not let us pass a file descriptor. So how to close ? | ||
* Also, does it make sense to close a device type file descriptor*/ | ||
return 0; | ||
} | ||
|
||
int BufferedSerial::isatty() | ||
{ | ||
return 1; | ||
|
||
} | ||
|
||
off_t BufferedSerial::seek(off_t offset, int whence) | ||
{ | ||
/*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking | ||
* buffer system (from an interrupt context) */ | ||
return -ESPIPE; | ||
} | ||
|
||
int BufferedSerial::sync() | ||
{ | ||
lock(); | ||
|
||
while (!_txbuf.empty()) { | ||
unlock(); | ||
// Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it? | ||
wait_ms(1); | ||
lock(); | ||
} | ||
|
||
unlock(); | ||
|
||
return 0; | ||
} | ||
|
||
ssize_t BufferedSerial::write(const void* buffer, size_t length) | ||
{ | ||
size_t data_written = 0; | ||
const char *buf_ptr = static_cast<const char *>(buffer); | ||
|
||
lock(); | ||
|
||
while (_txbuf.full()) { | ||
if (!_blocking) { | ||
unlock(); | ||
return -EAGAIN; | ||
} | ||
unlock(); | ||
wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? | ||
lock(); | ||
} | ||
|
||
while (data_written < length && !_txbuf.full()) { | ||
_txbuf.push(*buf_ptr++); | ||
data_written++; | ||
} | ||
|
||
core_util_critical_section_enter(); | ||
if (!_tx_irq_enabled) { | ||
BufferedSerial::tx_irq(); // only write to hardware in one place | ||
if (!_txbuf.empty()) { | ||
SerialBase::attach(callback(this, &BufferedSerial::tx_irq), TxIrq); | ||
_tx_irq_enabled = true; | ||
} | ||
} | ||
core_util_critical_section_exit(); | ||
|
||
unlock(); | ||
|
||
return data_written; | ||
} | ||
|
||
ssize_t BufferedSerial::read(void* buffer, size_t length) | ||
{ | ||
size_t data_read = 0; | ||
|
||
char *ptr = static_cast<char *>(buffer); | ||
|
||
lock(); | ||
|
||
while (_rxbuf.empty()) { | ||
if (!_blocking) { | ||
unlock(); | ||
return -EAGAIN; | ||
} | ||
unlock(); | ||
wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? | ||
lock(); | ||
} | ||
|
||
while (data_read < length && !_rxbuf.empty()) { | ||
_rxbuf.pop(*ptr++); | ||
data_read++; | ||
} | ||
|
||
unlock(); | ||
|
||
return data_read; | ||
} | ||
|
||
short BufferedSerial::poll(short events) const { | ||
|
||
short revents = 0; | ||
/* Check the Circular Buffer if space available for writing out */ | ||
if (!_txbuf.full()) { | ||
revents |= POLLOUT; | ||
} | ||
|
||
if (!_rxbuf.empty()) { | ||
revents |= POLLIN; | ||
} | ||
|
||
/*TODO Handle other event types */ | ||
|
||
return revents; | ||
} | ||
|
||
void BufferedSerial::lock(void) | ||
{ | ||
_mutex.lock(); | ||
} | ||
|
||
void BufferedSerial::unlock(void) | ||
{ | ||
_mutex.unlock(); | ||
} | ||
|
||
void BufferedSerial::rx_irq(void) | ||
{ | ||
bool was_empty = _rxbuf.empty(); | ||
|
||
/* Fill in the receive buffer if the peripheral is readable | ||
* and receive buffer is not full. */ | ||
while (SerialBase::readable()) { | ||
char data = SerialBase::_base_getc(); | ||
if (!_rxbuf.full()) { | ||
_rxbuf.push(data); | ||
} else { | ||
/* Drop - can we report in some way? */ | ||
} | ||
} | ||
|
||
/* Report the File handler that data is ready to be read from the buffer. */ | ||
if (was_empty && !_rxbuf.empty()) { | ||
_poll_change(this); | ||
} | ||
} | ||
|
||
// Also called from write to start transfer | ||
void BufferedSerial::tx_irq(void) | ||
{ | ||
bool was_full = _txbuf.full(); | ||
|
||
/* Write to the peripheral if there is something to write | ||
* and if the peripheral is available to write. */ | ||
while (!_txbuf.empty() && SerialBase::writeable()) { | ||
char data; | ||
_txbuf.pop(data); | ||
SerialBase::_base_putc(data); | ||
} | ||
|
||
if (_tx_irq_enabled && _txbuf.empty()) { | ||
SerialBase::attach(NULL, TxIrq); | ||
_tx_irq_enabled = false; | ||
} | ||
|
||
/* Report the File handler that data can be written to peripheral. */ | ||
if (was_full && !_txbuf.full()) { | ||
_poll_change(this); | ||
} | ||
} | ||
|
||
|
||
} //namespace mbed | ||
|
||
#endif //DEVICE_SERIAL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* mbed Microcontroller Library | ||
* Copyright (c) 2006-2017 ARM Limited | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#ifndef MBED_BUFFEREDSERIAL_H | ||
#define MBED_BUFFEREDSERIAL_H | ||
|
||
#include "platform/platform.h" | ||
|
||
#if DEVICE_SERIAL | ||
|
||
#include "FileHandle.h" | ||
#include "SerialBase.h" | ||
#include "PlatformMutex.h" | ||
#include "serial_api.h" | ||
#include "CircularBuffer.h" | ||
|
||
namespace mbed { | ||
class BufferedSerial : private SerialBase, public FileHandle { | ||
public: | ||
/** Create a BufferedSerial port, connected to the specified transmit and receive pins, with a particular baud rate. | ||
* @param tx Transmit pin | ||
* @param rx Receive pin | ||
* @param baud The baud rate of the serial port (optional, defaults to MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE) | ||
*/ | ||
BufferedSerial(PinName tx, PinName rx, int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE); | ||
|
||
/** Equivalent to POSIX poll(). Derived from FileHandle. | ||
* Provides a mechanism to multiplex input/output over a set of file handles. | ||
*/ | ||
virtual short poll(short events) const; | ||
|
||
virtual ssize_t write(const void* buffer, size_t length); | ||
|
||
virtual ssize_t read(void* buffer, size_t length); | ||
|
||
/** Acquire mutex */ | ||
virtual void lock(void); | ||
|
||
/** Release mutex */ | ||
virtual void unlock(void); | ||
|
||
virtual int close(); | ||
|
||
virtual int isatty(); | ||
|
||
virtual off_t seek(off_t offset, int whence); | ||
|
||
virtual int sync(); | ||
|
||
virtual int set_blocking(bool blocking) { _blocking = blocking; return 0; } | ||
|
||
private: | ||
|
||
/** Software serial buffers | ||
* By default buffer size is 256 for TX and 256 for RX. Configurable through mbed_app.json | ||
*/ | ||
CircularBuffer<char, MBED_CONF_PLATFORM_BUFFERED_SERIAL_RXBUF_SIZE> _rxbuf; | ||
CircularBuffer<char, MBED_CONF_PLATFORM_BUFFERED_SERIAL_TXBUF_SIZE> _txbuf; | ||
|
||
PlatformMutex _mutex; | ||
|
||
bool _blocking; | ||
bool _tx_irq_enabled; | ||
|
||
|
||
|
||
/** ISRs for serial | ||
* Routines to handle interrupts on serial pins. | ||
* Copies data into Circular Buffer. | ||
* Reports the state change to File handle. | ||
*/ | ||
void tx_irq(void); | ||
void rx_irq(void); | ||
|
||
|
||
}; | ||
} //namespace mbed | ||
|
||
|
||
#endif //DEVICE_SERIAL | ||
#endif /* MBED_BUFFEREDSERIAL_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters