Changes to support running on smaller memory LPC device LPC1764

Fork of mbed-dev by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers InterruptManager.cpp Source File

InterruptManager.cpp

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