diff --git a/hal/api/CAN.h b/hal/api/CAN.h index db613f6616e..241cd4c8229 100644 --- a/hal/api/CAN.h +++ b/hal/api/CAN.h @@ -22,7 +22,7 @@ #include "can_api.h" #include "can_helper.h" -#include "FunctionPointer.h" +#include "Callback.h" namespace mbed { @@ -206,34 +206,40 @@ class CAN { /** Attach a function to call whenever a CAN frame received interrupt is * generated. * - * @param fptr A pointer to a void function, or 0 to set as none + * @param func A pointer to a void function, or 0 to set as none * @param event Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, CAN::TxIrq for transmitted or aborted, CAN::EwIrq for error warning, CAN::DoIrq for data overrun, CAN::WuIrq for wake-up, CAN::EpIrq for error passive, CAN::AlIrq for arbitration lost, CAN::BeIrq for bus error) */ - void attach(void (*fptr)(void), IrqType type=RxIrq); + void attach(Callback func, IrqType type=RxIrq); /** Attach a member function to call whenever a CAN frame received interrupt * is generated. * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to be called * @param event Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, TxIrq for transmitted or aborted, EwIrq for error warning, DoIrq for data overrun, WuIrq for wake-up, EpIrq for error passive, AlIrq for arbitration lost, BeIrq for bus error) */ - template - void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) { - if((mptr != NULL) && (tptr != NULL)) { - _irq[type].attach(tptr, mptr); - can_irq_set(&_can, (CanIrqType)type, 1); - } - else { - can_irq_set(&_can, (CanIrqType)type, 0); - } + template + void attach(T* obj, void (T::*method)(), IrqType type=RxIrq) { + attach(Callback(obj, method), type); + } + + /** Attach a member function to call whenever a CAN frame received interrupt + * is generated. + * + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to be called + * @param event Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, TxIrq for transmitted or aborted, EwIrq for error warning, DoIrq for data overrun, WuIrq for wake-up, EpIrq for error passive, AlIrq for arbitration lost, BeIrq for bus error) + */ + template + void attach(T* obj, void (*method)(T*), IrqType type=RxIrq) { + attach(Callback(obj, method), type); } static void _irq_handler(uint32_t id, CanIrqType type); protected: - can_t _can; - FunctionPointer _irq[9]; + can_t _can; + Callback _irq[9]; }; } // namespace mbed diff --git a/hal/api/CallChain.h b/hal/api/CallChain.h index ebb796a3cd9..babdacbf91f 100644 --- a/hal/api/CallChain.h +++ b/hal/api/CallChain.h @@ -16,7 +16,7 @@ #ifndef MBED_CALLCHAIN_H #define MBED_CALLCHAIN_H -#include "FunctionPointer.h" +#include "Callback.h" #include namespace mbed { @@ -57,7 +57,7 @@ namespace mbed { * @endcode */ -typedef FunctionPointer* pFunctionPointer_t; +typedef Callback *pFunctionPointer_t; class CallChain { public: @@ -70,34 +70,34 @@ class CallChain { /** Add a function at the end of the chain * - * @param function A pointer to a void function + * @param func A pointer to a void function * * @returns - * The function object created for 'function' + * The function object created for 'func' */ - pFunctionPointer_t add(void (*function)(void)); + pFunctionPointer_t add(Callback func); /** Add a function at the end of the chain * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to be called * * @returns - * The function object created for 'tptr' and 'mptr' + * The function object created for 'obj' and 'method' */ - template - pFunctionPointer_t add(T *tptr, void (T::*mptr)(void)) { - return common_add(new FunctionPointer(tptr, mptr)); + template + pFunctionPointer_t add(T *obj, M method) { + return add(Callback(obj, method)); } /** Add a function at the beginning of the chain * - * @param function A pointer to a void function + * @param func A pointer to a void function * * @returns - * The function object created for 'function' + * The function object created for 'func' */ - pFunctionPointer_t add_front(void (*function)(void)); + pFunctionPointer_t add_front(Callback func); /** Add a function at the beginning of the chain * @@ -107,9 +107,9 @@ class CallChain { * @returns * The function object created for 'tptr' and 'mptr' */ - template - pFunctionPointer_t add_front(T *tptr, void (T::*mptr)(void)) { - return common_add_front(new FunctionPointer(tptr, mptr)); + template + pFunctionPointer_t add_front(T *obj, M method) { + return add_front(Callback(obj, method)); } /** Get the number of functions in the chain @@ -162,8 +162,6 @@ class CallChain { private: void _check_size(); - pFunctionPointer_t common_add(pFunctionPointer_t pf); - pFunctionPointer_t common_add_front(pFunctionPointer_t pf); pFunctionPointer_t* _chain; int _size; diff --git a/hal/api/Callback.h b/hal/api/Callback.h new file mode 100644 index 00000000000..b90baf91af0 --- /dev/null +++ b/hal/api/Callback.h @@ -0,0 +1,879 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 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_CALLBACK_H +#define MBED_CALLBACK_H + +#include +#include + +namespace mbed { + + +/** Callback class based on template specialization + */ +template +class Callback; + +/** Templated function class + */ +template +class Callback { +public: + /** Create a Callback with a static function + * @param func Static function to attach + */ + Callback(R (*func)(A0, A1, A2, A3, A4) = 0) { + attach(func); + } + + /** Create a Callback with a static function and bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + Callback(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) { + attach(obj, func); + } + + /** Create a Callback with a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + Callback(T *obj, R (T::*func)(A0, A1, A2, A3, A4)) { + attach(obj, func); + } + + /** Create a Callback with another Callback + * @param func Callback to attach + */ + Callback(const Callback &func) { + attach(func); + } + + /** Attach a static function + * @param func Static function to attach + */ + void attach(R (*func)(A0, A1, A2, A3, A4)) { + memcpy(&_func, &func, sizeof func); + _thunk = func ? &Callback::_staticthunk : 0; + } + + /** Attach a static function with a bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + void attach(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_boundthunk; + } + + /** Attach a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + void attach(T *obj, R (T::*func)(A0, A1, A2, A3, A4)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_methodthunk; + } + + /** Attach a Callback + * @param func The Callback to attach + */ + void attach(const Callback &func) { + _obj = func._obj; + memcpy(&_func, &func._func, sizeof _func); + _thunk = func._thunk; + } + + /** Call the attached function + */ + R call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + if (!_thunk) { + return (R)0; + } + return _thunk(_obj, &_func, a0, a1, a2, a3, a4); + } + + /** Call the attached function + */ + R operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call(a0, a1, a2, a3, a4); + } + + /** Test if function has been attached + */ + operator bool() const { + return _thunk; + } + + /** Static thunk for passing as C-style function + * @param func Callback to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return static_cast*>(func) + ->call(a0, a1, a2, a3, a4); + } + +private: + // Internal thunks for various function types + static R _staticthunk(void*, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return (*reinterpret_cast(func)) + (a0, a1, a2, a3, a4); + } + + template + static R _boundthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return (*reinterpret_cast(func)) + (static_cast(obj), a0, a1, a2, a3, a4); + } + + template + static R _methodthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return (static_cast(obj)->* + (*reinterpret_cast(func))) + (a0, a1, a2, a3, a4); + } + + // Stored as pointer to function and pointer to optional object + // Function pointer is stored as union of possible function types + // to garuntee proper size and alignment + struct _class; + union { + void (*_staticfunc)(); + void (*_boundfunc)(_class *); + void (_class::*_methodfunc)(); + } _func; + + void *_obj; + + // Thunk registered on attach to dispatch calls + R (*_thunk)(void*, void*, A0, A1, A2, A3, A4); +}; + +/** Templated function class + */ +template +class Callback { +public: + /** Create a Callback with a static function + * @param func Static function to attach + */ + Callback(R (*func)(A0, A1, A2, A3) = 0) { + attach(func); + } + + /** Create a Callback with a static function and bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + Callback(T *obj, R (*func)(T*, A0, A1, A2, A3)) { + attach(obj, func); + } + + /** Create a Callback with a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + Callback(T *obj, R (T::*func)(A0, A1, A2, A3)) { + attach(obj, func); + } + + /** Create a Callback with another Callback + * @param func Callback to attach + */ + Callback(const Callback &func) { + attach(func); + } + + /** Attach a static function + * @param func Static function to attach + */ + void attach(R (*func)(A0, A1, A2, A3)) { + memcpy(&_func, &func, sizeof func); + _thunk = func ? &Callback::_staticthunk : 0; + } + + /** Attach a static function with a bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + void attach(T *obj, R (*func)(T*, A0, A1, A2, A3)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_boundthunk; + } + + /** Attach a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + void attach(T *obj, R (T::*func)(A0, A1, A2, A3)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_methodthunk; + } + + /** Attach a Callback + * @param func The Callback to attach + */ + void attach(const Callback &func) { + _obj = func._obj; + memcpy(&_func, &func._func, sizeof _func); + _thunk = func._thunk; + } + + /** Call the attached function + */ + R call(A0 a0, A1 a1, A2 a2, A3 a3) { + if (!_thunk) { + return (R)0; + } + return _thunk(_obj, &_func, a0, a1, a2, a3); + } + + /** Call the attached function + */ + R operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + return call(a0, a1, a2, a3); + } + + /** Test if function has been attached + */ + operator bool() const { + return _thunk; + } + + /** Static thunk for passing as C-style function + * @param func Callback to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) { + return static_cast*>(func) + ->call(a0, a1, a2, a3); + } + +private: + // Internal thunks for various function types + static R _staticthunk(void*, void *func, A0 a0, A1 a1, A2 a2, A3 a3) { + return (*reinterpret_cast(func)) + (a0, a1, a2, a3); + } + + template + static R _boundthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3) { + return (*reinterpret_cast(func)) + (static_cast(obj), a0, a1, a2, a3); + } + + template + static R _methodthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3) { + return (static_cast(obj)->* + (*reinterpret_cast(func))) + (a0, a1, a2, a3); + } + + // Stored as pointer to function and pointer to optional object + // Function pointer is stored as union of possible function types + // to garuntee proper size and alignment + struct _class; + union { + void (*_staticfunc)(); + void (*_boundfunc)(_class *); + void (_class::*_methodfunc)(); + } _func; + + void *_obj; + + // Thunk registered on attach to dispatch calls + R (*_thunk)(void*, void*, A0, A1, A2, A3); +}; + +/** Templated function class + */ +template +class Callback { +public: + /** Create a Callback with a static function + * @param func Static function to attach + */ + Callback(R (*func)(A0, A1, A2) = 0) { + attach(func); + } + + /** Create a Callback with a static function and bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + Callback(T *obj, R (*func)(T*, A0, A1, A2)) { + attach(obj, func); + } + + /** Create a Callback with a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + Callback(T *obj, R (T::*func)(A0, A1, A2)) { + attach(obj, func); + } + + /** Create a Callback with another Callback + * @param func Callback to attach + */ + Callback(const Callback &func) { + attach(func); + } + + /** Attach a static function + * @param func Static function to attach + */ + void attach(R (*func)(A0, A1, A2)) { + memcpy(&_func, &func, sizeof func); + _thunk = func ? &Callback::_staticthunk : 0; + } + + /** Attach a static function with a bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + void attach(T *obj, R (*func)(T*, A0, A1, A2)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_boundthunk; + } + + /** Attach a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + void attach(T *obj, R (T::*func)(A0, A1, A2)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_methodthunk; + } + + /** Attach a Callback + * @param func The Callback to attach + */ + void attach(const Callback &func) { + _obj = func._obj; + memcpy(&_func, &func._func, sizeof _func); + _thunk = func._thunk; + } + + /** Call the attached function + */ + R call(A0 a0, A1 a1, A2 a2) { + if (!_thunk) { + return (R)0; + } + return _thunk(_obj, &_func, a0, a1, a2); + } + + /** Call the attached function + */ + R operator()(A0 a0, A1 a1, A2 a2) { + return call(a0, a1, a2); + } + + /** Test if function has been attached + */ + operator bool() const { + return _thunk; + } + + /** Static thunk for passing as C-style function + * @param func Callback to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1, A2 a2) { + return static_cast*>(func) + ->call(a0, a1, a2); + } + +private: + // Internal thunks for various function types + static R _staticthunk(void*, void *func, A0 a0, A1 a1, A2 a2) { + return (*reinterpret_cast(func)) + (a0, a1, a2); + } + + template + static R _boundthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2) { + return (*reinterpret_cast(func)) + (static_cast(obj), a0, a1, a2); + } + + template + static R _methodthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2) { + return (static_cast(obj)->* + (*reinterpret_cast(func))) + (a0, a1, a2); + } + + // Stored as pointer to function and pointer to optional object + // Function pointer is stored as union of possible function types + // to garuntee proper size and alignment + struct _class; + union { + void (*_staticfunc)(); + void (*_boundfunc)(_class *); + void (_class::*_methodfunc)(); + } _func; + + void *_obj; + + // Thunk registered on attach to dispatch calls + R (*_thunk)(void*, void*, A0, A1, A2); +}; + +/** Templated function class + */ +template +class Callback { +public: + /** Create a Callback with a static function + * @param func Static function to attach + */ + Callback(R (*func)(A0, A1) = 0) { + attach(func); + } + + /** Create a Callback with a static function and bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + Callback(T *obj, R (*func)(T*, A0, A1)) { + attach(obj, func); + } + + /** Create a Callback with a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + Callback(T *obj, R (T::*func)(A0, A1)) { + attach(obj, func); + } + + /** Create a Callback with another Callback + * @param func Callback to attach + */ + Callback(const Callback &func) { + attach(func); + } + + /** Attach a static function + * @param func Static function to attach + */ + void attach(R (*func)(A0, A1)) { + memcpy(&_func, &func, sizeof func); + _thunk = func ? &Callback::_staticthunk : 0; + } + + /** Attach a static function with a bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + void attach(T *obj, R (*func)(T*, A0, A1)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_boundthunk; + } + + /** Attach a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + void attach(T *obj, R (T::*func)(A0, A1)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_methodthunk; + } + + /** Attach a Callback + * @param func The Callback to attach + */ + void attach(const Callback &func) { + _obj = func._obj; + memcpy(&_func, &func._func, sizeof _func); + _thunk = func._thunk; + } + + /** Call the attached function + */ + R call(A0 a0, A1 a1) { + if (!_thunk) { + return (R)0; + } + return _thunk(_obj, &_func, a0, a1); + } + + /** Call the attached function + */ + R operator()(A0 a0, A1 a1) { + return call(a0, a1); + } + + /** Test if function has been attached + */ + operator bool() const { + return _thunk; + } + + /** Static thunk for passing as C-style function + * @param func Callback to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1) { + return static_cast*>(func) + ->call(a0, a1); + } + +private: + // Internal thunks for various function types + static R _staticthunk(void*, void *func, A0 a0, A1 a1) { + return (*reinterpret_cast(func)) + (a0, a1); + } + + template + static R _boundthunk(void *obj, void *func, A0 a0, A1 a1) { + return (*reinterpret_cast(func)) + (static_cast(obj), a0, a1); + } + + template + static R _methodthunk(void *obj, void *func, A0 a0, A1 a1) { + return (static_cast(obj)->* + (*reinterpret_cast(func))) + (a0, a1); + } + + // Stored as pointer to function and pointer to optional object + // Function pointer is stored as union of possible function types + // to garuntee proper size and alignment + struct _class; + union { + void (*_staticfunc)(); + void (*_boundfunc)(_class *); + void (_class::*_methodfunc)(); + } _func; + + void *_obj; + + // Thunk registered on attach to dispatch calls + R (*_thunk)(void*, void*, A0, A1); +}; + +/** Templated function class + */ +template +class Callback { +public: + /** Create a Callback with a static function + * @param func Static function to attach + */ + Callback(R (*func)(A0) = 0) { + attach(func); + } + + /** Create a Callback with a static function and bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + Callback(T *obj, R (*func)(T*, A0)) { + attach(obj, func); + } + + /** Create a Callback with a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + Callback(T *obj, R (T::*func)(A0)) { + attach(obj, func); + } + + /** Create a Callback with another Callback + * @param func Callback to attach + */ + Callback(const Callback &func) { + attach(func); + } + + /** Attach a static function + * @param func Static function to attach + */ + void attach(R (*func)(A0)) { + memcpy(&_func, &func, sizeof func); + _thunk = func ? &Callback::_staticthunk : 0; + } + + /** Attach a static function with a bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + void attach(T *obj, R (*func)(T*, A0)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_boundthunk; + } + + /** Attach a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + void attach(T *obj, R (T::*func)(A0)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_methodthunk; + } + + /** Attach a Callback + * @param func The Callback to attach + */ + void attach(const Callback &func) { + _obj = func._obj; + memcpy(&_func, &func._func, sizeof _func); + _thunk = func._thunk; + } + + /** Call the attached function + */ + R call(A0 a0) { + if (!_thunk) { + return (R)0; + } + return _thunk(_obj, &_func, a0); + } + + /** Call the attached function + */ + R operator()(A0 a0) { + return call(a0); + } + + /** Test if function has been attached + */ + operator bool() const { + return _thunk; + } + + /** Static thunk for passing as C-style function + * @param func Callback to call passed as void pointer + */ + static R thunk(void *func, A0 a0) { + return static_cast*>(func) + ->call(a0); + } + +private: + // Internal thunks for various function types + static R _staticthunk(void*, void *func, A0 a0) { + return (*reinterpret_cast(func)) + (a0); + } + + template + static R _boundthunk(void *obj, void *func, A0 a0) { + return (*reinterpret_cast(func)) + (static_cast(obj), a0); + } + + template + static R _methodthunk(void *obj, void *func, A0 a0) { + return (static_cast(obj)->* + (*reinterpret_cast(func))) + (a0); + } + + // Stored as pointer to function and pointer to optional object + // Function pointer is stored as union of possible function types + // to garuntee proper size and alignment + struct _class; + union { + void (*_staticfunc)(); + void (*_boundfunc)(_class *); + void (_class::*_methodfunc)(); + } _func; + + void *_obj; + + // Thunk registered on attach to dispatch calls + R (*_thunk)(void*, void*, A0); +}; + +/** Templated function class + */ +template +class Callback { +public: + /** Create a Callback with a static function + * @param func Static function to attach + */ + Callback(R (*func)() = 0) { + attach(func); + } + + /** Create a Callback with a static function and bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + Callback(T *obj, R (*func)(T*)) { + attach(obj, func); + } + + /** Create a Callback with a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + Callback(T *obj, R (T::*func)()) { + attach(obj, func); + } + + /** Create a Callback with another Callback + * @param func Callback to attach + */ + Callback(const Callback &func) { + attach(func); + } + + /** Attach a static function + * @param func Static function to attach + */ + void attach(R (*func)()) { + memcpy(&_func, &func, sizeof func); + _thunk = func ? &Callback::_staticthunk : 0; + } + + /** Attach a static function with a bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template + void attach(T *obj, R (*func)(T*)) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_boundthunk; + } + + /** Attach a member function + * @param obj Pointer to object to invoke member function on + * @param func Member function to attach + */ + template + void attach(T *obj, R (T::*func)()) { + _obj = static_cast(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &Callback::_methodthunk; + } + + /** Attach a Callback + * @param func The Callback to attach + */ + void attach(const Callback &func) { + _obj = func._obj; + memcpy(&_func, &func._func, sizeof _func); + _thunk = func._thunk; + } + + /** Call the attached function + */ + R call() { + if (!_thunk) { + return (R)0; + } + return _thunk(_obj, &_func); + } + + /** Call the attached function + */ + R operator()() { + return call(); + } + + /** Test if function has been attached + */ + operator bool() const { + return _thunk; + } + + /** Static thunk for passing as C-style function + * @param func Callback to call passed as void pointer + */ + static R thunk(void *func) { + return static_cast*>(func) + ->call(); + } + +private: + // Internal thunks for various function types + static R _staticthunk(void*, void *func) { + return (*reinterpret_cast(func)) + (); + } + + template + static R _boundthunk(void *obj, void *func) { + return (*reinterpret_cast(func)) + (static_cast(obj)); + } + + template + static R _methodthunk(void *obj, void *func) { + return (static_cast(obj)->* + (*reinterpret_cast(func))) + (); + } + + // Stored as pointer to function and pointer to optional object + // Function pointer is stored as union of possible function types + // to garuntee proper size and alignment + struct _class; + union { + void (*_staticfunc)(); + void (*_boundfunc)(_class *); + void (_class::*_methodfunc)(); + } _func; + + void *_obj; + + // Thunk registered on attach to dispatch calls + R (*_thunk)(void*, void*); +}; + + +} // namespace mbed + +#endif diff --git a/hal/api/FunctionPointer.h b/hal/api/FunctionPointer.h index 2d49ba035e1..b2ef2b971c2 100644 --- a/hal/api/FunctionPointer.h +++ b/hal/api/FunctionPointer.h @@ -16,187 +16,49 @@ #ifndef MBED_FUNCTIONPOINTER_H #define MBED_FUNCTIONPOINTER_H +#include "Callback.h" #include #include namespace mbed { -/* If we had variaditic templates, this wouldn't be a problem, but until C++11 is enabled, we are stuck with multiple classes... */ -/** A class for storing and calling a pointer to a static or member function - */ +// Declarations for backwards compatibility +// To be foward compatible, code should adopt the Callback class template -class FunctionPointerArg1{ +class FunctionPointerArg1 : public Callback { public: - /** Create a FunctionPointer, attaching a static function - * - * @param function The static function to attach (default is none) - */ - FunctionPointerArg1(R (*function)(A1) = 0) { - attach(function); - } + FunctionPointerArg1(R (*function)(A1) = 0) + : Callback(function) {} - /** 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 member function to attach - */ template - FunctionPointerArg1(T *object, R (T::*member)(A1)) { - attach(object, member); - } - - /** Attach a static function - * - * @param function The static function to attach (default is none) - */ - void attach(R (*function)(A1)) { - _p.function = function; - _membercaller = 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 member function to attach - */ - template - void attach(T *object, R (T::*member)(A1)) { - _p.object = static_cast(object); - *reinterpret_cast(_member) = member; - _membercaller = &FunctionPointerArg1::membercaller; - } - - /** Call the attached static or member function - */ - R call(A1 a) { - if (_membercaller == 0 && _p.function) { - return _p.function(a); - } else if (_membercaller && _p.object) { - return _membercaller(_p.object, _member, a); - } - return (R)0; - } - - /** Get registered static function - */ - R(*get_function(A1))() { - return _membercaller ? (R(*)(A1))0 : (R(*)(A1))_p.function; - } + FunctionPointerArg1(T *object, R (T::*member)(A1)) + : Callback(object, member) {} -#ifdef MBED_OPERATORS - R operator ()(A1 a) { - return call(a); + R (*get_function())(A1) { + return *reinterpret_cast(this); } - operator bool(void) const { - return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL; - } -#endif -private: - template - static R membercaller(void *object, uintptr_t *member, A1 a) { - T* o = static_cast(object); - R (T::**m)(A1) = reinterpret_cast(member); - return (o->**m)(a); - } - - union { - R (*function)(A1); // static function pointer - void *object; // object this pointer - } _p; - uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller - R (*_membercaller)(void*, uintptr_t*, A1); // registered membercaller function to convert back and call _m.member on _object }; -/** A class for storing and calling a pointer to a static or member function (R ()(void)) - */ template -class FunctionPointerArg1{ +class FunctionPointerArg1 : public Callback { public: - /** Create a FunctionPointer, attaching a static function - * - * @param function The static function to attach (default is none) - */ - FunctionPointerArg1(R (*function)(void) = 0) { - attach(function); - } + FunctionPointerArg1(R (*function)() = 0) + : Callback(function) {} - /** 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 - FunctionPointerArg1(T *object, R (T::*member)(void)) { - attach(object, member); - } - - /** Attach a static function - * - * @param function The void static function to attach (default is none) - */ - void attach(R (*function)(void)) { - _p.function = function; - _membercaller = 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, R (T::*member)(void)) { - _p.object = static_cast(object); - *reinterpret_cast(_member) = member; - _membercaller = &FunctionPointerArg1::membercaller; - } - - /** Call the attached static or member function - */ - R call(){ - if (_membercaller == 0 && _p.function) { - return _p.function(); - } else if (_membercaller && _p.object) { - return _membercaller(_p.object, _member); - } - return (R)0; - } + FunctionPointerArg1(T *object, R (T::*member)()) + : Callback(object, member) {} - /** Get registered static function - */ - R(*get_function())() { - return _membercaller ? (R(*)())0 : (R(*)())_p.function; + R (*get_function())() { + return *reinterpret_cast(this); } - -#ifdef MBED_OPERATORS - R operator ()(void) { - return call(); - } - operator bool(void) const { - return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL; - } -#endif - -private: - template - static R membercaller(void *object, uintptr_t *member) { - T* o = static_cast(object); - R (T::**m)(void) = reinterpret_cast(member); - return (o->**m)(); - } - - union { - R (*function)(void); // static function pointer - void *object; // object this pointer - } _p; - uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller - R (*_membercaller)(void*, uintptr_t*); // registered membercaller function to convert back and call _m.member on _object }; typedef FunctionPointerArg1 FunctionPointer; typedef FunctionPointerArg1 event_callback_t; + } // namespace mbed #endif diff --git a/hal/api/InterruptIn.h b/hal/api/InterruptIn.h index 88bc4308e83..0e519faef40 100644 --- a/hal/api/InterruptIn.h +++ b/hal/api/InterruptIn.h @@ -22,7 +22,7 @@ #include "gpio_api.h" #include "gpio_irq_api.h" -#include "FunctionPointer.h" +#include "Callback.h" namespace mbed { @@ -70,36 +70,34 @@ class InterruptIn { /** 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 + * @param func A pointer to a void function, or 0 to set as none */ - void rise(void (*fptr)(void)); + void rise(Callback func); /** 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 + * @param obj pointer to the object to call the member function on + * @param method 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); + template + void rise(T *obj, M method) { + rise(Callback(obj, method)); } /** 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 + * @param func A pointer to a void function, or 0 to set as none */ - void fall(void (*fptr)(void)); + void fall(Callback func); /** 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 + * @param obj pointer to the object to call the member function on + * @param method 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); + template + void fall(T *obj, M method) { + fall(Callback(obj, method)); } /** Set the input pin mode @@ -124,8 +122,8 @@ class InterruptIn { gpio_t gpio; gpio_irq_t gpio_irq; - FunctionPointer _rise; - FunctionPointer _fall; + Callback _rise; + Callback _fall; }; } // namespace mbed diff --git a/hal/api/SerialBase.h b/hal/api/SerialBase.h index 51aeb33e36c..ed2e744790b 100644 --- a/hal/api/SerialBase.h +++ b/hal/api/SerialBase.h @@ -21,7 +21,7 @@ #if DEVICE_SERIAL #include "Stream.h" -#include "FunctionPointer.h" +#include "Callback.h" #include "serial_api.h" #if DEVICE_SERIAL_ASYNCH @@ -89,25 +89,31 @@ class SerialBase { /** Attach a function to call whenever a serial interrupt is generated * - * @param fptr A pointer to a void function, or 0 to set as none + * @param func 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); + void attach(Callback func, IrqType type=RxIrq); /** Attach a member function to call whenever a serial interrupt is generated * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to be called * @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) { - if((mptr != NULL) && (tptr != NULL)) { - _irq[type].attach(tptr, mptr); - serial_irq_set(&_serial, (SerialIrq)type, 1); - } else { - serial_irq_set(&_serial, (SerialIrq)type, 0); - } + void attach(T *obj, void (T::*method)(), IrqType type=RxIrq) { + attach(Callback(obj, method), type); + } + + /** Attach a member function to call whenever a serial interrupt is generated + * + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to be called + * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template + void attach(T *obj, void (*method)(T*), IrqType type=RxIrq) { + attach(Callback(obj, method), type); } /** Generate a break condition on the serial line @@ -210,9 +216,9 @@ class SerialBase { DMAUsage _rx_usage; #endif - serial_t _serial; - FunctionPointer _irq[2]; - int _baud; + serial_t _serial; + Callback _irq[2]; + int _baud; }; diff --git a/hal/api/Ticker.h b/hal/api/Ticker.h index fda205da9a4..817394039b0 100644 --- a/hal/api/Ticker.h +++ b/hal/api/Ticker.h @@ -17,7 +17,7 @@ #define MBED_TICKER_H #include "TimerEvent.h" -#include "FunctionPointer.h" +#include "Callback.h" namespace mbed { @@ -65,22 +65,22 @@ class Ticker : public TimerEvent { /** Attach a function to be called by the Ticker, specifiying the interval in seconds * - * @param fptr pointer to the function to be called + * @param func 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); + void attach(Callback func, float t) { + attach_us(func, 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 obj pointer to the object to call the member function on + * @param method 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); + template + void attach(T *obj, M method, float t) { + attach(Callback(obj, method), t); } /** Attach a function to be called by the Ticker, specifiying the interval in micro-seconds @@ -88,8 +88,8 @@ class Ticker : public TimerEvent { * @param fptr pointer to the function to be called * @param t the time between calls in micro-seconds */ - void attach_us(void (*fptr)(void), timestamp_t t) { - _function.attach(fptr); + void attach_us(Callback func, timestamp_t t) { + _function.attach(func); setup(t); } @@ -99,10 +99,9 @@ class Ticker : public TimerEvent { * @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), timestamp_t t) { - _function.attach(tptr, mptr); - setup(t); + template + void attach_us(T *obj, M method, timestamp_t t) { + attach_us(Callback(obj, method), t); } virtual ~Ticker() { @@ -118,8 +117,8 @@ class Ticker : public TimerEvent { virtual void handler(); protected: - timestamp_t _delay; /**< Time delay (in microseconds) for re-setting the multi-shot callback. */ - FunctionPointer _function; /**< Callback. */ + timestamp_t _delay; /**< Time delay (in microseconds) for re-setting the multi-shot callback. */ + Callback _function; /**< Callback. */ }; } // namespace mbed diff --git a/hal/api/mbed.h b/hal/api/mbed.h index a5fbb4c9bc4..b98d78abd9c 100644 --- a/hal/api/mbed.h +++ b/hal/api/mbed.h @@ -63,6 +63,10 @@ #include "sleep_api.h" #include "rtc_time.h" +// mbed Non-hardware components +#include "Callback.h" +#include "FunctionPointer.h" + using namespace mbed; using namespace std; diff --git a/hal/common/CAN.cpp b/hal/common/CAN.cpp index 407e00bf175..b717f80461b 100644 --- a/hal/common/CAN.cpp +++ b/hal/common/CAN.cpp @@ -67,9 +67,9 @@ int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle return can_filter(&_can, id, mask, format, handle); } -void CAN::attach(void (*fptr)(void), IrqType type) { - if (fptr) { - _irq[(CanIrqType)type].attach(fptr); +void CAN::attach(Callback func, IrqType type) { + if (func) { + _irq[(CanIrqType)type].attach(func); can_irq_set(&_can, (CanIrqType)type, 1); } else { can_irq_set(&_can, (CanIrqType)type, 0); diff --git a/hal/common/CallChain.cpp b/hal/common/CallChain.cpp index e950903059e..4c4a9cba4d9 100644 --- a/hal/common/CallChain.cpp +++ b/hal/common/CallChain.cpp @@ -12,12 +12,19 @@ CallChain::~CallChain() { delete _chain; } -pFunctionPointer_t CallChain::add(void (*function)(void)) { - return common_add(new FunctionPointer(function)); +pFunctionPointer_t CallChain::add(Callback func) { + _check_size(); + _chain[_elements] = new Callback(func); + _elements ++; + return _chain[_elements]; } -pFunctionPointer_t CallChain::add_front(void (*function)(void)) { - return common_add_front(new FunctionPointer(function)); +pFunctionPointer_t CallChain::add_front(Callback func) { + _check_size(); + memmove(_chain + 1, _chain, _elements * sizeof(pFunctionPointer_t)); + _chain[0] = new Callback(func); + _elements ++; + return _chain[0]; } int CallChain::size() const { @@ -72,19 +79,4 @@ void CallChain::_check_size() { _chain = new_chain; } -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/hal/common/InterruptIn.cpp b/hal/common/InterruptIn.cpp index 92f70f2a5ee..414529869f2 100644 --- a/hal/common/InterruptIn.cpp +++ b/hal/common/InterruptIn.cpp @@ -39,9 +39,9 @@ void InterruptIn::mode(PinMode pull) { gpio_mode(&gpio, pull); } -void InterruptIn::rise(void (*fptr)(void)) { - if (fptr) { - _rise.attach(fptr); +void InterruptIn::rise(Callback func) { + if (func) { + _rise.attach(func); gpio_irq_set(&gpio_irq, IRQ_RISE, 1); } else { _rise.attach(NULL); @@ -49,9 +49,9 @@ void InterruptIn::rise(void (*fptr)(void)) { } } -void InterruptIn::fall(void (*fptr)(void)) { - if (fptr) { - _fall.attach(fptr); +void InterruptIn::fall(Callback func) { + if (func) { + _fall.attach(func); gpio_irq_set(&gpio_irq, IRQ_FALL, 1); } else { _fall.attach(NULL); diff --git a/hal/common/InterruptManager.cpp b/hal/common/InterruptManager.cpp index e92fb68d4e9..183404719f2 100644 --- a/hal/common/InterruptManager.cpp +++ b/hal/common/InterruptManager.cpp @@ -66,13 +66,6 @@ bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq) 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; } diff --git a/hal/common/SerialBase.cpp b/hal/common/SerialBase.cpp index 880a0212e66..94eca327d95 100644 --- a/hal/common/SerialBase.cpp +++ b/hal/common/SerialBase.cpp @@ -48,9 +48,9 @@ int SerialBase::writeable() { return serial_writable(&_serial); } -void SerialBase::attach(void (*fptr)(void), IrqType type) { - if (fptr) { - _irq[type].attach(fptr); +void SerialBase::attach(Callback func, IrqType type) { + if (func) { + _irq[type].attach(func); serial_irq_set(&_serial, (SerialIrq)type, 1); } else { serial_irq_set(&_serial, (SerialIrq)type, 0); diff --git a/rtos/rtos/Thread.cpp b/rtos/rtos/Thread.cpp index 004e651a643..14e195f5a2a 100644 --- a/rtos/rtos/Thread.cpp +++ b/rtos/rtos/Thread.cpp @@ -21,7 +21,7 @@ */ #include "Thread.h" -#include "mbed_error.h" +#include "mbed.h" #include "rtos_idle.h" // rt_tid2ptcb is an internal function which we exposed to get TCB for thread id @@ -32,10 +32,11 @@ extern "C" P_TCB rt_tid2ptcb(osThreadId thread_id); namespace rtos { -Thread::Thread(void (*task)(void const *argument), void *argument, +void Thread::constructor(Callback task, osPriority priority, uint32_t stack_size, unsigned char *stack_pointer) { + _task = task; #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM) - _thread_def.pthread = task; + _thread_def.pthread = (void (*)(const void *))Callback::thunk; _thread_def.tpriority = priority; _thread_def.stacksize = stack_size; if (stack_pointer != NULL) { @@ -53,7 +54,7 @@ Thread::Thread(void (*task)(void const *argument), void *argument, _thread_def.stack_pointer[i] = 0xE25A2EA5; } #endif - _tid = osThreadCreate(&_thread_def, argument); + _tid = osThreadCreate(&_thread_def, &_task); } osStatus Thread::terminate() { diff --git a/rtos/rtos/Thread.h b/rtos/rtos/Thread.h index 3e787983ab7..5dc55aeccdd 100644 --- a/rtos/rtos/Thread.h +++ b/rtos/rtos/Thread.h @@ -24,6 +24,7 @@ #include #include "cmsis_os.h" +#include "Callback.h" namespace rtos { @@ -37,10 +38,62 @@ class Thread { @param stack_size stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE). @param stack_pointer pointer to the stack area to be used by this thread (default: NULL). */ + Thread(mbed::Callback task, + osPriority priority=osPriorityNormal, + uint32_t stack_size=DEFAULT_STACK_SIZE, + unsigned char *stack_pointer=NULL) { + constructor(task, priority, stack_size, stack_pointer); + } + + /** Create a new thread, and start it executing the specified function. + @param obj argument to task. + @param method function to be executed by this thread. + @param argument pointer that is passed to the thread function as start argument. (default: NULL). + @param priority initial priority of the thread function. (default: osPriorityNormal). + @param stack_size stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE). + @param stack_pointer pointer to the stack area to be used by this thread (default: NULL). + */ + template + Thread(T *obj, void (T::*method)(), + osPriority priority=osPriorityNormal, + uint32_t stack_size=DEFAULT_STACK_SIZE, + unsigned char *stack_pointer=NULL) { + constructor(mbed::Callback(obj, method), + priority, stack_size, stack_pointer); + } + + /** Create a new thread, and start it executing the specified function. + @param obj argument to task. + @param method function to be executed by this thread. + @param argument pointer that is passed to the thread function as start argument. (default: NULL). + @param priority initial priority of the thread function. (default: osPriorityNormal). + @param stack_size stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE). + @param stack_pointer pointer to the stack area to be used by this thread (default: NULL). + */ + template + Thread(T *obj, void (*method)(T *), + osPriority priority=osPriorityNormal, + uint32_t stack_size=DEFAULT_STACK_SIZE, + unsigned char *stack_pointer=NULL) { + constructor(mbed::Callback(obj, method), + priority, stack_size, stack_pointer); + } + + /** Create a new thread, and start it executing the specified function. + Provided for backwards compatibility + @param task function to be executed by this thread. + @param argument pointer that is passed to the thread function as start argument. (default: NULL). + @param priority initial priority of the thread function. (default: osPriorityNormal). + @param stack_size stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE). + @param stack_pointer pointer to the stack area to be used by this thread (default: NULL). + */ Thread(void (*task)(void const *argument), void *argument=NULL, osPriority priority=osPriorityNormal, uint32_t stack_size=DEFAULT_STACK_SIZE, - unsigned char *stack_pointer=NULL); + unsigned char *stack_pointer=NULL) { + constructor(mbed::Callback(argument, (void (*)(void *))task), + priority, stack_size, stack_pointer); + } /** Terminate execution of a thread and remove it from Active Threads @return status code that indicates the execution status of the function. @@ -140,6 +193,14 @@ class Thread { virtual ~Thread(); private: + // Required to share definitions without + // delegated constructors + void constructor(mbed::Callback task, + osPriority priority=osPriorityNormal, + uint32_t stack_size=DEFAULT_STACK_SIZE, + unsigned char *stack_pointer=NULL); + + mbed::Callback _task; osThreadId _tid; osThreadDef_t _thread_def; bool _dynamic_stack;