mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

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  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "cmsis.h"
00018 #if defined(NVIC_NUM_VECTORS)
00019 
00020 // Suppress deprecation warnings since this whole
00021 // class is deprecated already
00022 #include "mbed_toolchain.h"
00023 #undef MBED_DEPRECATED_SINCE
00024 #define MBED_DEPRECATED_SINCE(...)
00025 
00026 #include "drivers/InterruptManager.h"
00027 #include "platform/mbed_critical.h"
00028 #include <string.h>
00029 
00030 #define CHAIN_INITIAL_SIZE    4
00031 
00032 namespace mbed {
00033 
00034 typedef void (*pvoidf)(void);
00035 
00036 InterruptManager *InterruptManager::_instance = (InterruptManager *)NULL;
00037 
00038 InterruptManager *InterruptManager::get()
00039 {
00040 
00041     if (NULL == _instance) {
00042         InterruptManager *temp = new InterruptManager();
00043 
00044         // Atomically set _instance
00045         core_util_critical_section_enter();
00046         if (NULL == _instance) {
00047             _instance = temp;
00048         }
00049         core_util_critical_section_exit();
00050 
00051         // Another thread got there first so delete ours
00052         if (temp != _instance) {
00053             delete temp;
00054         }
00055 
00056     }
00057     return _instance;
00058 }
00059 
00060 InterruptManager::InterruptManager()
00061 {
00062     // No mutex needed in constructor
00063     memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain *));
00064 }
00065 
00066 void InterruptManager::destroy()
00067 {
00068     // Not a good idea to call this unless NO interrupt at all
00069     // is under the control of the handler; otherwise, a system crash
00070     // is very likely to occur
00071     if (NULL != _instance) {
00072         delete _instance;
00073         _instance = (InterruptManager *)NULL;
00074     }
00075 }
00076 
00077 InterruptManager::~InterruptManager()
00078 {
00079     for (int i = 0; i < NVIC_NUM_VECTORS; i++)
00080         if (NULL != _chains[i]) {
00081             delete _chains[i];
00082         }
00083 }
00084 
00085 bool InterruptManager::must_replace_vector(IRQn_Type irq)
00086 {
00087     lock();
00088 
00089     int ret = false;
00090     int irq_pos = get_irq_index(irq);
00091     if (NULL == _chains[irq_pos]) {
00092         _chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE);
00093         _chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq));
00094         ret = true;
00095     }
00096     unlock();
00097     return ret;
00098 }
00099 
00100 pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front)
00101 {
00102     lock();
00103     int irq_pos = get_irq_index(irq);
00104     bool change = must_replace_vector(irq);
00105 
00106     pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function);
00107     if (change) {
00108         NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper);
00109     }
00110     unlock();
00111     return pf;
00112 }
00113 
00114 bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq)
00115 {
00116     int irq_pos = get_irq_index(irq);
00117     bool ret = false;
00118 
00119     lock();
00120     if (_chains[irq_pos] != NULL) {
00121         if (_chains[irq_pos]->remove(handler)) {
00122             ret = true;
00123         }
00124     }
00125     unlock();
00126 
00127     return ret;
00128 }
00129 
00130 void InterruptManager::irq_helper()
00131 {
00132     _chains[__get_IPSR()]->call();
00133 }
00134 
00135 int InterruptManager::get_irq_index(IRQn_Type irq)
00136 {
00137     // Pure function - no lock needed
00138     return (int)irq + NVIC_USER_IRQ_OFFSET;
00139 }
00140 
00141 void InterruptManager::static_irq_helper()
00142 {
00143     InterruptManager::get()->irq_helper();
00144 }
00145 
00146 void InterruptManager::lock()
00147 {
00148     _mutex.lock();
00149 }
00150 
00151 void InterruptManager::unlock()
00152 {
00153     _mutex.unlock();
00154 }
00155 
00156 } // namespace mbed
00157 
00158 #endif