6

I have the following C Structure which needs to be mapped to Java. Because I need to call a method from a DLL generated from the C code. The following is my structure.

typedef struct _ipj_iri_device
{
IPJ_READER_CONTEXT    reader_context;
IPJ_READER_IDENTIFIER reader_identifier;
uint32_t              receive_timeout_ms;

/* Internal Only */
uint8_t               sync_state;
bool                  wait_for_response;
uint32_t              frame_length;
uint32_t              receive_index;
uint8_t               receive_buffer[IPJ_RECEIVE_BUFFER_SIZE];

#if !defined(IRI_RX_ONLY)
uint8_t               transmit_buffer[IPJ_TRANSMIT_BUFFER_SIZE];
#endif

} ipj_iri_device;

The IPJ_READER_CONTEXT and IPJ_READER_IDENTIFIER looks like below.

typedef void* IPJ_READER_CONTEXT;
typedef void* IPJ_READER_IDENTIFIER;

How can I parse those two elements to map to Java? Please advice.

MWiesner
  • 8,868
  • 11
  • 36
  • 70
AnOldSoul
  • 4,017
  • 12
  • 57
  • 118
  • You can't explicitely work with (void) pointers in java. The closest you get to a void* is using an Object as a type (and save the relevant information in an individually created object for IPJ_READER_CONTEXT and IPJ_READER_IDENTIFIER) – ParkerHalo Nov 06 '15 at 07:41
  • If you're trying to call a shared library function from Java, where the library was written in C you may find SWIG is your friend? – bph Nov 06 '15 at 09:29
  • I couldn't use swig as I cannot edit the existing C code to adjust it to suit the requirements. – AnOldSoul Nov 06 '15 at 09:32
  • 1
    If you have a pointer in C, you can usually hold it's value in a Java `long`. The nice thing about JNI using primitives such a `long` is you can pass them directly from native to Java and back. Just remember that the only easy way to pass a primitive from native code back to Java is to *return* it as the return value from a native call. – Andrew Henle Nov 06 '15 at 11:26
  • [JNA](https://github.com/java-native-access/jna) provides facilities for handling this sort of mapping and also avoids you having to write or compile any additional native code. – technomage Nov 06 '15 at 16:06

3 Answers3

1

You can use JNIWrapper to map your C structure to Java and call the function from DLL.

The wrapper for the given structure will look like shown below (the values for the size constants need to be changed):

import com.jniwrapper.*;

public class IpjIriDevice extends Structure
{
    private static final int IPJ_RECEIVE_BUFFER_SIZE = 0;
    private static final int IPJ_TRANSMIT_BUFFER_SIZE = 0;

    private Pointer.Void reader_context = new Pointer.Void();
    private Pointer.Void reader_identifier = new Pointer.Void();
    private UInt32 receive_timeout_ms = new UInt32();
    private UInt8 sync_state = new UInt8();
    private Bool wait_for_response = new Bool();
    private UInt32 frame_length = new UInt32();
    private UInt32 receive_index = new UInt32();
    private PrimitiveArray receive_buffer = new PrimitiveArray(UInt8.class, IPJ_RECEIVE_BUFFER_SIZE);
    private PrimitiveArray transmit_buffer = new PrimitiveArray(UInt8.class, IPJ_TRANSMIT_BUFFER_SIZE);

    public IpjIriDevice()
    {
        init(new Parameter[] {
            reader_context,  
            reader_identifier,  
            receive_timeout_ms,  
            sync_state,  
            wait_for_response,  
            frame_length,  
            receive_index,  
            receive_buffer,  
            transmit_buffer
        });
    }

    public long getReaderContext()
    {
        return reader_context.getValue();
    }

    public long getReaderIdentifier()
    {
        return reader_identifier.getValue();
    }

    public long getReceiveTimeoutMs()
    {
        return receive_timeout_ms.getValue();
    }

    public void setReceiveTimeoutMs(long value)
    {
        receive_timeout_ms.setValue(value);
    }

    public long getSyncState()
    {
        return sync_state.getValue();
    }

    public void setSyncState(long value)
    {
        sync_state.setValue(value);
    }

    public boolean getWaitForResponse()
    {
        return wait_for_response.getValue();
    }

    public void setWaitForResponse(boolean value)
    {
        wait_for_response.setValue(value);
    }

    public long getFrameLength()
    {
        return frame_length.getValue();
    }

    public void setFrameLength(long value)
    {
        frame_length.setValue(value);
    }

    public long getReceiveIndex()
    {
        return receive_index.getValue();
    }

    public void setReceiveIndex(long value)
    {
        receive_index.setValue(value);
    }

    public PrimitiveArray getReceiveBuffer()
    {
        return receive_buffer;
    }

    public PrimitiveArray getTransmitBuffer()
    {
        return transmit_buffer;
    }

    public Object clone()
    {
        IpjIriDevice result = new IpjIriDevice();
        result.initFrom(this);
        return result;
    }
}

If you need a pointer to the structure instance, you should create the Pointer class instance:

IpjIriDevice structureInstance = new IpjIriDevice();
Pointer structurePtr = new Pointer(structureInstance);

After that, you can use the pointer instance to pass the function parameter. The following code demonstrates how to load the library and call the function from it:

DefaultLibraryLoader.getInstance().addPath(LIB_PATH);
Library library = new Library(LIB_NAME);
Function function = library.getFunction(FUNCTION_NAME);
long errorCode = function.invoke(returnValue, structurePtr);

If the structure is modified after the call, all the changes will be available in the structureInstance object.

As you can see, in this case you do not need to write any additional native code.

You can find more details about using JNIWrapper in its programmer's guide. Also, there is the JNIWrapper forum that contains answers to many popular questions.

Anna Dolbina
  • 1
  • 1
  • 8
  • 9
0

Here's an example of what your structure might look like using JNA:

public class ipj_iri_device extends Structure {
    Pointer               reader_context;
    Pointer               reader_identifier;
    int                   receive_timeout_ms;
    /* Internal Only */
    byte                  sync_state;
    // field size depends on size of 'bool'; "byte" is usually correct
    byte                  wait_for_response; 
    int                   frame_length;
    int                   receive_index;
    byte[]                receive_buffer = new byte[IPJ_RECEIVE_BUFFER_SIZE];
    // may or may not be used, check your native compile flag
    byte[]                transmit_buffer = new byte[IPJ_TRANSMIT_BUFFER_SIZE];
}

You can define the structures backing the reader_context and reader_identifier fields if you need their contents. If not, you can just pass them around as a generic Pointer.

EDIT

These structures may be used independently of the rest of JNA, all you need is a Pointer representation of the native memory to move data back and forth.

technomage
  • 9,861
  • 2
  • 26
  • 40
  • Do I need to have getters and setters to handle the elements of the structure? Does this work like the C# structure? Please advice. – AnOldSoul Nov 09 '15 at 01:22
  • And don't I need to implement the structure class with Structure.ByReference – AnOldSoul Nov 09 '15 at 01:45
  • JNA uses by reference semantics by default for function parameters, so an explicit `Structure.ByReference` is not required. `Structure.read()` and `Structure.write()` take care of synching field values with native memory, and are called automatically by JNA before and after native function calls. – technomage Nov 09 '15 at 15:07
-1

Aah after some long search here an interested one on OOP vs Functional paradigm. So here we can solve it like . Here goes the basic steps .

  • Name your Structure as a class .
  • Put all the attributes of structure as class attributes .

  • For those void * , in java you can use reference variables.

  • then for an struct instance as you got you structure by the name of ipj_iri_device , just create an object of the class named in bullet one.

    public class _ipj_iri_device{
         int IPJ_RECEIVE_BUFFER_SIZE ;
         //get a value from whereever the input is coming ,assign it to buffersize
         IPJ_READER_CONTEXT    reader_context;
         IPJ_READER_IDENTIFIER reader_identifier;
         boolean wait_for_response;
         uint32_t receive_timeout_ms;
         //here uint32_t is a type  i asumed .You will have to define it explicitly
    
        //rest of the vaariables / members of structure 
     }
    
Sachin
  • 359
  • 2
  • 18
  • If I create a reference variable what should be its properties? What should I do inside the reference type class? Please advice. – AnOldSoul Nov 06 '15 at 08:33
  • IPJ_READER_CONTEXT and IPJ_READER_IDENTIFIER are the types(basically a class) , you will have to define them according to your need but their return type would be void in your case . – Sachin Nov 06 '15 at 09:06
  • void pointer just refers to a memory address right? So If I define such a class I will not be having anything put inside the class. That's what I don't get. What will those classes contain? – AnOldSoul Nov 06 '15 at 09:27
  • Changing the `struct` to a `class` won't do anything to allow Java access into the data. – Andrew Henle Nov 06 '15 at 11:23