From 43d44450743ec94fd3b29dc226a0a0f275a1e010 Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Wed, 7 Aug 2013 14:43:26 +0300 Subject: [PATCH] Interrupt chaining: preliminary version --- libraries/mbed/api/CallChain.h | 57 ++++ libraries/mbed/api/FunctionPointer.h | 178 +++++----- libraries/mbed/api/InterruptIn.h | 313 +++++++++++------- libraries/mbed/api/InterruptManager.h | 68 ++++ libraries/mbed/api/Serial.h | 46 ++- libraries/mbed/api/Ticker.h | 270 ++++++++------- libraries/mbed/common/CallChain.cpp | 96 ++++++ libraries/mbed/common/FunctionPointer.cpp | 80 ++--- libraries/mbed/common/InterruptIn.cpp | 184 +++++----- libraries/mbed/common/InterruptManager.cpp | 89 +++++ libraries/mbed/common/Serial.cpp | 21 +- libraries/mbed/common/Ticker.cpp | 84 ++--- libraries/mbed/common/Timeout.cpp | 48 +-- .../TARGET_NXP/TARGET_LPC176X/cmsis_nvic.c | 8 +- .../TARGET_NXP/TARGET_LPC176X/cmsis_nvic.h | 4 + .../interrupt_chaining/interruptin/main.cpp | 113 +++++++ .../serial_interrupt/main.cpp | 41 +++ .../mbed/interrupt_chaining/ticker/main.cpp | 101 ++++++ 18 files changed, 1290 insertions(+), 511 deletions(-) create mode 100644 libraries/mbed/api/CallChain.h create mode 100644 libraries/mbed/api/InterruptManager.h create mode 100644 libraries/mbed/common/CallChain.cpp create mode 100644 libraries/mbed/common/InterruptManager.cpp create mode 100644 libraries/tests/mbed/interrupt_chaining/interruptin/main.cpp create mode 100644 libraries/tests/mbed/interrupt_chaining/serial_interrupt/main.cpp create mode 100644 libraries/tests/mbed/interrupt_chaining/ticker/main.cpp diff --git a/libraries/mbed/api/CallChain.h b/libraries/mbed/api/CallChain.h new file mode 100644 index 0000000000..ac403beba5 --- /dev/null +++ b/libraries/mbed/api/CallChain.h @@ -0,0 +1,57 @@ +#ifndef MBED_CALLCHAIN_H +#define MBED_CALLCHAIN_H + +#include "FunctionPointer.h" +#include + +namespace mbed { + +typedef FunctionPointer* pFunctionPointer_t; + +class CallChain { +public: + CallChain(int size = 4); + ~CallChain(); + + pFunctionPointer_t add(void (*function)(void)); + template + pFunctionPointer_t add(T *object, void (T::*member)(void)) { + return common_add(new FunctionPointer(object, member)); + } + + pFunctionPointer_t add_front(void (*function)(void)); + template + pFunctionPointer_t add_front(T *object, void (T::*member)(void)) { + return common_add_front(new FunctionPointer(object, member)); + } + + int size() const; + pFunctionPointer_t get(int i) const; + int find(pFunctionPointer_t f) const; + void clear(); + bool remove(pFunctionPointer_t f); + void call(); + +#ifdef MBED_OPERATORS + void operator ()(void) { + call(); + } + pFunctionPointer_t operator [](int i) const { + return get(i); + } +#endif + +private: + void _check_size(); + pFunctionPointer_t common_add(pFunctionPointer_t pf); + pFunctionPointer_t common_add_front(pFunctionPointer_t pf); + + pFunctionPointer_t* _chain; + int _size; + int _elements; +}; + +} // namespace mbed + +#endif + diff --git a/libraries/mbed/api/FunctionPointer.h b/libraries/mbed/api/FunctionPointer.h index 6e3855c03d..5ffecd954b 100644 --- a/libraries/mbed/api/FunctionPointer.h +++ b/libraries/mbed/api/FunctionPointer.h @@ -1,84 +1,94 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef MBED_FUNCTIONPOINTER_H -#define MBED_FUNCTIONPOINTER_H - -#include - -namespace mbed { - -/** A class for storing and calling a pointer to a static or member void function - */ -class FunctionPointer { -public: - - /** Create a FunctionPointer, attaching a static function - * - * @param function The void static function to attach (default is none) - */ - FunctionPointer(void (*function)(void) = 0); - - /** Create a FunctionPointer, attaching a member function - * - * @param object The object pointer to invoke the member function on (i.e. the this pointer) - * @param function The address of the void member function to attach - */ - template - FunctionPointer(T *object, void (T::*member)(void)) { - attach(object, member); - } - - /** Attach a static function - * - * @param function The void static function to attach (default is none) - */ - void attach(void (*function)(void) = 0); - - /** Attach a member function - * - * @param object The object pointer to invoke the member function on (i.e. the this pointer) - * @param function The address of the void member function to attach - */ - template - void attach(T *object, void (T::*member)(void)) { - _object = static_cast(object); - memcpy(_member, (char*)&member, sizeof(member)); - _membercaller = &FunctionPointer::membercaller; - _function = 0; - } - - /** Call the attached static or member function - */ - void call(); - -private: - template - static void membercaller(void *object, char *member) { - T* o = static_cast(object); - void (T::*m)(void); - memcpy((char*)&m, member, sizeof(m)); - (o->*m)(); - } - - void (*_function)(void); // static function pointer - 0 if none attached - void *_object; // object this pointer - 0 if none attached - char _member[16]; // raw member function pointer storage - converted back by registered _membercaller - void (*_membercaller)(void*, char*); // registered membercaller function to convert back and call _member on _object -}; - -} // namespace mbed - -#endif +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_FUNCTIONPOINTER_H +#define MBED_FUNCTIONPOINTER_H + +#include + +namespace mbed { + +typedef void (*pvoidf_t)(void); + +/** A class for storing and calling a pointer to a static or member void function + */ +class FunctionPointer { +public: + + /** Create a FunctionPointer, attaching a static function + * + * @param function The void static function to attach (default is none) + */ + FunctionPointer(void (*function)(void) = 0); + + /** Create a FunctionPointer, attaching a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the void member function to attach + */ + template + FunctionPointer(T *object, void (T::*member)(void)) { + attach(object, member); + } + + /** Attach a static function + * + * @param function The void static function to attach (default is none) + */ + void attach(void (*function)(void) = 0); + + /** Attach a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the void member function to attach + */ + template + void attach(T *object, void (T::*member)(void)) { + _object = static_cast(object); + memcpy(_member, (char*)&member, sizeof(member)); + _membercaller = &FunctionPointer::membercaller; + _function = 0; + } + + /** Call the attached static or member function + */ + void call(); + + pvoidf_t get_function() const { + return (pvoidf_t)_function; + } + +#ifdef MBED_OPERATORS + void operator ()(void); +#endif + +private: + template + static void membercaller(void *object, char *member) { + T* o = static_cast(object); + void (T::*m)(void); + memcpy((char*)&m, member, sizeof(m)); + (o->*m)(); + } + + void (*_function)(void); // static function pointer - 0 if none attached + void *_object; // object this pointer - 0 if none attached + char _member[16]; // raw member function pointer storage - converted back by registered _membercaller + void (*_membercaller)(void*, char*); // registered membercaller function to convert back and call _member on _object +}; + +} // namespace mbed + +#endif diff --git a/libraries/mbed/api/InterruptIn.h b/libraries/mbed/api/InterruptIn.h index 2889ee14e1..97cba460f4 100644 --- a/libraries/mbed/api/InterruptIn.h +++ b/libraries/mbed/api/InterruptIn.h @@ -1,126 +1,187 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef MBED_INTERRUPTIN_H -#define MBED_INTERRUPTIN_H - -#include "platform.h" - -#if DEVICE_INTERRUPTIN - -#include "gpio_api.h" -#include "gpio_irq_api.h" - -#include "FunctionPointer.h" - -namespace mbed { - -/** A digital interrupt input, used to call a function on a rising or falling edge - * - * Example: - * @code - * // Flash an LED while waiting for events - * - * #include "mbed.h" - * - * InterruptIn event(p16); - * DigitalOut led(LED1); - * - * void trigger() { - * printf("triggered!\n"); - * } - * - * int main() { - * event.rise(&trigger); - * while(1) { - * led = !led; - * wait(0.25); - * } - * } - * @endcode - */ -class InterruptIn { - -public: - - /** Create an InterruptIn connected to the specified pin - * - * @param pin InterruptIn pin to connect to - * @param name (optional) A string to identify the object - */ - InterruptIn(PinName pin); - virtual ~InterruptIn(); - - int read(); -#ifdef MBED_OPERATORS - operator int(); - -#endif - - /** Attach a function to call when a rising edge occurs on the input - * - * @param fptr A pointer to a void function, or 0 to set as none - */ - void rise(void (*fptr)(void)); - - /** Attach a member function to call when a rising edge occurs on the input - * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called - */ - template - void rise(T* tptr, void (T::*mptr)(void)) { - _rise.attach(tptr, mptr); - gpio_irq_set(&gpio_irq, IRQ_RISE, 1); - } - - /** Attach a function to call when a falling edge occurs on the input - * - * @param fptr A pointer to a void function, or 0 to set as none - */ - void fall(void (*fptr)(void)); - - /** Attach a member function to call when a falling edge occurs on the input - * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called - */ - template - void fall(T* tptr, void (T::*mptr)(void)) { - _fall.attach(tptr, mptr); - gpio_irq_set(&gpio_irq, IRQ_FALL, 1); - } - - /** Set the input pin mode - * - * @param mode PullUp, PullDown, PullNone - */ - void mode(PinMode pull); - - static void _irq_handler(uint32_t id, gpio_irq_event event); - -protected: - gpio_t gpio; - gpio_irq_t gpio_irq; - - FunctionPointer _rise; - FunctionPointer _fall; -}; - -} // namespace mbed - -#endif - -#endif +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_INTERRUPTIN_H +#define MBED_INTERRUPTIN_H + +#include "platform.h" + +#if DEVICE_INTERRUPTIN + +#include "gpio_api.h" +#include "gpio_irq_api.h" + +#include "FunctionPointer.h" +#include "CallChain.h" + +namespace mbed { + +/** A digital interrupt input, used to call a function on a rising or falling edge + * + * Example: + * @code + * // Flash an LED while waiting for events + * + * #include "mbed.h" + * + * InterruptIn event(p16); + * DigitalOut led(LED1); + * + * void trigger() { + * printf("triggered!\n"); + * } + * + * int main() { + * event.rise(&trigger); + * while(1) { + * led = !led; + * wait(0.25); + * } + * } + * @endcode + */ +class InterruptIn { + +public: + + /** Create an InterruptIn connected to the specified pin + * + * @param pin InterruptIn pin to connect to + * @param name (optional) A string to identify the object + */ + InterruptIn(PinName pin); + virtual ~InterruptIn(); + + int read(); +#ifdef MBED_OPERATORS + operator int(); + +#endif + + /** Attach a function to call when a rising edge occurs on the input + * + * @param fptr A pointer to a void function, or 0 to set as none + * + * @returns + * The function object created for 'fptr' + */ + pFunctionPointer_t rise(void (*fptr)(void)); + pFunctionPointer_t rise_add(void (*fptr)(void)) { + return rise_add_common(fptr); + } + pFunctionPointer_t rise_add_front(void (*fptr)(void)) { + return rise_add_common(fptr, true); + } + + /** Attach a member function to call when a rising edge occurs on the input + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + * + * @returns + * The function object created for 'tptr' and 'mptr' + */ + template + pFunctionPointer_t rise(T* tptr, void (T::*mptr)(void)) { + _rise.clear(); + pFunctionPointer_t pf = _rise.add(tptr, mptr); + gpio_irq_set(&gpio_irq, IRQ_RISE, 1); + return pf; + } + + template + pFunctionPointer_t rise_add(T* tptr, void (T::*mptr)(void)) { + return rise_add_common(tptr, mptr); + } + + template + pFunctionPointer_t rise_add_front(T* tptr, void (T::*mptr)(void)) { + return rise_add_common(tptr, mptr, true); + } + + bool rise_remove(pFunctionPointer_t pf); + + /** Attach a function to call when a falling edge occurs on the input + * + * @param fptr A pointer to a void function, or 0 to set as none + */ + pFunctionPointer_t fall(void (*fptr)(void)); + pFunctionPointer_t fall_add(void (*fptr)(void)) { + return fall_add_common(fptr); + } + pFunctionPointer_t fall_add_front(void (*fptr)(void)) { + return fall_add_common(fptr, true); + } + + /** Attach a member function to call when a falling edge occurs on the input + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template + pFunctionPointer_t fall(T* tptr, void (T::*mptr)(void)) { + _fall.clear(); + pFunctionPointer_t pf = _fall.add(tptr, mptr); + gpio_irq_set(&gpio_irq, IRQ_FALL, 1); + return pf; + } + template + pFunctionPointer_t fall_add(T* tptr, void (T::*mptr)(void)) { + return fall_add_common(tptr, mptr); + } + template + pFunctionPointer_t fall_add_front(T* tptr, void (T::*mptr)(void)) { + return fall_add_common(tptr, mptr, true); + } + + bool fall_remove(pFunctionPointer_t pf); + + /** Set the input pin mode + * + * @param mode PullUp, PullDown, PullNone + */ + void mode(PinMode pull); + + static void _irq_handler(uint32_t id, gpio_irq_event event); + +protected: + pFunctionPointer_t rise_add_common(void (*fptr)(void), bool front=false); + pFunctionPointer_t fall_add_common(void (*fptr)(void), bool front=false); + + template + pFunctionPointer_t rise_add_common(T* tptr, void (T::*mptr)(void), bool front=false) { + pFunctionPointer_t pf = front ? _rise.add_front(tptr, mptr) : _rise.add(tptr, mptr); + gpio_irq_set(&gpio_irq, IRQ_RISE, 1); + return pf; + } + template + pFunctionPointer_t fall_add_common(T* tptr, void (T::*mptr)(void), bool front=false) { + pFunctionPointer_t pf = front ? _fall.add_front(tptr, mptr) : _fall.add(tptr, mptr); + gpio_irq_set(&gpio_irq, IRQ_FALL, 1); + return pf; + } + + gpio_t gpio; + gpio_irq_t gpio_irq; + + CallChain _rise; + CallChain _fall; +}; + +} // namespace mbed + +#endif + +#endif diff --git a/libraries/mbed/api/InterruptManager.h b/libraries/mbed/api/InterruptManager.h new file mode 100644 index 0000000000..c7a5e4d128 --- /dev/null +++ b/libraries/mbed/api/InterruptManager.h @@ -0,0 +1,68 @@ +#ifndef MBED_INTERRUPTMANAGER_H +#define MBED_INTERRUPTMANAGER_H + +#include "cmsis_nvic.h" +#include "CallChain.h" +#include + +namespace mbed { + +class InterruptManager { +public: + static InterruptManager* get(); + static void destroy(); + + pFunctionPointer_t add_handler(void (*function)(void), IRQn_Type irq) { + return add_common(function, irq); + } + pFunctionPointer_t add_handler_front(void (*function)(void), IRQn_Type irq) { + return add_common(function, irq, true); + } + + template + pFunctionPointer_t add_handler(T* tptr, void (T::*mptr)(void), IRQn_Type irq) { + return add_common(tptr, mptr, irq); + } + template + pFunctionPointer_t add_handler_front(T* tptr, void (T::*mptr)(void), IRQn_Type irq) { + return add_common(tptr, mptr, irq, true); + } + + bool remove_handler(pFunctionPointer_t handler, IRQn_Type irq); + +private: + InterruptManager(); + ~InterruptManager(); + + // We declare the copy contructor and the assignment operator, but we don't + // implement them. This way, if someone tries to copy/assign our instance, + // he will get an error at compile time. + InterruptManager(const InterruptManager&); + InterruptManager& operator =(const InterruptManager&); + + template + pFunctionPointer_t add_common(T *tptr, void (T::*mptr)(void), IRQn_Type irq, bool front=false) { + int irq_pos = get_irq_index(irq); + bool change = must_replace_vector(irq); + + pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(tptr, mptr) : _chains[irq_pos]->add(tptr, mptr); + if (change) + NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper); + return pf; + } + + pFunctionPointer_t add_common(void (*function)(void), IRQn_Type irq, bool front=false); + bool must_replace_vector(IRQn_Type irq); + int get_irq_index(IRQn_Type irq); + void irq_helper(); + void add_helper(void (*function)(void), IRQn_Type irq, bool front=false); + static void static_irq_helper(); + + CallChain* _chains[NVIC_NUM_VECTORS]; + static InterruptManager* _instance; +}; + +} // namespace mbed + +#endif + diff --git a/libraries/mbed/api/Serial.h b/libraries/mbed/api/Serial.h index 2d830fb608..bec3c8a0a8 100644 --- a/libraries/mbed/api/Serial.h +++ b/libraries/mbed/api/Serial.h @@ -23,6 +23,7 @@ #include "Stream.h" #include "FunctionPointer.h" #include "serial_api.h" +#include "CallChain.h" namespace mbed { @@ -82,7 +83,7 @@ public: * @param parity The parity used (Serial::None, Serial::Odd, Serial::Even, Serial::Forced1, Serial::Forced0; default = Serial::None) * @param stop The number of stop bits (1 or 2; default = 1) */ - void format(int bits = 8, Parity parity=Serial::None, int stop_bits=1); + void format(int bits=8, Parity parity=Serial::None, int stop_bits=1); /** Determine if there is a character available to read * @@ -105,7 +106,15 @@ public: * @param fptr A pointer to a void function, or 0 to set as none * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) */ - void attach(void (*fptr)(void), IrqType type=RxIrq); + pFunctionPointer_t attach(void (*fptr)(void), IrqType type=RxIrq); + + pFunctionPointer_t add_handler(void (*fptr)(void), IrqType type=RxIrq) { + return add_handler_helper(fptr, type); + } + + pFunctionPointer_t add_handler_front(void (*fptr)(void), IrqType type=RxIrq) { + return add_handler_helper(fptr, type, true); + } /** Attach a member function to call whenever a serial interrupt is generated * @@ -114,12 +123,27 @@ public: * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) */ template - void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) { + pFunctionPointer_t attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) { if((mptr != NULL) && (tptr != NULL)) { - _irq[type].attach(tptr, mptr); + _irq[type].clear(); + pFunctionPointer_t pf = _irq[type].add(tptr, mptr); serial_irq_set(&_serial, (SerialIrq)type, 1); + return pf; } + else + return NULL; } + template + pFunctionPointer_t add_handler(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) { + return add_handler_helper(tptr, mptr, type); + } + + template + pFunctionPointer_t add_handler_front(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) { + return add_handler_helper(tptr, mptr, type, true); + } + + bool remove_handler(pFunctionPointer_t pf, IrqType type=RxIrq); /** Generate a break condition on the serial line */ @@ -130,9 +154,21 @@ public: protected: virtual int _getc(); virtual int _putc(int c); + pFunctionPointer_t add_handler_helper(void (*function)(void), IrqType type, bool front=false); + + template + pFunctionPointer_t add_handler_helper(T* tptr, void (T::*mptr)(void), IrqType type, bool front=false) { + if ((mptr != NULL) && (tptr != NULL)) { + pFunctionPointer_t pf = front ? _irq[type].add_front(tptr, mptr) : _irq[type].add(tptr, mptr); + serial_irq_set(&_serial, (SerialIrq)type, 1); + return pf; + } + else + return NULL; + } serial_t _serial; - FunctionPointer _irq[2]; + CallChain _irq[2]; int _baud; }; diff --git a/libraries/mbed/api/Ticker.h b/libraries/mbed/api/Ticker.h index 73da8a5fbe..48aec50afb 100644 --- a/libraries/mbed/api/Ticker.h +++ b/libraries/mbed/api/Ticker.h @@ -1,117 +1,153 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef MBED_TICKER_H -#define MBED_TICKER_H - -#include "TimerEvent.h" -#include "FunctionPointer.h" - -namespace mbed { - -/** A Ticker is used to call a function at a recurring interval - * - * You can use as many seperate Ticker objects as you require. - * - * Example: - * @code - * // Toggle the blinking led after 5 seconds - * - * #include "mbed.h" - * - * Ticker timer; - * DigitalOut led1(LED1); - * DigitalOut led2(LED2); - * - * int flip = 0; - * - * void attime() { - * flip = !flip; - * } - * - * int main() { - * timer.attach(&attime, 5); - * while(1) { - * if(flip == 0) { - * led1 = !led1; - * } else { - * led2 = !led2; - * } - * wait(0.2); - * } - * } - * @endcode - */ -class Ticker : public TimerEvent { - -public: - - /** Attach a function to be called by the Ticker, specifiying the interval in seconds - * - * @param fptr pointer to the function to be called - * @param t the time between calls in seconds - */ - void attach(void (*fptr)(void), float t) { - attach_us(fptr, t * 1000000.0f); - } - - /** Attach a member function to be called by the Ticker, specifiying the interval in seconds - * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called - * @param t the time between calls in seconds - */ - template - void attach(T* tptr, void (T::*mptr)(void), float t) { - attach_us(tptr, mptr, t * 1000000.0f); - } - - /** Attach a function to be called by the Ticker, specifiying the interval in micro-seconds - * - * @param fptr pointer to the function to be called - * @param t the time between calls in micro-seconds - */ - void attach_us(void (*fptr)(void), unsigned int t) { - _function.attach(fptr); - setup(t); - } - - /** Attach a member function to be called by the Ticker, specifiying the interval in micro-seconds - * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called - * @param t the time between calls in micro-seconds - */ - template - void attach_us(T* tptr, void (T::*mptr)(void), unsigned int t) { - _function.attach(tptr, mptr); - setup(t); - } - - /** Detach the function - */ - void detach(); - -protected: - void setup(unsigned int t); - virtual void handler(); - - unsigned int _delay; - FunctionPointer _function; -}; - -} // namespace mbed - -#endif +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_TICKER_H +#define MBED_TICKER_H + +#include "TimerEvent.h" +#include "FunctionPointer.h" +#include "CallChain.h" + +namespace mbed { + +/** A Ticker is used to call a function at a recurring interval + * + * You can use as many seperate Ticker objects as you require. + * + * Example: + * @code + * // Toggle the blinking led after 5 seconds + * + * #include "mbed.h" + * + * Ticker timer; + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * + * int flip = 0; + * + * void attime() { + * flip = !flip; + * } + * + * int main() { + * timer.attach(&attime, 5); + * while(1) { + * if(flip == 0) { + * led1 = !led1; + * } else { + * led2 = !led2; + * } + * wait(0.2); + * } + * } + * @endcode + */ +class Ticker : public TimerEvent { + +public: + + /** Attach a function to be called by the Ticker, specifiying the interval in seconds + * + * @param fptr pointer to the function to be called + * @param t the time between calls in seconds + */ + pFunctionPointer_t attach(void (*fptr)(void), float t) { + return attach_us(fptr, t * 1000000.0f); + } + + pFunctionPointer_t add_function(void (*fptr)(void)) { + return add_function_helper(fptr); + } + + pFunctionPointer_t add_function_front(void (*fptr)(void)) { + return add_function_helper(fptr, true); + } + + /** Attach a member function to be called by the Ticker, specifiying the interval in seconds + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + * @param t the time between calls in seconds + */ + template + pFunctionPointer_t attach(T* tptr, void (T::*mptr)(void), float t) { + return attach_us(tptr, mptr, t * 1000000.0f); + } + + template + pFunctionPointer_t add_function(T* tptr, void (T::*mptr)(void)) { + return add_function_helper(tptr, mptr); + } + + template + pFunctionPointer_t add_function_front(T* tptr, void (T::*mptr)(void)) { + return add_function_helper(tptr, mptr, true); + } + + /** Attach a function to be called by the Ticker, specifiying the interval in micro-seconds + * + * @param fptr pointer to the function to be called + * @param t the time between calls in micro-seconds + */ + pFunctionPointer_t attach_us(void (*fptr)(void), unsigned int t) { + pFunctionPointer_t pf = _chain.add(fptr); + setup(t); + return pf; + } + + /** Attach a member function to be called by the Ticker, specifiying the interval in micro-seconds + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + * @param t the time between calls in micro-seconds + */ + template + pFunctionPointer_t attach_us(T* tptr, void (T::*mptr)(void), unsigned int t) { + pFunctionPointer_t pf = _chain.add(mptr, tptr); + setup(t); + return pf; + } + + /** Detach the function + */ + void detach(); + + bool remove_function(pFunctionPointer_t pf) { + bool res = _chain.remove(pf); + if (res && _chain.size() == 0) + detach(); + return res; + } + +protected: + void setup(unsigned int t); + pFunctionPointer_t add_function_helper(void (*fptr)(void), bool front=false); + virtual void handler(); + + template + pFunctionPointer_t add_function_helper(T* tptr, void (T::*mptr)(void), bool front=false) { + if (_chain.size() == 0) + return NULL; + return front ? _chain.add_front(tptr, mptr) : _chain.add(tptr, mptr); + } + + unsigned int _delay; + CallChain _chain; +}; + +} // namespace mbed + +#endif diff --git a/libraries/mbed/common/CallChain.cpp b/libraries/mbed/common/CallChain.cpp new file mode 100644 index 0000000000..963267b9ef --- /dev/null +++ b/libraries/mbed/common/CallChain.cpp @@ -0,0 +1,96 @@ +#include "CallChain.h" +#include "cmsis.h" + +namespace mbed { + +CallChain::CallChain(int size) : _size(size), _elements(0) { + _chain = new pFunctionPointer_t[size](); +} + +CallChain::~CallChain() { + clear(); + delete _chain; +} + +pFunctionPointer_t CallChain::add(void (*function)(void)) { + return common_add(new FunctionPointer(function)); +} + +pFunctionPointer_t CallChain::add_front(void (*function)(void)) { + return common_add_front(new FunctionPointer(function)); +} + +int CallChain::size() const { + return _elements; +} + +pFunctionPointer_t CallChain::get(int i) const { + if (i < 0 || i >= _elements) + return NULL; + return _chain[i]; +} + +int CallChain::find(pFunctionPointer_t f) const { + for (int i = 0; i < _elements; i++) + if (f == _chain[i]) + return i; + return -1; +} + +void CallChain::clear() { + __disable_irq(); + for(int i = 0; i < _elements; i ++) { + delete _chain[i]; + _chain[i] = NULL; + } + _elements = 0; + __enable_irq(); +} + +bool CallChain::remove(pFunctionPointer_t f) { + int i; + + if ((i = find(f)) == -1) + return false; + __disable_irq(); + if (i != _elements - 1) + memmove(_chain + i, _chain + i + 1, (_elements - i - 1) * sizeof(pFunctionPointer_t)); + delete f; + _elements --; + __enable_irq(); + return true; +} + +void CallChain::call() { + for(int i = 0; i < _elements; i++) + _chain[i]->call(); +} + +void CallChain::_check_size() { + if (_elements < _size) + return; + __disable_irq(); + _size = (_size < 4) ? 4 : _size + 4; + pFunctionPointer_t* new_chain = new pFunctionPointer_t[_size](); + memcpy(new_chain, _chain, _elements * sizeof(pFunctionPointer_t)); + delete _chain; + _chain = new_chain; + __enable_irq(); +} + +pFunctionPointer_t CallChain::common_add(pFunctionPointer_t pf) { + _check_size(); + _chain[_elements] = pf; + _elements ++; + return pf; +} + +pFunctionPointer_t CallChain::common_add_front(pFunctionPointer_t pf) { + _check_size(); + memmove(_chain + 1, _chain, _elements * sizeof(pFunctionPointer_t)); + _chain[0] = pf; + _elements ++; + return pf; +} + +} // namespace mbed diff --git a/libraries/mbed/common/FunctionPointer.cpp b/libraries/mbed/common/FunctionPointer.cpp index ab02510a18..849d1ff034 100644 --- a/libraries/mbed/common/FunctionPointer.cpp +++ b/libraries/mbed/common/FunctionPointer.cpp @@ -1,37 +1,43 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "FunctionPointer.h" - -namespace mbed { - -FunctionPointer::FunctionPointer(void (*function)(void)) { - attach(function); -} - -void FunctionPointer::attach(void (*function)(void)) { - _function = function; - _object = 0; -} - -void FunctionPointer::call(void) { - if (_function) { - _function(); - } else if (_object) { - _membercaller(_object, _member); - } -} - -} // namespace mbed +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "FunctionPointer.h" + +namespace mbed { + +FunctionPointer::FunctionPointer(void (*function)(void)) { + attach(function); +} + +void FunctionPointer::attach(void (*function)(void)) { + _function = function; + _object = 0; +} + +void FunctionPointer::call(void) { + if (_function) { + _function(); + } else if (_object) { + _membercaller(_object, _member); + } +} + +#ifdef MBED_OPERATORS +void FunctionPointer::operator ()(void) { + call(); +} +#endif + +} // namespace mbed diff --git a/libraries/mbed/common/InterruptIn.cpp b/libraries/mbed/common/InterruptIn.cpp index 5aba42e605..4b577298c0 100644 --- a/libraries/mbed/common/InterruptIn.cpp +++ b/libraries/mbed/common/InterruptIn.cpp @@ -1,74 +1,110 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "InterruptIn.h" - -#if DEVICE_INTERRUPTIN - -namespace mbed { - -InterruptIn::InterruptIn(PinName pin) { - gpio_irq_init(&gpio_irq, pin, (&InterruptIn::_irq_handler), (uint32_t)this); - gpio_init(&gpio, pin, PIN_INPUT); -} - -InterruptIn::~InterruptIn() { - gpio_irq_free(&gpio_irq); -} - -int InterruptIn::read() { - return gpio_read(&gpio); -} - -void InterruptIn::mode(PinMode pull) { - gpio_mode(&gpio, pull); -} - -void InterruptIn::rise(void (*fptr)(void)) { - if (fptr) { - _rise.attach(fptr); - gpio_irq_set(&gpio_irq, IRQ_RISE, 1); - } else { - gpio_irq_set(&gpio_irq, IRQ_RISE, 0); - } -} - -void InterruptIn::fall(void (*fptr)(void)) { - if (fptr) { - _fall.attach(fptr); - gpio_irq_set(&gpio_irq, IRQ_FALL, 1); - } else { - gpio_irq_set(&gpio_irq, IRQ_FALL, 0); - } -} - -void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) { - InterruptIn *handler = (InterruptIn*)id; - switch (event) { - case IRQ_RISE: handler->_rise.call(); break; - case IRQ_FALL: handler->_fall.call(); break; - case IRQ_NONE: break; - } -} - -#ifdef MBED_OPERATORS -InterruptIn::operator int() { - return read(); -} -#endif - -} // namespace mbed - -#endif +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "InterruptIn.h" + +#if DEVICE_INTERRUPTIN + +namespace mbed { + +InterruptIn::InterruptIn(PinName pin) { + gpio_irq_init(&gpio_irq, pin, (&InterruptIn::_irq_handler), (uint32_t)this); + gpio_init(&gpio, pin, PIN_INPUT); +} + +InterruptIn::~InterruptIn() { + gpio_irq_free(&gpio_irq); +} + +int InterruptIn::read() { + return gpio_read(&gpio); +} + +void InterruptIn::mode(PinMode pull) { + gpio_mode(&gpio, pull); +} + +pFunctionPointer_t InterruptIn::rise(void (*fptr)(void)) { + pFunctionPointer_t pf = NULL; + _rise.clear(); + if (fptr) { + pf = _rise.add(fptr); + gpio_irq_set(&gpio_irq, IRQ_RISE, 1); + } else { + gpio_irq_set(&gpio_irq, IRQ_RISE, 0); + } + return pf; +} + +pFunctionPointer_t InterruptIn::rise_add_common(void (*fptr)(void), bool front) { + if (NULL == fptr) + return NULL; + pFunctionPointer_t pf = front ? _rise.add_front(fptr) : _rise.add(fptr); + gpio_irq_set(&gpio_irq, IRQ_RISE, 1); + return pf; +} + +bool InterruptIn::rise_remove(pFunctionPointer_t pf) { + bool res = _rise.remove(pf); + if (res && _rise.size() == 0) + gpio_irq_set(&gpio_irq, IRQ_RISE, 0); + return res; +} + +pFunctionPointer_t InterruptIn::fall(void (*fptr)(void)) { + pFunctionPointer_t pf = NULL; + _fall.clear(); + if (fptr) { + pf = _fall.add(fptr); + gpio_irq_set(&gpio_irq, IRQ_FALL, 1); + } else { + gpio_irq_set(&gpio_irq, IRQ_FALL, 0); + } + return pf; +} + +pFunctionPointer_t InterruptIn::fall_add_common(void (*fptr)(void), bool front) { + if (NULL == fptr) + return NULL; + pFunctionPointer_t pf = front ? _fall.add_front(fptr) : _fall.add(fptr); + gpio_irq_set(&gpio_irq, IRQ_FALL, 1); + return pf; +} + +bool InterruptIn::fall_remove(pFunctionPointer_t pf) { + bool res = _fall.remove(pf); + if (res && _fall.size() == 0) + gpio_irq_set(&gpio_irq, IRQ_FALL, 0); + return res; +} + +void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) { + InterruptIn *handler = (InterruptIn*)id; + switch (event) { + case IRQ_RISE: handler->_rise.call(); break; + case IRQ_FALL: handler->_fall.call(); break; + case IRQ_NONE: break; + } +} + +#ifdef MBED_OPERATORS +InterruptIn::operator int() { + return read(); +} +#endif + +} // namespace mbed + +#endif diff --git a/libraries/mbed/common/InterruptManager.cpp b/libraries/mbed/common/InterruptManager.cpp new file mode 100644 index 0000000000..476bd89176 --- /dev/null +++ b/libraries/mbed/common/InterruptManager.cpp @@ -0,0 +1,89 @@ +#include "InterruptManager.h" +#include + +#define CHAIN_INITIAL_SIZE 4 + +namespace mbed { + +typedef void (*pvoidf)(void); + +InterruptManager* InterruptManager::_instance = 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 = 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] = NULL; + } + return true; +} + +void InterruptManager::irq_helper() { + _chains[get_irq_index(NVIC_GetActiveInterrupt())]->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 + diff --git a/libraries/mbed/common/Serial.cpp b/libraries/mbed/common/Serial.cpp index eb20350722..27f300eaee 100644 --- a/libraries/mbed/common/Serial.cpp +++ b/libraries/mbed/common/Serial.cpp @@ -44,15 +44,32 @@ int Serial::writeable() { return serial_writable(&_serial); } -void Serial::attach(void (*fptr)(void), IrqType type) { +pFunctionPointer_t Serial::attach(void (*fptr)(void), IrqType type) { + pFunctionPointer_t pf = NULL; + _irq[type].clear(); if (fptr) { - _irq[type].attach(fptr); + pf = _irq[type].add(fptr); serial_irq_set(&_serial, (SerialIrq)type, 1); } else { serial_irq_set(&_serial, (SerialIrq)type, 0); } + return pf; } +pFunctionPointer_t Serial::add_handler_helper(void (*fptr)(void), IrqType type, bool front) { + if (NULL == fptr) + return NULL; + pFunctionPointer_t pf = front ? _irq[type].add_front(fptr) : _irq[type].add(fptr); + serial_irq_set(&_serial, (SerialIrq)type, 1); + return pf; +} + +bool Serial::remove_handler(pFunctionPointer_t pf, IrqType type) { + bool res = _irq[type].remove(pf); + if (res && _irq[type].size() == 0) + serial_irq_set(&_serial, (SerialIrq)type, 0); + return res; +} void Serial::_irq_handler(uint32_t id, SerialIrq irq_type) { Serial *handler = (Serial*)id; diff --git a/libraries/mbed/common/Ticker.cpp b/libraries/mbed/common/Ticker.cpp index 7ae73ef089..fd27ca1cb1 100644 --- a/libraries/mbed/common/Ticker.cpp +++ b/libraries/mbed/common/Ticker.cpp @@ -1,39 +1,45 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "Ticker.h" - -#include "TimerEvent.h" -#include "FunctionPointer.h" - -namespace mbed { - -void Ticker::detach() { - remove(); - _function.attach(0); -} - -void Ticker::setup(unsigned int t) { - remove(); - _delay = t; - insert(_delay + us_ticker_read()); -} - -void Ticker::handler() { - insert(event.timestamp + _delay); - _function.call(); -} - -} // namespace mbed +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "Ticker.h" + +#include "TimerEvent.h" +#include "FunctionPointer.h" + +namespace mbed { + +void Ticker::detach() { + remove(); + _chain.clear(); +} + +void Ticker::setup(unsigned int t) { + remove(); + _delay = t; + insert(_delay + us_ticker_read()); +} + +void Ticker::handler() { + insert(event.timestamp + _delay); + _chain.call(); +} + +pFunctionPointer_t Ticker::add_function_helper(void (*fptr)(void), bool front) { + if (_chain.size() == 0) + return NULL; + return front ? _chain.add_front(fptr) : _chain.add(fptr); +} + +} // namespace mbed diff --git a/libraries/mbed/common/Timeout.cpp b/libraries/mbed/common/Timeout.cpp index ed7950212b..87e6738988 100644 --- a/libraries/mbed/common/Timeout.cpp +++ b/libraries/mbed/common/Timeout.cpp @@ -1,24 +1,24 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "Timeout.h" - -namespace mbed { - -void Timeout::handler() { - _function.call(); -} - -} // namespace mbed +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "Timeout.h" + +namespace mbed { + +void Timeout::handler() { + _chain.call(); +} + +} // namespace mbed diff --git a/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.c b/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.c index 52bfcfbfc3..aa04feacdc 100644 --- a/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.c +++ b/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.c @@ -5,7 +5,6 @@ */ #include "cmsis_nvic.h" -#define NVIC_NUM_VECTORS (16 + 33) // CORE + MCU Peripherals #define NVIC_RAM_VECTOR_ADDRESS (0x10000000) // Location of vectors in RAM #define NVIC_FLASH_VECTOR_ADDRESS (0x0) // Initial vector position in flash @@ -22,11 +21,14 @@ void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) { } SCB->VTOR = (uint32_t)NVIC_RAM_VECTOR_ADDRESS; } - vectors[IRQn + 16] = vector; + vectors[IRQn + NVIC_USER_IRQ_OFFSET] = vector; } uint32_t NVIC_GetVector(IRQn_Type IRQn) { uint32_t *vectors = (uint32_t*)SCB->VTOR; - return vectors[IRQn + 16]; + return vectors[IRQn + NVIC_USER_IRQ_OFFSET]; } +IRQn_Type NVIC_GetActiveInterrupt(void) { + return (IRQn_Type)((SCB->ICSR & 0x1FF) - NVIC_USER_IRQ_OFFSET); +} diff --git a/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.h b/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.h index 299d3879be..2864079edd 100644 --- a/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.h +++ b/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/cmsis_nvic.h @@ -9,12 +9,16 @@ #include "cmsis.h" +#define NVIC_NUM_VECTORS (16 + 33) +#define NVIC_USER_IRQ_OFFSET 16 + #ifdef __cplusplus extern "C" { #endif void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector); uint32_t NVIC_GetVector(IRQn_Type IRQn); +IRQn_Type NVIC_GetActiveInterrupt(void); #ifdef __cplusplus } diff --git a/libraries/tests/mbed/interrupt_chaining/interruptin/main.cpp b/libraries/tests/mbed/interrupt_chaining/interruptin/main.cpp new file mode 100644 index 0000000000..8278e019f7 --- /dev/null +++ b/libraries/tests/mbed/interrupt_chaining/interruptin/main.cpp @@ -0,0 +1,113 @@ +#include "test_env.h" + +DigitalOut myled(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); + +volatile int checks = 0; +volatile int total = 0; +void in_handler() { + checks++; + led2 = !led2; +} + +#if defined(TARGET_KL25Z) +#define PIN_OUT PTC7 +#define PIN_IN PTA1 + +#elif defined(TARGET_KL05Z) +#define PIN_OUT PTB11 +#define PIN_IN PTB1 + +#elif defined(TARGET_LPC812) +#define PIN_OUT D10 +#define PIN_IN D11 + +#else +#define PIN_IN (p5) +#define PIN_OUT (p25) + +#endif + +DigitalOut out(PIN_OUT); +InterruptIn in(PIN_IN); + +void flipper() { + for (int i = 0; i < 5; i++) { + out = 1; myled = 1; wait(0.2); + + out = 0; myled = 0; wait(0.2); + } +} + +void flipper2() { + led3 = !led3; +} + +void handler2() { + total++; +} + +int object_cnt = 0; + +class Incrementer { +public: + Incrementer() : _cnt(0) {} + void inc() { _cnt++; } + int get() const { return _cnt; } +private: + int _cnt; +}; + +int main() { + out = 0; myled = 0; + + //Test falling edges first + Incrementer i1; + in.rise(NULL); + in.fall(in_handler); + in.fall_add(handler2); + in.fall_add(flipper2); + in.fall_add_front(&i1, &Incrementer::inc); + flipper(); + + if(checks != 5 || i1.get() != 5) { + printf("falling edges test failed\n"); + notify_completion(false); + } + + //Now test rising edges + Incrementer i2; + in.rise(in_handler); + in.rise_add(handler2); + in.rise_add(&i2, &Incrementer::inc); + in.rise_add_front(flipper2); + in.fall(NULL); + flipper(); + + if (checks != 10 || i2.get() != 5) { + printf("raising edges test failed\n"); + notify_completion(false); + } + + //Finally test both + in.rise(in_handler); + in.rise_add(handler2); + pFunctionPointer_t rise_led = in.rise_add(flipper2); + in.fall(in_handler); + in.fall_add(handler2); + pFunctionPointer_t fall_led = in.fall_add(flipper2); + if (!in.rise_remove(rise_led) || !in.fall_remove(fall_led)) { + printf("remove handler failed\n"); + notify_completion(false); + } + flipper(); + + if (checks != 20) { + printf("Simultaneous rising and falling edges failed! check=%d\n", checks); + notify_completion(false); + } + printf("Total: %d\n", total); + notify_completion(true); + return 0; +} diff --git a/libraries/tests/mbed/interrupt_chaining/serial_interrupt/main.cpp b/libraries/tests/mbed/interrupt_chaining/serial_interrupt/main.cpp new file mode 100644 index 0000000000..924f262229 --- /dev/null +++ b/libraries/tests/mbed/interrupt_chaining/serial_interrupt/main.cpp @@ -0,0 +1,41 @@ +#include "mbed.h" + +DigitalOut led1(LED1); +DigitalOut led2(LED2); + +Serial computer(USBTX, USBRX); + +// This function is called when a character goes into the TX buffer. +void txCallback() { + led1 = !led1; +} + +// This function is called when a character goes into the RX buffer. +void rxCallback() { + led2 = !led2; + computer.putc(computer.getc()); +} + +class Counter { +public: + Counter(const char* name): _name(name), _cnt(0) {} + void inc() { _cnt++; } + void show() const { printf("%s: %d\n", _name, _cnt); } + int get() const { return _cnt; } + ~Counter() { show(); } +private: + const char *_name; + volatile int _cnt; +}; + +int main() { + printf("start test\n"); + Counter rx("RX bytes"), tx("TX bytes"); + + computer.attach(&txCallback, Serial::TxIrq); + computer.add_handler(&tx, &Counter::inc, Serial::TxIrq); + computer.attach(&rxCallback, Serial::RxIrq); + computer.add_handler_front(&rx, &Counter::inc, Serial::RxIrq); + + while (rx.get() < 40); +} diff --git a/libraries/tests/mbed/interrupt_chaining/ticker/main.cpp b/libraries/tests/mbed/interrupt_chaining/ticker/main.cpp new file mode 100644 index 0000000000..e1f4a5919c --- /dev/null +++ b/libraries/tests/mbed/interrupt_chaining/ticker/main.cpp @@ -0,0 +1,101 @@ +#include "mbed.h" +#include "InterruptManager.h" +#include "cmsis.h" +#include "test_env.h" + +Serial pc(USBTX, USBRX); + +Ticker flipper_1; +DigitalOut led1(LED1); +int led1_state = 0; +void flip_1() { + if (led1_state) { + led1 = 0; led1_state = 0; + } else { + led1 = 1; led1_state = 1; + } +} + +class Sender { +public: + Sender(Serial&s, char c): _s(s), _c(c) {} + void send() { _s.putc(_c); } +private: + Serial& _s; + char _c; +}; +Ticker flipper_2; +Sender s1(pc, '1'); +Sender s2(pc, '2'); + +#if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC4088) +# define LED_NAME LED2 +#elif defined(TARGET_KL05Z) +# define LED_NAME LED2 +#else +# define LED_NAME PTE31 +#endif + +DigitalOut led2(LED_NAME); +int led2_state = 0; +void flip_2() { + if (led2_state) { + led2 = 0; led2_state = 0; + } else { + led2 = 1; led2_state = 1; + } +} + +void testme(void) { + pc.putc('!'); +} + +class Counter { +public: + void inc(void) { + count ++; + } + int get_count(void) const { + return count; + } +private: + static int count; +}; + +int Counter::count = 0; + +int main() { + led1 = 0; + led2 = 0; + uint32_t initial_handler, final_handler; + Counter c; + + // Test chaining inside Serial class + flipper_1.attach(&flip_1, 1.0); // the address of the function to be attached (flip) and the interval (1 second) + flipper_1.add_function_front(&s1, &Sender::send); + flipper_2.attach(&flip_2, 2.0); // the address of the function to be attached (flip) and the interval (2 seconds) + flipper_2.add_function(&s2, &Sender::send); + + // Test global chaining (InterruptManager) + printf("Handler initially: %08X\n", initial_handler = NVIC_GetVector(TIMER3_IRQn)); + InterruptManager *pManager = InterruptManager::get(); + pFunctionPointer_t ptm = pManager->add_handler(testme, TIMER3_IRQn); + pFunctionPointer_t pinc = pManager->add_handler_front(&c, &Counter::inc, TIMER3_IRQn); + printf("Handler after calling InterruptManager: %08X\n", NVIC_GetVector(TIMER3_IRQn)); + + wait(4.0); + + if (!pManager->remove_handler(ptm, TIMER3_IRQn) || !pManager->remove_handler(pinc, TIMER3_IRQn)) { + printf ("remove handler failed.\n"); + notify_completion(false); + } + printf("Interrupt handler calls: %d\n", c.get_count()); + printf("Handler after removing previously added functions: %08X\n", final_handler = NVIC_GetVector(TIMER3_IRQn)); + + if (initial_handler != final_handler) { + printf( "InteruptManager test failed.\n"); + notify_completion(false); + } + + while(1); +}