如何在 JNA 结构中映射联合
How to map a union in a JNA Structure
我需要使用 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。现在,我不确定我是否映射了所有子结构和工会如预期或我忘记了什么。有没有人和这样的事情有关系?
当读取像 s_xl_tag_data
这样的 Union
时,您必须使用带有 class 或字段名称的 setType()
告诉联盟正在读取其哪些字段,然后在联盟上调用 read()
。
首次填充父结构时自动执行此操作的一种方法是重写父结构中的 read()
方法。
将此方法添加到您的 s_xl_event
结构中:
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();
}
作为将联合元素的 class 传递给 setType()
的替代方法,您可以传递包含变量名称的 String
,例如 "msg"
, "chipState"
,或"linMsgApi"
,等等
另外请注意,您在 Structure
中使用的 getFieldOrder()
方法在最新版本的 JNA 中已弃用。您应该改用 @FieldOrder
注释。
我需要使用 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。现在,我不确定我是否映射了所有子结构和工会如预期或我忘记了什么。有没有人和这样的事情有关系?
当读取像 s_xl_tag_data
这样的 Union
时,您必须使用带有 class 或字段名称的 setType()
告诉联盟正在读取其哪些字段,然后在联盟上调用 read()
。
首次填充父结构时自动执行此操作的一种方法是重写父结构中的 read()
方法。
将此方法添加到您的 s_xl_event
结构中:
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();
}
作为将联合元素的 class 传递给 setType()
的替代方法,您可以传递包含变量名称的 String
,例如 "msg"
, "chipState"
,或"linMsgApi"
,等等
另外请注意,您在 Structure
中使用的 getFieldOrder()
方法在最新版本的 JNA 中已弃用。您应该改用 @FieldOrder
注释。