I have a C API which takes a callback and examines the integer return value of that callback to decide what to do: a return value of 0 means stop doing stuff, any other value means continue to block and process stuff. I have exposed this callback to mJS but my problem is that the integer return value seen by the C code is always coming out as 1. What am I doing wrong? How can I get the correct integer return value in my C code?
Here’s how I am coding it:
// The callback is of this form
int cb(void *, void *);
int (*pgStoredCb)(void *, void *) = NULL;
void *pgStoredCbParams = NULL
void *pgStoredCbUserData = NULL
// Set up the callback
void setCb(int(*pCb) (void *, void *), void *pCbParams, void *pCbUserData) {
pgStoredCb = pCb;
pgStoredCbParams = pCbParams;
pgStoredCbUserData = pCbUserData;
}
// Use the callback
void eventHasOccurred{} {
if (pgStoredCb != NULL) {
if (pgStoredCb(pgStoredCbParams, pgStoredCbUserData)) {
printf("Callback returned true.\n");
}
}
}
…and in mJS it is used like this:
let cb = function(pParam) {
print("Callback has been called with \"", pParam, "\" and is returning 0.\n");
return 0;
};
let cbParam = "Hello World!";
let cbSet = ffi('void setCb(int(*) (void *, userdata), void *pCbParams, userdata');
cbSet(cb, cbParam, null);
After correcting some syntax errors in your example code it runs as expected for different values of retVal:
mJS
let cb = function (pParam) {
let retVal = -2;
print("init.js - Callback has been called with \"", pParam, "\" and is returning ", retVal);
return retVal;
};
C
void eventHasOccurred() {
if (pgStoredCb != NULL) {
int ret_val = pgStoredCb(pgStoredCbParams, pgStoredCbUserData);
LOG(LL_INFO,
("%s:%d - Callback returned %d.\n", __FUNCTION__, __LINE__, ret_val));
}
}
Output:
[May 17 15:03:48.557] init.js - Callback has been called with " <foreign_ptr@3ffcbac9> " and is returning -2
[May 17 15:03:48.563] main.c:19 eventHasOccurred:19 - Callback returned -2.
[May 17 15:04:51.787] init.js - Callback has been called with " <foreign_ptr@3ffcbac5> " and is returning 0
[May 17 15:04:51.794] main.c:19 eventHasOccurred:19 - Callback returned 0.
[May 17 15:05:38.246] init.js - Callback has been called with " <foreign_ptr@3ffcbac5> " and is returning 3
[May 17 15:05:38.253] main.c:19 eventHasOccurred:19 - Callback returned 3.
Thanks for trying that: as you have spotted, my code was an illustration of what I’m doing rather than actually what I’m doing, since the case in question is buried inside a larger block of code. I will debug a bit further and reply again here.
Well, it looks like the issue I had is down to types. The actual C API that needs to be called expects a callback which returns a bool and, of course, doesn’t have the userdata parmeter that mJS needs, so I had to insert a “relay” function which returned an int and added the void * parameter for userdata, something like this (and here I have inserted some debug for this problem):
If in JS I return 6 then returnValue is 1 and returnValueInt is, indeed, 6, which I guess is fair enough (though I have to say that I didn’t realise the compiler was going to force 6 to 1 for the bool, must be some newfangled C requirement ). However, if in JS I return trueor I return false then in both cases returnValue is 1 and returnValueInt is -1. This is why I thought the return value was broken, 'cos it’s the same for true or false (and indeed for 6 if you’re only looking at the bool value and don’t realise compilers have moved on). Of course, if in JS I return 0 or 1 then I get the expected values back in C code, so I will do that, it just seems a bit odd that the bool values don’t work as one might expect; the joys of Javascript best effort type munging I guess .
Sorry, yes, as @nliviu pointed out, there were syntax errors in the code I typed above, it was only meant as an illustration of the problem not the code I actually used. The line:
MJS error: bad ffi signature: “void setCb(int(*) (void *, userdata), void ( * ), userdata)”: only one callback is allowed
In mjs_ffi.c there is this comment:
/*
* We already have parsed some callback argument. Currently we don’t
* support more than one callback argument, so, return error
* TODO(dfrank): probably improve
*/
Ah, no, that would give you two callbacks, in this case there is only one callback but it takes two parameters: a void * and a userdata (which, as far as C is considered, will be a void * but it has to be called userdata in the function signature inside mJS so that mJS can make special use of it).
// Set up the callback
void setCb(int(*pCb) (void *, void *), void *pCbParams, void *pCbUserData) {
pgStoredCb = pCb;
pgStoredCbParams = pCbParams;
pgStoredCbUserData = pCbUserData;
}
// Use the callback
void eventHasOccurred() {
if (pgStoredCb != NULL) {
int ret_val = pgStoredCb(pgStoredCbParams, pgStoredCbUserData);
ESP_LOGI(TAG, “eventHasOccurred: %s:%d - Callback returned %d.\n”, FUNCTION, LINE, ret_val);
}
}
JS:
let cb = function (pParam) {
let retVal = -2;
print('–mjs: Callback has been called with ', pParam, ’ and is returning ', retVal);
return retVal;
};
let cbParam = ‘Hello World!’;
let cbSet = ffi(‘void setCb(int(*) (void *, userdata), void *, userdata)’);
cbSet(cb, cbParam, null);