inport from local

Dependents:   Hobbyking_Cheetah_0511

Committer:
NYX
Date:
Mon Mar 16 06:35:48 2020 +0000
Revision:
0:85b3fd62ea1a
reinport to mbed;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
NYX 0:85b3fd62ea1a 1 /* mbed Microcontroller Library
NYX 0:85b3fd62ea1a 2 * Copyright (c) 2006-2017 ARM Limited
NYX 0:85b3fd62ea1a 3 *
NYX 0:85b3fd62ea1a 4 * Licensed under the Apache License, Version 2.0 (the "License");
NYX 0:85b3fd62ea1a 5 * you may not use this file except in compliance with the License.
NYX 0:85b3fd62ea1a 6 * You may obtain a copy of the License at
NYX 0:85b3fd62ea1a 7 *
NYX 0:85b3fd62ea1a 8 * http://www.apache.org/licenses/LICENSE-2.0
NYX 0:85b3fd62ea1a 9 *
NYX 0:85b3fd62ea1a 10 * Unless required by applicable law or agreed to in writing, software
NYX 0:85b3fd62ea1a 11 * distributed under the License is distributed on an "AS IS" BASIS,
NYX 0:85b3fd62ea1a 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
NYX 0:85b3fd62ea1a 13 * See the License for the specific language governing permissions and
NYX 0:85b3fd62ea1a 14 * limitations under the License.
NYX 0:85b3fd62ea1a 15 */
NYX 0:85b3fd62ea1a 16
NYX 0:85b3fd62ea1a 17 #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)
NYX 0:85b3fd62ea1a 18
NYX 0:85b3fd62ea1a 19 #include <errno.h>
NYX 0:85b3fd62ea1a 20 #include "UARTSerial.h"
NYX 0:85b3fd62ea1a 21 #include "platform/mbed_poll.h"
NYX 0:85b3fd62ea1a 22 #include "platform/mbed_wait_api.h"
NYX 0:85b3fd62ea1a 23
NYX 0:85b3fd62ea1a 24 namespace mbed {
NYX 0:85b3fd62ea1a 25
NYX 0:85b3fd62ea1a 26 UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
NYX 0:85b3fd62ea1a 27 SerialBase(tx, rx, baud),
NYX 0:85b3fd62ea1a 28 _blocking(true),
NYX 0:85b3fd62ea1a 29 _tx_irq_enabled(false),
NYX 0:85b3fd62ea1a 30 _dcd_irq(NULL)
NYX 0:85b3fd62ea1a 31 {
NYX 0:85b3fd62ea1a 32 /* Attatch IRQ routines to the serial device. */
NYX 0:85b3fd62ea1a 33 SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
NYX 0:85b3fd62ea1a 34 }
NYX 0:85b3fd62ea1a 35
NYX 0:85b3fd62ea1a 36 UARTSerial::~UARTSerial()
NYX 0:85b3fd62ea1a 37 {
NYX 0:85b3fd62ea1a 38 delete _dcd_irq;
NYX 0:85b3fd62ea1a 39 }
NYX 0:85b3fd62ea1a 40
NYX 0:85b3fd62ea1a 41 void UARTSerial::dcd_irq()
NYX 0:85b3fd62ea1a 42 {
NYX 0:85b3fd62ea1a 43 wake();
NYX 0:85b3fd62ea1a 44 }
NYX 0:85b3fd62ea1a 45
NYX 0:85b3fd62ea1a 46 void UARTSerial::set_baud(int baud)
NYX 0:85b3fd62ea1a 47 {
NYX 0:85b3fd62ea1a 48 SerialBase::baud(baud);
NYX 0:85b3fd62ea1a 49 }
NYX 0:85b3fd62ea1a 50
NYX 0:85b3fd62ea1a 51 void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
NYX 0:85b3fd62ea1a 52 {
NYX 0:85b3fd62ea1a 53 delete _dcd_irq;
NYX 0:85b3fd62ea1a 54 _dcd_irq = NULL;
NYX 0:85b3fd62ea1a 55
NYX 0:85b3fd62ea1a 56 if (dcd_pin != NC) {
NYX 0:85b3fd62ea1a 57 _dcd_irq = new InterruptIn(dcd_pin);
NYX 0:85b3fd62ea1a 58 if (active_high) {
NYX 0:85b3fd62ea1a 59 _dcd_irq->fall(callback(this, &UARTSerial::dcd_irq));
NYX 0:85b3fd62ea1a 60 } else {
NYX 0:85b3fd62ea1a 61 _dcd_irq->rise(callback(this, &UARTSerial::dcd_irq));
NYX 0:85b3fd62ea1a 62 }
NYX 0:85b3fd62ea1a 63 }
NYX 0:85b3fd62ea1a 64 }
NYX 0:85b3fd62ea1a 65
NYX 0:85b3fd62ea1a 66 int UARTSerial::close()
NYX 0:85b3fd62ea1a 67 {
NYX 0:85b3fd62ea1a 68 /* Does not let us pass a file descriptor. So how to close ?
NYX 0:85b3fd62ea1a 69 * Also, does it make sense to close a device type file descriptor*/
NYX 0:85b3fd62ea1a 70 return 0;
NYX 0:85b3fd62ea1a 71 }
NYX 0:85b3fd62ea1a 72
NYX 0:85b3fd62ea1a 73 int UARTSerial::isatty()
NYX 0:85b3fd62ea1a 74 {
NYX 0:85b3fd62ea1a 75 return 1;
NYX 0:85b3fd62ea1a 76
NYX 0:85b3fd62ea1a 77 }
NYX 0:85b3fd62ea1a 78
NYX 0:85b3fd62ea1a 79 off_t UARTSerial::seek(off_t offset, int whence)
NYX 0:85b3fd62ea1a 80 {
NYX 0:85b3fd62ea1a 81 /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
NYX 0:85b3fd62ea1a 82 * buffer system (from an interrupt context) */
NYX 0:85b3fd62ea1a 83 return -ESPIPE;
NYX 0:85b3fd62ea1a 84 }
NYX 0:85b3fd62ea1a 85
NYX 0:85b3fd62ea1a 86 int UARTSerial::sync()
NYX 0:85b3fd62ea1a 87 {
NYX 0:85b3fd62ea1a 88 api_lock();
NYX 0:85b3fd62ea1a 89
NYX 0:85b3fd62ea1a 90 while (!_txbuf.empty()) {
NYX 0:85b3fd62ea1a 91 api_unlock();
NYX 0:85b3fd62ea1a 92 // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
NYX 0:85b3fd62ea1a 93 wait_ms(1);
NYX 0:85b3fd62ea1a 94 api_lock();
NYX 0:85b3fd62ea1a 95 }
NYX 0:85b3fd62ea1a 96
NYX 0:85b3fd62ea1a 97 api_unlock();
NYX 0:85b3fd62ea1a 98
NYX 0:85b3fd62ea1a 99 return 0;
NYX 0:85b3fd62ea1a 100 }
NYX 0:85b3fd62ea1a 101
NYX 0:85b3fd62ea1a 102 void UARTSerial::sigio(Callback<void()> func) {
NYX 0:85b3fd62ea1a 103 core_util_critical_section_enter();
NYX 0:85b3fd62ea1a 104 _sigio_cb = func;
NYX 0:85b3fd62ea1a 105 if (_sigio_cb) {
NYX 0:85b3fd62ea1a 106 short current_events = poll(0x7FFF);
NYX 0:85b3fd62ea1a 107 if (current_events) {
NYX 0:85b3fd62ea1a 108 _sigio_cb();
NYX 0:85b3fd62ea1a 109 }
NYX 0:85b3fd62ea1a 110 }
NYX 0:85b3fd62ea1a 111 core_util_critical_section_exit();
NYX 0:85b3fd62ea1a 112 }
NYX 0:85b3fd62ea1a 113
NYX 0:85b3fd62ea1a 114 ssize_t UARTSerial::write(const void* buffer, size_t length)
NYX 0:85b3fd62ea1a 115 {
NYX 0:85b3fd62ea1a 116 size_t data_written = 0;
NYX 0:85b3fd62ea1a 117 const char *buf_ptr = static_cast<const char *>(buffer);
NYX 0:85b3fd62ea1a 118
NYX 0:85b3fd62ea1a 119 api_lock();
NYX 0:85b3fd62ea1a 120
NYX 0:85b3fd62ea1a 121 while (_txbuf.full()) {
NYX 0:85b3fd62ea1a 122 if (!_blocking) {
NYX 0:85b3fd62ea1a 123 api_unlock();
NYX 0:85b3fd62ea1a 124 return -EAGAIN;
NYX 0:85b3fd62ea1a 125 }
NYX 0:85b3fd62ea1a 126 api_unlock();
NYX 0:85b3fd62ea1a 127 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
NYX 0:85b3fd62ea1a 128 api_lock();
NYX 0:85b3fd62ea1a 129 }
NYX 0:85b3fd62ea1a 130
NYX 0:85b3fd62ea1a 131 while (data_written < length && !_txbuf.full()) {
NYX 0:85b3fd62ea1a 132 _txbuf.push(*buf_ptr++);
NYX 0:85b3fd62ea1a 133 data_written++;
NYX 0:85b3fd62ea1a 134 }
NYX 0:85b3fd62ea1a 135
NYX 0:85b3fd62ea1a 136 core_util_critical_section_enter();
NYX 0:85b3fd62ea1a 137 if (!_tx_irq_enabled) {
NYX 0:85b3fd62ea1a 138 UARTSerial::tx_irq(); // only write to hardware in one place
NYX 0:85b3fd62ea1a 139 if (!_txbuf.empty()) {
NYX 0:85b3fd62ea1a 140 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
NYX 0:85b3fd62ea1a 141 _tx_irq_enabled = true;
NYX 0:85b3fd62ea1a 142 }
NYX 0:85b3fd62ea1a 143 }
NYX 0:85b3fd62ea1a 144 core_util_critical_section_exit();
NYX 0:85b3fd62ea1a 145
NYX 0:85b3fd62ea1a 146 api_unlock();
NYX 0:85b3fd62ea1a 147
NYX 0:85b3fd62ea1a 148 return data_written;
NYX 0:85b3fd62ea1a 149 }
NYX 0:85b3fd62ea1a 150
NYX 0:85b3fd62ea1a 151 ssize_t UARTSerial::read(void* buffer, size_t length)
NYX 0:85b3fd62ea1a 152 {
NYX 0:85b3fd62ea1a 153 size_t data_read = 0;
NYX 0:85b3fd62ea1a 154
NYX 0:85b3fd62ea1a 155 char *ptr = static_cast<char *>(buffer);
NYX 0:85b3fd62ea1a 156
NYX 0:85b3fd62ea1a 157 api_lock();
NYX 0:85b3fd62ea1a 158
NYX 0:85b3fd62ea1a 159 while (_rxbuf.empty()) {
NYX 0:85b3fd62ea1a 160 if (!_blocking) {
NYX 0:85b3fd62ea1a 161 api_unlock();
NYX 0:85b3fd62ea1a 162 return -EAGAIN;
NYX 0:85b3fd62ea1a 163 }
NYX 0:85b3fd62ea1a 164 api_unlock();
NYX 0:85b3fd62ea1a 165 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
NYX 0:85b3fd62ea1a 166 api_lock();
NYX 0:85b3fd62ea1a 167 }
NYX 0:85b3fd62ea1a 168
NYX 0:85b3fd62ea1a 169 while (data_read < length && !_rxbuf.empty()) {
NYX 0:85b3fd62ea1a 170 _rxbuf.pop(*ptr++);
NYX 0:85b3fd62ea1a 171 data_read++;
NYX 0:85b3fd62ea1a 172 }
NYX 0:85b3fd62ea1a 173
NYX 0:85b3fd62ea1a 174 api_unlock();
NYX 0:85b3fd62ea1a 175
NYX 0:85b3fd62ea1a 176 return data_read;
NYX 0:85b3fd62ea1a 177 }
NYX 0:85b3fd62ea1a 178
NYX 0:85b3fd62ea1a 179 bool UARTSerial::hup() const
NYX 0:85b3fd62ea1a 180 {
NYX 0:85b3fd62ea1a 181 return _dcd_irq && _dcd_irq->read() != 0;
NYX 0:85b3fd62ea1a 182 }
NYX 0:85b3fd62ea1a 183
NYX 0:85b3fd62ea1a 184 void UARTSerial::wake()
NYX 0:85b3fd62ea1a 185 {
NYX 0:85b3fd62ea1a 186 if (_sigio_cb) {
NYX 0:85b3fd62ea1a 187 _sigio_cb();
NYX 0:85b3fd62ea1a 188 }
NYX 0:85b3fd62ea1a 189 }
NYX 0:85b3fd62ea1a 190
NYX 0:85b3fd62ea1a 191 short UARTSerial::poll(short events) const {
NYX 0:85b3fd62ea1a 192
NYX 0:85b3fd62ea1a 193 short revents = 0;
NYX 0:85b3fd62ea1a 194 /* Check the Circular Buffer if space available for writing out */
NYX 0:85b3fd62ea1a 195
NYX 0:85b3fd62ea1a 196
NYX 0:85b3fd62ea1a 197 if (!_rxbuf.empty()) {
NYX 0:85b3fd62ea1a 198 revents |= POLLIN;
NYX 0:85b3fd62ea1a 199 }
NYX 0:85b3fd62ea1a 200
NYX 0:85b3fd62ea1a 201 /* POLLHUP and POLLOUT are mutually exclusive */
NYX 0:85b3fd62ea1a 202 if (hup()) {
NYX 0:85b3fd62ea1a 203 revents |= POLLHUP;
NYX 0:85b3fd62ea1a 204 } else if (!_txbuf.full()) {
NYX 0:85b3fd62ea1a 205 revents |= POLLOUT;
NYX 0:85b3fd62ea1a 206 }
NYX 0:85b3fd62ea1a 207
NYX 0:85b3fd62ea1a 208 /*TODO Handle other event types */
NYX 0:85b3fd62ea1a 209
NYX 0:85b3fd62ea1a 210 return revents;
NYX 0:85b3fd62ea1a 211 }
NYX 0:85b3fd62ea1a 212
NYX 0:85b3fd62ea1a 213 void UARTSerial::lock()
NYX 0:85b3fd62ea1a 214 {
NYX 0:85b3fd62ea1a 215 // This is the override for SerialBase.
NYX 0:85b3fd62ea1a 216 // No lock required as we only use SerialBase from interrupt or from
NYX 0:85b3fd62ea1a 217 // inside our own critical section.
NYX 0:85b3fd62ea1a 218 }
NYX 0:85b3fd62ea1a 219
NYX 0:85b3fd62ea1a 220 void UARTSerial::unlock()
NYX 0:85b3fd62ea1a 221 {
NYX 0:85b3fd62ea1a 222 // This is the override for SerialBase.
NYX 0:85b3fd62ea1a 223 }
NYX 0:85b3fd62ea1a 224
NYX 0:85b3fd62ea1a 225 void UARTSerial::api_lock(void)
NYX 0:85b3fd62ea1a 226 {
NYX 0:85b3fd62ea1a 227 _mutex.lock();
NYX 0:85b3fd62ea1a 228 }
NYX 0:85b3fd62ea1a 229
NYX 0:85b3fd62ea1a 230 void UARTSerial::api_unlock(void)
NYX 0:85b3fd62ea1a 231 {
NYX 0:85b3fd62ea1a 232 _mutex.unlock();
NYX 0:85b3fd62ea1a 233 }
NYX 0:85b3fd62ea1a 234
NYX 0:85b3fd62ea1a 235 void UARTSerial::rx_irq(void)
NYX 0:85b3fd62ea1a 236 {
NYX 0:85b3fd62ea1a 237 bool was_empty = _rxbuf.empty();
NYX 0:85b3fd62ea1a 238
NYX 0:85b3fd62ea1a 239 /* Fill in the receive buffer if the peripheral is readable
NYX 0:85b3fd62ea1a 240 * and receive buffer is not full. */
NYX 0:85b3fd62ea1a 241 while (SerialBase::readable()) {
NYX 0:85b3fd62ea1a 242 char data = SerialBase::_base_getc();
NYX 0:85b3fd62ea1a 243 if (!_rxbuf.full()) {
NYX 0:85b3fd62ea1a 244 _rxbuf.push(data);
NYX 0:85b3fd62ea1a 245 } else {
NYX 0:85b3fd62ea1a 246 /* Drop - can we report in some way? */
NYX 0:85b3fd62ea1a 247 }
NYX 0:85b3fd62ea1a 248 }
NYX 0:85b3fd62ea1a 249
NYX 0:85b3fd62ea1a 250 /* Report the File handler that data is ready to be read from the buffer. */
NYX 0:85b3fd62ea1a 251 if (was_empty && !_rxbuf.empty()) {
NYX 0:85b3fd62ea1a 252 wake();
NYX 0:85b3fd62ea1a 253 }
NYX 0:85b3fd62ea1a 254 }
NYX 0:85b3fd62ea1a 255
NYX 0:85b3fd62ea1a 256 // Also called from write to start transfer
NYX 0:85b3fd62ea1a 257 void UARTSerial::tx_irq(void)
NYX 0:85b3fd62ea1a 258 {
NYX 0:85b3fd62ea1a 259 bool was_full = _txbuf.full();
NYX 0:85b3fd62ea1a 260
NYX 0:85b3fd62ea1a 261 /* Write to the peripheral if there is something to write
NYX 0:85b3fd62ea1a 262 * and if the peripheral is available to write. */
NYX 0:85b3fd62ea1a 263 while (!_txbuf.empty() && SerialBase::writeable()) {
NYX 0:85b3fd62ea1a 264 char data;
NYX 0:85b3fd62ea1a 265 _txbuf.pop(data);
NYX 0:85b3fd62ea1a 266 SerialBase::_base_putc(data);
NYX 0:85b3fd62ea1a 267 }
NYX 0:85b3fd62ea1a 268
NYX 0:85b3fd62ea1a 269 if (_tx_irq_enabled && _txbuf.empty()) {
NYX 0:85b3fd62ea1a 270 SerialBase::attach(NULL, TxIrq);
NYX 0:85b3fd62ea1a 271 _tx_irq_enabled = false;
NYX 0:85b3fd62ea1a 272 }
NYX 0:85b3fd62ea1a 273
NYX 0:85b3fd62ea1a 274 /* Report the File handler that data can be written to peripheral. */
NYX 0:85b3fd62ea1a 275 if (was_full && !_txbuf.full() && !hup()) {
NYX 0:85b3fd62ea1a 276 wake();
NYX 0:85b3fd62ea1a 277 }
NYX 0:85b3fd62ea1a 278 }
NYX 0:85b3fd62ea1a 279
NYX 0:85b3fd62ea1a 280 } //namespace mbed
NYX 0:85b3fd62ea1a 281
NYX 0:85b3fd62ea1a 282 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)