Milosch Meriac / CThunk

Dependents:   cthunk_example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CThunk.h Source File

CThunk.h

00001 /* General C++ Object Thunking class
00002  *
00003  * - allows direct callbacks to non-static C++ class functions
00004  * - keeps track for the corresponding class instance
00005  * - supports an optional context parameter for the called function
00006  * - ideally suited for class object receiving interrupts (NVIC_SetVector)
00007  *
00008  * Copyright (c) 2014 ARM Limited
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License");
00011  * you may not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  *     http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS,
00018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  */
00022  
00023 #ifndef __CTHUNK_H__
00024 #define __CTHUNK_H__
00025 
00026 #if defined(__CORTEX_M3) || defined(__thumb2__)
00027 #  define CTHUNK_OPCODE 0x8007E89F;
00028 #  define CTHUNK_ADDRESS 1
00029 #else
00030 #  error "TODO: add support for non-cortex-m3 trampoline, too"
00031 #endif
00032 
00033 /* IRQ/Exception compatible thunk entry function */
00034 typedef void (*CThunkEntry)(void);
00035 
00036 template<class T>
00037 class CThunk
00038 {
00039     public:
00040         typedef void (T::*CCallbackSimple)(void);
00041         typedef void (T::*CCallback)(void* context);
00042 
00043         inline CThunk(T *instance)
00044         {
00045             init(instance, NULL, NULL);
00046         }
00047 
00048         inline CThunk(T *instance, CCallback callback)
00049         {
00050             init(instance, callback, NULL);
00051         }
00052 
00053         inline CThunk(T *instance, CCallbackSimple callback)
00054         {
00055             init(instance, (CCallback)callback, NULL);
00056         }
00057 
00058         inline CThunk(T &instance, CCallback callback)
00059         {
00060             init(instance, callback, NULL);
00061         }
00062 
00063         inline CThunk(T &instance, CCallbackSimple callback)
00064         {
00065             init(instance, (CCallback)callback, NULL);
00066         }
00067 
00068         inline CThunk(T &instance, CCallback callback, void* context)
00069         {
00070             init(instance, callback, context);
00071         }
00072 
00073         inline void callback(CCallback callback)
00074         {
00075             m_callback = callback;
00076         }
00077 
00078         inline void callback(CCallbackSimple callback)
00079         {
00080             m_callback = (CCallback)callback;
00081         }
00082 
00083         inline void context(void* context)
00084         {
00085             m_thunk.context = (uint32_t)context;
00086         }
00087 
00088         inline void context(uint32_t context)
00089         {
00090             m_thunk.context = context;
00091         }
00092         
00093         inline uint32_t entry(void)
00094         {
00095             return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS);
00096         }
00097 
00098         /* get thunk entry point for connecting rhunk to an IRQ table */
00099         inline operator CThunkEntry(void)
00100         {
00101             return (CThunkEntry)entry();
00102         }
00103 
00104         /* get thunk entry point for connecting rhunk to an IRQ table */
00105         inline operator uint32_t(void)
00106         {
00107             return entry();
00108         }
00109 
00110         /* simple test function */
00111         inline void call(void)
00112         {
00113             ((CThunkEntry)(entry())();
00114         }
00115 
00116     private:
00117         T* m_instance;
00118         volatile CCallback m_callback;
00119 
00120         typedef struct
00121         {
00122             volatile uint32_t code;
00123             volatile uint32_t instance;
00124             volatile uint32_t context;
00125             volatile uint32_t callback;
00126             volatile uint32_t trampoline;
00127         } __attribute__((packed)) CThunkTrampoline;
00128 
00129         static void trampoline(T* instance, void* context, CCallback* callback)
00130         {
00131             if(instance && *callback)
00132                 (static_cast<T*>(instance)->**callback)(context);
00133         }
00134 
00135         volatile CThunkTrampoline m_thunk;
00136 
00137         inline void init(T *instance, CCallback callback, void* context)
00138         {
00139             /* remember callback - need to add this level of redirection
00140                as pointer size for member functions differs between platforms */
00141             m_callback = callback;
00142 
00143             /* populate thunking trampoline */
00144             m_thunk.code = CTHUNK_OPCODE;
00145             m_thunk.context = (uint32_t)context;
00146             m_thunk.instance = (uint32_t)instance;
00147             m_thunk.callback = (uint32_t)&m_callback;
00148             m_thunk.trampoline = (uint32_t)&trampoline;
00149 
00150             __ISB();
00151             __DSB();
00152         }
00153 };
00154 
00155 #endif/*__CTHUNK_H__*/