如何在JNA结构中映射联合

时间:2019-05-08 15:12:45

标签: java jna unions

我需要使用JNA将几个C结构转换为Java。我的结构是如此组成:

struct s_xl_event {
XLeventTag tag;
unsigned char chanIndex;
unsigned short transId;
unsigned short portHandle;
unsigned char flags;
unsigned char reserved;
XLuint64 timeStamp;
union s_xl_tag_data tagData;
};

union s_xl_tag_data {
struct s_xl_can_msg msg;
struct s_xl_chip_state chipState;
union s_xl_lin_msg_api linMsgApi;
struct s_xl_sync_pulse syncPulse;
struct s_xl_daio_data daioData;
struct s_xl_transceiver transceiver;
};

struct s_xl_can_msg {
unsigned long id;
unsigned short flags;
unsigned short dlc;
XLuint64 res1;
unsigned char data[MAX_MSG_LEN];
XLuint64 res2;
};

我只添加了我需要的主要结构,还因为所有相关结构都与s_xl_can_msg类似。

在Java中,我使用JNA做到了这一点

public static class s_xl_event extends Structure {
    public byte tag;
    public byte chanIndex;
    public short transId;
    public short portHandle;
    public byte flags;
    public byte reserved;
    public long timeStamp;
    public s_xl_tag_data tagData;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("tag","chanIndex","transId","portHandle","flags","reserved","timeStamp","tagData");
    }
}

public static class s_xl_tag_data extends Union {
    public s_xl_can_msg msg;
    public s_xl_chip_state chipState;
    public s_xl_lin_msg_api linMsgApi;
    public s_xl_sync_pulse syncPulse;
    public s_xl_daio_data daioData;
    public s_xl_transceiver transceiver;
}

public static class s_xl_lin_msg extends Structure {        
    public byte id;
    public byte dlc;
    public short flags;
    public byte[] data = new byte[8];
    public byte crc;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("id","dlc","flags","data","crc");
    }
}

当我使用方法

short xlReceive(long portHandle, IntByReference eventCount, s_xl_event eventList);

我获得与s_xl_event中所有字段相关的值,除了tagData之外,其中所有字段均填充为0。现在,我不确定是否已映射所有子结构和联合符合预期,否则我忘记了一些东西。有没有人与这种事情有关?

1 个答案:

答案 0 :(得分:0)

在读取Union之类的s_xl_tag_data时,必须使用带有类名或字段名的setType()来告诉Union正在读取哪个字段,然后调用{{ 1}}。

在首次填充父结构时自动执行此操作的一种方法是,通过重写父结构中的read()方法。

将此方法添加到您的read()结构中:

s_xl_event

作为将类传递给union元素的类public void read() { // read from native memory, populate tag super.read(); // set union type based on tag switch(tag) { case XL_RECEIVE_MSG: case XL_TRANSMIT_MSG: tagData.setType(s_xl_can_msg.class); break; case XL_CHIP_STATE: tagData.setType(s_xl_chip_state.class); break; case XL_LIN_MSG: tagData.setType(s_xl_lin_msg_api.class); break; // ... add other cases here... default: // add default type or throw exception etc. break; } // now read tagData from native memory tagData.read(); } 的替代方法,您可以传递包含变量名称的setType(),例如String"msg",或"chipState"

还要注意,在"linMsgApi"中使用的getFieldOrder()方法在最新版本的JNA中已弃用。您应该改用Structure批注。