Registering a callback in C++ from a joystick device library - c++

I found a library to handle joystick USB devices in C++ in
simple cross-platform gamepad library so I am trying to attach the callbacks from it to my application. So it has the following definitions
struct Gamepad_device {
unsigned int deviceID;
const char * description;
int vendorID;
int productID;
unsigned int numAxes;
unsigned int numButtons;
float * axisStates;
bool * buttonStates;
void * privateData;
};
[...]
/* Registers a function to be called whenever a device is attached. The specified
function will be called only during calls to Gamepad_init() and
Gamepad_detectDevices(), in the thread from which those functions were called.
Calling this function with a NULL argument will stop any previously registered
callback from being called subsequently. */
void Gamepad_deviceAttachFunc
(void (* callback)
(struct Gamepad_device * device, void * context), void * context);
Thus I am trying to attach this function Gamepad_deviceAttachFunc to a private function in my application.
I tried to register my private function joystickIsAttached (Gamepad_device device) using
Gamepad_deviceAttachFunc(joystickIsAttached(*Gamepad_device));
and
Gamepad_deviceAttachFunc(joystickIsAttached(*Gamepad_device));
but both lead me to
error: expected primary-expression before ')' token
Gamepad_deviceAttachFunc(joystickIsAttached(*Gamepad_device));
or
error: expected primary-expression before ')' token
Gamepad_deviceAttachFunc(joystickIsAttached(Gamepad_device));
Update
I also tried to define the called function as
void joystickDeviceAttachedCallback
(struct Gamepad_device * device, void * context);
and register the callback using
Gamepad_deviceAttachFunc(joystickDeviceAttachedCallback, (void *) 0x1);
but this leads to
error: cannot convert 'MainWindow::joystickDeviceAttachedCallback'
from type 'void (MainWindow::)(Gamepad_device*, void*)' to type 'void
()(Gamepad_device, void*)'
Gamepad_deviceAttachFunc(joystickDeviceAttachedCallback, (void *) 0x1);
Thus what did I do wrong (and how can I fix it?)?
Thanks.

Related

ESP32: Compile errors when using IRAM_ATTR

I am sure I am doing something really stupid, but here goes..
I get a compile error when I use IRAM_ATTR for my ISR. I am compiling for ESP32.
Here is the definition of the ISR
void
IRAM_ATTR
detectsBlockOccupancy() {
....
ISR code..
...
}
And here is the first usage:
void setup() {
// Set Sensor pin as interrupt, assign interrupt function and set RISING mode
attachInterrupt(digitalPinToInterrupt(BDInterruptPin), detectsBlockOccupancy, RISING);
...
}
The error I get is as follows:
In function 'void setup()': Node0:226:90: error: invalid conversion
from 'int ()()' to 'void ()()' [-fpermissive]
attachInterrupt(digitalPinToInterrupt(BDInterruptPin), detectsBlockOccupancy, RISING);
^ In file included from
C:\Users\vibhas\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\cores\esp32/esp32-hal.h:53:0,
from C:\Users\vibhas\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\cores\esp32/Arduino.h:35,
from sketch\Node0.ino.cpp:1: C:\Users\vibhas\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\cores\esp32/esp32-hal-gpio.h:81:6:
note: initializing argument 2 of 'void attachInterrupt(uint8_t, void
()(), int)' void attachInterrupt(uint8_t pin, void ()(void), int
mode);
^
If I remove the IRAM_ATTR then it compiles fine. It seems to think that I am trying to pass a different type of function pointer.
What could I be doing wrong ?
Thanks
vibhas

VRPN C++ code compiles on Linux but not Windows

I've built a VRPN client on Linux. It's based on this: http://www.vrgeeks.org/vrpn/tutorial---use-vrpn
Here's some of the code:
vrpn_Analog_Remote * analog = NULL;
vrpn_Button_Remote * button = NULL;
vrpn_Tracker_Remote * tracker = NULL;
// Things happen...
analog = new vrpn_Analog_Remote("pathToAnalog");
analog->register_change_handler(NULL, handleAnalog);
button = new vrpn_Button_Remote("pathToButton");
button->register_change_handler(NULL, handleButton);
tracker = new vrpn_Tracker_Remote("pathToTracker");
tracker->register_change_handler(NULL, handleTracker);
Here are the callbacks refered to in this code:
void handleAnalog(void * userData, const vrpn_ANALOGCB a) {
// Do stuff...
}
void handleButton(void * userData, const vrpn_BUTTONCB b) {
// Do stuff...
}
void handleTracker(void * userData, const vrpn_TRACKERCB t) {
// Do stuff...
}
And here is where all of these references to VRPN are defined:
https://github.com/vrpn/vrpn/blob/master/vrpn_Analog.h#L168
https://github.com/vrpn/vrpn/blob/master/vrpn_Button.h#L225
https://github.com/vrpn/vrpn/blob/master/vrpn_Tracker.h#L284
These compile without even a warning on Linux and can actually be used. Everything worked as expected. All the types here seem to satisfy the compiler, g++.
But on Windows, whether I use Visual Studio 2015 or MinGW's g++, I get this for the first two callback registrations:
invalid conversion from 'void (*)(void*, vrpn_ANALOGCB) {aka void (*)(void*, _vrpn_ANALOGCB)}' to 'vrpn_ANALOGCHANGEHANDLER {aka
void (__attribute__((__stdcall__)) *)(void*, _vrpn_ANALOGCB)}' [-fpermissive]
invalid conversion from 'void (*)(void*, vrpn_BUTTONCB) {aka void (*)(void*, _vrpn_BUTTONCB)}' to 'vrpn_BUTTONCHANGEHANDLER {aka
void (__attribute__((__stdcall__)) *)(void*, _vrpn_BUTTONCB)}' [-fpermissive]
And for the last one, I get a different error:
call of overloaded 'register_change_handler(NULL, void (&)(void*, vrpn_TRACKERCB))' is
ambiguous
Now that I'm typing this, I'm thinking maybe VRPN was compiled differently on Windows and that's why the compiler now has a problem with my code. But I'm very lost as to what to do.
Try declaring your callbacks like this:
void VRPN_CALLBACK handleAnalog(void * userData, const vrpn_ANALOGCB a) {
// Do stuff...
}
For linux, the VRPN_CALLBACK define is empty, so you did not notice any problems there. For windows, the VRPN library devs decided that they expect a callback that adheres to the __stdcall calling-convention. Thus you have to declare your function accordingly, and the most painless+portable way is to use the very same VRPN_CALLBACK define that they provide.
Clues to this came from your links to the code at github:
[vrpn_Analog.h]
typedef void(VRPN_CALLBACK *vrpn_ANALOGCHANGEHANDLER)(void *userdata,
const vrpn_ANALOGCB info);
and the callback define is made here:
[vrpn_Configure.h]
#ifdef _WIN32 // [ ...
#define VRPN_CALLBACK __stdcall
#else // ... ] WIN32 [
#define VRPN_CALLBACK
#endif // ] not WIN32

passing a class member function: type issues

I use the AccelStepper library in my Arduino project, the library has a constructor, with functions as parameters:
AccelStepper(void (*forward)(), void (*backward)());
In the main sketch, this is the code used:
void forwardstep() {
AFstepper->onestep(FORWARD, stepType); //some code to move the motor
}
void backwardstep() {
AFstepper->onestep(BACKWARD, stepType); //some code to move the motor
}
AccelStepper stepper(forwardstep, backwardstep);
as long as this code is in the main sketch, everything works well.
I have created a class that has an AccelStepper object and the forwardstep() and backwardstep() functions as members, but I cannot pass the functions to the constructor of AccelStepper:
.h file:
#define IICADDRESS 0x60
class FilterWheel : public Device
{
public:
FilterWheel();
void forwardstep();
void backwardstep();
void (*fwdstp)(); //function pointer
void (*bckwdstp)(); //function pointer
private:
//Adafruit Motor Shield object
Adafruit_MotorShield AFMS;
//Adafruit Stepper Motor object
Adafruit_StepperMotor *AFstepper;
//AccelStepper wrapper
AccelStepper stepper;
};
.cpp file:
#include "FilterWheel.h"
//constructor
FilterWheel::FilterWheel()
{
fwdstp = &FilterWheel::forwardstep;
bckwdstp = &FilterWheel::backwardstep;
Adafruit_MotorShield AFMS (IICADDRESS);
Adafruit_StepperMotor *AFstepper = AFMS.getStepper(200, 1); //M1 M2
//AccelStepper stepper(forwardstep, backwardstep); //doesn't work
AccelStepper stepper(fwdstp, bckwdstp); //works only if fwdstp = &FilterWheel::forwardstep; and bckwdstp = &FilterWheel::backwardstep; are commented out
}
//go 1 step forward
void FilterWheel::forwardstep() {
AFstepper->onestep(FORWARD, stepType);
}
//go 1 step backward
void FilterWheel::backwardstep() {
AFstepper->onestep(BACKWARD, stepType);
}
when I try to pass the functions directly,
AccelStepper stepper(forwardstep, backwardstep);
the compiler shows the following error:
FilterWheel.cpp:34: error: no matching function for call to 'AccelStepper::AccelStepper(<unresolved overloaded function type>, <unresolved overloaded function type>)'
AccelStepper.h:AccelStepper(void (*)(), void (*)())
AccelStepper.h:AccelStepper(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, bool)
AccelStepper.h:AccelStepper(const AccelStepper&)
Error compiling
when I attach the functions to the function pointers,
fwdstp = &FilterWheel::forwardstep;
bckwdstp = &FilterWheel::backwardstep;
AccelStepper stepper(fwdstp, bckwdstp);
the compiler shows these errors:
FilterWheel.cpp:In constructor 'FilterWheel::FilterWheel()'
FilterWheel.cpp:22: error: cannot convert 'void (FilterWheel::*)()' to 'void (*)()' in assignment
FilterWheel.cpp:23: error: cannot convert 'void (FilterWheel::*)()' to 'void (*)()' in assignment
Error compiling
how can I solve this issue?
forwardstep() and backwardstep() are non-static member functions, so this fwdstp = &FilterWheel::forwardstep; is a pointer to member function, it can't be converted to pointer to function because it needs an object to call it on.
You have to make your functions static or standalone.

Invalid conversion from void (*) (...) to void (*) (...) in OpenCL clCreateContext

I'm taking my first steps into both C++ and OpenCL to perform parallel computing, but I'm running into a bug attempting to pass a listener function to clCreateContext. My program (not shown) is crashing without error, so I need to add a function to forward OpenCL errors to stdout/stderr. The clCreateContext function has an argument for a function pointer that can be set to forward error messages to stdout or stderr. I get a compile time error however using Codeblocks/MinGW:
invalid conversion from 'void (*)(const char*, const void*, size_t, void*)' to
'void (*)(const char*, const void*, size_t, void*)'
I've replicated the problem in the code below:
#include <stdlib.h>
#include <stdio.h>
#include <CL\cl.h>
void pfn_notify(const char *errinfo, const void *private_info, size_t cb, void *user_data)
{
fprintf(stderr, "OpenCL Error (via pfn_notify): %s\n", errinfo);
}
int main()
{
/*Get platform and device info*/
cl_platform_id platform_id = NULL;
cl_uint ret_num_platforms;
cl_int ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
cl_device_id device_id = NULL;
cl_uint ret_num_devices;
ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &ret_num_devices);
/*Create openCL context*/
cl_context context = clCreateContext(NULL, 1, &device_id, &pfn_notify, NULL, &ret);
/*Some line after this throws an error*/
}
I have seen code examples of using this exact method and pfn_notify that have worked, and am not sure why my program isn't even compiling. Thanks in advance, and let me know if there's anything else I can post to help.
You need to declare your function as
void CL_CALLBACK pfn_notify(.....
As the commentors point out; if this code is in a C++ file then it also needs to be:
extern "C" void CL_CALLBACK pfn_notify(.....

Trying to create posix thread and get invalid conversion from 'void*' to 'void* (__attribute__((__cdecl__)) *)(void*) error

Sorry if I'm not as descriptive as I should be, I'm nearly asleep as I type this. I am trying to create a posix thread in my c++ code compiling with g++ on mingw. Here's the except of the code I'm trying to compile
static void processNextNodeOnQueue(queue<TreeNode*> &toComputeQueue) {...}
void static processNodes(void* ptr) {
pair<queue<TreeNode*>*, bool*> *input = (pair<queue<TreeNode*>*, bool*>*) ptr;
while(*(input->second)) {
pthread_mutex_lock(&mutex1);
if(input->first->empty()) return;
pthread_mutex_unlock(&mutex1);
processNextNodeOnQueue(*(input->first));
}
}
void startThinking() {
thinking = true;
mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_t thread;
pair<queue<TreeNode*>*, bool*> *input = new pair<queue<TreeNode*>*, bool*>(&toComputeQueue, &thinking);
int thereadId = pthread_create(&thread, NULL, (void*)&processNodes, (void*) input );
delete input;
}
void stopThinking() {
//set thinking to false and wait for threads to wrap up
thinking = false;
}
void processForTime(double seconds) {
clock_t t;
int f;
t = clock();
startThinking();
//something to wait for an amount of time
stopThinking();
}
Here's the full compiler output in case I missed something
C:\Users\Maxwell\SkyDrive\RPI\Fall 2013\IHSS-1964\Connect 4\MaxAI>g++ -g -pthread -std=c++11 -o3 *.cpp -o Max.exe
In file included from unit_tests.h:5:0,
from main.cpp:11:
search_tree.h: In member function 'void BoardSearchTree::startThinking()':
search_tree.h:221:85: error: invalid conversion from 'void*' to 'void* (__attribute__((__cdecl__)) *)(void*)' [-fpermissive]
int thereadId = pthread_create(&thread, NULL, (void*)&processNodes, (void*) input );
^
In file included from search_tree.h:12:0,
from unit_tests.h:5,
from main.cpp:11:
c:\mingw\include\pthread.h:940:31: error: initializing argument 3 of 'int pthread_create(pthread_t*, pthread_attr_t_*const*, void* (__attribute__((__cdecl__)) *)(void*), void*)' [-fpermissive] PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
The third parameter to pthread_create is a void *(*start_routine) (void *) - a function pointer. You are casting the function to a (void*) which is both unnecessary and incorrect. Just remove the cast:
pthread_create(&thread, NULL, processNodes, (void*) input );
Also since input is a pointer you don't need to cast it either, all pointers (save pointers-to-members) are implicitly convertible to void*):
pthread_create(&thread, NULL, processNodes, input );
Assuming you're using the pthread-w32 library from here, then the following header information is relevant:
#define PTW32_CDECL __cdecl
PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
const pthread_attr_t * attr,
void *(PTW32_CDECL *start) (void *),
void *arg);
What this shows is that the start parameter should be a function pointer that uses the __cdecl calling convention.
Try changing your processNodes function prototype to the following:
static void PTW32_CDECL processNodes(void* ptr)
The compiler should then create your thread function with the correct calling convention as expected by pthread_create.