FastArduino  v1.7
C++ library to build fast but small Arduino/AVR projects
interrupts.h
Go to the documentation of this file.
1 // Copyright 2016-2021 Jean-Francois Poilpret
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
65 #ifndef INTERRUPTS_HH
66 #define INTERRUPTS_HH
67 
68 #include "boards/io.h"
69 #include <avr/interrupt.h>
70 
72 // Macro found on https://tty1.net/blog/2008/avr-gcc-optimisations_en.html
73 // This allows processing pointers to SRAM data be performed directly from Y, Z registers
74 // this may optimize code size on some circumstances
75 #define FIX_BASE_POINTER(_ptr) __asm__ __volatile__("" : "=b"(_ptr) : "0"(_ptr))
76 
85 namespace interrupt
86 {
88  template<typename Handler> void register_handler(Handler&);
89  template<typename Handler> class HandlerHolder
90  {
91  public:
92  static Handler* handler()
93  {
94  return handler_;
95  }
96 
97  using Holder = HandlerHolder<Handler>;
98 
99  template<typename Ret, typename... Args> struct ArgsHolder
100  {
101  template<Ret (Handler::*Callback)(Args...)> struct CallbackHolder
102  {
103  static Ret handle(Args... args)
104  {
105  Handler* handler_instance = Holder::handler();
106  FIX_BASE_POINTER(handler_instance);
107  return (handler_instance->*Callback)(args...);
108  }
109  };
110  };
111 
112  private:
113  static Handler* handler_;
114  friend void register_handler<Handler>(Handler&);
115  };
116 
117  template<typename Handler> Handler* HandlerHolder<Handler>::handler_ = nullptr;
118 
119  // Used by ISR to perform a callback to a PTMF
120  // Found great inspiration for this pattern there:
121  // https://stackoverflow.com/questions/9779105/generic-member-function-pointer-as-a-template-parameter
122  template<typename T, T> struct CallbackHandler;
123  template<typename HANDLER, typename RET, typename... ARGS, RET (HANDLER::*CALLBACK)(ARGS...)>
124  struct CallbackHandler<RET (HANDLER::*)(ARGS...), CALLBACK>
125  {
126  static RET call(ARGS... args)
127  {
128  // NOTE the following line does not compile, it must be broken down for the compiler to understand
129  // return HandlerHolder<HANDLER>::ArgsHolder<RET, ARGS...>::CallbackHolder<CALLBACK>::handle(args...);
130  using HOLDER = HandlerHolder<HANDLER>;
131  using ARGS_HOLDER = typename HOLDER::template ArgsHolder<RET, ARGS...>;
132  using CALLBACK_HOLDER = typename ARGS_HOLDER::template CallbackHolder<CALLBACK>;
133  return CALLBACK_HOLDER::handle(args...);
134  }
135  };
136  template<typename RET, typename... ARGS, RET (*CALLBACK)(ARGS...)>
137  struct CallbackHandler<RET (*)(ARGS...), CALLBACK>
138  {
139  static RET call(ARGS... args)
140  {
141  return CALLBACK(args...);
142  }
143  };
145 
157  template<typename Handler> void register_handler(Handler& handler)
158  {
159  HandlerHolder<Handler>::handler_ = &handler;
160  }
161 }
162 
164 
165 // Macro often used to build vector names from parameters
166 #define CAT3(X, Y, Z) X##Y##Z
167 
169 
170 #endif /* INTERRUPTS_HH */
171 
interrupt
Defines API to handle AVR interruptions.
Definition: int.h:100
interrupt::register_handler
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Definition: interrupts.h:157