Lambda timer

I have written this snippet of code using the lambda function

//CODE//
void SquareWave(int pin,
                unsigned long offtime,
                unsigned long ontime,
                int Vpinled,
                float flow1,
                float flow2)
{
  analogWrite(pin, flow1);
  Blynk.virtualWrite(Vpinled, 0);
  timer.setTimeout(ontime, []()
  {
    analogWrite(pin, flow2);
    Blynk.virtualWrite(Vpinled, 255);
  });
}

//ERROR MESSAGE//

Arduino: 1.8.9 (Windows 10), Board: "LOLIN(WEMOS) D1 R2 & mini, 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:2MB OTA:~1019KB), v2 Lower Memory, Disabled, None, Only Sketch, 921600"

C:\Users\proie\Dropbox\ARDUINO\arduino 1.8.9\AQUART_BLYNK_COMPUTER\WAVEMAKER_PLUGBAR\WAVEMAKER_PLUGBAR.ino:55:33: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

 SNTPtime NTPch("uk.pool.ntp.org");

                                 ^

C:\Users\proie\Dropbox\ARDUINO\arduino 1.8.9\AQUART_BLYNK_COMPUTER\WAVEMAKER_PLUGBAR\FUNCTION.ino: In lambda function:

FUNCTION:629:17: error: 'pin' is not captured

     analogWrite(pin, flow2);

                 ^

FUNCTION:629:22: error: 'flow2' is not captured

     analogWrite(pin, flow2);

                      ^

FUNCTION:630:24: error: 'Vpinled' is not captured

     Blynk.virtualWrite(Vpinled, 255);

                        ^

exit status 1
'pin' is not captured

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Does anybody know why ā€œpin is not capturedā€?

You can modify the code as follows:


void SquareWave(int pin,
                unsigned long offtime,
                unsigned long ontime,
                int Vpinled,
                float flow1,
                float flow2)
{
  // to pass parameters to lambda function. You can use global vars
  static    int   _pin      = pin;
  static    int   _Vpinled  = Vpinled;
  static  float   _flow2    = flow2;

  analogWrite(pin, flow1);
  Blynk.virtualWrite(Vpinled, 0);

  timer.setTimeout(ontime, []()
  {
    analogWrite(_pin, _flow2);
    Blynk.virtualWrite(_Vpinled, 255);
  });
}

Lambda function, if using parameters, not global or static, inside the function, is a little bit complicated, and will create non-captured errors as you experienced. If you need more info, please read

https://en.cppreference.com/w/cpp/language/lambda

captures - a comma-separated list of zero or more captures, optionally beginning with a capture-default.
See below for the detailed description of captures.

A lambda expression can use a variable without capturing it if the variable

  • is a non-local variable or has static or thread local storage duration (in which case the variable cannot be captured), or
  • is a reference that has been initialized with a constant expression.

A lambda expression can read the value of a variable without capturing it if the variable

  • has const non-volatile integral or enumeration type and has been initialized with a constant expression, or
  • is constexpr and has no mutable members.
1 Like

Thanks for that

Just tested thisā€¦ it works thanks a lot.

Just one more question is it possible to put a lambda timer within a lambda timer ie.
timer.setTimeout(xxxxL,
{
do some actionā€¦
timer.setTimeout(yyyyL,
{
do some action
}));

  timer.setTimeout(time2, []()
  {
    do some action
    timer.setTimeout(time2, []()
    {
      do some action
  })});

Certainly if you have very very good reason to do so, you can apply the same capture rules to have them cascading.

For example

void SquareWave(int pin,
                unsigned long offtime,
                unsigned long ontime,
                int Vpinled,
                float flow1,
                float flow2)
{
  // to pass parameters to lambda function. You can use global vars
  static  int           _pin      = pin;
  static  int           _Vpinled  = Vpinled;
  static  float         _flow1    = flow1;
  static  float         _flow2    = flow2;
  static  unsigned long _ontime   = ontime;
  static  unsigned long _offtime  = offtime;

  analogWrite(pin, flow1);
  Blynk.virtualWrite(Vpinled, 0);

  timer.setTimeout(_ontime, []()
  {
    analogWrite(_pin, _flow2);
    Blynk.virtualWrite(_Vpinled, 255);
    
    timer.setTimeout(_offtime, []()
    {
      analogWrite(_pin, _flow1);
      Blynk.virtualWrite(_Vpinled, 0);
    });
  });
}

But the more I know about lambda function, the less Iā€™m using as I donā€™t see the real reason to use it.
IMHO, when we write code, we try to make it easily portable, readable, understandable and not error-prone.
The lambda function is just a decorating pet. Without the lambda function, the programming community still survive well. If you still insist to use it, you have to check why and might need a better design.
You can see that you have to unnecessarily declare variables static or global. For system with less memory (UNO/Nano/Mega), you can have not enough memory issues, compared to when youā€™re using dynamic allocating memory (stack).

1 Like

Thanks for your response. Very Imformative.

@khoih Here is another issue relating to the Lambda timer if you could explain

CODE
//NIGHT STATES//////////////////////////////////////////////////////////////////////////
      case wNIGHT_1P:
      {
        unsigned long DayPeriod = svNightSTART - svNightSTOP;   //Total day period in secs
        unsigned long NightPeriod = DaySecs - DayPeriod;        //Total night period in secs
        unsigned long NightMillis = NightPeriod * 1000;
        
        Blynk.virtualWrite(V12, (svMinFlow*100)/1023);
        Blynk.virtualWrite(V13, 0);
        analogWrite(PUMP1, svMinFlow);
        timer.setTimeout(NightMillis, []()
        {
          WaveState = SWITCH; 
        });
      }
      break;

      case wNIGHT_2P:
      {
        unsigned long DayPeriod = svNightSTART - svNightSTOP;   //Total day period in secs
        unsigned long NightPeriod = DaySecs - DayPeriod;        //Total night period in secs
        unsigned long NightMillis = NightPeriod * 1000;
        
        Blynk.virtualWrite(V12, (svMinFlow*100)/1023);
        Blynk.virtualWrite(V13, (svMinFlow*100)/1023);
        analogWrite(PUMP1, svMinFlow);
        analogWrite(PUMP2, svMinFlow);
        timer.setTimeout(NightMillis, []()
        {
          WaveState = SWITCH; 
        });
      }
      break;

ā€œjump to case label [-fpermissive]ā€ What does this mean?

Shouldnā€™t your break command be within the curly brackets that explicitly define the case definition?
As it is, it seems to be ā€˜floatingā€™ in no manā€™s land.

Pete.

Ahhhhhhā€¦ā€¦Of course!!