General thunking class to allow C-style callbacks to C++ class members - including optional parameters.

Dependents:   cthunk_example

Committer:
meriac
Date:
Wed Aug 20 13:36:46 2014 +0000
Revision:
6:ef94278e2225
Parent:
5:df90d98292a6
Child:
7:289963aeee06
added gcc thumb2 detection;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
meriac 0:7de85300ea3a 1 /* General C++ Object Thunking class
meriac 0:7de85300ea3a 2 *
meriac 0:7de85300ea3a 3 * - allows direct callbacks to non-static C++ class functions
meriac 0:7de85300ea3a 4 * - keeps track for the corresponding class instance
meriac 0:7de85300ea3a 5 * - supports an optional context parameter for the called function
meriac 0:7de85300ea3a 6 * - ideally suited for class object receiving interrupts (NVIC_SetVector)
meriac 0:7de85300ea3a 7 *
meriac 0:7de85300ea3a 8 * Copyright (c) 2014 ARM Limited
meriac 0:7de85300ea3a 9 *
meriac 0:7de85300ea3a 10 * Licensed under the Apache License, Version 2.0 (the "License");
meriac 0:7de85300ea3a 11 * you may not use this file except in compliance with the License.
meriac 0:7de85300ea3a 12 * You may obtain a copy of the License at
meriac 0:7de85300ea3a 13 *
meriac 0:7de85300ea3a 14 * http://www.apache.org/licenses/LICENSE-2.0
meriac 0:7de85300ea3a 15 *
meriac 0:7de85300ea3a 16 * Unless required by applicable law or agreed to in writing, software
meriac 0:7de85300ea3a 17 * distributed under the License is distributed on an "AS IS" BASIS,
meriac 0:7de85300ea3a 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
meriac 0:7de85300ea3a 19 * See the License for the specific language governing permissions and
meriac 0:7de85300ea3a 20 * limitations under the License.
meriac 0:7de85300ea3a 21 */
meriac 0:7de85300ea3a 22
meriac 0:7de85300ea3a 23 #ifndef __CTHUNK_H__
meriac 0:7de85300ea3a 24 #define __CTHUNK_H__
meriac 0:7de85300ea3a 25
meriac 6:ef94278e2225 26 #if defined(__CORTEX_M3) || defined(__thumb2__)
meriac 5:df90d98292a6 27 # define CTHUNK_OPCODE 0x8007E89F;
meriac 5:df90d98292a6 28 # define CTHUNK_ADDRESS 1
meriac 5:df90d98292a6 29 #else
meriac 5:df90d98292a6 30 # error "TODO: add support for non-cortex-m3 trampoline, too"
meriac 5:df90d98292a6 31 #endif
meriac 5:df90d98292a6 32
meriac 0:7de85300ea3a 33 /* IRQ/Exception compatible thunk entry function */
meriac 0:7de85300ea3a 34 typedef void (*CThunkEntry)(void);
meriac 3:51023d181133 35 typedef void (*CThunkCallback)(void* instance, void* context);
meriac 0:7de85300ea3a 36
meriac 0:7de85300ea3a 37 template<class T>
meriac 0:7de85300ea3a 38 class CThunk
meriac 0:7de85300ea3a 39 {
meriac 0:7de85300ea3a 40 public:
meriac 0:7de85300ea3a 41 typedef void (T::*CCallbackSimple)(void);
meriac 0:7de85300ea3a 42 typedef void (T::*CCallback)(void* context);
meriac 0:7de85300ea3a 43
meriac 1:53a00c956d82 44 inline CThunk(T *instance)
meriac 0:7de85300ea3a 45 {
meriac 0:7de85300ea3a 46 init(instance, NULL, NULL);
meriac 0:7de85300ea3a 47 }
meriac 0:7de85300ea3a 48
meriac 5:df90d98292a6 49 inline CThunk(T *instance, CCallback callback)
meriac 5:df90d98292a6 50 {
meriac 5:df90d98292a6 51 init(instance, callback, NULL);
meriac 5:df90d98292a6 52 }
meriac 5:df90d98292a6 53
meriac 5:df90d98292a6 54 inline CThunk(T *instance, CCallbackSimple callback)
meriac 5:df90d98292a6 55 {
meriac 5:df90d98292a6 56 init(instance, (CCallback)callback, NULL);
meriac 5:df90d98292a6 57 }
meriac 5:df90d98292a6 58
meriac 0:7de85300ea3a 59 inline CThunk(T &instance, CCallback callback)
meriac 0:7de85300ea3a 60 {
meriac 0:7de85300ea3a 61 init(instance, callback, NULL);
meriac 0:7de85300ea3a 62 }
meriac 0:7de85300ea3a 63
meriac 0:7de85300ea3a 64 inline CThunk(T &instance, CCallbackSimple callback)
meriac 0:7de85300ea3a 65 {
meriac 0:7de85300ea3a 66 init(instance, (CCallback)callback, NULL);
meriac 0:7de85300ea3a 67 }
meriac 0:7de85300ea3a 68
meriac 0:7de85300ea3a 69 inline CThunk(T &instance, CCallback callback, void* context)
meriac 0:7de85300ea3a 70 {
meriac 0:7de85300ea3a 71 init(instance, callback, context);
meriac 0:7de85300ea3a 72 }
meriac 0:7de85300ea3a 73
meriac 3:51023d181133 74 inline void callback(CCallback callback)
meriac 0:7de85300ea3a 75 {
meriac 3:51023d181133 76 m_callback = callback;
meriac 0:7de85300ea3a 77 }
meriac 0:7de85300ea3a 78
meriac 3:51023d181133 79 inline void callback(CCallbackSimple callback)
meriac 0:7de85300ea3a 80 {
meriac 3:51023d181133 81 m_callback = (CCallback)callback;
meriac 0:7de85300ea3a 82 }
meriac 0:7de85300ea3a 83
meriac 3:51023d181133 84 inline void context(void* context)
meriac 3:51023d181133 85 {
meriac 3:51023d181133 86 m_thunk.context = (uint32_t)context;
meriac 3:51023d181133 87 }
meriac 3:51023d181133 88
meriac 3:51023d181133 89 inline void context(uint32_t context)
meriac 0:7de85300ea3a 90 {
meriac 0:7de85300ea3a 91 m_thunk.context = context;
meriac 0:7de85300ea3a 92 }
meriac 0:7de85300ea3a 93
meriac 0:7de85300ea3a 94 /* get thunk entry point for connecting rhunk to an IRQ table */
meriac 0:7de85300ea3a 95 inline operator CThunkEntry(void)
meriac 0:7de85300ea3a 96 {
meriac 3:51023d181133 97 /* TODO: check thumb */
meriac 5:df90d98292a6 98 return (CThunkEntry)(((uint32_t)&m_thunk)|CTHUNK_ADDRESS);
meriac 0:7de85300ea3a 99 }
meriac 0:7de85300ea3a 100
meriac 0:7de85300ea3a 101 /* get thunk entry point for connecting rhunk to an IRQ table */
meriac 0:7de85300ea3a 102 inline operator uint32_t(void)
meriac 0:7de85300ea3a 103 {
meriac 1:53a00c956d82 104 return (uint32_t)&m_thunk;
meriac 0:7de85300ea3a 105 }
meriac 0:7de85300ea3a 106
meriac 0:7de85300ea3a 107 /* simple test function */
meriac 0:7de85300ea3a 108 inline void call(void)
meriac 0:7de85300ea3a 109 {
meriac 3:51023d181133 110 /* TODO: check thumb */
meriac 5:df90d98292a6 111 ((CThunkEntry)(((uint32_t)&m_thunk)|CTHUNK_ADDRESS))();
meriac 0:7de85300ea3a 112 }
meriac 0:7de85300ea3a 113
meriac 0:7de85300ea3a 114 private:
meriac 4:e4a106e8f3fe 115 T* m_instance;
meriac 3:51023d181133 116 volatile CCallback m_callback;
meriac 4:e4a106e8f3fe 117
meriac 0:7de85300ea3a 118 typedef struct
meriac 0:7de85300ea3a 119 {
meriac 3:51023d181133 120 volatile uint32_t code;
meriac 3:51023d181133 121 volatile uint32_t instance;
meriac 3:51023d181133 122 volatile uint32_t context;
meriac 3:51023d181133 123 volatile uint32_t callback;
meriac 4:e4a106e8f3fe 124 volatile uint32_t trampoline;
meriac 0:7de85300ea3a 125 } __attribute__((packed)) CThunkTrampoline;
meriac 0:7de85300ea3a 126
meriac 4:e4a106e8f3fe 127 static void trampoline(T* instance, void* context, CCallback* callback)
meriac 3:51023d181133 128 {
meriac 4:e4a106e8f3fe 129 if(instance && *callback)
meriac 4:e4a106e8f3fe 130 (static_cast<T*>(instance)->**callback)(context);
meriac 3:51023d181133 131 }
meriac 3:51023d181133 132
meriac 3:51023d181133 133 volatile CThunkTrampoline m_thunk;
meriac 3:51023d181133 134
meriac 3:51023d181133 135 inline void init(T *instance, CCallback callback, void* context)
meriac 0:7de85300ea3a 136 {
meriac 5:df90d98292a6 137 /* remember callback - need to add this level of redirection
meriac 5:df90d98292a6 138 as pointer size for member functions differs between platforms */
meriac 4:e4a106e8f3fe 139 m_callback = callback;
meriac 4:e4a106e8f3fe 140
meriac 4:e4a106e8f3fe 141 /* populate thunking trampoline */
meriac 5:df90d98292a6 142 m_thunk.code = CTHUNK_OPCODE;
meriac 3:51023d181133 143 m_thunk.context = (uint32_t)context;
meriac 3:51023d181133 144 m_thunk.instance = (uint32_t)instance;
meriac 4:e4a106e8f3fe 145 m_thunk.callback = (uint32_t)&m_callback;
meriac 4:e4a106e8f3fe 146 m_thunk.trampoline = (uint32_t)&trampoline;
meriac 4:e4a106e8f3fe 147
meriac 3:51023d181133 148 __ISB();
meriac 3:51023d181133 149 __DSB();
meriac 0:7de85300ea3a 150 }
meriac 0:7de85300ea3a 151 };
meriac 0:7de85300ea3a 152
meriac 1:53a00c956d82 153 #endif/*__CTHUNK_H__*/