Nicolas Borla / Mbed OS ROME2_Robot_Firmware
Committer:
boro
Date:
Mon Mar 16 13:12:31 2020 +0000
Revision:
0:4beb2ea291ec
a

Who changed what in which revision?

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