Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SerialBase.cpp Source File

SerialBase.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "drivers/SerialBase.h"
00017 #include "platform/mbed_wait_api.h"
00018 #include "platform/mbed_critical.h"
00019 #include "platform/mbed_sleep.h"
00020 
00021 #if DEVICE_SERIAL
00022 
00023 namespace mbed {
00024 
00025 SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
00026 #if DEVICE_SERIAL_ASYNCH
00027                                                  _thunk_irq(this), _tx_usage(DMA_USAGE_NEVER),
00028                                                  _rx_usage(DMA_USAGE_NEVER), _tx_callback(NULL),
00029                                                  _rx_callback(NULL),
00030 #endif
00031                                                 _serial(), _baud(baud) {
00032     // No lock needed in the constructor
00033 
00034     for (size_t i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
00035         _irq[i] = NULL;
00036     }
00037 
00038     serial_init(&_serial, tx, rx);
00039     serial_baud(&_serial, _baud);
00040     serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
00041 }
00042 
00043 void SerialBase::baud(int baudrate) {
00044     lock();
00045     serial_baud(&_serial, baudrate);
00046     _baud = baudrate;
00047     unlock();
00048 }
00049 
00050 void SerialBase::format(int bits, Parity parity, int stop_bits) {
00051     lock();
00052     serial_format(&_serial, bits, (SerialParity)parity, stop_bits);
00053     unlock();
00054 }
00055 
00056 int SerialBase::readable() {
00057     lock();
00058     int ret = serial_readable(&_serial);
00059     unlock();
00060     return ret;
00061 }
00062 
00063 
00064 int SerialBase::writeable() {
00065     lock();
00066     int ret = serial_writable(&_serial);
00067     unlock();
00068     return ret;
00069 }
00070 
00071 void SerialBase::attach(Callback<void()> func, IrqType type) {
00072     lock();
00073     // Disable interrupts when attaching interrupt handler
00074     core_util_critical_section_enter();
00075     if (func) {
00076         // lock deep sleep only the first time
00077         if (!_irq[type]) {
00078             sleep_manager_lock_deep_sleep();
00079         } 
00080         _irq[type] = func;
00081         serial_irq_set(&_serial, (SerialIrq)type, 1);
00082     } else {
00083         // unlock deep sleep only the first time
00084         if (_irq[type]) {
00085             sleep_manager_unlock_deep_sleep();
00086         } 
00087         _irq[type] = NULL;
00088         serial_irq_set(&_serial, (SerialIrq)type, 0);
00089     }
00090     core_util_critical_section_exit();
00091     unlock();
00092 }
00093 
00094 void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) {
00095     SerialBase *handler = (SerialBase*)id;
00096     if (handler->_irq[irq_type]) {
00097         handler->_irq[irq_type]();
00098     }
00099 }
00100 
00101 int SerialBase::_base_getc() {
00102     // Mutex is already held
00103     return serial_getc(&_serial);
00104 }
00105 
00106 int SerialBase::_base_putc(int c) {
00107     // Mutex is already held
00108     serial_putc(&_serial, c);
00109     return c;
00110 }
00111 
00112 void SerialBase::send_break() {
00113     lock();
00114   // Wait for 1.5 frames before clearing the break condition
00115   // This will have different effects on our platforms, but should
00116   // ensure that we keep the break active for at least one frame.
00117   // We consider a full frame (1 start bit + 8 data bits bits +
00118   // 1 parity bit + 2 stop bits = 12 bits) for computation.
00119   // One bit time (in us) = 1000000/_baud
00120   // Twelve bits: 12000000/baud delay
00121   // 1.5 frames: 18000000/baud delay
00122   serial_break_set(&_serial);
00123   wait_us(18000000/_baud);
00124   serial_break_clear(&_serial);
00125   unlock();
00126 }
00127 
00128 void SerialBase::lock() {
00129     // Stub
00130 }
00131 
00132 void SerialBase:: unlock() {
00133     // Stub
00134 }
00135 
00136 SerialBase::~SerialBase()
00137 {
00138     // No lock needed in destructor
00139 
00140     // Detaching interrupts releases the sleep lock if it was locked
00141     for (int irq = 0; irq < IrqCnt; irq++) {
00142         attach(NULL, (IrqType)irq);
00143     }
00144 }
00145 
00146 #if DEVICE_SERIAL_FC
00147 void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) {
00148     lock();
00149     FlowControl flow_type = (FlowControl)type;
00150     switch(type) {
00151         case RTS:
00152             serial_set_flow_control(&_serial, flow_type, flow1, NC);
00153             break;
00154 
00155         case CTS:
00156             serial_set_flow_control(&_serial, flow_type, NC, flow1);
00157             break;
00158 
00159         case RTSCTS:
00160         case Disabled:
00161             serial_set_flow_control(&_serial, flow_type, flow1, flow2);
00162             break;
00163 
00164         default:
00165             break;
00166     }
00167     unlock();
00168 }
00169 #endif
00170 
00171 #if DEVICE_SERIAL_ASYNCH
00172 
00173 int SerialBase::write(const uint8_t *buffer, int length, const event_callback_t& callback, int event)
00174 {
00175     if (serial_tx_active(&_serial)) {
00176         return -1; // transaction ongoing
00177     }
00178     start_write((void *)buffer, length, 8, callback, event);
00179     return 0;
00180 }
00181 
00182 int SerialBase::write(const uint16_t *buffer, int length, const event_callback_t& callback, int event)
00183 {
00184     if (serial_tx_active(&_serial)) {
00185         return -1; // transaction ongoing
00186     }
00187     start_write((void *)buffer, length, 16, callback, event);
00188     return 0;
00189 }
00190 
00191 void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_width, const event_callback_t& callback, int event)
00192 {
00193     _tx_callback = callback;
00194 
00195     _thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
00196     sleep_manager_lock_deep_sleep();
00197     serial_tx_asynch(&_serial, buffer, buffer_size, buffer_width, _thunk_irq.entry(), event, _tx_usage);
00198 }
00199 
00200 void SerialBase::abort_write(void)
00201 {
00202     // rx might still be active
00203     if (_rx_callback) {
00204         sleep_manager_unlock_deep_sleep();
00205     }
00206     _tx_callback = NULL;
00207     serial_tx_abort_asynch(&_serial);
00208 }
00209 
00210 void SerialBase::abort_read(void)
00211 {
00212     // tx might still be active
00213     if (_tx_callback) {
00214         sleep_manager_unlock_deep_sleep();
00215     }
00216     _rx_callback = NULL;
00217     serial_rx_abort_asynch(&_serial);
00218 }
00219 
00220 int SerialBase::set_dma_usage_tx(DMAUsage usage)
00221 {
00222     if (serial_tx_active(&_serial)) {
00223         return -1;
00224     }
00225     _tx_usage = usage;
00226     return 0;
00227 }
00228 
00229 int SerialBase::set_dma_usage_rx(DMAUsage usage)
00230 {
00231     if (serial_tx_active(&_serial)) {
00232         return -1;
00233     }
00234     _rx_usage = usage;
00235     return 0;
00236 }
00237 
00238 int SerialBase::read(uint8_t *buffer, int length, const event_callback_t& callback, int event, unsigned char char_match)
00239 {
00240     if (serial_rx_active(&_serial)) {
00241         return -1; // transaction ongoing
00242     }
00243     start_read((void*)buffer, length, 8, callback, event, char_match);
00244     return 0;
00245 }
00246 
00247 
00248 int SerialBase::read(uint16_t *buffer, int length, const event_callback_t& callback, int event, unsigned char char_match)
00249 {
00250     if (serial_rx_active(&_serial)) {
00251         return -1; // transaction ongoing
00252     }
00253     start_read((void*)buffer, length, 16, callback, event, char_match);
00254     return 0;
00255 }
00256 
00257 
00258 void SerialBase::start_read(void *buffer, int buffer_size, char buffer_width, const event_callback_t& callback, int event, unsigned char char_match)
00259 {
00260     _rx_callback = callback;
00261     _thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
00262     sleep_manager_lock_deep_sleep();
00263     serial_rx_asynch(&_serial, buffer, buffer_size, buffer_width, _thunk_irq.entry(), event, char_match, _rx_usage);
00264 }
00265 
00266 void SerialBase::interrupt_handler_asynch(void)
00267 {
00268     int event = serial_irq_handler_asynch(&_serial);
00269     int rx_event = event & SERIAL_EVENT_RX_MASK;
00270     bool unlock_deepsleep = false;
00271 
00272     if (_rx_callback && rx_event) {
00273         unlock_deepsleep = true;
00274         _rx_callback.call(rx_event);
00275     }
00276 
00277     int tx_event = event & SERIAL_EVENT_TX_MASK;
00278     if (_tx_callback && tx_event) {
00279         unlock_deepsleep = true;
00280         _tx_callback.call(tx_event);
00281     }
00282     // unlock if tx or rx events are generated
00283     if (unlock_deepsleep) {
00284         sleep_manager_unlock_deep_sleep();
00285     }
00286 }
00287 
00288 #endif
00289 
00290 } // namespace mbed
00291 
00292 #endif