Preliminary main mbed library for nexpaq development
Diff: hal/common/InterruptManager.cpp
- Revision:
- 0:6c56fb4bc5f0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hal/common/InterruptManager.cpp Fri Nov 04 20:27:58 2016 +0000 @@ -0,0 +1,122 @@ +#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