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

Dependents:   cthunk_example

Committer:
meriac
Date:
Thu Aug 21 17:09:11 2014 +0000
Revision:
9:d3b51b06ac54
Parent:
8:12fc2cda71af
Added CThunkIRQ class

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 0:7de85300ea3a 35
meriac 0:7de85300ea3a 36 template<class T>
meriac 0:7de85300ea3a 37 class CThunk
meriac 0:7de85300ea3a 38 {
meriac 0:7de85300ea3a 39 public:
meriac 0:7de85300ea3a 40 typedef void (T::*CCallbackSimple)(void);
meriac 0:7de85300ea3a 41 typedef void (T::*CCallback)(void* context);
meriac 0:7de85300ea3a 42
meriac 1:53a00c956d82 43 inline CThunk(T *instance)
meriac 0:7de85300ea3a 44 {
meriac 0:7de85300ea3a 45 init(instance, NULL, NULL);
meriac 0:7de85300ea3a 46 }
meriac 0:7de85300ea3a 47
meriac 5:df90d98292a6 48 inline CThunk(T *instance, CCallback callback)
meriac 5:df90d98292a6 49 {
meriac 5:df90d98292a6 50 init(instance, callback, NULL);
meriac 5:df90d98292a6 51 }
meriac 5:df90d98292a6 52
meriac 5:df90d98292a6 53 inline CThunk(T *instance, CCallbackSimple callback)
meriac 5:df90d98292a6 54 {
meriac 5:df90d98292a6 55 init(instance, (CCallback)callback, NULL);
meriac 5:df90d98292a6 56 }
meriac 5:df90d98292a6 57
meriac 0:7de85300ea3a 58 inline CThunk(T &instance, CCallback callback)
meriac 0:7de85300ea3a 59 {
meriac 0:7de85300ea3a 60 init(instance, callback, NULL);
meriac 0:7de85300ea3a 61 }
meriac 0:7de85300ea3a 62
meriac 0:7de85300ea3a 63 inline CThunk(T &instance, CCallbackSimple callback)
meriac 0:7de85300ea3a 64 {
meriac 0:7de85300ea3a 65 init(instance, (CCallback)callback, NULL);
meriac 0:7de85300ea3a 66 }
meriac 0:7de85300ea3a 67
meriac 0:7de85300ea3a 68 inline CThunk(T &instance, CCallback callback, void* context)
meriac 0:7de85300ea3a 69 {
meriac 0:7de85300ea3a 70 init(instance, callback, context);
meriac 0:7de85300ea3a 71 }
meriac 0:7de85300ea3a 72
meriac 3:51023d181133 73 inline void callback(CCallback callback)
meriac 0:7de85300ea3a 74 {
meriac 3:51023d181133 75 m_callback = callback;
meriac 0:7de85300ea3a 76 }
meriac 0:7de85300ea3a 77
meriac 3:51023d181133 78 inline void callback(CCallbackSimple callback)
meriac 0:7de85300ea3a 79 {
meriac 3:51023d181133 80 m_callback = (CCallback)callback;
meriac 0:7de85300ea3a 81 }
meriac 0:7de85300ea3a 82
meriac 3:51023d181133 83 inline void context(void* context)
meriac 3:51023d181133 84 {
meriac 3:51023d181133 85 m_thunk.context = (uint32_t)context;
meriac 3:51023d181133 86 }
meriac 3:51023d181133 87
meriac 3:51023d181133 88 inline void context(uint32_t context)
meriac 0:7de85300ea3a 89 {
meriac 0:7de85300ea3a 90 m_thunk.context = context;
meriac 0:7de85300ea3a 91 }
meriac 9:d3b51b06ac54 92
meriac 9:d3b51b06ac54 93 inline uint32_t entry(void)
meriac 9:d3b51b06ac54 94 {
meriac 9:d3b51b06ac54 95 return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS);
meriac 9:d3b51b06ac54 96 }
meriac 0:7de85300ea3a 97
meriac 0:7de85300ea3a 98 /* get thunk entry point for connecting rhunk to an IRQ table */
meriac 0:7de85300ea3a 99 inline operator CThunkEntry(void)
meriac 0:7de85300ea3a 100 {
meriac 9:d3b51b06ac54 101 return (CThunkEntry)entry();
meriac 0:7de85300ea3a 102 }
meriac 0:7de85300ea3a 103
meriac 0:7de85300ea3a 104 /* get thunk entry point for connecting rhunk to an IRQ table */
meriac 0:7de85300ea3a 105 inline operator uint32_t(void)
meriac 0:7de85300ea3a 106 {
meriac 9:d3b51b06ac54 107 return entry();
meriac 0:7de85300ea3a 108 }
meriac 0:7de85300ea3a 109
meriac 0:7de85300ea3a 110 /* simple test function */
meriac 0:7de85300ea3a 111 inline void call(void)
meriac 0:7de85300ea3a 112 {
meriac 9:d3b51b06ac54 113 ((CThunkEntry)(entry())();
meriac 0:7de85300ea3a 114 }
meriac 0:7de85300ea3a 115
meriac 0:7de85300ea3a 116 private:
meriac 4:e4a106e8f3fe 117 T* m_instance;
meriac 3:51023d181133 118 volatile CCallback m_callback;
meriac 4:e4a106e8f3fe 119
meriac 0:7de85300ea3a 120 typedef struct
meriac 0:7de85300ea3a 121 {
meriac 3:51023d181133 122 volatile uint32_t code;
meriac 3:51023d181133 123 volatile uint32_t instance;
meriac 3:51023d181133 124 volatile uint32_t context;
meriac 3:51023d181133 125 volatile uint32_t callback;
meriac 4:e4a106e8f3fe 126 volatile uint32_t trampoline;
meriac 0:7de85300ea3a 127 } __attribute__((packed)) CThunkTrampoline;
meriac 0:7de85300ea3a 128
meriac 4:e4a106e8f3fe 129 static void trampoline(T* instance, void* context, CCallback* callback)
meriac 3:51023d181133 130 {
meriac 4:e4a106e8f3fe 131 if(instance && *callback)
meriac 4:e4a106e8f3fe 132 (static_cast<T*>(instance)->**callback)(context);
meriac 3:51023d181133 133 }
meriac 3:51023d181133 134
meriac 3:51023d181133 135 volatile CThunkTrampoline m_thunk;
meriac 3:51023d181133 136
meriac 3:51023d181133 137 inline void init(T *instance, CCallback callback, void* context)
meriac 0:7de85300ea3a 138 {
meriac 5:df90d98292a6 139 /* remember callback - need to add this level of redirection
meriac 5:df90d98292a6 140 as pointer size for member functions differs between platforms */
meriac 4:e4a106e8f3fe 141 m_callback = callback;
meriac 4:e4a106e8f3fe 142
meriac 4:e4a106e8f3fe 143 /* populate thunking trampoline */
meriac 5:df90d98292a6 144 m_thunk.code = CTHUNK_OPCODE;
meriac 3:51023d181133 145 m_thunk.context = (uint32_t)context;
meriac 3:51023d181133 146 m_thunk.instance = (uint32_t)instance;
meriac 4:e4a106e8f3fe 147 m_thunk.callback = (uint32_t)&m_callback;
meriac 4:e4a106e8f3fe 148 m_thunk.trampoline = (uint32_t)&trampoline;
meriac 4:e4a106e8f3fe 149
meriac 3:51023d181133 150 __ISB();
meriac 3:51023d181133 151 __DSB();
meriac 0:7de85300ea3a 152 }
meriac 0:7de85300ea3a 153 };
meriac 0:7de85300ea3a 154
meriac 1:53a00c956d82 155 #endif/*__CTHUNK_H__*/