问题
I am trying to use the Vector XL Driver Library (vxlapi64.dll) using java code. I created a JNA project to read vxlapi64.dll
and mapped data types also, but output is producing wrong values for the elements of the structure.
C code structure:
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 mapping Structure:
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;
}
I have sample c code which reads the dll and it is getting correct values but using JNA it's not giving correct output values. Is the structure mapping correct or any thing I missed?
Actual output with c code :
- 02 channels Hardware Configuration -
- Ch:00, CM:0x001, Virtual Channel 1, no Cab!
- Ch:01, CM:0x002, Virtual Channel 2, no Cab!
output for above mapping :
- 2 channels Hardware Configuration -
- Ch:01 , CM: 0x000 , Virtual Channel 1 no Cab!
Ch:00 , CM: 0x000 , Virtual Channel 2 no Cab!
Daniel Widdis as suggested you if i could change UnsignedInt to int and XLuint64 to long the output is coming as below
2 channels Hardware Configuration -
- Ch:00 , CM: 0x1000000070000 , Virtual Channel 1 no Cab!
- Ch:700 , CM: 0x1010001000100 , al Channel 2
Consolidated code :
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 {
};
};
}
output:
--------------------------------------------------
- 2 channels Hardware Configuration -
--------------------------------------------------
- Ch:00 , CM: 0x001 , Virtual Channel 1 no Cab!
- Ch:01 , CM: 0x000 , Virtual Channel 2 no Cab!
回答1:
As I've noted in the comments thread, you were incorrectly using a 4-byte mapping (UnsignedInt
) for the 8-byte structure element XLuint64
. That should be replaced by an 8-byte variable (such as long
). While technically correct, there's a lot of overhead creating an object for every one of the unsigned int
values, so it's generally a good idea to simplify your structure and just place int
structure elements there, and deal with the unsigned-ness when interpreting the value.
Your sample output shows that the name
for the second element omits the characters Virtu
, suggesting your mappings are off by 5 bytes.
Your mapping for XLbusParams
is definitely wrong, however. You are using a Union
for the data, but you are only listing one element which happens to have 17 bytes, so that's what JNA is using for the size of your Union. Given the presence of the 4 byte _donotuse
element added to make your structure compatible with the newer version, you need a 32-byte XLbusParams
structure. With 4 bytes for the busType
that means your Union needs to take up 28 bytes.
A "quick fix" is to add a second element inside your union, a 28-byte data field, e.g., public byte[] data = new byte[28];
. This assumes you are always dealing with the Can
internal type, which may work for your use case. Properly you should map all the different types inside the union and test the value of busType
to know which one you're reading. Additionally, for a Union you may need to take extra steps to actually read the data.
For further troubleshooting, use the JNA Structure
class toString()
which will output the value of all primitive elements in the structure (another advantage to use int
and long
) and permit you to line up the values element-by-element with the expected C output to identify where your byte mismatch is.
来源:https://stackoverflow.com/questions/58839290/wrong-output-is-coming-from-structure-filed-values-in-jna