I use ESP-IDF 4.2 and want to create a freeRTOS timer. My code is similar to what I have used successfully before but now I get a compilation error that I can't resolve. My code is based on the example in the ESP-IDF documentation on the xTimerCreate function. In the documentation an array of timers is created, whereas I want to create only one.
Here is my code:
void myTimerCallback(void){
std::cout << "test timer callback" << std::endl;
};
TimerHandle_t create_freeRTOSTimer(){
TimerHandle_t timerHandle;
int32_t Id = 0;
int durationTicks = 100;
timerHandle = xTimerCreate( "Timer", // Just a text name, not used by the kernel.
durationTicks, // The timer period in ticks.
pdTRUE, // The timer will auto-reload itself when it expires.
( void * ) Id, // unique id.
myTimerCallback // Callback when timer expires.
);
return timerHandle;
};
This is the compiler response:
error: invalid conversion from 'void ()()' to
'TimerCallbackFunction_t' {aka 'void ()(void*)'} [-fpermissive]
myTimerCallback // Each timer calls the same callback when it expires.
^~~~~~~~~~~~~~~ In file included from ../components/NiCMidi/src/../include/timer.h:46,
from ../components/NiCMidi/src/timer.cpp:26: C:/Users/Fred/esp-idf/components/freertos/include/freertos/timers.h:267:33:
note: initializing argument 5 of 'void* xTimerCreate(const char*,
TickType_t, UBaseType_t, void*, TimerCallbackFunction_t)'
TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed
for strings and single characters only. */
For testing I replaced the myTimerCallback in the call of xTimerCreate by NULL. Then the compiler does not complain.
Oops, I forgot to use a parameter in the definition of the callback function!
When I use void myTimerCallback(TimerHandle_t pxTimer) for the definition, everything is OK!
Related
For my microcontroller project I need custom timer with possibility to change interruption handler function. I created a Timer class for this.
I need to initialize ESP32 timer with function.
That is how I am trying to do this:
class Timer
{
private:
hw_timer_t* timer = nullptr;
std::function<void(void)>& onTimer;
public:
Timer(uint16_t intervalMs, std::function<void(void)>& newOnTimer): onTimer(newOnTimer)
{
timer = timerBegin(0, 40, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, intervalMs * 1000, true);
}
void start()
{
timerAlarmEnable(timer);
}
};
And timer initialization:
Timer t = Timer(250, []IRAM_ATTR(){
Serial.print("Tick ");
Serial.println(millis());
if(point)
{
point = false;
d.clearPixel(4, 4);
return;
}
point = true;
d.drawPixel(4,4);
});
But when I am launching it, I get:
sketch.ino: In constructor 'Timer::Timer(uint16_t, std::function<void()>&)':
sketch.ino:1161:35: error: cannot convert 'std::function<void()>*' to 'void (*)()'
timerAttachInterrupt(timer, &onTimer, true);
^~~~~~~~
In file included from /esp32/hardware/esp32/2.0.4/cores/esp32/esp32-hal.h:88,
from /esp32/hardware/esp32/2.0.4/cores/esp32/Arduino.h:36,
from sketch.ino.cpp:1:
/esp32/hardware/esp32/2.0.4/cores/esp32/esp32-hal-timer.h:39:53: note: initializing argument 2 of 'void timerAttachInterrupt(hw_timer_t*, void (*)(), bool)'
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
~~~~~~~^~~~~~~~~
sketch.ino: At global scope:
sketch.ino:1341:16: error: expected primary-expression before '(' token
Timer t = Timer(250, []IRAM_ATTR(){
^
In file included from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/hal/esp32/include/hal/cpu_ll.h:18,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/hal/include/hal/cpu_hal.h:16,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_hw_support/include/esp_cpu.h:14,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_hw_support/include/soc/cpu.h:14,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_hw_support/include/soc/spinlock.h:11,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/freertos/port/xtensa/include/freertos/portmacro.h:42,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/freertos/include/freertos/portable.h:51,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/freertos/include/freertos/FreeRTOS.h:63,
from /esp32/hardware/esp32/2.0.4/cores/esp32/Arduino.h:33,
from sketch.ino.cpp:1:
sketch.ino: In lambda function:
/esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_common/include/esp_attr.h:150:46: error: expected '{' before '__attribute__'
#define _SECTION_ATTR_IMPL(SECTION, COUNTER) __attribute__((section(SECTION "." _COUNTER_STRINGIFY(COUNTER))))
^~~~~~~~~~~~~
/esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_common/include/esp_attr.h:23:19: note: in expansion of macro '_SECTION_ATTR_IMPL'
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)
^~~~~~~~~~~~~~~~~~
sketch.ino:1341:24: note: in expansion of macro 'IRAM_ATTR'
Timer t = Timer(250, []IRAM_ATTR(){
^~~~~~~~~
sketch.ino: At global scope:
sketch.ino:1341:24: error: expected ')' before '__attribute__'
Timer t = Timer(250, []IRAM_ATTR(){
~ ^
)
Error during build: exit status 1
I am not expert in C++, so I totally don't understand what I need to do there to fix it.
Could anyone who knows what to do tell me about this, please?
Thank you in advance.
The signature of timerAttachInterrupt is
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
Like the error says, you cannot convert a std::function<void()>* to a void(*)(). While std::function<...> is a class that can wrap pretty much any callable object and store the data needed (eg. the variables captured in a lambda), function pointers are just simple addresses in memory.
If your lambdas are simple and don't capture anything, like the one in your example, std::function is overkill. You can just use void(*)() instead and the issue is solved.
Otherwise, if your lambdas do capture stuff, then you need std::function and perhaps some static member variables.
Since you seem to be using only one timer, you could do something like this:
class Timer
{
private:
hw_timer_t* timer = nullptr;
static std::function<void(void)> onTimer;
static void onTimerCaller()
{
onTimer();
}
public:
Timer(uint16_t intervalMs, std::function<void(void)>&& newOnTimer)
{
if (onTimer)
{
// another Timer already exists. Show an error, somehow
}
onTimer = std::move(newOnTimer);
timer = timerBegin(0, 40, true);
timerAttachInterrupt(timer, &onTimerCaller, true);
timerAlarmWrite(timer, intervalMs * 1000, true);
}
void start()
{
timerAlarmEnable(timer);
}
};
The most important changes are1:
Add a onTimerCaller static function (that can be converted to void(*)() and therefore used with timerAttachInterrupt) which calls onTimer;
onTimer is now static, so it can be accessed from onTimerCaller.
Also note that I tried to keep the class as simple as possible. It should also have copy/move constructors/operators and a destructor. Additionally, there's not really much reason to even use a class in this case. A namespace with some functions would be simpler and cleaner.
It is also possible to support multiple timers, but I believe this may be enough for your use-case. Let me know if you'd like to see a version for multiple timers.
1 I also did some minor changes, like moving the std::function into the class to avoid a dangling reference.
I have to create new thread and send parameters to the threaded function, can't make it work though.
I was working according to this reference: http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Here is the thread creation (with the errors in the comments):
System::Threading::Thread^ T = gcnew System::Threading::Thread(gcnew System::Threading::ParameterizedThreadStart(this, &Server::ClientHandler)); // ERROR: 'void Server::ClientHandler(System::Object ^,System::Object ^)' : the specified function does not match the delegate type 'void (System::Object ^)'
T->Start(ClientSocket); // ERROR: 'System::Threading::Thread::Start' : no overloaded function takes 2 arguments
Here is ClientHandler decleration:
void Server::ClientHandler(Object^ data, Object^ data1);
I tried it with only one parameter, and I had only the second error.
P.S, in ClientHandler function I have to convert the Object^ parameters to SOCKET* and SOCKADDR_IN*, how it can be done?
My try:
SOCKET* _Sock = (SOCKET*)data;
SOCKADDR_IN* _ADDR = (SOCKADDR_IN*)data1;
I'm using visual studio 2012.
Pretty sure that declaration for Server::ClientHandler is incorrect.
Should be:
void Server::ClientHandler(Object^ data)
{
//Do stuff with data here..
}
System::Threading::Thread^ T = gcnew System::Threading::Thread(gcnew System::Threading::ParameterizedThreadStart(this, &Server::ClientHandler));
T->Start("Pass Your Data Here");
I just told Xcode to compile everything as Objective-C++ and now I have errors from casting.
void audioRouteChangeListenerCallback (
void *aInUserData,
AudioSessionPropertyID aInPropertyID,
UInt32 aInPropertyValueSize,
const void *aInPropertyValue
) {
// Ensure that this callback was invoked because of an audio route change
if (aInPropertyID != kAudioSessionProperty_AudioRouteChange) return;
// This callback, being outside the implementation block, needs a reference to the MixerHostAudio
// object, which it receives in the inUserData parameter. You provide this reference when
// registering this callback (see the call to AudioSessionAddPropertyListener).
TJUSimpleSequencer *lAudioObject = (TJUSimpleSequencer *) aInUserData;
// if application sound is not playing, there's nothing to do, so return.
if (NO == lAudioObject.isPlaying) {
NSLog (#"Audio route change while application audio is stopped.");
return;
} else {
// Determine the specific type of audio route change that occurred.
CFDictionaryRef routeChangeDictionary = aInPropertyValue; // !!! invalid conversion from 'const void*' to 'const __CFDictionary*'
CFNumberRef routeChangeReasonRef =
CFDictionaryGetValue (
routeChangeDictionary,
CFSTR (kAudioSession_AudioRouteChangeKey_Reason)
); // !!! invalid conversion from 'const void*' to 'const __CFNumber*'
When i try to use static_cast<CFDictionaryRef>(aInPropertyValue), I get nothing. As though (which is probably true) I am not using it correctly.
Use regular C cast?
CFDictionaryRef routeChangeDictionary = ( CFDictionaryRef )aInPropertyValue;
Edit 0:
How about this for that function call (if you're sure it's a number :)
CFNumberRef routeChangeReasonRef =
( CFNumberRef )CFDictionaryGetValue ( ...
Edit 1:
Take a look at The Definitive C++ Book Guide and List then.
I'm new on C++ and I'm trying to make some testing with C++ and SDL and in SDL we have a function:
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param);
which I can pass a callback for the timer created.
But apparently it converts my instance this to *void so I can't retrieve it again on the update method which is static, and it's interesting but the the SDL_AddTime doesn't work on a non static callback function.
Well, so my problem is that when trying to call the public method render through the void* param argument It complains about not being a pointer-to-object-type...
Is there any way I can get the Character instance again inside the update method since I don't have control over the SDL_AddTime function and I have to pass the required parameters?
Thanks
#include "Character.h"
Character::Character(void)
{
timer = SDL_AddTimer(33, update, this);
this->render(); // is called without problem
}
//static method
Uint32 Character::update(Uint32 interval,void* param)
{
param->render(); // yields: 'void*' is not a pointer-to-object type;
SDL_Event event;
event.type = SDL_USEREVENT;
event.user.code = 1020;
event.user.data1 = param;
SDL_PushEvent(&event);
return interval;
}
void Character::render(void)
{
printf("rendering character \n");
}
You don't need a reinterpret_cast - a static_cast should be OK:
Character * cp = static_cast <Character *>( param );
You should avoid reinterpret_cast - it is almost always implementation specific, and may hide problems - just like old-style C casts.
Cast your param pointer to a Character:
Character * charPtr = reinterpret_cast<Character *>(param);
charPtr->render();
The reason is that C++ is a strong typed language. To change one type to another, you need to cast it first:
Uint32 Character::update(Uint32 interval, void* param)
{
reinterpret_cast<Character* >(param)->render();
/* ... */
}
Just for reference, if you were to call a lot of stuff in a function, to save all the nasty reinterpret_cast stuff everywhere you can do
Character * myCharacter = reinterpret_cast<Character* >(param);
Which then lets you do 'myCharacter->render();' or whathaveyou...
Using C++.
pthread_t threads[STORAGE]; // 0-99
...
void run()
Error>>> int status = pthread_create(&threads[0], NULL, updateMessages, (void *) NULL);
if (status != 0)
{
printf("pthread_create returned error code %d\n", status);
exit(-1);
}
...
void ClientHandler::updateMessages(void *)
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
...
Compile Error:
TCPClient.cpp:109: error: argument of type ‘void (ClientHandler::)(void*)’ does not match ‘void* (*)(void*)’
I can't figure out whats wrong.
Thanks in advance.
A pointer to a member function is different from a global function with the same signature since the member function needs an additional object on which it operates. Therefore pointers to these two types of functions are not compatible.
In this case this means that you cannot pass a member function pointer to pthread_create but only a pointer to a non-member (or static) function. A work around for this problem is to use the forth parameter of pthread_create to pass a pointer to a object to a global function which then calls the method of the passed object:
class ClientHandler {
public:
void updateMessages();
void run();
};
// Global function that will be the threads main function.
// It expects a pointer to a ClientHandler object.
extern "C"
void *CH_updateMessages(void *ch) {
// Call "real" main function
reinterpret_cast<ClientHandler*>(ch)->updateMessages();
return 0;
}
void ClientHandler::run() {
// Start thread and pass pointer to the current object
int status = pthread_create(&threads[0], NULL, CH_updateMessages, (void*)this);
...
}
It's nothing to do with threads, it's a normal C++ error, you're just passing an incompatible type of function pointer.
A function pointer is not the same as a member instance function pointer, even if their signature is the same; this is because there is an implicit reference to *this passed. You can't avoid this.
As pthread_create takes a free function, create a static function(is a free function) inside ClientHandler
static void Callback(void * this_pointer,int other_arg) {
ClientHandler* self = static_cast< ClientHandler*>(this_pointer);
self-> updateMessages(other_arg);
}
and call pthread_create as follows
pthread_create(&threads[0], NULL, &ClientHandler::Callback, (void *) pointer_to_ClientHandler,int other_arg);
That works because Callback is free function
YoLinux has a nice pthread tutorial that my help you in learning about threads.
As others have already said, the problem is that the signatures between the functions are different. Class member functions always have a "secret" extra parameter, the this pointer. So you can never pass a member function where a global function is expected. You can hack around this either with libraries such as Boost.Bind, or by making the function a static member of the class.
But the simplest, and most elegant solution is to use a different threading API.
Boost.Thread is a very nice threading library for C++ (pthreads is designed for C, and that's why it doesnt play well with C++ features such as class methods).
I'd recommend using that.
Your code could be rewritten as something like this:
class ClientHandler {
public:
ClientHandler(/* All the parameters you want to pass to the thread. Unlike pthreads you have complete type safety and can pass as many parameters to this constructor as you like */){...}
void operator()() // boost.thread calls operator() to run the thread, with no parameters. (Since all parameters were passed in the constructor and saved as member variables
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
// whatever arguments you want to pass to the thread can be stored here as member variables
};
boost::threead_group gr; // can store all your threads here, rather than being limited to your fixed-size array
gr.create_thread(ClientHandler(/* construct a ClientHandler object with the parameters you like*/));
You're passing a member function instead of a global, normal, one.
Just define:
void updateMessages(void *) {
static ClientHandler c;
// use c..
}