You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
NPE when processing open62541.h on Windows 7 (32 bit) #569
There is an open source implementation of OPC UA in written C (http://open62541.org). The single header file called open62541.h (version 0.1 is available for download from their website) throws an NPE in Result.java (215) - see attached console output. The UA_WorkItem struct was being processed.
I believe that the NPE is related to the empty UA_Server struct, because when I provide a dummy implementation of it (struct UA_Server { int i; };) in a header file that includes open62541.h, the NPE disappears.
Yes, I do have a java client working with release 0.1.1 for read/write and browse. The design involved working around restrictions imposed by jnaerator, primarily that structs
cannot be passed by value, so all wrapper functions use pointers for arguments and return values.
The major steps are to:
(1) Write wrapper functions in C that expose just the functionality of interest (e.g. connect, disconnect, read, write, browse). These functions follow a design that the side that
allocates memory is responsible for freeing it (which might require copying the data to pass to java). These C functions are in wrapper62541.h and wrapper62541.c. For example, to connect to
the server, first create the client, connect and then read, write or browse:
(2) Build a dll from the Open62541 source that also includes these functions (I used Eclipse CDT IDE and MinGW C tool chain).
(3) Run jnaerator with Bridj interface with the wrapper62541.h input file (which also includes open62541.h). Here's the input file:
// library name to match dll name
-library Open62541Ext
// source header file
wrapper62541.h
// output folder
-o .
// verbose
-v
// individual output files
-mode Directory
// Windows 32 bit
-arch win32
// use JNA or BridJ interface
-runtime BridJ
// skip deprecated functions
-skipDeprecated
// WIN32 pre-processor flag
-D_WIN32=
// force file overwrite
-f
// java package name
-package
(4) In java I wrote UaClient, UaNode, UaNodeId and UaUtils classes that call into these JNA generated classes. If interested, I can attach the entire source as well as some testing code.
For example, some UaClient's methods are:
public class UaClient {
// wrapped client
private Pointer<UA_Client> client;
// connection flag
boolean isConnected = false;
public UaClient() {
// create client
client = Open62541ExtLibrary.createClient();
}
public synchronized void connect(String serverUrl) throws Exception {
Pointer<Byte> endpointUrl = Pointer
.pointerToBytes(serverUrl.getBytes());
IntValuedEnum<UA_StatusCode> status = Open62541ExtLibrary
.connectClient(client, endpointUrl);
if (status != UA_StatusCode.UA_STATUSCODE_GOOD) {
throw new Exception("Bad connect status: "
+ UaUtils.convertStatusToHexCode(status));
}
isConnected = true;
}
// node must have name space index and identifier set
public synchronized void read(UaNode node) throws Exception {
if (node == null) {
return;
}
Pointer<UA_NodeId> nodeToRead = UaUtils.uaNodeIdFromNode(node);
Pointer<UA_ReadResponse> response = Open62541ExtLibrary.synchRead(
client, nodeToRead);
UA_Variant variant = getVariant(response);
node.setVariantData(variant);
// TODO: variant should be deleted too
Open62541ExtLibrary.deleteReadResponse(response);
}
public synchronized void browse(UaNode parentNode) throws Exception {
if (parentNode == null) {
return;
}
short nodeNSIndex = parentNode.getMainNodeId().getNamespaceIndex();
IntValuedEnum<identifierType_enum> typeEnum = parentNode
.getMainNodeId().getTypeEnum();
Pointer<UA_NodeId> parentNodeId = null;
Pointer<UA_String> pStringId = null;
// numeric node
if (typeEnum
.equals(UA_NodeId.identifierType_enum.UA_NODEIDTYPE_NUMERIC)) {
int numericId = parentNode.getMainNodeId().getNumericIdentifier();
parentNodeId = Open62541ExtLibrary.createNumericNodeId(nodeNSIndex,
numericId);
}
// string node
else if (typeEnum
.equals(UA_NodeId.identifierType_enum.UA_NODEIDTYPE_STRING)) {
String stringId = parentNode.getMainNodeId().getStringIdentifier();
pStringId = UaUtils.uaStringFromString(stringId);
parentNodeId = Open62541ExtLibrary.createStringNodeId(nodeNSIndex,
pStringId);
} else {
throw new Exception("Unsupported node type: " + typeEnum);
}
Pointer<UA_BrowseResponse> browseResponse = Open62541ExtLibrary
.browseNode(client, parentNodeId);
UA_BrowseResponse response = browseResponse.get();
UA_ResponseHeader responseHeader = response.responseHeader();
if (responseHeader.serviceResult() != UA_StatusCode.UA_STATUSCODE_GOOD) {
throw new Exception("Bad browsed status code: "
+ responseHeader.serviceResult());
}
Pointer<UA_BrowseResult> pResult = response.results();
int bound = response.resultsSize();
// iterator has an unknown bound, so keep a counter
int loopCount = 0;
for (UA_BrowseResult browseResult : pResult) {
if (loopCount == bound) {
break;
}
loopCount++;
int innerBound = browseResult.referencesSize();
Pointer<UA_ReferenceDescription> pRef = browseResult.references();
if (pRef == null) {
continue;
}
inspectReferenceDescription(pRef, innerBound, parentNode);
}
if (pStringId != null) {
pStringId.release();
}
return;
}
public synchronized void write(UaNode node, Object value) throws Exception {
if (node == null || value == null) {
return;
}
Pointer<UA_Variant> valueToWrite = null;
if (value instanceof Boolean) {
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_BOOLEAN,
Pointer.pointerToBoolean((Boolean) value));
} else if (value instanceof Byte) {
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_BYTE,
Pointer.pointerToByte((Byte) value));
} else if (value instanceof Short) {
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_INT16,
Pointer.pointerToShort((Short) value));
} else if (value instanceof Integer) {
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_INT32,
Pointer.pointerToInt((Integer) value));
} else if (value instanceof Long) {
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_INT64,
Pointer.pointerToLong((Long) value));
} else if (value instanceof Float) {
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_FLOAT,
Pointer.pointerToFloat((Float) value));
} else if (value instanceof Double) {
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_DOUBLE,
Pointer.pointerToDouble((Double) value));
} else if (value instanceof String) {
Pointer<UA_String> uaString = UaUtils
.uaStringFromString((String) value);
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_STRING, uaString);
} else if (value instanceof ZonedDateTime) {
long uaDateTime = UaUtils.uaDateTimeFromTime((ZonedDateTime) value);
valueToWrite = Open62541ExtLibrary.createScalarVariant(
(short) Open62541ExtLibrary.UA_TYPES_DATETIME,
Pointer.pointerToLong(uaDateTime));
} else {
System.out.println("Unrecognized object class"
+ value.getClass().getSimpleName());
return;
}
Pointer<UA_NodeId> nodeToWrite = UaUtils.uaNodeIdFromNode(node);
Pointer<UA_WriteResponse> response = Open62541ExtLibrary.synchWrite(
client, nodeToWrite, valueToWrite);
UA_ResponseHeader responseHeader = response.get().responseHeader();
if (responseHeader.serviceResult() != UA_StatusCode.UA_STATUSCODE_GOOD) {
throw new Exception("Bad status code on write: "
+ UaUtils.convertStatusToHexCode(responseHeader
.serviceResult()));
}
node.setVariantData(valueToWrite.get());
Open62541ExtLibrary.deleteWriteResponse(response);
Open62541ExtLibrary.deleteVariant(valueToWrite);
}
...
}
These methods are called like this:
UaClient uaClient = new UaClient();
String serverUrl = "opc.tcp://localhost:16664";
uaClient.connect(serverUrl);
short nsIndex = 1;
String id = "the.answer";
// write
UaNode node = new UaNode(nsIndex, id);
uaClient.write(node, value);
System.out.println("Wrote to node: " + node);
// read
uaClient.read(node);
System.out.println("Read node: " + node);
// browse single node
short nsIndex = 1;
int numericId = -1;
String stringId = "the.answer";
UaNode topNode = null;
// read it first to get the value and data type
if (numericId != -1) {
topNode = new UaNode(nsIndex, numericId);
} else {
topNode = new UaNode(nsIndex, stringId);
}
uaClient.read(topNode);
System.out.println("Browsing parent node:" + topNode);
uaClient.browse(topNode);
List<UaNode> childNodes = topNode.getChildren();
for (UaNode childNode : childNodes) {
System.out.println(" Browsed child node: " + childNode);
}
Hello,
Thanks very much for these details. I'm working at CERN (http://cern.ch) on
a project that aims at propagating OPC-UA data over the web. Would you be
interested in collaborating on such a task through Github ? Is there an
existing repository, or should we fork nativelibs4java ?
Thanks
Activity
bcopy commentedon Nov 4, 2015
@billran : Hi, I'm curious to know whether your JNA mappings are working out for you. You can look me up on Linkedin or at CERN.
point85 commentedon Nov 4, 2015
Yes, I do have a java client working with release 0.1.1 for read/write and browse. The design involved working around restrictions imposed by jnaerator, primarily that structs
cannot be passed by value, so all wrapper functions use pointers for arguments and return values.
The major steps are to:
(1) Write wrapper functions in C that expose just the functionality of interest (e.g. connect, disconnect, read, write, browse). These functions follow a design that the side that
allocates memory is responsible for freeing it (which might require copying the data to pass to java). These C functions are in wrapper62541.h and wrapper62541.c. For example, to connect to
the server, first create the client, connect and then read, write or browse:
UA_EXPORT UA_Client *createClient();
UA_EXPORT UA_StatusCode connectClient(UA_Client *client, char *endpointUrl);
UA_EXPORT UA_ReadResponse *synchRead(UA_Client *client, UA_NodeId *nodeId);
UA_EXPORT UA_WriteResponse *synchWrite(UA_Client *client, UA_NodeId *nodeId, UA_Variant *value);
UA_EXPORT UA_BrowseResponse *browseNode(UA_Client *client, UA_NodeId *nodeId);
UA_Client *createClient() {
UA_Client *client = UA_Client_new(UA_ClientConfig_standard,
Logger_Stdout_new());
return client;
}
UA_StatusCode connectClient(UA_Client *client, char *endpointUrl) {
UA_StatusCode retval = UA_Client_connect(client,
ClientNetworkLayerTCP_connect, endpointUrl);
return retval;
}
UA_ReadResponse *synchRead(UA_Client *client, UA_NodeId *nodeId) {
UA_ReadRequest rReq;
UA_ReadRequest_init(&rReq);
rReq.nodesToRead = UA_ReadValueId_new();
rReq.nodesToReadSize = 1;
rReq.nodesToRead[0].nodeId = *nodeId;
rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
}
UA_WriteResponse *synchWrite(UA_Client *client, UA_NodeId *nodeId,
UA_Variant *value) {
}
UA_BrowseResponse *browseNode(UA_Client *client, UA_NodeId *nodeId) {
}
(2) Build a dll from the Open62541 source that also includes these functions (I used Eclipse CDT IDE and MinGW C tool chain).
(3) Run jnaerator with Bridj interface with the wrapper62541.h input file (which also includes open62541.h). Here's the input file:
// library name to match dll name
-library Open62541Ext
// source header file
wrapper62541.h
// output folder
-o .
// verbose
-v
// individual output files
-mode Directory
// Windows 32 bit
-arch win32
// use JNA or BridJ interface
-runtime BridJ
// skip deprecated functions
-skipDeprecated
// WIN32 pre-processor flag
-D_WIN32=
// force file overwrite
-f
// java package name
-package
(4) In java I wrote UaClient, UaNode, UaNodeId and UaUtils classes that call into these JNA generated classes. If interested, I can attach the entire source as well as some testing code.
For example, some UaClient's methods are:
public class UaClient {
bcopy commentedon Nov 5, 2015