How to do that?
Thanks.
Can I pass parameter to Timer callback?
Re: Can I pass parameter to Timer callback?
Not directly.
You can make the timer callback a bound method in a class. This example shows how this is done:
https://github.com/dhylands/upy-example ... eat_irq.py
So the timer callback function has to take exactly 1 argument, which is the timer object that the IRQ is being called for. However, since the callback is bound to self, you can reference self.ticks and self.led from within the timer callback.
You can make the timer callback a bound method in a class. This example shows how this is done:
https://github.com/dhylands/upy-example ... eat_irq.py
So the timer callback function has to take exactly 1 argument, which is the timer object that the IRQ is being called for. However, since the callback is bound to self, you can reference self.ticks and self.led from within the timer callback.
-
- Posts: 2
- Joined: Thu Apr 23, 2020 11:35 am
Re: Can I pass parameter to Timer callback?
t1 = Timer(1)
z = 400
t1.init(period=2000, mode=Timer.ONE_SHOT, callback=lambda b: test(z))
it work for me
z = 400
t1.init(period=2000, mode=Timer.ONE_SHOT, callback=lambda b: test(z))
it work for me
-
- Posts: 144
- Joined: Mon Jul 25, 2022 9:45 pm
Re: Can I pass parameter to Timer callback?
@davidsmith, How did it work? Using lambda? What does the callback declaration look like? Your example is incomplete. Can you show the callback declaration please?
-
- Posts: 144
- Joined: Mon Jul 25, 2022 9:45 pm
Re: Can I pass parameter to Timer callback?
Figured it out, you just qualify the argument list as usual for the call back, so lambda t: SOME_FUNCTION(SOME_ARGUMENT) for example.
Re: Can I pass parameter to Timer callback?
You can reach this with minimal effort.
Many functions we use in Micropython are implemented in C to save space on the Microcontroller.
If any possible use-case is implemented by Micropython, the firmware won't fit on all Microcontrollers.
- Anonymous function: lambda
Code: Select all
from machine import Timer my_callback = lambda timer: print(42) Timer(1).init(mode=Timer.ONE_SHOT, period=1000, callback=my_callback)
- Normal function
Code: Select all
from machine import Timer def my_callback(timer): print(42) Timer(1).init(mode=Timer.ONE_SHOT, period=1000, callback=my_callback)
- With a closure (modified):
Code: Select all
from machine import Timer def timer_partial(func, *args, **kwargs): # added timer as a mandatory argument # to filter it out def inner(timer, *iargs, **ikwargs): return func(*args, *iargs, **kwargs, **ikwargs) return inner Timer(1).init(mode=Timer.ONE_SHOT, period=1000, callback=timer_partial(print, "Hello World", end="=======\n"))
- With a class:
Code: Select all
from machine import Timer class MyCallback: def __init__(self, value): self.value = value def callback(self, timer): """ Callback is called by Timer. The first argument is the instance of the class The second argument is the instance of the timer, which is not used here """ print("===", self.value, "===") def __call__(self, timer): """ This enables the possibility to call the instance directly. """ self.callback(timer) def __repr__(self): """ Method to have a nice representation, but it's not required. """ return f"{self.__class__.__name__}(value={self.value})" my_callback = MyCallback(1337) # works, because of the __call__ method: Timer(1).init(mode=Timer.ONE_SHOT, period=1000, callback=my_callback) # without having the __call__ method: Timer(1).init(mode=Timer.ONE_SHOT, period=1000, callback=my_callback.callback)
Code: Select all
from time import sleep
from machine import Timer
def partial(func, *args, **kwargs):
def inner(*iargs, **ikwargs):
return func(*args, *iargs, **kwargs, **ikwargs)
return inner
class TimerCallback:
_instances = []
__slots__ = ("_timer", "_callbacks", "_id", "delay", "mode")
def __init__(self, id, delay, mode=Timer.PERIODIC):
if id in self._instances:
raise RuntimeError(f"Timer with id {id} exists already")
self.delay = delay
self.mode = mode
self._id = id
self._callbacks = []
self._timer = Timer(id)
self._instances.append(id)
def _callback(self, timer):
for callback in self._callbacks:
callback()
def start(self):
self._timer.init(mode=self.mode, period=self.delay, callback=self._callback)
def stop(self):
self._timer.deinit()
def add_callback(self, callback, *args, **kwargs):
if not callable(callback):
raise TypeError("Callback must be callable")
prepared_callback = partial(callback, *args, **kwargs)
self._callbacks.append(prepared_callback)
return prepared_callback
def del_callback(self, prepared_callback):
if prepared_callback in self._callbacks:
self._callbacks.remove(prepared_callback)
def kill(self):
self._timer.deinit()
if self._id in self._instances:
self._instances.remove(self._id)
tc = TimerCallback(1, 5000)
tc.add_callback(print, "Hello", "World", sep="\t", end="\n\n\n\n")
my_callback_reference = tc.add_callback(print, "Hello World 2")
tc.start()
sleep(11)
tc.stop()
try:
tc2 = TimerCallback(1, 300)
except RuntimeError as e:
print(e.args[0])
tc.kill()
# will remove also the id
try:
tc2 = TimerCallback(1, 3000)
except RuntimeError as e:
print(e.args[0])
tc2.add_callback(print, "Lesser args")
tc2.start()
sleep(12)
tc2.kill()
If any possible use-case is implemented by Micropython, the firmware won't fit on all Microcontrollers.