General thunking class to allow C-style callbacks to C++ class members - including optional parameters.
CThunk.h@0:7de85300ea3a, 2014-08-13 (annotated)
- Committer:
- meriac
- Date:
- Wed Aug 13 07:43:23 2014 +0000
- Revision:
- 0:7de85300ea3a
- Child:
- 1:53a00c956d82
Initial Commit - F' Yeah.
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 | 0:7de85300ea3a | 26 | /* IRQ/Exception compatible thunk entry function */ |
meriac | 0:7de85300ea3a | 27 | typedef void (*CThunkEntry)(void); |
meriac | 0:7de85300ea3a | 28 | |
meriac | 0:7de85300ea3a | 29 | /* template for thunk trampoline */ |
meriac | 0:7de85300ea3a | 30 | #ifdef __thumb__ |
meriac | 0:7de85300ea3a | 31 | #define CTHUNK_OPCODES_SIZE 8 |
meriac | 0:7de85300ea3a | 32 | #else |
meriac | 0:7de85300ea3a | 33 | #error "TODO: add support for non-thumb trampoline, too" |
meriac | 0:7de85300ea3a | 34 | #endif |
meriac | 0:7de85300ea3a | 35 | |
meriac | 0:7de85300ea3a | 36 | extern const uint8_t g_cthunk_opcodes[CTHUNK_OPCODES_SIZE]; |
meriac | 0:7de85300ea3a | 37 | |
meriac | 0:7de85300ea3a | 38 | template<class T> |
meriac | 0:7de85300ea3a | 39 | class CThunk |
meriac | 0:7de85300ea3a | 40 | { |
meriac | 0:7de85300ea3a | 41 | public: |
meriac | 0:7de85300ea3a | 42 | typedef void (T::*CCallbackSimple)(void); |
meriac | 0:7de85300ea3a | 43 | typedef void (T::*CCallback)(void* context); |
meriac | 0:7de85300ea3a | 44 | |
meriac | 0:7de85300ea3a | 45 | inline CThunk(void) |
meriac | 0:7de85300ea3a | 46 | { |
meriac | 0:7de85300ea3a | 47 | /* copy ARM thumb compatible pcode preamble */ |
meriac | 0:7de85300ea3a | 48 | memcpy( |
meriac | 0:7de85300ea3a | 49 | &m_thunk.code, |
meriac | 0:7de85300ea3a | 50 | &g_cthunk_opcodes, |
meriac | 0:7de85300ea3a | 51 | CTHUNK_OPCODES_SIZE |
meriac | 0:7de85300ea3a | 52 | ); |
meriac | 0:7de85300ea3a | 53 | /* set remainder to zero */ |
meriac | 0:7de85300ea3a | 54 | memset( |
meriac | 0:7de85300ea3a | 55 | &m_thunk.code + CTHUNK_OPCODES_SIZE, |
meriac | 0:7de85300ea3a | 56 | 0, sizeof(m_thunk.code) - CTHUNK_OPCODES_SIZE |
meriac | 0:7de85300ea3a | 57 | ); |
meriac | 0:7de85300ea3a | 58 | } |
meriac | 0:7de85300ea3a | 59 | |
meriac | 0:7de85300ea3a | 60 | inline CThunk(T &instance) |
meriac | 0:7de85300ea3a | 61 | { |
meriac | 0:7de85300ea3a | 62 | init(instance, NULL, NULL); |
meriac | 0:7de85300ea3a | 63 | } |
meriac | 0:7de85300ea3a | 64 | |
meriac | 0:7de85300ea3a | 65 | inline CThunk(T &instance, CCallback callback) |
meriac | 0:7de85300ea3a | 66 | { |
meriac | 0:7de85300ea3a | 67 | init(instance, callback, NULL); |
meriac | 0:7de85300ea3a | 68 | } |
meriac | 0:7de85300ea3a | 69 | |
meriac | 0:7de85300ea3a | 70 | inline CThunk(T &instance, CCallbackSimple callback) |
meriac | 0:7de85300ea3a | 71 | { |
meriac | 0:7de85300ea3a | 72 | init(instance, (CCallback)callback, NULL); |
meriac | 0:7de85300ea3a | 73 | } |
meriac | 0:7de85300ea3a | 74 | |
meriac | 0:7de85300ea3a | 75 | inline CThunk(T &instance, CCallback callback, void* context) |
meriac | 0:7de85300ea3a | 76 | { |
meriac | 0:7de85300ea3a | 77 | init(instance, callback, context); |
meriac | 0:7de85300ea3a | 78 | } |
meriac | 0:7de85300ea3a | 79 | |
meriac | 0:7de85300ea3a | 80 | inline CThunk& operator=(T &instance) |
meriac | 0:7de85300ea3a | 81 | { |
meriac | 0:7de85300ea3a | 82 | m_thunk.instance = &instance; |
meriac | 0:7de85300ea3a | 83 | return *this; |
meriac | 0:7de85300ea3a | 84 | } |
meriac | 0:7de85300ea3a | 85 | |
meriac | 0:7de85300ea3a | 86 | inline CThunk& operator=(CCallback callback) |
meriac | 0:7de85300ea3a | 87 | { |
meriac | 0:7de85300ea3a | 88 | m_thunk.callback = callback; |
meriac | 0:7de85300ea3a | 89 | return *this; |
meriac | 0:7de85300ea3a | 90 | } |
meriac | 0:7de85300ea3a | 91 | |
meriac | 0:7de85300ea3a | 92 | inline CThunk& operator=(CCallbackSimple callback) |
meriac | 0:7de85300ea3a | 93 | { |
meriac | 0:7de85300ea3a | 94 | m_thunk.callback = (CCallback)callback; |
meriac | 0:7de85300ea3a | 95 | return *this; |
meriac | 0:7de85300ea3a | 96 | } |
meriac | 0:7de85300ea3a | 97 | |
meriac | 0:7de85300ea3a | 98 | inline CThunk& operator=(void* context) |
meriac | 0:7de85300ea3a | 99 | { |
meriac | 0:7de85300ea3a | 100 | m_thunk.context = context; |
meriac | 0:7de85300ea3a | 101 | return *this; |
meriac | 0:7de85300ea3a | 102 | } |
meriac | 0:7de85300ea3a | 103 | |
meriac | 0:7de85300ea3a | 104 | inline CThunk& operator=(uint32_t context) |
meriac | 0:7de85300ea3a | 105 | { |
meriac | 0:7de85300ea3a | 106 | m_thunk.context = (void*)context; |
meriac | 0:7de85300ea3a | 107 | return *this; |
meriac | 0:7de85300ea3a | 108 | } |
meriac | 0:7de85300ea3a | 109 | |
meriac | 0:7de85300ea3a | 110 | /* get thunk entry point for connecting rhunk to an IRQ table */ |
meriac | 0:7de85300ea3a | 111 | inline operator CThunkEntry(void) |
meriac | 0:7de85300ea3a | 112 | { |
meriac | 0:7de85300ea3a | 113 | return (CThunkEntry)&m_thunk.code; |
meriac | 0:7de85300ea3a | 114 | } |
meriac | 0:7de85300ea3a | 115 | |
meriac | 0:7de85300ea3a | 116 | /* get thunk entry point for connecting rhunk to an IRQ table */ |
meriac | 0:7de85300ea3a | 117 | inline operator uint32_t(void) |
meriac | 0:7de85300ea3a | 118 | { |
meriac | 0:7de85300ea3a | 119 | return (uint32_t)&m_thunk.code; |
meriac | 0:7de85300ea3a | 120 | } |
meriac | 0:7de85300ea3a | 121 | |
meriac | 0:7de85300ea3a | 122 | /* simple test function */ |
meriac | 0:7de85300ea3a | 123 | inline void call(void) |
meriac | 0:7de85300ea3a | 124 | { |
meriac | 0:7de85300ea3a | 125 | ((CThunkEntry)&m_thunk.code)(); |
meriac | 0:7de85300ea3a | 126 | } |
meriac | 0:7de85300ea3a | 127 | |
meriac | 0:7de85300ea3a | 128 | private: |
meriac | 0:7de85300ea3a | 129 | typedef struct |
meriac | 0:7de85300ea3a | 130 | { |
meriac | 0:7de85300ea3a | 131 | uint8_t code[CTHUNK_OPCODES_SIZE]; |
meriac | 0:7de85300ea3a | 132 | T* instance; |
meriac | 0:7de85300ea3a | 133 | void* context; |
meriac | 0:7de85300ea3a | 134 | CCallback callback; |
meriac | 0:7de85300ea3a | 135 | } __attribute__((packed)) CThunkTrampoline; |
meriac | 0:7de85300ea3a | 136 | |
meriac | 0:7de85300ea3a | 137 | CThunkTrampoline m_thunk; |
meriac | 0:7de85300ea3a | 138 | |
meriac | 0:7de85300ea3a | 139 | inline void init(T &instance, CCallback callback, void* context) |
meriac | 0:7de85300ea3a | 140 | { |
meriac | 0:7de85300ea3a | 141 | memcpy(&m_thunk.code, &g_cthunk_opcodes, CTHUNK_OPCODES_SIZE); |
meriac | 0:7de85300ea3a | 142 | m_thunk.instance = &instance; |
meriac | 0:7de85300ea3a | 143 | m_thunk.context = context; |
meriac | 0:7de85300ea3a | 144 | m_thunk.callback = callback; |
meriac | 0:7de85300ea3a | 145 | } |
meriac | 0:7de85300ea3a | 146 | }; |
meriac | 0:7de85300ea3a | 147 | |
meriac | 0:7de85300ea3a | 148 | #endif/*__CTHUNK_H__*/ |