Erste version der Software für der Prototyp

Committer:
borlanic
Date:
Fri Mar 30 14:07:05 2018 +0000
Revision:
4:75df35ef4fb6
Parent:
0:380207fcb5c1
commentar

Who changed what in which revision?

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