Search code examples
androidandroid-ndkfunction-pointersfunction-parameter

Making function pointers in C to Java functions


I am re-writing a Palm Pilot program to Android, and have hit a wall. My lack of C experience leaves me completely at a loss for ideas. This is the original C code :

The .h file :

typedef void (__stdcall *fp_setbaud)(WORD);
typedef short (__stdcall *fp_get)(WORD);
typedef void (__stdcall *fp_put)(BYTE);
typedef void (__stdcall *fp_flush)(void);
typedef void (__stdcall *fp_delay)(WORD);
//typedef void (__stdcall *fp_err)(WORD);
typedef short (__stdcall *fp_ProgressUpdate)(WORD);

The .c file :

fp_setbaud RelayAPI_SetBaud;
fp_get RelayAPI_get;
fp_put RelayAPI_put;
fp_flush RelayAPI_flush;
fp_delay RelayAPI_delay;
fp_ProgressUpdate RelayAPI_ProgressUpdateTX;
fp_ProgressUpdate RelayAPI_ProgressUpdateRX;


BYTE __stdcall InitRelay(fp_setbaud _setbaud, fp_get _get, fp_put _put, fp_flush _flush, fp_delay _delay){

    RelayAPI_SetBaud=_setbaud;
    RelayAPI_get=_get;
    RelayAPI_put=_put;
    RelayAPI_flush=_flush;
    RelayAPI_delay=_delay;
    RelayAPI_ProgressUpdateTX=0;
    RelayAPI_ProgressUpdateRX=0;
    ...
}

Then later in the code, These functions are called as follows :

if(baud9600) RelayAPI_SetBaud(9600);
else RelayAPI_SetBaud(1200);

In the main method of the old C file InitRelay is called like this...

InitRelay(Changeit,getit,putit,flushit,delayit);

The five parameters are all functions declared in that main file.

I would like to call InitRelay from my Java code, but all of those functions that it is passed deal with Palm Pilot functionality. I have rewritten them all in Java for the Android application and would like to use those. So, this is what I have done...

jmethodID changeID;
jmethodID getID;
jmethodID putID;
jmethodID flushID;
jmethodID delayID;
// These two below are COMPLETELY wrong.
jmethodID RelayAPI_ProgressUpdateTX;
jmethodID RelayAPI_ProgressUpdateRX;
jclass    bluetoothClass;

BYTE __stdcall InitRelayJava( JNIEnv *env, jobject obj  ) {

bluetoothClass = (*env)->GetObjectClass( env, obj );

    changeID = (*env)->GetMethodID( env, bluetoothClass, "changeitJava", "(I)Z"  );
    getID    = (*env)->GetMethodID( env, bluetoothClass, "getitJava"   , "()V"   );
    putID    = (*env)->GetMethodID( env, bluetoothClass, "putitJava"   , "([B)V" );
    flushID  = (*env)->GetMethodID( env, bluetoothClass, "flushitJava" , "()V"   );
    delayID  = (*env)->GetMethodID( env, bluetoothClass, "delayitJava" , "(I)V"  );

    RelayAPI_SetBaud= env->CallBooleanMethod( bluetoothClass, changeID , int rate    );
    RelayAPI_get    = env->CallVoidMethod   ( bluetoothClass, getID                  );
    RelayAPI_put    = env->CallVoidMethod   ( bluetoothClass, putID    , byte[] buff );
    RelayAPI_flush  = env->CallVoidMethod   ( bluetoothClass, flushID                );
    RelayAPI_delay  = env->CallVoidMethod   ( bluetoothClass, delayID                );
    RelayAPI_ProgressUpdateTX=0;
    RelayAPI_ProgressUpdateRX=0;
    ....
}

There are 2 problems with what I have done: 1) RelayAPI_* members aren't declared in the Android version of the program because I do not know the correct type to name them. 2) When I actually define the RelayAPI_* members in the Android version, it isn't at all what I am trying to do. The env->CallXXXMethod calls are actually CALLING those methods (in an incorrect way I know, its written out for you to visualize). I need to set those members equal to POINTERS to those function calls.

If anyone knows what I can do for these two problems please let me know. If I'm going about it all wrong, I'd also appreciate that information. Here are some tutorials I have been working with but don't see anything pertaining to the problem I am having.

Tutorial 1

Tutorial 2

Tutorial 3


Solution

  • What about something like this:

    typedef void (*fp_setbaud)(WORD);
    
    void WrapSetBaud(WORD w) {
        env->CallBooleanMethod( bluetoothClass ...
    }
    
    fp_setbaud RelayAPI_SetBaud = WrapSetBaud;
    

    And so on. You get the picture I hope. You'd have to save env globally somewhere for the wrappers to access it.