FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
interrupts.h
Go to the documentation of this file.
1// Copyright 2016-2023 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))
77
85namespace interrupt
86{
88 template<typename Handler> void register_handler(Handler&);
89 template<typename Handler> void unregister_handler(Handler&);
90
91 template<typename Handler> class HandlerHolder
92 {
93 public:
94 static Handler* handler()
95 {
96 return handler_;
97 }
98
99 using Holder = HandlerHolder<Handler>;
100
101 template<typename Ret, typename... Args> struct ArgsHolder
102 {
103 template<Ret (Handler::*Callback)(Args...)> struct CallbackHolder
104 {
105 static Ret handle(Args... args)
106 {
107 Handler* handler_instance = Holder::handler();
108 FIX_BASE_POINTER(handler_instance);
109 return (handler_instance->*Callback)(args...);
110 }
111 static Ret safe_handle(Args... args)
112 {
113 Handler* handler_instance = Holder::handler();
114 if (handler_instance == nullptr)
115 return Ret{};
116 FIX_BASE_POINTER(handler_instance);
117 return (handler_instance->*Callback)(args...);
118 }
119 };
120 };
121
122 private:
123 static Handler* handler_;
124 friend void register_handler<Handler>(Handler&);
125 friend void unregister_handler<Handler>(Handler&);
126 };
127
128 template<typename Handler> Handler* HandlerHolder<Handler>::handler_ = nullptr;
129
130 // Used by ISR to perform a callback to a PTMF
131 // Found great inspiration for this pattern there:
132 // https://stackoverflow.com/questions/9779105/generic-member-function-pointer-as-a-template-parameter
133 template<typename T, T> struct CallbackHandler;
134 template<typename HANDLER, typename RET, typename... ARGS, RET (HANDLER::*CALLBACK)(ARGS...)>
135 struct CallbackHandler<RET (HANDLER::*)(ARGS...), CALLBACK>
136 {
137 static RET call(ARGS... args)
138 {
139 // NOTE the following line does not compile, it must be broken down for the compiler to understand
140 // return HandlerHolder<HANDLER>::ArgsHolder<RET, ARGS...>::CallbackHolder<CALLBACK>::handle(args...);
141 using HOLDER = HandlerHolder<HANDLER>;
142 using ARGS_HOLDER = typename HOLDER::template ArgsHolder<RET, ARGS...>;
143 using CALLBACK_HOLDER = typename ARGS_HOLDER::template CallbackHolder<CALLBACK>;
144 return CALLBACK_HOLDER::handle(args...);
145 }
146 static RET safe_call(ARGS... args)
147 {
148 // NOTE the following line does not compile, it must be broken down for the compiler to understand
149 // return HandlerHolder<HANDLER>::ArgsHolder<RET, ARGS...>::CallbackHolder<CALLBACK>::handle(args...);
150 using HOLDER = HandlerHolder<HANDLER>;
151 using ARGS_HOLDER = typename HOLDER::template ArgsHolder<RET, ARGS...>;
152 using CALLBACK_HOLDER = typename ARGS_HOLDER::template CallbackHolder<CALLBACK>;
153 return CALLBACK_HOLDER::safe_handle(args...);
154 }
155 };
156 template<typename RET, typename... ARGS, RET (*CALLBACK)(ARGS...)>
157 struct CallbackHandler<RET (*)(ARGS...), CALLBACK>
158 {
159 static RET call(ARGS... args)
160 {
161 return CALLBACK(args...);
162 }
163 static RET safe_call(ARGS... args)
164 {
165 return CALLBACK(args...);
166 }
167 };
169
185 template<typename Handler> void register_handler(Handler& handler)
186 {
187 HandlerHolder<Handler>::handler_ = &handler;
188 }
189
207 template<typename Handler> void unregister_handler(Handler& handler)
208 {
209 if (HandlerHolder<Handler>::handler_ == &handler)
210 HandlerHolder<Handler>::handler_ = nullptr;
211 }
212}
213
215
216// Macro often used to build vector names from parameters
217#define CAT3(X, Y, Z) X##Y##Z
218
220
221#endif /* INTERRUPTS_HH */
Defines API to handle AVR interruptions.
Definition: int.h:100
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Definition: interrupts.h:185
void unregister_handler(Handler &handler)
Unregister a class instance that was previously registered with interrupt::register_handler.
Definition: interrupts.h:207