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

Dependents:   cthunk_example

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?

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 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__*/