Elijah Stanger-Jones / mbed-dev-f303
Committer:
elijahsj
Date:
Mon Nov 09 00:33:19 2020 -0500
Revision:
2:4364577b5ad8
Parent:
1:8a094db1347f
copied mbed library

Who changed what in which revision?

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