1232

Committer:
ganlikun
Date:
Mon Oct 24 15:19:39 2022 +0000
Revision:
0:06036f8bee2d
11

Who changed what in which revision?

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