我正在尝试使用 Vector XL Driver Library (vxlapi64.dll)使用java代码。我创建了一个 JNA 项目来读取 vxlapi64.dll
并映射数据类型,但输出为结构元素生成错误的值。
C代码结构:
typedef struct s_xl_channel_config {
char name [XL_MAX_LENGTH + 1];
unsigned char hwType;
unsigned char hwIndex;
unsigned char hwChannel;
unsigned short transceiverType;
unsigned short transceiverState;
unsigned short configError;
unsigned char channelIndex;
XLuint64 channelMask;
unsigned int channelCapabilities;
unsigned int channelBusCapabilities;
// Channel
unsigned char isOnBus;
unsigned int connectedBusType;
XLbusParams busParams;
unsigned int _doNotUse;
unsigned int driverVersion;
unsigned int interfaceVersion;
unsigned int raw_data[10];
unsigned int serialNumber;
unsigned int articleNumber;
char transceiverName [XL_MAX_LENGTH +1]
unsigned int specialCabFlags;
unsigned int dominantTimeout;
unsigned char dominantRecessiveDelay;
unsigned char recessiveDominantDelay;
unsigned char connectionInfo;
unsigned char currentlyAvailableTimestamps;
unsigned short minimalSupplyVoltage;
unsigned short maximalSupplyVoltage;
unsigned int maximalBaudrate;
unsigned char fpgaCoreCapabilities;
unsigned char specialDeviceStatus;
unsigned short channelBusActiveCapabilities; s)
unsigned short breakOffset;
unsigned short delimiterOffset;
unsigned int reserved[3];
} XL_CHANNEL_CONFIG;
Java映射结构:
public static class XLchannelConfig extends Structure{
public byte[] name = new byte[XL_MAX_LENGTH + 1];
public byte hwType;
public byte hwIndex;
public byte hwChannel;
public short transceiverType;
public short transceiverState;
public short configError;
public byte channelIndex;
public UnsignedInt channelMask;
public UnsignedInt channelCapabilities;
public UnsignedInt channelBusCapabilities;
public byte isOnBus;
public UnsignedInt connectedBusType;
public XLbusParams busParams;
public UnsignedInt _doNotUse;
public UnsignedInt driverVersion;
public UnsignedInt interfaceVersion;
public UnsignedInt[] raw_data = new UnsignedInt[10];
public UnsignedInt serialNumber;
public UnsignedInt articleNumber;
public byte[] transceiverName = new byte[XL_MAX_LENGTH +1];
public UnsignedInt specialCabFlags;
public UnsignedInt dominantTimeout;
public byte dominantRecessiveDelay;
public byte recessiveDominantDelay;
public byte connectionInfo;
public byte currentlyAvailableTimestamps;
public short minimalSupplyVoltage;
public short maximalSupplyVoltage;
public UnsignedInt maximalBaudrate;
public byte fpgaCoreCapabilities;
public byte specialDeviceStatus;
public short channelBusActiveCapabilities;
public short breakOffset;
public short delimiterOffset;
public UnsignedInt[] reserved = new UnsignedInt[3];
@Override
protected List getFieldOrder() {
return Arrays.asList(
"name",
"hwType",
"hwIndex",
"hwChannel",
"transceiverType",
"transceiverState",
"configError",
"channelIndex",
"channelMask",
"channelCapabilities",
"channelBusCapabilities",
"isOnBus",
"connectedBusType",
"busParams",
"_doNotUse",
"driverVersion",
"interfaceVersion",
"raw_data",
"serialNumber",
"articleNumber",
"transceiverName",
"specialCabFlags",
"dominantTimeout",
"dominantRecessiveDelay",
"recessiveDominantDelay",
"connectionInfo",
"currentlyAvailableTimestamps",
"minimalSupplyVoltage",
"maximalSupplyVoltage",
"maximalBaudrate",
"fpgaCoreCapabilities",
"specialDeviceStatus",
"channelBusActiveCapabilities",
"breakOffset",
"delimiterOffset",
"reserved");
}
public XLchannelConfig() {
super();
read();
}
@Override
protected void allocateMemory() {
super.allocateMemory();
}
public XLchannelConfig(Pointer pointer) {
super();
useMemory(pointer);
read();
}
public static class ByReference extends XLchannelConfig implements Structure.ByReference {
public ByReference(){
super();
read();
}
public ByReference(Pointer p) { super(p);
ensureAllocated();
useMemory(p);
byte[] buffer = new byte[size()];
this.getPointer().read(0, buffer, 0, buffer.length);
getPointer().write(0, buffer, 0, buffer.length);
read();}
};
public static class ByValue extends XLchannelConfig implements Structure.ByValue {
public ByValue() {
super();
read();
}
public ByValue(Pointer p) { super(p);
useMemory(p);
read();}
};
}
public class UnsignedInt extends IntegerType {
public UnsignedInt() {
super(4, false);
}
}
public static class XLbusParams extends Structure{
public int busType;
public Data data;
}
public static class Data extends Union{
public Can can;
}
public static class Can extends Structure{
public int bitRate;
public byte sjw;
public byte tseg1;
public byte tseg2;
public byte sam; // 1 or 3
public byte outputMode;
public byte[] reserved = new byte[7];
public byte canOpMode;
}
我有示例 c 代码,它读取 dll 并且它获取正确的值,但使用 JNA 它没有给出正确的输出值。结构映射正确还是我遗漏了什么?
C 代码的实际输出:
- 02 channel 硬件配置 -
- Ch:00,CM:0x001,虚拟 channel 1,无出租车!
- Ch:01,CM:0x002,虚拟 channel 2,无 Cab!
上述映射的输出:
2 channel 硬件配置 -
Ch:01,CM:0x000,虚拟 channel 1 无出租车!
Ch:00,CM:0x000,虚拟 channel 2 无 Cab!
Daniel Widdis 建议您,如果我可以将 UnsignedInt 更改为 int,将 XLuint64 更改为 long,输出如下
2 channel 硬件配置 -
Ch:00,CM:0x1000000070000,虚拟 channel 1 无出租车!
Ch:700,CM:0x1010001000100,所有 channel 2
合并代码:
package load;
import java.util.Arrays;
import java.util.List;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.Union;
public interface VxLib extends Library{
public static int XL_CONFIG_MAX_CHANNELS = 64;
public static int XL_MAX_LENGTH = 41;
VxLib INSTANCE = (VxLib) Native.load((Platform.isWindows() ? "vxlapi64" : "vxlapi64Port"), VxLib.class);
int xlOpenDriver();
int xlGetDriverConfig(s_xl_driver_config pDriverConfig);
String xlGetErrorString(int status);
public static class s_xl_driver_config extends Structure {
public int dllVersion;
public int channelCount;
public int[] reserved = new int[4];
public XLchannelConfig[] channel = new XLchannelConfig[XL_CONFIG_MAX_CHANNELS];
public s_xl_driver_config() {
super();
read();
}
public s_xl_driver_config(Pointer p) {
super(p);
read();
}
protected List<String> getFieldOrder() {
return Arrays.asList("dllVersion", "channelCount", "reserved", "channel");
}
/**
* @param channelCount total number of channels<br>
* @param reserved C type : unsigned int[10]<br>
* @param channel [channelCount]<br>
* C type : XLchannelConfig[64]
*/
public s_xl_driver_config(int dllVersion, int channelCount, int reserved[], XLchannelConfig channel[]) {
super();
this.dllVersion = dllVersion;
this.channelCount = channelCount;
if ((reserved.length != this.reserved.length))
throw new IllegalArgumentException("Wrong array size !");
this.reserved = reserved;
if ((channel.length != this.channel.length))
throw new IllegalArgumentException("Wrong array size !");
this.channel = channel;
}
public static class ByReference extends s_xl_driver_config implements Structure.ByReference {
};
public static class ByValue extends s_xl_driver_config implements Structure.ByValue {
};
};
public static class XLchannelConfig extends Structure {
public byte[] name = new byte[XL_MAX_LENGTH + 1];
public byte hwType;
public byte hwIndex;
public byte hwChannel;
public short transceiverType;
public int transceiverState;
public byte channelIndex;
public long channelMask;
public int channelCapabilities;
public int channelBusCapabilities;
public byte isOnBus;
public int connectedBusType;
public XLbusParams busParams;
public int driverVersion;
public int interfaceVersion;
public int[] raw_data = new int[7];
public int serialNumber;
public int articleNumber;
public byte[] transceiverName = new byte[XL_MAX_LENGTH + 1];
public int specialCabFlags;
public int dominantTimeout;
public int[] reserved = new int[7];
public XLchannelConfig() {
super();
read();
}
public XLchannelConfig(Pointer p) {
super(p);
read();
}
protected List<String> getFieldOrder() {
return Arrays.asList("name", "hwType", "hwIndex", "hwChannel", "transceiverType", "transceiverState", "channelIndex", "channelMask", "channelCapabilities", "channelBusCapabilities", "isOnBus", "connectedBusType", "busParams", "driverVersion", "interfaceVersion", "raw_data", "serialNumber", "articleNumber", "transceiverName", "specialCabFlags", "dominantTimeout", "reserved");
}
public static class ByReference extends XLchannelConfig implements Structure.ByReference {
};
public static class ByValue extends XLchannelConfig implements Structure.ByValue {
};
};
public static class XLbusParams extends Structure {
public int busType;
/** C type : data_union */
public data_union data;
/** <i>native declaration : line 23</i> */
public static class data_union extends Union {
/** C type : can_struct */
public can_struct can;
/** C type : canFD_struct */
public canFD_struct canFD;
/** C type : most_struct */
public most_struct most;
/** C type : flexray_struct */
public flexray_struct flexray;
/** C type : ethernet_struct */
public ethernet_struct ethernet;
/** C type : a429_struct */
public a429_struct a429;
/** C type : unsigned char[28] */
public byte[] raw = new byte[28];
/** <i>native declaration : line 24</i> */
public static class can_struct extends Structure {
public int bitRate;
public byte sjw;
public byte tseg1;
public byte tseg2;
/** 1 or 3 */
public byte sam;
public byte outputMode;
/** C type : unsigned char[7] */
public byte[] reserved = new byte[7];
public byte canOpMode;
public can_struct() {
super();
setAlignType(ALIGN_GNUC);
read();
}
public can_struct(Pointer p) {
super(p);
read();
}
protected List<String> getFieldOrder() {
return Arrays.asList("bitRate", "sjw", "tseg1", "tseg2", "sam", "outputMode", "reserved", "canOpMode");
}
/**
* @param sam 1 or 3<br>
* @param reserved C type : unsigned char[7]
*/
public can_struct(int bitRate, byte sjw, byte tseg1, byte tseg2, byte sam, byte outputMode, byte reserved[], byte canOpMode) {
super();
this.bitRate = bitRate;
this.sjw = sjw;
this.tseg1 = tseg1;
this.tseg2 = tseg2;
this.sam = sam;
this.outputMode = outputMode;
if ((reserved.length != this.reserved.length))
throw new IllegalArgumentException("Wrong array size !");
this.reserved = reserved;
this.canOpMode = canOpMode;
}
public static class ByReference extends can_struct implements Structure.ByReference {
};
public static class ByValue extends can_struct implements Structure.ByValue {
};
};
/** <i>native declaration : line 34</i> */
public static class canFD_struct extends Structure {
public int arbitrationBitRate;
public byte sjwAbr;
public byte tseg1Abr;
public byte tseg2Abr;
public byte samAbr;
public byte outputMode;
public byte sjwDbr;
public byte tseg1Dbr;
public byte tseg2Dbr;
public int dataBitRate;
public byte canOpMode;
public canFD_struct() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("arbitrationBitRate", "sjwAbr", "tseg1Abr", "tseg2Abr", "samAbr", "outputMode", "sjwDbr", "tseg1Dbr", "tseg2Dbr", "dataBitRate", "canOpMode");
}
public static class ByReference extends canFD_struct implements Structure.ByReference {
};
public static class ByValue extends canFD_struct implements Structure.ByValue {
};
};
/** <i>native declaration : line 47</i> */
public static class most_struct extends Structure {
public int activeSpeedGrade;
public int compatibleSpeedGrade;
public int inicFwVersion;
public most_struct() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("activeSpeedGrade", "compatibleSpeedGrade", "inicFwVersion");
}
public most_struct(int activeSpeedGrade, int compatibleSpeedGrade, int inicFwVersion) {
super();
this.activeSpeedGrade = activeSpeedGrade;
this.compatibleSpeedGrade = compatibleSpeedGrade;
this.inicFwVersion = inicFwVersion;
}
public static class ByReference extends most_struct implements Structure.ByReference {
};
public static class ByValue extends most_struct implements Structure.ByValue {
};
};
/** <i>native declaration : line 52</i> */
public static class flexray_struct extends Structure {
public int status;
public int cfgMode;
public int baudrate;
public flexray_struct() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("status", "cfgMode", "baudrate");
}
public flexray_struct(int status, int cfgMode, int baudrate) {
super();
this.status = status;
this.cfgMode = cfgMode;
this.baudrate = baudrate;
}
public static class ByReference extends flexray_struct implements Structure.ByReference {
};
public static class ByValue extends flexray_struct implements Structure.ByValue {
};
};
/** <i>native declaration : line 57</i> */
public static class ethernet_struct extends Structure {
/** C type : unsigned char[6] */
public byte[] macAddr = new byte[6];
public byte connector;
public byte phy;
public byte link;
public byte speed;
public byte clockMode;
public byte bypass;
public ethernet_struct() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("macAddr", "connector", "phy", "link", "speed", "clockMode", "bypass");
}
/** @param macAddr C type : unsigned char[6] */
public ethernet_struct(byte macAddr[], byte connector, byte phy, byte link, byte speed, byte clockMode, byte bypass) {
super();
if ((macAddr.length != this.macAddr.length))
throw new IllegalArgumentException("Wrong array size !");
this.macAddr = macAddr;
this.connector = connector;
this.phy = phy;
this.link = link;
this.speed = speed;
this.clockMode = clockMode;
this.bypass = bypass;
}
public static class ByReference extends ethernet_struct implements Structure.ByReference {
};
public static class ByValue extends ethernet_struct implements Structure.ByValue {
};
};
/** <i>native declaration : line 66</i> */
public static class a429_struct extends Structure {
public short channelDirection;
public short res1;
/** C type : dir_union */
public dir_union dir;
/** <i>native declaration : line 69</i> */
public static class dir_union extends Union {
/** C type : tx_struct */
public tx_struct tx;
/** C type : rx_struct */
public rx_struct rx;
/** C type : unsigned char[24] */
public byte[] raw = new byte[24];
/** <i>native declaration : line 70</i> */
public static class tx_struct extends Structure {
public int bitrate;
public int parity;
public int minGap;
public tx_struct() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("bitrate", "parity", "minGap");
}
public tx_struct(int bitrate, int parity, int minGap) {
super();
this.bitrate = bitrate;
this.parity = parity;
this.minGap = minGap;
}
public static class ByReference extends tx_struct implements Structure.ByReference {
};
public static class ByValue extends tx_struct implements Structure.ByValue {
};
};
/** <i>native declaration : line 75</i> */
public static class rx_struct extends Structure {
public int bitrate;
public int minBitrate;
public int maxBitrate;
public int parity;
public int minGap;
public int autoBaudrate;
public rx_struct() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("bitrate", "minBitrate", "maxBitrate", "parity", "minGap", "autoBaudrate");
}
public rx_struct(int bitrate, int minBitrate, int maxBitrate, int parity, int minGap, int autoBaudrate) {
super();
this.bitrate = bitrate;
this.minBitrate = minBitrate;
this.maxBitrate = maxBitrate;
this.parity = parity;
this.minGap = minGap;
this.autoBaudrate = autoBaudrate;
}
public static class ByReference extends rx_struct implements Structure.ByReference {
};
public static class ByValue extends rx_struct implements Structure.ByValue {
};
};
public dir_union() {
super();
}
/** @param raw C type : unsigned char[24] */
public dir_union(byte raw[]) {
super();
if ((raw.length != this.raw.length))
throw new IllegalArgumentException("Wrong array size !");
this.raw = raw;
setType(byte[].class);
}
/** @param tx C type : tx_struct */
public dir_union(tx_struct tx) {
super();
this.tx = tx;
setType(tx_struct.class);
}
/** @param rx C type : rx_struct */
public dir_union(rx_struct rx) {
super();
this.rx = rx;
setType(rx_struct.class);
}
public static class ByReference extends dir_union implements Structure.ByReference {
};
public static class ByValue extends dir_union implements Structure.ByValue {
};
};
public a429_struct() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("channelDirection", "res1", "dir");
}
/** @param dir C type : dir_union */
public a429_struct(short channelDirection, short res1, dir_union dir) {
super();
this.channelDirection = channelDirection;
this.res1 = res1;
this.dir = dir;
}
public static class ByReference extends a429_struct implements Structure.ByReference {
};
public static class ByValue extends a429_struct implements Structure.ByValue {
};
};
public data_union() {
super();
}
public data_union(Pointer p) {
super(p);
read();
}
/** @param raw C type : unsigned char[28] */
public data_union(byte raw[]) {
super();
if ((raw.length != this.raw.length))
throw new IllegalArgumentException("Wrong array size !");
this.raw = raw;
setType(byte[].class);
}
/** @param most C type : most_struct */
public data_union(most_struct most) {
super();
this.most = most;
setType(most_struct.class);
}
/** @param a429 C type : a429_struct */
public data_union(a429_struct a429) {
super();
this.a429 = a429;
setType(a429_struct.class);
}
/** @param canFD C type : canFD_struct */
public data_union(canFD_struct canFD) {
super();
this.canFD = canFD;
setType(canFD_struct.class);
}
/** @param flexray C type : flexray_struct */
public data_union(flexray_struct flexray) {
super();
this.flexray = flexray;
setType(flexray_struct.class);
}
/** @param ethernet C type : ethernet_struct */
public data_union(ethernet_struct ethernet) {
super();
this.ethernet = ethernet;
setType(ethernet_struct.class);
}
/** @param can C type : can_struct */
public data_union(can_struct can) {
super();
this.can = can;
setType(can_struct.class);
}
public static class ByReference extends data_union implements Structure.ByReference {
};
public static class ByValue extends data_union implements Structure.ByValue {
};
};
public XLbusParams() {
super();
}
public XLbusParams(Pointer p) {
super(p);
read();
}
protected List<String> getFieldOrder() {
return Arrays.asList("busType", "data");
}
/** @param data C type : data_union */
public XLbusParams(short busType, data_union data) {
super();
this.busType = busType;
this.data = data;
}
public static class ByReference extends XLbusParams implements Structure.ByReference {
};
public static class ByValue extends XLbusParams implements Structure.ByValue {
};
};
}
输出:
--------------------------------------------------
- 2 channels Hardware Configuration -
--------------------------------------------------
- Ch:00 , CM: 0x001 , Virtual Channel 1 no Cab!
- Ch:01 , CM: 0x000 , Virtual Channel 2 no Cab!
最佳答案
正如我在评论线程中指出的,您错误地对 8 字节结构元素 XLuint64
使用 4 字节映射 (UnsignedInt
)。应将其替换为 8 字节变量(例如 long
)。虽然技术上是正确的,但为每个无符号 int
值创建一个对象会产生大量开销,因此简化结构并仅放置 int
结构通常是一个好主意元素,并在解释值时处理无符号性。
您的示例输出显示第二个元素的 name
省略了字符 Virtu
,这表明您的映射存在 5 个字节的偏差。
但是,您对 XLbusParams 的映射肯定是错误的。您正在使用 Union
来存储数据,但您只列出了一个恰好有 17 个字节的元素,因此这就是 JNA 用于确定 Union 大小的元素。鉴于添加了 4 字节 _donotuse
元素以使您的结构与新版本兼容,您需要一个 32 字节 XLbusParams
结构。 busType
占 4 个字节,这意味着您的 Union 需要占用 28 个字节。
“快速修复”是在联合体中添加第二个元素,即 28 字节数据字段,例如 public byte[] data = new byte[28];
。这假设您始终处理 Can
内部类型,这可能适合您的用例。正确地,您应该映射联合内的所有不同类型并测试 busType
的值以了解您正在读取哪一种类型。此外,对于联合,您可能需要采取额外的步骤来实际读取数据。
要进一步进行故障排除,请使用 JNA Structure
类 toString()
,它将输出结构中所有原始元素的值(使用 int 的另一个优点
和 long
),并允许您将值逐个元素与预期的 C 输出对齐,以确定字节不匹配的位置。
关于java - 错误的输出来自 JNA 中的结构字段值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58839290/