mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

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