Merge pull request #9797 from ARMmbed/fh_enable

API to temporarily enable/disable FileHandles
pull/9965/head
Martin Kojtal 2019-03-01 14:26:18 +01:00 committed by GitHub
commit 596b9f740e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 192 additions and 28 deletions

View File

@ -120,6 +120,16 @@ void UARTSerial::tx_irq(void)
{
}
int UARTSerial::enable_input(bool enabled)
{
return 0;
}
int UARTSerial::enable_output(bool enabled)
{
return 0;
}
void UARTSerial::wait_ms(uint32_t millisec)
{

View File

@ -32,11 +32,13 @@ UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
SerialBase(tx, rx, baud),
_blocking(true),
_tx_irq_enabled(false),
_rx_irq_enabled(true),
_rx_irq_enabled(false),
_tx_enabled(true),
_rx_enabled(true),
_dcd_irq(NULL)
{
/* Attatch IRQ routines to the serial device. */
SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
enable_rx_irq();
}
UARTSerial::~UARTSerial()
@ -188,11 +190,10 @@ ssize_t UARTSerial::write(const void *buffer, size_t length)
}
core_util_critical_section_enter();
if (!_tx_irq_enabled) {
if (_tx_enabled && !_tx_irq_enabled) {
UARTSerial::tx_irq(); // only write to hardware in one place
if (!_txbuf.empty()) {
SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
_tx_irq_enabled = true;
enable_tx_irq();
}
}
core_util_critical_section_exit();
@ -231,11 +232,10 @@ ssize_t UARTSerial::read(void *buffer, size_t length)
}
core_util_critical_section_enter();
if (!_rx_irq_enabled) {
if (_rx_enabled && !_rx_irq_enabled) {
UARTSerial::rx_irq(); // only read from hardware in one place
if (!_rxbuf.full()) {
SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
_rx_irq_enabled = true;
enable_rx_irq();
}
}
core_util_critical_section_exit();
@ -314,8 +314,7 @@ void UARTSerial::rx_irq(void)
}
if (_rx_irq_enabled && _rxbuf.full()) {
SerialBase::attach(NULL, RxIrq);
_rx_irq_enabled = false;
disable_rx_irq();
}
/* Report the File handler that data is ready to be read from the buffer. */
@ -337,8 +336,7 @@ void UARTSerial::tx_irq(void)
}
if (_tx_irq_enabled && _txbuf.empty()) {
SerialBase::attach(NULL, TxIrq);
_tx_irq_enabled = false;
disable_tx_irq();
}
/* Report the File handler that data can be written to peripheral. */
@ -347,6 +345,69 @@ void UARTSerial::tx_irq(void)
}
}
/* These are all called from critical section */
void UARTSerial::enable_rx_irq()
{
SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
_rx_irq_enabled = true;
}
void UARTSerial::disable_rx_irq()
{
SerialBase::attach(NULL, RxIrq);
_rx_irq_enabled = false;
}
void UARTSerial::enable_tx_irq()
{
SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
_tx_irq_enabled = true;
}
void UARTSerial::disable_tx_irq()
{
SerialBase::attach(NULL, TxIrq);
_tx_irq_enabled = false;
}
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();
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();
return 0;
}
void UARTSerial::wait_ms(uint32_t millisec)
{
/* wait_ms implementation for RTOS spins until exact microseconds - we

View File

@ -152,6 +152,36 @@ public:
return _blocking;
}
/** Enable or disable input
*
* Control enabling of device for input. This is primarily intended
* for temporary power-saving; the overall ability of the device to operate for
* input and/or output may be fixed at creation time, but this call can
* allow input to be temporarily disabled to permit power saving without
* losing device state.
*
* @param enabled true to enable input, false to disable.
*
* @return 0 on success
* @return Negative error code on failure
*/
virtual int enable_input(bool enabled);
/** Enable or disable output
*
* Control enabling of device for output. This is primarily intended
* for temporary power-saving; the overall ability of the device to operate for
* input and/or output may be fixed at creation time, but this call can
* allow output to be temporarily disabled to permit power saving without
* losing device state.
*
* @param enabled true to enable output, false to disable.
*
* @return 0 on success
* @return Negative error code on failure
*/
virtual int enable_output(bool enabled);
/** Register a callback on state change of the file.
*
* The specified callback will be called on state changes such as when
@ -242,6 +272,11 @@ private:
/** Unbuffered write - invoked when write called from critical section */
ssize_t write_unbuffered(const char *buf_ptr, size_t length);
void enable_rx_irq();
void disable_rx_irq();
void enable_tx_irq();
void disable_tx_irq();
/** Software serial buffers
* By default buffer size is 256 for TX and 256 for RX. Configurable through mbed_app.json
*/
@ -255,6 +290,8 @@ private:
bool _blocking;
bool _tx_irq_enabled;
bool _rx_irq_enabled;
bool _tx_enabled;
bool _rx_enabled;
InterruptIn *_dcd_irq;
/** Device Hanged up

View File

@ -220,6 +220,42 @@ public:
return true;
}
/** Enable or disable input
*
* Control enabling of device for input. This is primarily intended
* for temporary power-saving; the overall ability of the device to operate for
* input and/or output may be fixed at creation time, but this call can
* allow input to be temporarily disabled to permit power saving without
* losing device state.
*
* @param enabled true to enable input, false to disable.
*
* @return 0 on success
* @return Negative error code on failure
*/
virtual int enable_input(bool enabled)
{
return -EINVAL;
}
/** Enable or disable output
*
* Control enabling of device for output. This is primarily intended
* for temporary power-saving; the overall ability of the device to operate for
* input and/or output may be fixed at creation time, but this call can
* allow output to be temporarily disabled to permit power saving without
* losing device state.
*
* @param enabled true to enable output, false to disable.
*
* @return 0 on success
* @return Negative error code on failure
*/
virtual int enable_output(bool enabled)
{
return -EINVAL;
}
/** Check for poll event flags
* You can use or ignore the input parameter. You can return all events
* or check just the events listed in events.

View File

@ -291,7 +291,7 @@ static FileHandle *get_console(int fd)
}
/* Deal with the fact C library may not _open descriptors 0, 1, 2 - auto bind */
static FileHandle *get_fhc(int fd)
FileHandle *mbed::mbed_file_handle(int fd)
{
if (fd >= OPEN_MAX) {
return NULL;
@ -491,13 +491,13 @@ extern "C" FILEHANDLE PREFIX(_open)(const char *name, int openflags)
/* Use the posix convention that stdin,out,err are filehandles 0,1,2.
*/
if (std::strcmp(name, __stdin_name) == 0) {
get_fhc(STDIN_FILENO);
mbed_file_handle(STDIN_FILENO);
return STDIN_FILENO;
} else if (std::strcmp(name, __stdout_name) == 0) {
get_fhc(STDOUT_FILENO);
mbed_file_handle(STDOUT_FILENO);
return STDOUT_FILENO;
} else if (std::strcmp(name, __stderr_name) == 0) {
get_fhc(STDERR_FILENO);
mbed_file_handle(STDERR_FILENO);
return STDERR_FILENO;
}
#endif
@ -556,7 +556,7 @@ extern "C" int PREFIX(_close)(FILEHANDLE fh)
extern "C" int close(int fildes)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
filehandles[fildes] = NULL;
if (fhc == NULL) {
errno = EBADF;
@ -668,7 +668,7 @@ finish:
extern "C" ssize_t write(int fildes, const void *buf, size_t length)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -762,8 +762,7 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int
extern "C" ssize_t read(int fildes, void *buf, size_t length)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -790,7 +789,7 @@ extern "C" int _isatty(FILEHANDLE fh)
extern "C" int isatty(int fildes)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return 0;
@ -829,7 +828,7 @@ int _lseek(FILEHANDLE fh, int offset, int whence)
extern "C" off_t lseek(int fildes, off_t offset, int whence)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -845,7 +844,7 @@ extern "C" off_t lseek(int fildes, off_t offset, int whence)
extern "C" int ftruncate(int fildes, off_t length)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -869,7 +868,7 @@ extern "C" int PREFIX(_ensure)(FILEHANDLE fh)
extern "C" int fsync(int fildes)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -887,7 +886,7 @@ extern "C" int fsync(int fildes)
#ifdef __ARMCC_VERSION
extern "C" long PREFIX(_flen)(FILEHANDLE fh)
{
FileHandle *fhc = get_fhc(fh);
FileHandle *fhc = mbed_file_handle(fh);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -965,7 +964,7 @@ extern "C" int _fstat(int fh, struct stat *st)
extern "C" int fstat(int fildes, struct stat *st)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -978,7 +977,7 @@ extern "C" int fstat(int fildes, struct stat *st)
extern "C" int fcntl(int fildes, int cmd, ...)
{
FileHandle *fhc = get_fhc(fildes);
FileHandle *fhc = mbed_file_handle(fildes);
if (fhc == NULL) {
errno = EBADF;
return -1;
@ -1023,7 +1022,7 @@ extern "C" int poll(struct pollfd fds[], nfds_t nfds, int timeout)
for (nfds_t n = 0; n < nfds; n++) {
// Underlying FileHandle poll returns POLLNVAL if given NULL, so
// we don't need to take special action.
fhs[n].fh = get_fhc(fds[n].fd);
fhs[n].fh = mbed_file_handle(fds[n].fd);
fhs[n].events = fds[n].events;
}
int ret = poll(fhs, nfds, timeout);

View File

@ -133,6 +133,27 @@ FileHandle *mbed_target_override_console(int fd);
*/
FileHandle *mbed_override_console(int fd);
/** Look up the Mbed file handle corresponding to a file descriptor
*
* This conversion function permits an application to find the underlying
* FileHandle object corresponding to a POSIX file descriptor.
*
* This allows access to specialized behavior only available via the
* FileHandle API.
*
* Example of saving power by disabling console input - for buffered serial,
* this would release the RX interrupt handler, which would release the
* deep sleep lock.
* @code
* mbed_file_handle(STDIN_FILENO)->enable_input(false);
* @endcode
*
* @param fd file descriptor
* @return FileHandle pointer
* NULL if descriptor does not correspond to a FileHandle (only
* possible if it's not open with current implementation).
*/
FileHandle *mbed_file_handle(int fd);
}
typedef mbed::DirHandle DIR;