Hey guys!
I have been using my Photons for day, and I have found a problem. My code will compile and flash, but whenever I call one of the cloud functions from my library the Photon crashes. I have included the tinker framework into my code, and it does not crash when one of its cloud functions is called.
In the .cpp file, I had to write the cloud functions like this to make it want to compile.
int moveNeckCloud(String data);
int moveRightCloud(String data);
int moveLeftCloud(String data);
int moodlightsCloud(String red, String green, String blue);
int slaveToggle(String data);
I don’t know why this is happening. It’s probably something to do with the rest of my code. If anyone wants to create a pull request, here is the Github Link.
You can use the arguments to make them do different things though. I see three ‘move’ functions, which can be combined into one, should you send the direction in the argument.
I think this is because of the conversions that happen in order to make the code compile. This also happens with Spark.subscribe() and and atttachInterrupt()
Compiling code for photon
Including:
/home/nrobinson/github/sparkbot-default/firmware/main.ino
/home/nrobinson/github/sparkbot-default/firmware/sparkbot-default.h
/home/nrobinson/github/sparkbot-default/firmware/sparkbot-default.cpp
attempting to compile firmware
pushing file: /home/nrobinson/github/sparkbot-default/firmware/main.ino
pushing file: /home/nrobinson/github/sparkbot-default/firmware/sparkbot-default.h
pushing file: /home/nrobinson/github/sparkbot-default/firmware/sparkbot-default.cpp
Errors
sparkbot-default.cpp: In member function 'void sparkbot::begin()':
sparkbot-default.cpp:53:60: warning: converting from 'int (sparkbot::)(String)' to 'int ()(String)' [-Wpmf-conversions]
Spark.function("moveServos", (int ()(String))&sparkbot::moveCloud);
^
sparkbot-default.cpp:54:60: warning: converting from 'int (sparkbot::)(String)' to 'int ()(String)' [-Wpmf-conversions]
Spark.function("moodlights", (int ()(String))&sparkbot::moodlightsCloud);
^
sparkbot-default.cpp:55:61: warning: converting from 'int (sparkbot::)(String)' to 'int ()(String)' [-Wpmf-conversions]
Spark.function("enableSlave", (int ()(String))&sparkbot::slaveToggle);
^
sparkbot-default.cpp:57:58: warning: converting from 'void (sparkbot::)(const char*, const char*)' to 'EventHandler {aka void ()(const char, const char*)}' [-Wpmf-conversions]
Spark.subscribe("syncServos", (EventHandler)&sparkbot::syncServosSlave, MY_DEVICES);
^
sparkbot-default.cpp:58:51: warning: converting from 'void (sparkbot::)(const char, const char*)' to 'EventHandler {aka void ()(const char, const char*)}' [-Wpmf-conversions]
Spark.subscribe("RGB", (EventHandler)&sparkbot::RGBSlave, MY_DEVICES);
^
sparkbot-default.cpp: In member function 'void sparkbot::startLeftButton()':
sparkbot-default.cpp:400:65: warning: converting from 'void (sparkbot::)()' to 'raw_interrupt_handler_t {aka void ()()}' [-Wpmf-conversions]
attachInterrupt(LEFTBUTTON, (raw_interrupt_handler_t)&sparkbot::switchLights, RISING);
^
sparkbot-default.cpp: In member function 'void sparkbot::startRightButton()':
sparkbot-default.cpp:405:66: warning: converting from 'void (sparkbot::)()' to 'raw_interrupt_handler_t {aka void ()()}' [-Wpmf-conversions]
attachInterrupt(RIGHTBUTTON, (raw_interrupt_handler_t)&sparkbot::sync, RISING);
^
make[1]: *** [../build/target/user/platform-6sparkbot-default.o] Error 1
make: *** [user] Error 2
Well I wish Mat was back from vacation, but I think you are running into the difference between calling a C function and calling C++ method. Spark.function() is always called in with C calling conventions.
The short answer is you need a C wrapper function around your C++ methods to make this work. You can put these wrappers in your C++ class file if you declare them as extern “C” them so the linker knows what to do.
// auto means: let the compile figure out what kind of std::function needs to be created
auto moveNeckCloudHandler = std::bind(&sparkbot::moveNeckCloud, &sb, std::placeholders::_1);
Spark.function("moveNeck", moveNeckCloudHandler);
Full example:
class Service {
public:
int handler(String arg) {
return 0;
}
};
Service myService;
void setup() {
// See http://stackoverflow.com/questions/7582546/using-generic-stdfunction-objects-with-member-functions-in-one-class
// auto is replaced by std::function<int(String)>
// std::placeholders::_1 is necessary for a method taking 1 argument
auto serviceHandler = std::bind(&Service::handler, &myService, std::placeholders::_1);
Spark.function("test", serviceHandler);
}
void loop() {
}
Thank you very much, I am trying this, but always get this error.
sparkbot-default.cpp:64:44: error: no matching function for call to 'CloudClass::function(const char [11], std::_Bind<std::_Mem_fn(sparkbot*, std::_Placeholder<1>)>*)'
Spark.function("moveServos", &moveWrapper);
I was trying the way that @bko mentioned. Now I am trying the way that you are suggesting when I made that reply, I was using moveWrapper as the name of the handler, similar to the example you gave.
sparkbot-default.cpp:64:44: error: no matching function for call to 'CloudClass::function(const char [11], std::_Bind<std::_Mem_fn<int (sparkbot::)(String)>(sparkbot, std::_Placeholder<1>)>*)'
Spark.function("moveServos", &moveHandler);
^
sparkbot-default.cpp:64:44: error: no matching function for call to 'CloudClass::function(const char [11], std::_Bind<std::_Mem_fn<int (sparkbot::*)(String)>(sparkbot*, std::_Placeholder<1>)>*)'
Spark.function("moveServos", &moveHandler);
^
sparkbot-default.cpp:64:44: note: candidates are:
In file included from ../wiring/inc/spark_wiring.h:45:0,
from ./inc/application.h:29,
from sparkbot-default.h:1,
from sparkbot-default.cpp:1:
../wiring/inc/spark_wiring_cloud.h:49:17: note: static bool CloudClass::function(const char*, int (*)(String))
static bool function(const char *funcKey, user_function_int_str_t* func)
^
../wiring/inc/spark_wiring_cloud.h:49:17: note: no known conversion for argument 2 from 'std::_Bind<std::_Mem_fn<int (sparkbot::*)(String)>(sparkbot*, std::_Placeholder<1>)>*' to 'int (*)(String)'
../wiring/inc/spark_wiring_cloud.h:54:17: note: static bool CloudClass::function(const char*, user_std_function_int_str_t, void*)
static bool function(const char *funcKey, user_std_function_int_str_t func, void* reserved=NULL)
^
../wiring/inc/spark_wiring_cloud.h:54:17: note: no known conversion for argument 2 from 'std::_Bind<std::_Mem_fn<int (sparkbot::*)(String)>(sparkbot*, std::_Placeholder<1>)>*' to 'user_std_function_int_str_t {aka std::function<int(String)>}'