1

Committer:
valeyev
Date:
Tue Mar 13 07:17:50 2018 +0000
Revision:
0:e056ac8fecf8
looking for...

Who changed what in which revision?

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