Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers InterruptManager.cpp Source File

InterruptManager.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 "cmsis.h"
00017 #if defined(NVIC_NUM_VECTORS)
00018 
00019 // Suppress deprecation warnings since this whole
00020 // class is deprecated already
00021 #include "mbed_toolchain.h"
00022 #undef MBED_DEPRECATED_SINCE
00023 #define MBED_DEPRECATED_SINCE(...)
00024 
00025 #include "drivers/InterruptManager.h"
00026 #include "platform/mbed_critical.h"
00027 #include <string.h>
00028 
00029 #define CHAIN_INITIAL_SIZE    4
00030 
00031 namespace mbed {
00032 
00033 typedef void (*pvoidf)(void);
00034 
00035 InterruptManager* InterruptManager::_instance = (InterruptManager*)NULL;
00036 
00037 InterruptManager* InterruptManager::get() {
00038 
00039     if (NULL == _instance) {
00040         InterruptManager* temp = new InterruptManager();
00041 
00042         // Atomically set _instance
00043         core_util_critical_section_enter();
00044         if (NULL == _instance) {
00045             _instance = temp;
00046         }
00047         core_util_critical_section_exit();
00048 
00049         // Another thread got there first so delete ours
00050         if (temp != _instance) {
00051             delete temp;
00052         }
00053 
00054     }
00055     return _instance;
00056 }
00057 
00058 InterruptManager::InterruptManager() {
00059     // No mutex needed in constructor
00060     memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain*));
00061 }
00062 
00063 void InterruptManager::destroy() {
00064     // Not a good idea to call this unless NO interrupt at all
00065     // is under the control of the handler; otherwise, a system crash
00066     // is very likely to occur
00067     if (NULL != _instance) {
00068         delete _instance;
00069         _instance = (InterruptManager*)NULL;
00070     }
00071 }
00072 
00073 InterruptManager::~InterruptManager() {
00074     for(int i = 0; i < NVIC_NUM_VECTORS; i++)
00075         if (NULL != _chains[i])
00076             delete _chains[i];
00077 }
00078 
00079 bool InterruptManager::must_replace_vector(IRQn_Type irq) {
00080     lock();
00081 
00082     int ret = false;
00083     int irq_pos = get_irq_index(irq);
00084     if (NULL == _chains[irq_pos]) {
00085         _chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE);
00086         _chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq));
00087         ret = true;
00088     }
00089     unlock();
00090     return ret;
00091 }
00092 
00093 pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front) {
00094     lock();
00095     int irq_pos = get_irq_index(irq);
00096     bool change = must_replace_vector(irq);
00097 
00098     pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function);
00099     if (change)
00100         NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper);
00101     unlock();
00102     return pf;
00103 }
00104 
00105 bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq) {
00106     int irq_pos = get_irq_index(irq);
00107     bool ret = false;
00108 
00109     lock();
00110     if (_chains[irq_pos] != NULL) {
00111         if (_chains[irq_pos]->remove(handler)) {
00112             ret = true;
00113         }
00114     }
00115     unlock();
00116 
00117     return ret;
00118 }
00119 
00120 void InterruptManager::irq_helper() {
00121     _chains[__get_IPSR()]->call();
00122 }
00123 
00124 int InterruptManager::get_irq_index(IRQn_Type irq) {
00125     // Pure function - no lock needed
00126     return (int)irq + NVIC_USER_IRQ_OFFSET;
00127 }
00128 
00129 void InterruptManager::static_irq_helper() {
00130     InterruptManager::get()->irq_helper();
00131 }
00132 
00133 void InterruptManager::lock() {
00134     _mutex.lock();
00135 }
00136 
00137 void InterruptManager::unlock() {
00138     _mutex.unlock();
00139 }
00140 
00141 } // namespace mbed
00142 
00143 #endif