This is probably easy for many of you, but I am at a loss as to how Lambda/anonymous function work.
While I may not attempt to use this in any of my code in the near future, It intrigues me and I am spending way too much time trying to grasp how to trigger this lambda/anonymous function What am I missing.
I have read many examples but none are geared towards Arduino. I have used similar code in Javascript like JQuery but it isn't quite working for me to grasp what I am missing.
Lambda:
[a](int a) {Serial.print(a); };
This compiles but I cant get Serial.print(a); to trigger.
I assume it needs to be a part of some other function but how do I make that work?
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop() {
int a =1;
[a](int a) {Serial.print(a); };
Serial.println(".");
delay(100);
}
What brought this up is with the ESP8266 and the spi interface as a slave uses this coding. I would like to .understand it enough to possibly use it with the UNO also
ESP8266 Example:
/*
SPI Slave Demo Sketch
Connect the SPI Master device to the following pins on the esp8266:
GPIO NodeMCU Name | Uno
===================================
15 D8 SS | D10
13 D7 MOSI | D11
12 D6 MISO | D12
14 D5 SCK | D13
Note: If the ESP is booting at a moment when the SPI Master has the Select line HIGH (deselected)
the ESP8266 WILL FAIL to boot!
See SPISlave_SafeMaster example for possible workaround
*/
#include "SPISlave.h"
uint8_t* _Source = (const uint8_t*)(const void*)&SPIB;
void setup()
{
Serial.begin(115200);
Serial.setDebugOutput(true);
// data has been received from the master. Beware that len is always 32
// and the buffer is autofilled with zeroes if data is less than 32 bytes long
// It's up to the user to implement protocol for handling data length
SPISlave.onData([](uint8_t * _Source, size_t len) {
SPISlave.setData(_Source);
Serial.printf("Question: %s\n", (char *)_Source);
});
// The master has read out outgoing data buffer
// that buffer can be set with SPISlave.setData
SPISlave.onDataSent([]() {
Serial.println("Answer Sent");
});
// status has been received from the master.
// The status register is a special register that bot the slave and the master can write to and read from.
// Can be used to exchange small data or status information
SPISlave.onStatus([](uint32_t data) {
Serial.printf("Status: %u\n", data);
SPISlave.setStatus(millis()); //set next status
});
// The master has read the status register
SPISlave.onStatusSent([]() {
Serial.println("Status Sent");
});
// Setup SPI Slave registers and pins
SPISlave.begin();
// Set the status register (if the master reads it, it will read this value)
SPISlave.setStatus(millis());
// Sets the data registers. Limited to 32 bytes at a time.
// SPISlave.setData(uint8_t * data, size_t len); is also available with the same limitation
SPISlave.setData("Ask me a question!");
}
void loop() {}
[quote author=Nick Gammon date=1479796246 link=msg=3010912]
Arduino uses C++. So there is nothing specifically "Arduino" about your question.
I don't see where you are calling your function.[/quote]
except I can't get figure out how to get the "calling" thing to work lol I have tried using other C++ code examples that are out there and should work but nothing complies when i try to use it in the arduino environment. Please give me the clue I am missing. How to call a lambda/anonymous function that will compile in the arduino environment. I rarely have this type of struggle I can usually figure it out but this is eluding me :o
[quote author=Nick Gammon date=1479797965 link=msg=3010937]
See this C++11 - Lambda Closures, the Definitive Guide - Cprogramming.com
You are making a lambda function but you aren't calling it.
This is nothing to do with "the arduino environment". It is C++11 stuff.[/quote]
Thank you! I was at whits end. I understand that its not specifically Arduino, but I have not found anything that works with arduino that isn't extremely complex or completely undocumented and confusing. Thank you for this link I greatly appreciate the help. I will attempt to create a simple example that works with arduino Uno, Document it well and post it for others to discover.
Z
A lambda might be more usefully used where you want an inline function such as a callback. For example, to sort some numbers:
const int COUNT = 10;
int someNumbers [COUNT] = { 7342, 54, 21, 42, 18, -5, 30, 998, 999, 3 };
void setup ()
{
Serial.begin (115200);
Serial.println ();
// sort using inline compare function
qsort (someNumbers, COUNT, sizeof (int),
// inline lambda to do comparisons
[] (const void * arg1, const void * arg2)
{
int * a = (int *) arg1; // cast to pointers to int
int * b = (int *) arg2;
// a less than b?
if (*a < *b)
return -1;
// a greater than b?
if (*a > *b)
return 1;
// must be equal
return 0;
} // end of lambda function
);
for (int i = 0; i < COUNT; i++)
Serial.println (someNumbers [i]);
} // end of setup
void loop () { }
Read this - basically it lets you set up a function with a "closure" - that is, when it is closed it gets a copy of an external variable. They do have their uses.
AWOL:
I have to agree; the syntax looks strained.
The "[]" seems to set you up for some sort of array.
Then it all turns to poo.
Not going to dispute the syntax issue, but in desktop C++ programs anonymous functions work great with STL algorithms. If you're using something like find_if with a predicate you only use once at that point, instead of making a named function somewhere else that you need to hunt down you can inline it with a lambda like Nick showed with qsort.
Without a port of std::function though I imagine it's of very limited usefulness.
This is wonderful! Thank you Nick Gammon, Jiggy-Ninja and AWOL for your contribution to my understanding. Especially you Nick Gammon having code that actually compiles and works has given me an understanding I was lacking.
now my question is how to create a function that I can use Lambda in like SPISlave does :
void setup()
{
// status has been received from the master.
// The status register is a special register that bot the slave and the master can write to and read from.
// Can be used to exchange small data or status information
SPISlave.onStatus(
// inline lambda
[](uint32_t data) {
Serial.printf("Status: %u\n", data);
SPISlave.setStatus(data); //set next status
} // end of lambda function
);
}
The class function SPISlave.onStatus() is this accepting a callback function? SPISlave library
in the .h file
typedef std::function<void(uint32_t status)> SpiSlaveStatusHandler;
...
SpiSlaveStatusHandler _status_cb;
------------------------------------------------------------------------
int the .cpp file
void SPISlaveClass::onStatus(SpiSlaveStatusHandler cb)
{
_status_cb = cb;
}
void SPISlaveClass::_status_rx(uint32_t data)
{
if(_status_cb) {
_status_cb(data);
}
}
As I see this, the lambda function is created as an anonymous lambda function and then stored in _status_cb or at least a pointer to it. now later on this can be ran when the _status_rx() is triggered and data is passed to the lambda function.
Wow.. am I close?
Had another idea :o :
attachInterrupt() can accept lambda function as its second argument!!! I Get how to do this!!! Thank you!
#define interruptPin 2
volatile unsigned long timeX = 1;
volatile unsigned long LastTime;
volatile int PulseCtrX;
void setup() {
attachInterrupt(digitalPinToInterrupt(interruptPin),
// inline lambda
[]() {
unsigned long Time;
Time = micros();
timeX = (Time - LastTime); // this time is accumulative between readings
LastTime = Time;
PulseCtrX ++; // will usually be 1 unless something else delays the use of hte sample
} // end of lambda function
, FALLING); // end of attachInterrupt()
}
void loop() {
// Other code to handle tachometer input
}
Lambda Blink without Delay!!! with Call Back example!
typedef void (*voidFuncPtr)(void);// Create a type to point to a function.
static volatile voidFuncPtr _CallBackFunctionPointer; // Create an instance of the empty function pointer
void BlinkIt(volatile voidFuncPtr CallBackFunctionPointer) {
_CallBackFunctionPointer= CallBackFunctionPointer; // assign a function to the empty function pointer
}
void Blink(unsigned long msDelaTime) {
if (CallBackFunctionPointer) {
static unsigned long _ATimer;
if ( (unsigned long)(millis() - _ATimer) >= (msDelaTime)) {
_ATimer = millis();
_CallBackFunctionPointer(); // call the function we assigned to the once empty function pointer
}
}
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
BlinkIt(// BlinkIt takes a function for an Input we are going to use a lambda function
// Lambda function Starting here
[]() {
digitalWrite(13, !digitalRead(13));
} // Lambda function ends here
); // end of BlinkIt function
}
void loop() {
Blink(1000);
}
Help me correct my terminology. I am self taught Except for 1 C programming class back in 1992
That is awsome. I could have sworn I had trouble using lambdas with a function pointer before and I couldn't get it to work. That you for posting something that works.