General thunking class to allow C-style callbacks to C++ class members - including optional parameters.
CThunk.h@9:d3b51b06ac54, 2014-08-21 (annotated)
- 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?
User | Revision | Line number | New 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__*/ |