I am trying to use a timer to repeatedly change the PWM Output over time to have a smooth transition when the brightness changes. I keep getting this error when trying to compile the code:
/Users/jt/Documents/Arduino/libraries/SingleColorLight/SingleColorLight.cpp: In constructor 'CSingleColorLight::CSingleColorLight(int)':
/Users/jt/Documents/Arduino/libraries/SingleColorLight/SingleColorLight.cpp:13:58: error: cannot convert 'CSingleColorLight::DimmerCallback' from type 'void (CSingleColorLight::)(void*)' to type 'void ()(void)'
ets_timer_setfn(&Dimmer, this->DimmerCallback, NULL);
Here is my code:
class CSingleColorLight {
private:
int pin;
int intensitySetPoint;
int intensityActual;
int percentageBuffer;
ETSTimer Dimmer;
int dimmerCount;
public:
CSingleColorLight(int _pin);
bool setIntensity(int _intensity);
int getIntensity();
bool getStatus(void);
bool setStatus(bool _status);
void DimmerCallback(void*);
};
and in the cpp file:
void CSingleColorLight::DimmerCallback(void*) {
if(dimmerCount>0){
dimmerCount--;
intensityActual++;
} else if(dimmerCount<0){
dimmerCount++;
intensityActual--;
} else {
ets_timer_disarm(&Dimmer);
}
analogWrite(pin, percentageToTime[intensityActual]);
return;
}
It asks for a pointer, right? Any idea how to fix this?
Thanks a lot!
If you want DimmerCallback to take a void* argument, then you need to name it, like
void CSingleColorLight::DimmerCallback(void* x)
but you are not using the void* in the code. It looks like you should just get rid of it, so it would be
void CSingleColorLight::DimmerCallback()
int the cpp and
void DimmerCallback();
in the header.
A void* argument is a pointer that can point to any data type, it is not the same as void which is just no argument.
Related
Take this simplified example:
Command.h:
class Command {
public:
template<typename Func>
Command(Func newToExecute) : toExecute([&newToExecute](){newToExecute();}) { }
void callFunction(); //defined in Command.cpp -> calls function with toExecute();
private:
std::function<void()> toExecute;
};
Main.cpp:
void test(int var = 0) {
//does irrelevant things
}
int main() {
Command testCommand(test);
testCommand.callFunction();
return 0;
}
When trying to run this I get an error from the compiler using MinGW:
error: too few arguments to function Command(Func newToExecute) : toExecute([&newToExecute](){newToExecute();}) { }
Now I wouldn't have done all this just to save a simple void function, if this wasn't working:
//in the Command class:
Command(std::function<void()> newToExecute) : toExecute(std::move(newToExecute)) { } //rest unchanged
//in the main function:
Command testCommand([](){test();}); //rest unchanged
Coming from the last code example I see no reason, why the first one shouldn't work. Would anyone please explain why it is not working?
Edit: Missed a small detail in the working version, but still not closer to the explanation.
Your second version doesn't take the address of test. The type of that &test is void (*)(int), not void (*)().
This is also why you can't construct a std::function<void()> from test directly.
This question already has answers here:
Use class member functions as callbacks?
(6 answers)
Closed 3 years ago.
Arduino's attachInterrupt requires a callback function of type void(*)(), but I'd like to pass it a member function instead. I can't use a C++ member function here because of its implicit this argument.
Background
I know it's possible to use C++ member functions as callbacks. For example, FreeRTOS' xTaskCreate(...) takes a callback function of type void(*)(*).
isocpp.org has a nice FAQ on the use of member functions as callbacks.
In this related question user thiton writes:
Most sane callback libraries allow you to pass this void* argument to the functions as a way to have user-defined data in it
Perhaps the Arduino library is not "sane?" or perhaps this is design decision made to simplify the Arduino API?
it's there... inside attachInterrupt
I'm programming for an ESP32. In the arduino-esp32 implementation of attachInterrupt, there's a function called __attachInterruptFunctionalArg(...) that seems to do exactly what I want, but since it's not part of the Arduino API, I'm hesitant to include it in a project that's for public consumption because it may break.
Example program
// An attempt to summarize https://github.com/pierremolinaro/acan2517/issues/4
#include <stdio.h>
#include <stdint.h>
#include <functional>
#define IRAM_ATTR __attribute__((section(".iram1")))
// from `esp32-hal-gpio.c`
typedef void (*voidFuncPtrArg)(void*);
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional);
// from Arduino `FunctionalInterrupt.cpp`
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode);
void IRAM_ATTR interruptFunctional(void* arg);
// from Arduino `FunctionalInterrupt.h`
struct InterruptArgStructure {
std::function<void(void)> interruptFunction;
};
// from ACAN2517
class ACAN2517
{
public: ACAN2517 (const int interrupt_pin);
public: void begin (void (* inInterruptServiceRoutine) (void));
public: void begin_functional (void (* inInterruptServiceRoutine) (void *), void *);
public: void isr(void);
private: const int interrupt_pin;
};
ACAN2517::ACAN2517 (const int interrupt_pin):
interrupt_pin(interrupt_pin)
{};
#define FALLING 0
// This won't work with a member function
void ACAN2517::begin (void (* inInterruptServiceRoutine) (void)) {
attachInterrupt(interrupt_pin, inInterruptServiceRoutine, FALLING);
}
// This will, but is prone to breakage when the Arduino internals change
void ACAN2517::begin_functional (void (* inInterruptServiceRoutine) (void *), void *arg)
{
__attachInterruptFunctionalArg(interrupt_pin, inInterruptServiceRoutine, arg, FALLING, true);
}
void ACAN2517::isr(void)
{
printf("fhtagn");
}
//===
// User code begin
//===
#define N_DRIVERS 3
ACAN2517 g_driver(23); // Initializing a driver instance statically
ACAN2517 *drivers[N_DRIVERS];
void call_ACAN_isr(void *arg)
{
ACAN2517 *driver = (ACAN2517 *)arg;
driver->isr();
}
int main()
{
g_driver.begin( []{g_driver.isr();} ); // No problem
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
drivers[i]->begin( []{drivers[i]->isr();} );
// ERROR
// static void lambda []void ()->void::_FUN()
// an enclosing-function local variable cannot be referenced in a lambda body unless it is in the capture list
}
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
drivers[i]->begin( [i]{drivers[i]->isr();} );
// ERROR
// no suitable conversion function from "lambda []void ()->void" to "void (*)()" exists
}
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
ACAN2517 *driver = drivers[i];
drivers[i]->begin_functional( [driver]{driver->isr();}, driver);
// Not sure how to get this to work in a lambda...
}
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
ACAN2517 *driver = drivers[i];
drivers[i]->begin_functional( call_ACAN_isr, driver);
// OK
}
}
//===
// User code end
//===
// from esp32-hal-gpio.c
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional)
{
// ...
}
// from Arduino `FunctionalInterrupt.cpp`
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
{
// use the local interrupt routine which takes the ArgStructure as argument
__attachInterruptFunctionalArg (pin, (voidFuncPtrArg)interruptFunctional, new InterruptArgStructure{intRoutine}, mode, true);
}
void IRAM_ATTR interruptFunctional(void* arg)
{
InterruptArgStructure* localArg = (InterruptArgStructure*)arg;
if (localArg->interruptFunction)
{
localArg->interruptFunction();
}
}
I can't use a C++ member function here because of its implicit this argument.
Yes, that is exactly the problem and this can't be solved without extra code, if your API did not provide something what lets you store some additional data like the this pointer.
What you simply can do is:
Write your own wrapper and register the callback to the original handler. But that creates another indirection which increases the latency.
The other way is not as simple, but a bit less slow:
Write your own interrupt handler and callback registration. As you have the original sources of the arduino libs, you simply can replace the stuff around the attachInterrupt function.
Sorry, but there is no magic way to generate a data store for this without any additional software.
I am working on a Particle project and coming from JS so I'm challenged by callbacks in C++. I am trying to refactor my Firebase code into a reusable class and for this I need callbacks:
void setup() {
firebase = new Firebase;
Serial.begin(9600);
firebase->subscribe();
firebase->setCallback(readCallback);
}
void readCallback(JsonObject& root)
{
r = root["r"];
g = root["g"];
b = root["b"];
Serial.printlnf("Yes! r=%d g=%d b=%d d=%d", r, g, b);
}
Firebase.h:
#ifndef Firebase_h
#define Firebase_h
#include <SparkJson.h>
class Firebase {
public:
Firebase();
void
subscribe(),
setCallback(void (*readCallback)(JsonObject& root));
private:
static void getDataHandler(const char *topic, const char *data);
void (*_readCallback)(JsonObject& root);
};
#endif
Firebase.m:
#include "Particle.h"
// This #include statement was automatically added by the Particle IDE.
#include <SparkJson.h>
#include "ArduinoJson.h"
#include "Firebase.h"
Firebase::Firebase(void) {
Serial.printlnf("Firebase instance created");
}
void Firebase::getDataHandler(const char *topic, const char *data) {
Serial.printlnf("getDataHandler invoked");
StaticJsonBuffer<256> jsonBuffer;
char *mutableCopy = strdup(data);
JsonObject& root = jsonBuffer.parseObject(mutableCopy);
free(mutableCopy);
Serial.printlnf("data received: %s", data);
// _readCallback(root);
}
void Firebase::subscribe() {
Serial.printlnf("Firebase subscribe");
Particle.subscribe("hook-response/test3rdata", getDataHandler, MY_DEVICES);
}
void Firebase::setCallback(void (*readCallback)(JsonObject& root))
{
Serial.printlnf("set callback");
_readCallback = readCallback;
}
When getDataHandler is static everything seems to work but naturally I am having trouble accessing the callback and I get:
invalid use of member 'Firebase::_readCallback' in static member
function
When it's not static I get for this line:
Particle.subscribe("hook-response/test3rdata", getDataHandler, MY_DEVICES);
the following error:
invalid use of non-static member function
When I try to bind it as advised here:
Particle.subscribe("hook-response/test3rdata", std::bind(&Firebase::getDataHandler,this), MY_DEVICES);
I get a mistype as Particle.subscribe does not expect a binded method:
no matching function for call to 'CloudClass::subscribe(const char
[25], std::_Bind_helper::type, Spark_Subscription_Scope_TypeDef)'
Is there a way around it?
You are getting this error because std::bind returns a function object that adheres to the signature void() and not void(char const*, char const*). The reason being, that you didn't specify any placeholders for those arguments. So a quick fix would be:
std::bind(&Firebase::getDataHandler, this, std::placeholders::_1, std::placeholders::_2)
Now the bind helper expects two parameters which it will forward to the bound member function.
Having said all that, there is no reason to use std::bind if a lambda will suffice. Lambdas are in fact superior in most regards. In C++14 there's virtually no reason to use std::bind at all. And even in C++11, your use case can be dealt with by a simple lambda:
Particle.subscribe("hook-response/test3rdata", [this](char const* a, char const* b) { getDataHandler(a, b); }, MY_DEVICES);
This question already has an answer here:
g++ error: ‘vec’ does not name a type [duplicate]
(1 answer)
Closed 8 years ago.
Ok so I am trying to map some of my member functions in the .h file this is to be able to use the map when I implement the code. However, after hours I have gotten nowhere so I would like suggestions or if anyone knows how to implement this. For reference these are the errors.
./Assembler.h:51:2: error: C++ requires a type specifier for all declarations
functions["load"] = load;
^~~~~~~~~
./Assembler.h:51:12: error: size of array has non-integer type 'const char [5]'
functions["load"] = load;
^~~~~~
./Assembler.h:51:2: error: duplicate member 'functions'
functions["load"] = load;
^
As for my header file it with the problem coming from the map:
#include <vector>
#include <iostream>
#include <map>
#include <string>
#include <fstream>
using namespace std;
class Assembler {
public:
Assembler(string filename);//Argument will be passed from the os.cpp file
void parse();// Will go through the a file to output the .o file
void load();
void loadi();
void store();
void add();
void addi();
void addc();
void addci();
void sub();
void subi();
void subc();
void subci();
void ander();
void andi();
void xorer();
void xori();
void negate();
void shl();
void shla();
void shr();
void shra();
void compr();
void compri();
void getstat();
void putstat();
void jump();
void jumpl();
void jumpe();
void jumpg();
void call();
void ret();
void read();
void write();
void halt();
void noop();
private:
typedef void (*function)();
map<string, function> functions;
functions["load"] = load;
fstream in, out; //One will be the .s file while the other will be the .o file
string opcode;
int rd, rs, constant, addr, machcode; //Different parts of the instruction
};
Any help or suggestions would be appreciated. Thanks
Only static const integral data members can be initialized within a class. You probably need to move functions["load"] = load; to a function's definition.
And also, you need to change them to:
typedef void (Assembler::*function)();
...
functions["load"] = &Assembler::load;
Within C++ class declaration, you cannot have member initialiser or executable statement, Have this one
functions["load"] = load;
within constructor
Take a look at your class declaration: everything's compiling fine except
functions["load"] = load;
This is an assignment and initializes the functions map with something. That is not allowed in the declaration which is a "contract" (in the case of an interface) or "explanation" of how your class is composed and what methods/members has.
The right spot to put such an initialization is in your constructor's definition (i.e. in the part of the code that actually contains the code of your methods, specifically when the object gets created if you intend to initialize stuff.. i.e. the constructor).
I'm trying to create a C++ application using SDL and SDL_Mixer for audio, and am trying to follow this tutorial. However, using SDL_Mixer's Mix_HookMusicFinished() isn't working, giving the error: argument of type 'void (CApp::)()' does not match 'void (*)()'
I've researched this error, and it seems the problem is that cleanMusic is a member function of CApp. I can't tell how to solve the problem, however, since most problems similar to this one are centered around pthread_create(). My cleanMusic() function needs to be able to access music_ which is a private variable of CApp. How can I resolve the error?
Here is the code for CApp.h, CApp::handleKeyEvents(), and CApp::cleanMusic(). Let me know if you need to see something else.
CApp.h
#ifndef CAPP_H
#define CAPP_H
#include <SDL.h>
#include <SDL_mixer.h>
#include <gl\gl.h>
#include <gl\glu.h>
class CApp {
private:
bool isRunning_;
private:
void cleanMusic();
private:
SDL_Surface *surfDisplay_;
Mix_Music *music_;
bool isRotating_;
GLfloat rQuad_;
public:
CApp();
int run();
public:
bool initialize();
void handleEvents(SDL_Event *event);
void loopData();
void render();
void clean();
public:
void handleKeyEvents(SDL_KeyboardEvent *key);
};
#endif // CAPP_H
CApp::handleKeyEvents()
#include "CApp.h"
void CApp::handleKeyEvents(SDL_KeyboardEvent *key) {
switch(key->keysym.sym) {
case SDLK_m:
if (key->state == SDL_PRESSED) {
if(music_ == NULL) {
music_ = Mix_LoadMUS("resources\\audio\\boop.wav");
Mix_PlayMusic(music_, 0);
Mix_HookMusicFinished(cleanMusic);
isRotating_ = true;
} else {
Mix_HaltMusic();
cleanMusic();
isRotating_ = false;
}
}
break;
default:
break;
}
}
CApp::cleanMusic()
#include "CApp.h"
void CApp::cleanMusic() {
Mix_FreeMusic(music_);
music_ = NULL;
}
Two changes. cleanMusic needs to be static.
static void cleanMusic();
Second, you register the hook with:
Mix_HookMusicFinished(&CApp::cleanMusic);
Since your method is now static, music_ needs to be static as well.
static Mix_Music *music_;
This means that there will only be one instance of this variable shared between all instantiations of CApp. Since I haven't seen all of your code, I can't tell if this is an issue.
void cleanMusic(); is what is known as a member function. A member function is very different from a normal function. The reason your compiler complains is because Mix_HookMusicFinished expects a normal function pointer of type void (*)(), but you are trying to pass a member function pointer of type void (CApp::*)(). These types are incompatible.
The simplest solution is just to make cleanMusic a normal function and Mix_Music *music; a global:
Mix_Music *music;
void cleanMusic() {
Mix_FreeMusic(music);
music = NULL;
}
Another way is to make them both static members:
static void cleanMusic();
static Mix_Music *music_;