RTC auf true

Committer:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Revision:
2:7aab896b1a3b
Parent:
0:38ceb79fef03
2019-03-13

Who changed what in which revision?

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