mbed library sources

Committer:
ebrus
Date:
Wed Jul 27 18:35:32 2016 +0000
Revision:
0:0a673c671a56
4

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ebrus 0:0a673c671a56 1 #include "InterruptManager.h"
ebrus 0:0a673c671a56 2 #include <string.h>
ebrus 0:0a673c671a56 3
ebrus 0:0a673c671a56 4 #define CHAIN_INITIAL_SIZE 4
ebrus 0:0a673c671a56 5
ebrus 0:0a673c671a56 6 namespace mbed {
ebrus 0:0a673c671a56 7
ebrus 0:0a673c671a56 8 typedef void (*pvoidf)(void);
ebrus 0:0a673c671a56 9
ebrus 0:0a673c671a56 10 InterruptManager* InterruptManager::_instance = (InterruptManager*)NULL;
ebrus 0:0a673c671a56 11
ebrus 0:0a673c671a56 12 InterruptManager* InterruptManager::get() {
ebrus 0:0a673c671a56 13 if (NULL == _instance)
ebrus 0:0a673c671a56 14 _instance = new InterruptManager();
ebrus 0:0a673c671a56 15 return _instance;
ebrus 0:0a673c671a56 16 }
ebrus 0:0a673c671a56 17
ebrus 0:0a673c671a56 18 InterruptManager::InterruptManager() {
ebrus 0:0a673c671a56 19 memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain*));
ebrus 0:0a673c671a56 20 }
ebrus 0:0a673c671a56 21
ebrus 0:0a673c671a56 22 void InterruptManager::destroy() {
ebrus 0:0a673c671a56 23 // Not a good idea to call this unless NO interrupt at all
ebrus 0:0a673c671a56 24 // is under the control of the handler; otherwise, a system crash
ebrus 0:0a673c671a56 25 // is very likely to occur
ebrus 0:0a673c671a56 26 if (NULL != _instance) {
ebrus 0:0a673c671a56 27 delete _instance;
ebrus 0:0a673c671a56 28 _instance = (InterruptManager*)NULL;
ebrus 0:0a673c671a56 29 }
ebrus 0:0a673c671a56 30 }
ebrus 0:0a673c671a56 31
ebrus 0:0a673c671a56 32 InterruptManager::~InterruptManager() {
ebrus 0:0a673c671a56 33 for(int i = 0; i < NVIC_NUM_VECTORS; i++)
ebrus 0:0a673c671a56 34 if (NULL != _chains[i])
ebrus 0:0a673c671a56 35 delete _chains[i];
ebrus 0:0a673c671a56 36 }
ebrus 0:0a673c671a56 37
ebrus 0:0a673c671a56 38 bool InterruptManager::must_replace_vector(IRQn_Type irq) {
ebrus 0:0a673c671a56 39 int irq_pos = get_irq_index(irq);
ebrus 0:0a673c671a56 40
ebrus 0:0a673c671a56 41 if (NULL == _chains[irq_pos]) {
ebrus 0:0a673c671a56 42 _chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE);
ebrus 0:0a673c671a56 43 _chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq));
ebrus 0:0a673c671a56 44 return true;
ebrus 0:0a673c671a56 45 }
ebrus 0:0a673c671a56 46 return false;
ebrus 0:0a673c671a56 47 }
ebrus 0:0a673c671a56 48
ebrus 0:0a673c671a56 49 pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front) {
ebrus 0:0a673c671a56 50 int irq_pos = get_irq_index(irq);
ebrus 0:0a673c671a56 51 bool change = must_replace_vector(irq);
ebrus 0:0a673c671a56 52
ebrus 0:0a673c671a56 53 pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function);
ebrus 0:0a673c671a56 54 if (change)
ebrus 0:0a673c671a56 55 NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper);
ebrus 0:0a673c671a56 56 return pf;
ebrus 0:0a673c671a56 57 }
ebrus 0:0a673c671a56 58
ebrus 0:0a673c671a56 59 bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq) {
ebrus 0:0a673c671a56 60 int irq_pos = get_irq_index(irq);
ebrus 0:0a673c671a56 61
ebrus 0:0a673c671a56 62 if (NULL == _chains[irq_pos])
ebrus 0:0a673c671a56 63 return false;
ebrus 0:0a673c671a56 64 if (!_chains[irq_pos]->remove(handler))
ebrus 0:0a673c671a56 65 return false;
ebrus 0:0a673c671a56 66 // If there's a single function left in the chain, swith the interrupt vector
ebrus 0:0a673c671a56 67 // to call that function directly. This way we save both time and space.
ebrus 0:0a673c671a56 68 if (_chains[irq_pos]->size() == 1 && NULL != _chains[irq_pos]->get(0)->get_function()) {
ebrus 0:0a673c671a56 69 NVIC_SetVector(irq, (uint32_t)_chains[irq_pos]->get(0)->get_function());
ebrus 0:0a673c671a56 70 delete _chains[irq_pos];
ebrus 0:0a673c671a56 71 _chains[irq_pos] = (CallChain*) NULL;
ebrus 0:0a673c671a56 72 }
ebrus 0:0a673c671a56 73 return true;
ebrus 0:0a673c671a56 74 }
ebrus 0:0a673c671a56 75
ebrus 0:0a673c671a56 76 void InterruptManager::irq_helper() {
ebrus 0:0a673c671a56 77 _chains[__get_IPSR()]->call();
ebrus 0:0a673c671a56 78 }
ebrus 0:0a673c671a56 79
ebrus 0:0a673c671a56 80 int InterruptManager::get_irq_index(IRQn_Type irq) {
ebrus 0:0a673c671a56 81 return (int)irq + NVIC_USER_IRQ_OFFSET;
ebrus 0:0a673c671a56 82 }
ebrus 0:0a673c671a56 83
ebrus 0:0a673c671a56 84 void InterruptManager::static_irq_helper() {
ebrus 0:0a673c671a56 85 InterruptManager::get()->irq_helper();
ebrus 0:0a673c671a56 86 }
ebrus 0:0a673c671a56 87
ebrus 0:0a673c671a56 88 } // namespace mbed
ebrus 0:0a673c671a56 89