mbed library sources. Supersedes mbed-src. RTC working even after reset
Fork of mbed-dev by
Diff: common/InterruptManager.cpp
- Revision:
- 144:ef7eb2e8f9f7
- Parent:
- 0:9b334a45a8ff
--- a/common/InterruptManager.cpp Tue Aug 02 14:07:36 2016 +0000 +++ b/common/InterruptManager.cpp Fri Sep 02 15:07:44 2016 +0100 @@ -1,93 +1,122 @@ -#include "cmsis.h" -#if defined(NVIC_NUM_VECTORS) - -#include "InterruptManager.h" -#include <string.h> - -#define CHAIN_INITIAL_SIZE 4 - -namespace mbed { - -typedef void (*pvoidf)(void); - -InterruptManager* InterruptManager::_instance = (InterruptManager*)NULL; - -InterruptManager* InterruptManager::get() { - if (NULL == _instance) - _instance = new InterruptManager(); - return _instance; -} - -InterruptManager::InterruptManager() { - memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain*)); -} - -void InterruptManager::destroy() { - // Not a good idea to call this unless NO interrupt at all - // is under the control of the handler; otherwise, a system crash - // is very likely to occur - if (NULL != _instance) { - delete _instance; - _instance = (InterruptManager*)NULL; - } -} - -InterruptManager::~InterruptManager() { - for(int i = 0; i < NVIC_NUM_VECTORS; i++) - if (NULL != _chains[i]) - delete _chains[i]; -} - -bool InterruptManager::must_replace_vector(IRQn_Type irq) { - int irq_pos = get_irq_index(irq); - - if (NULL == _chains[irq_pos]) { - _chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE); - _chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq)); - return true; - } - return false; -} - -pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front) { - int irq_pos = get_irq_index(irq); - bool change = must_replace_vector(irq); - - pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function); - if (change) - NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper); - return pf; -} - -bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq) { - int irq_pos = get_irq_index(irq); - - if (NULL == _chains[irq_pos]) - return false; - if (!_chains[irq_pos]->remove(handler)) - return false; - // If there's a single function left in the chain, swith the interrupt vector - // to call that function directly. This way we save both time and space. - if (_chains[irq_pos]->size() == 1 && NULL != _chains[irq_pos]->get(0)->get_function()) { - NVIC_SetVector(irq, (uint32_t)_chains[irq_pos]->get(0)->get_function()); - delete _chains[irq_pos]; - _chains[irq_pos] = (CallChain*) NULL; - } - return true; -} - -void InterruptManager::irq_helper() { - _chains[__get_IPSR()]->call(); -} - -int InterruptManager::get_irq_index(IRQn_Type irq) { - return (int)irq + NVIC_USER_IRQ_OFFSET; -} - -void InterruptManager::static_irq_helper() { - InterruptManager::get()->irq_helper(); -} - -} // namespace mbed - -#endif +#include "cmsis.h" +#if defined(NVIC_NUM_VECTORS) + +#include "InterruptManager.h" +#include "critical.h" +#include <string.h> + +#define CHAIN_INITIAL_SIZE 4 + +namespace mbed { + +typedef void (*pvoidf)(void); + +InterruptManager* InterruptManager::_instance = (InterruptManager*)NULL; + +InterruptManager* InterruptManager::get() { + + if (NULL == _instance) { + InterruptManager* temp = new InterruptManager(); + + // Atomically set _instance + core_util_critical_section_enter(); + if (NULL == _instance) { + _instance = temp; + } + core_util_critical_section_exit(); + + // Another thread got there first so delete ours + if (temp != _instance) { + delete temp; + } + + } + return _instance; +} + +InterruptManager::InterruptManager() { + // No mutex needed in constructor + memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain*)); +} + +void InterruptManager::destroy() { + // Not a good idea to call this unless NO interrupt at all + // is under the control of the handler; otherwise, a system crash + // is very likely to occur + if (NULL != _instance) { + delete _instance; + _instance = (InterruptManager*)NULL; + } +} + +InterruptManager::~InterruptManager() { + for(int i = 0; i < NVIC_NUM_VECTORS; i++) + if (NULL != _chains[i]) + delete _chains[i]; +} + +bool InterruptManager::must_replace_vector(IRQn_Type irq) { + lock(); + + int ret = false; + int irq_pos = get_irq_index(irq); + if (NULL == _chains[irq_pos]) { + _chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE); + _chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq)); + ret = true; + } + unlock(); + return ret; +} + +pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front) { + lock(); + int irq_pos = get_irq_index(irq); + bool change = must_replace_vector(irq); + + pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function); + if (change) + NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper); + unlock(); + return pf; +} + +bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq) { + int irq_pos = get_irq_index(irq); + bool ret = false; + + lock(); + if (_chains[irq_pos] != NULL) { + if (_chains[irq_pos]->remove(handler)) { + ret = true; + } + } + unlock(); + + return ret; +} + +void InterruptManager::irq_helper() { + _chains[__get_IPSR()]->call(); +} + +int InterruptManager::get_irq_index(IRQn_Type irq) { + // Pure function - no lock needed + return (int)irq + NVIC_USER_IRQ_OFFSET; +} + +void InterruptManager::static_irq_helper() { + InterruptManager::get()->irq_helper(); +} + +void InterruptManager::lock() { + _mutex.lock(); +} + +void InterruptManager::unlock() { + _mutex.unlock(); +} + +} // namespace mbed + +#endif