Elijah Stanger-Jones / mbed-dev
Committer:
saloutos
Date:
Thu Nov 26 04:08:56 2020 +0000
Revision:
0:083111ae2a11
first commit of leaned mbed dev lib

Who changed what in which revision?

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