3

I want to use the Ticker library of the ESP8266 Arduino core to (asynchronously) delay the switch of a pin to a desired state like below. I am not sure about the "here is" function definitions and I am having a hard time to find some documentation. Please have a look at what I tried so far:

#include <Ticker.h>

Ticker change_pin;

...

    uint8_t desired_state = 1;
    ...
    change_pin.attach_ms(100, [](uint8_t state_to_change_to){
        if( digitalRead(PIN) != state_to_change_to ) {
            digitalWrite(PIN, state_to_change_to);
        }
        else {
            change_pin.detach();
        }
    }, desired_state);

But the compiler's yelling:

espIKEA:145: error: no matching function for call to 'Ticker::attach_ms(int, toogle_light(uint8_t)::__lambda0, uint8_t&)'

   }, des_state);

               ^

...

C:\Users\USER\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\Ticker/Ticker.h:45:7: note:   candidate expects 2 arguments, 3 provided

C:\Users\USER\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\Ticker/Ticker.h:62:7: note: template<class TArg> void Ticker::attach_ms(uint32_t, void (*)(TArg), TArg)

  void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)

       ^

C:\Users\USER\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\Ticker/Ticker.h:62:7: note:   template argument deduction/substitution failed:

C:\Users\USER\Documents\Arduino\Scratch\pintest\pintest.ino:145:15: note:   mismatched types 'void (*)(TArg)' and 'toogle_light(u8)::__lambda0'

   }, des_state);

               ^

So, I am having too few knowledge to understand what to do about it. I really would like to avoid having a separate function for the callback body.

PS: Important source file can be found here: Ticker.h

1

The function you are trying to call is a template function:

template<typename TArg>
void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
{
    ....
}

So, you need to tell it what type of parameter you are passing:

change_pin.attach_ms<uint8_t>(100, [](uint8_t state_to_change_to) {
//                     ^- tell the compiler about the parameter
    ....
}, desired_state);

To pass more than one parameter: Since the library only allows one parameter, I would create a struct and pass a pointer to it.

struct callback_parameter {
    int i;
    char *p;
};

Then create one of these structs and pass the address of it. You just have to make sure the struct is valid the entire time the timer is running. So either use new, static, or make it global.

callback_parameter param; // global variable

...

change_pin.attach_ms<callback_parameter *>(100, [](callback_parameter * state_to_change_to) {
    ....
}, &param);
  • compiles now. thank you! what about passing multiple parameters? <uint8_t, char*> ? – milkpirate Jun 13 '17 at 13:30
  • @milkpirate I've updated the answer. – Johnny Mopp Jun 13 '17 at 13:47
0

It looks like you are trying to do a lambda function and that's a bit too modern for the Arduino compiler.

So you have:

change_pin.attach_ms(100, ????, desired_state);

Its just the ???? we need to sort, which you have:

void DoStuff (state_to_change_to)
{
    if( digitalRead(PIN) != state_to_change_to ) 
    {
        digitalWrite(PIN, state_to_change_to);
    }
    else 
    {
        change_pin.detach();
    }
}

Now you can't just define your own function signature, it has to be either callback_t or callback_with_arg_t. So to make your "DoSTuff" function comply with callback_with_arg_t you have to define it as:

void DoStuff (void* argument);

Which means inside you function you will have to do this:

void DoStuff (void* argument)
{
    if (argument != NULL)
    {
       const uint8_t state_to_change_to = *argument;
       if( digitalRead(PIN) != state_to_change_to ) 
       .... As above.

Does that make sense?

The library defines the signature of the function that acts as the call back, it has to otherwise it wouldn't be able to provide all the parameters. void* gets around any pretence at type safe behaviour and is fine as long as you are careful to control what can get passed through those parameters. Always remember if you are working asynchronously there is no guarantee that data will still exist when you process it, if its dynamic memory it could have been freed/deleted or variables can go out of scope.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.