001

Committer:
ganlikun
Date:
Sun Jun 12 14:02:44 2022 +0000
Revision:
0:13413ea9a877
00

Who changed what in which revision?

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