From 8e42a32d00469b21737b59dd5b099781ea93c525 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 13 May 2016 14:54:46 -0500 Subject: [PATCH 1/6] Add Callback, an improved FunctionPointer class - Adopt C++11 style template arguments, requires rename to Callback - Add constructor for C style callback functions - Add constructor for Callbacks - Add static function for passing to C style callbacks --- hal/api/Callback.h | 861 +++++++++++++++++++++++++++++++++++++++++++++ hal/api/mbed.h | 3 + 2 files changed, 864 insertions(+) create mode 100644 hal/api/Callback.h diff --git a/hal/api/Callback.h b/hal/api/Callback.h new file mode 100644 index 0000000000..fa1f5ecc3f --- /dev/null +++ b/hal/api/Callback.h @@ -0,0 +1,861 @@ +/* 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) { + 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) { + 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) { + 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) { + 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) { + 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() { + 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/mbed.h b/hal/api/mbed.h index 9540ba65b4..8d615d4c6f 100644 --- a/hal/api/mbed.h +++ b/hal/api/mbed.h @@ -64,6 +64,9 @@ #include "sleep_api.h" #include "rtc_time.h" +// mbed Non-hardware components +#include "Callback.h" + using namespace mbed; using namespace std; From 8b330ae8a6bf4a216c2f0a0de363b0b1adfc881b Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 13 May 2016 14:55:11 -0500 Subject: [PATCH 2/6] Add callback tests --- hal/TESTS/api/callback/main.cpp | 248 ++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 hal/TESTS/api/callback/main.cpp diff --git a/hal/TESTS/api/callback/main.cpp b/hal/TESTS/api/callback/main.cpp new file mode 100644 index 0000000000..057b5ac367 --- /dev/null +++ b/hal/TESTS/api/callback/main.cpp @@ -0,0 +1,248 @@ +#include "mbed.h" +#include "test_env.h" +#include "unity.h" +#include "utest.h" + +using namespace utest::v1; + + +// static functions +template +T static_func5(T a0, T a1, T a2, T a3, T a4) { return a0 | a1 | a2 | a3 | a4; } +template +T static_func4(T a0, T a1, T a2, T a3) { return a0 | a1 | a2 | a3; } +template +T static_func3(T a0, T a1, T a2) { return a0 | a1 | a2; } +template +T static_func2(T a0, T a1) { return a0 | a1; } +template +T static_func1(T a0) { return a0; } +template +T static_func0() { return 0; } + +// class functions +template +struct Thing { + T t; + Thing() : t(0x80) {} + + T member_func5(T a0, T a1, T a2, T a3, T a4) { return t | a0 | a1 | a2 | a3 | a4; } + T member_func4(T a0, T a1, T a2, T a3) { return t | a0 | a1 | a2 | a3; } + T member_func3(T a0, T a1, T a2) { return t | a0 | a1 | a2; } + T member_func2(T a0, T a1) { return t | a0 | a1; } + T member_func1(T a0) { return t | a0; } + T member_func0() { return t; } +}; + +// bound functions +template +T bound_func5(Thing *t, T a0, T a1, T a2, T a3, T a4) { return t->t | a0 | a1 | a2 | a3 | a4; } +template +T bound_func4(Thing *t, T a0, T a1, T a2, T a3) { return t->t | a0 | a1 | a2 | a3; } +template +T bound_func3(Thing *t, T a0, T a1, T a2) { return t->t | a0 | a1 | a2; } +template +T bound_func2(Thing *t, T a0, T a1) { return t->t | a0 | a1; } +template +T bound_func1(Thing *t, T a0) { return t->t | a0; } +template +T bound_func0(Thing *t) { return t->t; } + + +// function call and result verification +template +struct Verifier { + static void verify5(Callback func) { + T result = func(0x01, 0x02, 0x04, 0x08, 0x10); + TEST_ASSERT_EQUAL(result, 0x1f); + } + + template + static void verify5(O *obj, M method) { + Callback func(obj, method); + T result = func(0x01, 0x02, 0x04, 0x08, 0x10); + TEST_ASSERT_EQUAL(result, 0x9f); + } + + static void verify4(Callback func) { + T result = func(0x01, 0x02, 0x04, 0x08); + TEST_ASSERT_EQUAL(result, 0x0f); + } + + template + static void verify4(O *obj, M method) { + Callback func(obj, method); + T result = func(0x01, 0x02, 0x04, 0x08); + TEST_ASSERT_EQUAL(result, 0x8f); + } + + static void verify3(Callback func) { + T result = func(0x01, 0x02, 0x04); + TEST_ASSERT_EQUAL(result, 0x07); + } + + template + static void verify3(O *obj, M method) { + Callback func(obj, method); + T result = func(0x01, 0x02, 0x04); + TEST_ASSERT_EQUAL(result, 0x87); + } + + static void verify2(Callback func) { + T result = func(0x01, 0x02); + TEST_ASSERT_EQUAL(result, 0x03); + } + + template + static void verify2(O *obj, M method) { + Callback func(obj, method); + T result = func(0x01, 0x02); + TEST_ASSERT_EQUAL(result, 0x83); + } + + static void verify1(Callback func) { + T result = func(0x01); + TEST_ASSERT_EQUAL(result, 0x01); + } + + template + static void verify1(O *obj, M method) { + Callback func(obj, method); + T result = func(0x01); + TEST_ASSERT_EQUAL(result, 0x81); + } + + static void verify0(Callback func) { + T result = func(); + TEST_ASSERT_EQUAL(result, 0x00); + } + + template + static void verify0(O *obj, M method) { + Callback func(obj, method); + T result = func(); + TEST_ASSERT_EQUAL(result, 0x80); + } +}; + + +// test dispatch +template +void test_dispatch5() { + Thing thing; + Verifier::verify5(static_func5); + Verifier::verify5(&thing, &Thing::member_func5); + Verifier::verify5(&thing, &bound_func5); + + Callback callback(static_func5); + Verifier::verify5(callback); + callback.attach(&thing, &bound_func5); + Verifier::verify5(&callback, &Callback::call); + Verifier::verify5((void*)&callback, &Callback::thunk); +} + +template +void test_dispatch4() { + Thing thing; + Verifier::verify4(static_func4); + Verifier::verify4(&thing, &Thing::member_func4); + Verifier::verify4(&thing, &bound_func4); + + Callback callback(static_func4); + Verifier::verify4(callback); + callback.attach(&thing, &bound_func4); + Verifier::verify4(&callback, &Callback::call); + Verifier::verify4((void*)&callback, &Callback::thunk); +} + +template +void test_dispatch3() { + Thing thing; + Verifier::verify3(static_func3); + Verifier::verify3(&thing, &Thing::member_func3); + Verifier::verify3(&thing, &bound_func3); + + Callback callback(static_func3); + Verifier::verify3(callback); + callback.attach(&thing, &bound_func3); + Verifier::verify3(&callback, &Callback::call); + Verifier::verify3((void*)&callback, &Callback::thunk); +} + +template +void test_dispatch2() { + Thing thing; + Verifier::verify2(static_func2); + Verifier::verify2(&thing, &Thing::member_func2); + Verifier::verify2(&thing, &bound_func2); + + Callback callback(static_func2); + Verifier::verify2(callback); + callback.attach(&thing, &bound_func2); + Verifier::verify2(&callback, &Callback::call); + Verifier::verify2((void*)&callback, &Callback::thunk); +} + +template +void test_dispatch1() { + Thing thing; + Verifier::verify1(static_func1); + Verifier::verify1(&thing, &Thing::member_func1); + Verifier::verify1(&thing, &bound_func1); + + Callback callback(static_func1); + Verifier::verify1(callback); + callback.attach(&thing, &bound_func1); + Verifier::verify1(&callback, &Callback::call); + Verifier::verify1((void*)&callback, &Callback::thunk); +} + +template +void test_dispatch0() { + Thing thing; + Verifier::verify0(static_func0); + Verifier::verify0(&thing, &Thing::member_func0); + Verifier::verify0(&thing, &bound_func0); + + Callback callback(static_func0); + Verifier::verify0(callback); + callback.attach(&thing, &bound_func0); + Verifier::verify0(&callback, &Callback::call); + Verifier::verify0((void*)&callback, &Callback::thunk); +} + + +// Test setup +status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(40, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Testing callbacks with 5 ints", test_dispatch5), + Case("Testing callbacks with 4 ints", test_dispatch4), + Case("Testing callbacks with 3 ints", test_dispatch3), + Case("Testing callbacks with 2 ints", test_dispatch2), + Case("Testing callbacks with 1 ints", test_dispatch1), + Case("Testing callbacks with 0 ints", test_dispatch0), + + Case("Testing callbacks with 5 uchars", test_dispatch5), + Case("Testing callbacks with 4 uchars", test_dispatch4), + Case("Testing callbacks with 3 uchars", test_dispatch3), + Case("Testing callbacks with 2 uchars", test_dispatch2), + Case("Testing callbacks with 1 uchars", test_dispatch1), + Case("Testing callbacks with 0 uchars", test_dispatch0), + + Case("Testing callbacks with 5 uint64s", test_dispatch5), + Case("Testing callbacks with 4 uint64s", test_dispatch4), + Case("Testing callbacks with 3 uint64s", test_dispatch3), + Case("Testing callbacks with 2 uint64s", test_dispatch2), + Case("Testing callbacks with 1 uint64s", test_dispatch1), + Case("Testing callbacks with 0 uint64s", test_dispatch0), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} From bf498de1277000d2aa821c9daf2d5c80e6d54105 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 13 May 2016 14:55:48 -0500 Subject: [PATCH 3/6] Add backward compatiblity for FunctionPointer class using Callback effectively: typedef Callback FunctionPointerArg1 typedef Callback FunctionPointerArg1 typedef Callback FunctionPointer typedef Callback event_callback_t --- hal/TESTS/api/callback/main.cpp | 19 ++++ hal/api/FunctionPointer.h | 174 ++++---------------------------- hal/api/mbed.h | 1 + 3 files changed, 38 insertions(+), 156 deletions(-) diff --git a/hal/TESTS/api/callback/main.cpp b/hal/TESTS/api/callback/main.cpp index 057b5ac367..27fab43173 100644 --- a/hal/TESTS/api/callback/main.cpp +++ b/hal/TESTS/api/callback/main.cpp @@ -211,6 +211,22 @@ void test_dispatch0() { Verifier::verify0((void*)&callback, &Callback::thunk); } +template +void test_fparg1() { + Thing thing; + FunctionPointerArg1 fp(static_func1); + Verifier::verify1(fp); + Verifier::verify1(fp.get_function()); +} + +template +void test_fparg0() { + Thing thing; + FunctionPointerArg1 fp(static_func0); + Verifier::verify0(fp); + Verifier::verify0(fp.get_function()); +} + // Test setup status_t test_setup(const size_t number_of_cases) { @@ -239,6 +255,9 @@ Case cases[] = { Case("Testing callbacks with 2 uint64s", test_dispatch2), Case("Testing callbacks with 1 uint64s", test_dispatch1), Case("Testing callbacks with 0 uint64s", test_dispatch0), + + Case("Testing FunctionPointerArg1 compatibility", test_fparg1), + Case("Testing FunctionPointer compatibility", test_fparg0), }; Specification specification(test_setup, cases); diff --git a/hal/api/FunctionPointer.h b/hal/api/FunctionPointer.h index 2d49ba035e..b2ef2b971c 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); - } + FunctionPointerArg1(T *object, R (T::*member)(A1)) + : Callback(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; + R (*get_function())(A1) { + return *reinterpret_cast(this); } - - /** 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; - } - -#ifdef MBED_OPERATORS - R operator ()(A1 a) { - return call(a); - } - 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); - } + FunctionPointerArg1(T *object, R (T::*member)()) + : Callback(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; + R (*get_function())() { + return *reinterpret_cast(this); } - - /** 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; - } - - /** Get registered static function - */ - R(*get_function())() { - return _membercaller ? (R(*)())0 : (R(*)())_p.function; - } - -#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/mbed.h b/hal/api/mbed.h index 8d615d4c6f..e1a6a12e01 100644 --- a/hal/api/mbed.h +++ b/hal/api/mbed.h @@ -66,6 +66,7 @@ // mbed Non-hardware components #include "Callback.h" +#include "FunctionPointer.h" using namespace mbed; using namespace std; From 4984077d071ad6cea3c0ee6cbedbf6749c73861f Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 15 May 2016 16:17:47 -0500 Subject: [PATCH 4/6] Adopt Callback class in hal --- hal/api/CAN.h | 24 +++++++++------------- hal/api/CallChain.h | 36 ++++++++++++++++----------------- hal/api/InterruptIn.h | 36 ++++++++++++++++----------------- hal/api/SerialBase.h | 27 ++++++++++--------------- hal/api/Ticker.h | 33 +++++++++++++++--------------- hal/common/CAN.cpp | 6 +++--- hal/common/CallChain.cpp | 30 ++++++++++----------------- hal/common/InterruptIn.cpp | 12 +++++------ hal/common/InterruptManager.cpp | 7 ------- hal/common/SerialBase.cpp | 6 +++--- 10 files changed, 93 insertions(+), 124 deletions(-) diff --git a/hal/api/CAN.h b/hal/api/CAN.h index db613f6616..65221ccdec 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,28 @@ public: /** 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); - } + void attach(T* obj, void (T::*method)(void), 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 ebb796a3cd..babdacbf91 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 @@ public: /** 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 @@ public: * @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 @@ public: 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/InterruptIn.h b/hal/api/InterruptIn.h index 88bc4308e8..0e519faef4 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 @@ public: /** 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 @@ protected: 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 51aeb33e36..e9387f48ac 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,20 @@ public: /** 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); - } + template + void attach(T *obj, M method, IrqType type=RxIrq) { + attach(Callback(obj, method), type); } /** Generate a break condition on the serial line @@ -210,9 +205,9 @@ protected: 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 fda205da9a..817394039b 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 @@ 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 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 @@ public: * @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 @@ public: * @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 @@ protected: 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/common/CAN.cpp b/hal/common/CAN.cpp index 407e00bf17..b717f80461 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 e950903059..4c4a9cba4d 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 92f70f2a5e..414529869f 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 e92fb68d4e..183404719f 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 880a0212e6..94eca327d9 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); From e1c42a3afc123baab63fb506f4ddcacd49032e84 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 15 May 2016 16:50:45 -0500 Subject: [PATCH 5/6] Adopt Callback class in rtos Threads --- core/mbed-rtos/rtos/Thread.cpp | 27 +++++++----- core/mbed-rtos/rtos/Thread.h | 81 ++++++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 15 deletions(-) diff --git a/core/mbed-rtos/rtos/Thread.cpp b/core/mbed-rtos/rtos/Thread.cpp index 402295e8d7..61e533a521 100644 --- a/core/mbed-rtos/rtos/Thread.cpp +++ b/core/mbed-rtos/rtos/Thread.cpp @@ -21,14 +21,16 @@ */ #include "Thread.h" -#include "mbed_error.h" +#include "mbed.h" #include "rtos_idle.h" namespace rtos { -Thread::Thread(osPriority priority, - uint32_t stack_size, unsigned char *stack_pointer): - _tid(NULL), _dynamic_stack(stack_pointer == NULL) { +void Thread::constructor(osPriority priority, + uint32_t stack_size, unsigned char *stack_pointer) { + _tid = NULL; + _dynamic_stack = (stack_pointer == NULL); + #ifdef __MBED_CMSIS_RTOS_CM _thread_def.tpriority = priority; _thread_def.stacksize = stack_size; @@ -36,15 +38,17 @@ Thread::Thread(osPriority priority, #endif } -Thread::Thread(void (*task)(void const *argument), void *argument, - osPriority priority, uint32_t stack_size, unsigned char *stack_pointer): - _tid(NULL), _dynamic_stack(stack_pointer == NULL) { +void Thread::constructor(Callback task, + osPriority priority, uint32_t stack_size, unsigned char *stack_pointer) { + _tid = NULL; + _dynamic_stack = (stack_pointer == NULL); + #ifdef __MBED_CMSIS_RTOS_CM _thread_def.tpriority = priority; _thread_def.stacksize = stack_size; _thread_def.stack_pointer = (uint32_t*)stack_pointer; #endif - switch(start(task, argument)) { + switch(start(task)) { case osErrorResource: error("OS ran out of threads!\n"); break; @@ -58,13 +62,13 @@ Thread::Thread(void (*task)(void const *argument), void *argument, } } -osStatus Thread::start(void (*task)(void const *argument), void *argument) { +osStatus Thread::start(Callback task) { if (_tid != NULL) { return osErrorParameter; } #ifdef __MBED_CMSIS_RTOS_CM - _thread_def.pthread = task; + _thread_def.pthread = (void (*)(const void *))Callback::thunk; if (_thread_def.stack_pointer == NULL) { _thread_def.stack_pointer = new uint32_t[_thread_def.stacksize/sizeof(uint32_t)]; if (_thread_def.stack_pointer == NULL) @@ -76,7 +80,8 @@ osStatus Thread::start(void (*task)(void const *argument), void *argument) { _thread_def.stack_pointer[i] = 0xE25A2EA5; } #endif - _tid = osThreadCreate(&_thread_def, argument); + _task = task; + _tid = osThreadCreate(&_thread_def, &_task); if (_tid == NULL) { if (_dynamic_stack) delete[] (_thread_def.stack_pointer); return osErrorResource; diff --git a/core/mbed-rtos/rtos/Thread.h b/core/mbed-rtos/rtos/Thread.h index 275f6fe5c9..f28706d465 100644 --- a/core/mbed-rtos/rtos/Thread.h +++ b/core/mbed-rtos/rtos/Thread.h @@ -24,6 +24,7 @@ #include #include "cmsis_os.h" +#include "Callback.h" namespace rtos { @@ -37,26 +38,87 @@ public: */ Thread(osPriority priority=osPriorityNormal, uint32_t stack_size=DEFAULT_STACK_SIZE, - unsigned char *stack_pointer=NULL); + unsigned char *stack_pointer=NULL) { + constructor(priority, stack_size, stack_pointer); + } /** Create a new thread, and start it executing the specified function. @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(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 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 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); + } /** Starts a thread executing the specified function. @param task function to be executed by this thread. @param argument pointer that is passed to the thread function as start argument. (default: NULL). @return status code that indicates the execution status of the function. */ - osStatus start(void (*task)(void const *argument), void *argument=NULL); + osStatus start(mbed::Callback task); + + /** Starts a thread executing the specified function. + @param obj argument to task. + @param method function to be executed by this thread. + @return status code that indicates the execution status of the function. + */ + template + osStatus start(T *obj, M method) { + return start(mbed::Callback(obj, method)); + } /** Wait for thread to terminate @return status code that indicates the execution status of the function. @@ -165,6 +227,17 @@ public: virtual ~Thread(); private: + // Required to share definitions without without + // delegated constructors + void constructor(osPriority priority=osPriorityNormal, + uint32_t stack_size=DEFAULT_STACK_SIZE, + unsigned char *stack_pointer=NULL); + 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; From dd6a24b76db92dc185257673e1fa4519c1b228ef Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 16 May 2016 11:48:09 -0500 Subject: [PATCH 6/6] Adopt Callback class in NetworkSocketAPI --- net/NetworkSocketAPI/Socket.cpp | 2 +- net/NetworkSocketAPI/Socket.h | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index fd32a30cb8..b525a2d6ae 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -148,7 +148,7 @@ int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen) } -void Socket::attach(FunctionPointer callback) +void Socket::attach(Callback callback) { _lock.lock(); diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index bee2d11a74..cb9d01df12 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -145,9 +145,9 @@ public: * The callback may be called in an interrupt context and should not * perform expensive operations such as recv/send calls. * - * @param callback Function to call on state change + * @param func Function to call on state change */ - void attach(FunctionPointer callback); + void attach(Callback func); /** Register a callback on state change of the socket * @@ -158,12 +158,12 @@ public: * The callback may be called in an interrupt context and should not * perform expensive operations such as recv/send calls. * - * @param tptr Pointer to object to call method on - * @param mptr Method to call on state change + * @param obj Pointer to object to call method on + * @param method Method to call on state change */ template - void attach(T *tptr, M mptr) { - attach(FunctionPointer(tptr, mptr)); + void attach(T *obj, M method) { + attach(Callback(obj, method)); } protected: @@ -176,7 +176,7 @@ protected: NetworkStack *_iface; void *_socket; uint32_t _timeout; - FunctionPointer _callback; + Callback _callback; rtos::Mutex _lock; };