I am trying to use siUSBxp.dll with java using(JNA) generally every thing fine
but I have problem with SI_CheckRXQueue sometimes it is working fine but sometimes give
"QueueStatus = SI_RX_NO_OVERRUN)" this problem happens only in java
I tried to use same function in c++ it is always working correctly but in java most of the times give me "Queue-status = SI_RX_NO_OVERRUN" and NumBytesInQueue, =0
This is java implementation using JNA :
int SI_CheckRXQueue (HANDLE Handle, IntByReference NumBytesInQueue,IntByReference QueueStatus);
This is native C siUSBxp.dll code
SI_STATUS SI_CheckRXQueue (HANDLE Handle, LPDWORD NumBytesInQueue,LPDWORD QueueStatus)
could you please help me to
Related
I have been reading about the Panama Project recently.
I understand that it will be the next generation replacement to JNI - it will allow java developers to code on the native layer using Java (which is amazing IMHO).
The usage is simple from what I can tell looking at jnr-posix, for example:
public class FileTest {
private static POSIX posix;
#BeforeClass
public static void setUpClass() throws Exception {
posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true);
}
#Test
public void utimesTest() throws Throwable {
// FIXME: On Windows this is working but providing wrong numbers and therefore getting wrong results.
if (!Platform.IS_WINDOWS) {
File f = File.createTempFile("utimes", null);
int rval = posix.utimes(f.getAbsolutePath(), new long[]{800, 200}, new long[]{900, 300});
assertEquals("utimes did not return 0", 0, rval);
FileStat stat = posix.stat(f.getAbsolutePath());
assertEquals("atime seconds failed", 800, stat.atime());
assertEquals("mtime seconds failed", 900, stat.mtime());
// The nano secs part is available in other stat implementations. We really just want to verify that the
// nsec portion of the timeval is passed through to the POSIX call.
// Mac seems to fail this test sporadically.
if (stat instanceof NanosecondFileStat && !Platform.IS_MAC) {
NanosecondFileStat linuxStat = (NanosecondFileStat) stat;
assertEquals("atime useconds failed", 200000, linuxStat.aTimeNanoSecs());
assertEquals("mtime useconds failed", 300000, linuxStat.mTimeNanoSecs());
}
f.delete();
}
}
// ....
// ....
// ....
}
My question is this - having worked with JNI, and knowing how cumbersome it is, will there be a solution for porting existing JNI solutions to the Panama format?
IE - go over the generated (via the deprecated javah) C header file and given implementation in C of the header file, identify functions which can be replaced by the Panama API, then generate a java output file?
Or will existing JNI solutions need to be refactored by hand?
Additional links :
OpenJDK: Panama
Working with Native Libraries in Java
JEP 191: Foreign Function Interface thanks to a comment made by Holger
The JNI format is as follows:
Java -> JNI glue-code library -> Native code
One of the goals of project panama is to remove this middle layer and get:
Java -> Native code
The idea is that you can use a command line tool to process a native header (.h) file to generate a Java interface for calling the native code, and the JDK code will do the rest at runtime as far as connecting the 2 together goes.
If your current JNI code does a lot of stuff in this glue-code layer, then that might have to be re-written on the Java side when porting to panama. (this depends on how much could be done automatically by the used interface extraction tool).
But if you are using something like JNA or JNR then moving to panama should be relatively easy, since those 2 have very similar APIs, where you bind an interface to a native library as well.
But questions like:
will there be a solution for porting existing JNI solutions to the Panama format?
Are difficult to answer, since nobody can predict the future. I feel that there are enough differences between panama and JNI that an automatic 1-to-1 conversion between the 2 will probably not be possible. Though if your glue-code is not doing much besides forwarding arguments then the interface extraction tool will probably be able to do all the work for you.
If you're interested you could take a look at the early access builds of panama that started shipping recently: https://jdk.java.net/panama/
Or watch a recent talk about it: https://youtu.be/cfxBrYud9KM
I have a large amount of Java code (only calculation functions, no UI) that I want to reuse as a static library in iOS. My approach was to use robovm and follow the unofficial way to create a static library described in the two articles in the robovm forum: 1 Basic way and 2 Refined version
Trying to follow the steps exactly as described I got stuck unfortunately after creating the shared library with the script, linking the library (.a) in Xcode and building the project successfully.
During runtime I see that my C++ bridge code is called but the JNI calls back to the library fail with a BAD_ACCESS. For example the following line crashes:
jclass myJavaClass = jniEnv->FindClass("com/test/robovm/bridge/MyJavaRoboCode");
in this method:
void callSomethingInJava(const char* arg) {
// To call into java from your native app, use JNI
Env* rvmEnv = rvmGetEnv();
JNIEnv* jniEnv = &(rvmEnv->jni);
jclass myJavaClass = jniEnv->FindClass("com/test/robovm/bridge/MyJavaRoboCode");
jmethodID myJavaMethod = jniEnv->GetStaticMethodID(myJavaClass, "callJava", "(Ljava/lang/String;)V");
jstring argAsJavaString = jniEnv->NewStringUTF(arg);
jniEnv->CallStaticVoidMethod(myJavaClass, myJavaMethod, argAsJavaString);
}
The same is true if I try to use the rvmXX methods directly instead of JNI and try to access something in my "Java" classes. It looks like the rvmEnv is not fully initialized. (I double checked for package name errors or typos).
It would be great if someone already succeeded with the creation of a shared static library from a robovm project and could share the experience here or point me in the right direction to resolve the issue.
As you mentioned, you probably haven't finished initialising robovm.
You'll need to create a method, say initRoboVM(), to somewhat mirror bc.c's main method. This will be called by your code when you want to initialise robovm. You'll need to pass the app path in, which you can hardcode when you're testing.
initRoboVM() will need some modifications, namely it should not call your Java app's main method, well, at least, that's what well behaving libraries should not do IMO. It should also not call rvmShutdown.
I've got a problem when I try to run a R script from Java Netbeans on Mac OS. I truly look for an answer of this problem on internet but nothing works.
I've used Rserve and Runtime.getRuntime().exec("Rscript myScript.R") but neither of them works with my program.
When I use Rserve, I run Rserve(args="--no-save") on R console and Rconnection.eval("\myscript.R") on Java program and when I execute it, the program continues running without any response, no errors either and no stops. In fact when I try to execute a more simply R script, like calculate the mean or something like that, it works, but when I try to coerce a data.frame in a xts/zoo time series or just to load xts/zoo library first in my script, the program doesn't stop running and does nothing.
On the other hand, when I try to execute "Runtime.getRuntime().exec("Rscript myScript.R")" like appears in other similar post, nothing happens. The program looks to execute the script but it doesn't give me any result although stops running at least. Maybe it is because of Mac OS and that I couldn't indicate to Java what is the Rscript or R.app path, I don't really know.
Thank you very much in advance and I wish you could help me.
Javi.
The file code is:
public void Rconnection () {
RConnection c=new RConnection();
System.out.println("INFO : Trying to Connect to R");
c.parseAndEval("source(\"/scriptname.R\")");
System.out.println("Greeting from R:" + result.asString());
c.close();
}
And the R script is:
EU.df <- read.csv("/myinput.csv",header=T)
EU.xts <- xts(EU.df[,2:5],seq(as.Date("1970-01-02"),len=nrow(EU.df),by="day"))
write.csv(EU.df, file = "/myoutputfile.csv",row.names=FALSE)
Maybe it's because of some problems with R libraries or because of MAC OS.
Have you tried using JRI? That might "block" unlike RServe and give you better messages.
For example:
REngine re = new JRIEngine(new String[] { "--no-save" }, new RCallback(), false);
re.parseAndEval("source(\"/scriptname.R\")");
re.close();
Android with NDK has support to C/C++ code and iOS with Objective-C++ has support too, so how can I write applications with native C/C++ code shared between Android and iOS?
Update.
This answer is quite popular even four years after I write it, in this four years a lot of things has changed, so I decided to update my answer to fit better our current reality. The answer idea does not change; the implementation has changed a little. My English also has changed, it has improved a lot, so the answer is more understandable to everyone now.
Please take a look at the repo so you can download and run the code I'll show below.
The Answer
Before I show the code, please take a lot on the following diagram.
Each OS has its UI and peculiarities, so we intend to write specific code to each platform in this regard. In other hands, all logic code, business rules, and things that can be shared we intend to write using C++, so we can compile the same code to each platform.
In the diagram, you can see the C++ layer at the lowest level. All shared code is in this segment. The highest level is regular Obj-C / Java / Kotlin code, no news here, the hard part is the middle layer.
The middle layer to iOS side is simple; you only need to configure your project to build using a variant of Obj-c know as Objective-C++ and it is all, you have access to C++ code.
The thing became harder on the Android side, both languages, Java and Kotlin, on Android, run under a Java Virtual Machine. So the only way to access C++ code is using JNI, please take time to read the basics of JNI. Fortunately, today's Android Studio IDE has vast improvements on JNI side, and a lot of problems are shown to you while you edit your code.
The code by steps
Our sample is a simple app that you send a text to CPP, and it converts that text to something else and returns it. The idea is, iOS will send "Obj-C" and Android will send "Java" from their respective languages, and the CPP code will create a text as a follow "cpp says hello to << text received >>".
Shared CPP code
First of all, we are going to create the shared CPP code, doing it we have a simple header file with the method declaration that receives the desired text:
#include <iostream>
const char *concatenateMyStringWithCppString(const char *myString);
And the CPP implementation:
#include <string.h>
#include "Core.h"
const char *CPP_BASE_STRING = "cpp says hello to %s";
const char *concatenateMyStringWithCppString(const char *myString) {
char *concatenatedString = new char[strlen(CPP_BASE_STRING) + strlen(myString)];
sprintf(concatenatedString, CPP_BASE_STRING, myString);
return concatenatedString;
}
Unix
An interesting bonus is, we can also use the same code for Linux and Mac as well as other Unix systems. This possibility is especially useful because we can test our shared code faster, so we are going to create a Main.cpp as follow to execute it from our machine and see if the shared code is working.
#include <iostream>
#include <string>
#include "../CPP/Core.h"
int main() {
std::string textFromCppCore = concatenateMyStringWithCppString("Unix");
std::cout << textFromCppCore << '\n';
return 0;
}
To build the code, you need to execute:
$ g++ Main.cpp Core.cpp -o main
$ ./main
cpp says hello to Unix
iOS
It is time to implement on the mobile side. As far as iOS has a simple integration we are starting with it. Our iOS app is a typical Obj-c app with only one difference; the files are .mm and not .m. i.e. It is an Obj-C++ app, not an Obj-C app.
To a better organization, we create the CoreWrapper.mm as follow:
#import "CoreWrapper.h"
#implementation CoreWrapper
+ (NSString*) concatenateMyStringWithCppString:(NSString*)myString {
const char *utfString = [myString UTF8String];
const char *textFromCppCore = concatenateMyStringWithCppString(utfString);
NSString *objcString = [NSString stringWithUTF8String:textFromCppCore];
return objcString;
}
#end
This class has the responsibility to convert CPP types and calls to Obj-C types and calls. It is not mandatory once you can call CPP code on any file you want on Obj-C, but it helps to keep the organisation, and outside your wrapper files you maintain a complete Obj-C styled code, only the wrappers file become CPP styled.
Once your wrapper is connected to the CPP code, you can use it as a standard Obj-C code, e.g. ViewController"
#import "ViewController.h"
#import "CoreWrapper.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *label;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString* textFromCppCore = [CoreWrapper concatenateMyStringWithCppString:#"Obj-C++"];
[_label setText:textFromCppCore];
}
#end
Take a look of how the app looks:
Android
Now it is time for Android integration. Android uses Gradle as the build system, and to C/C++ code it uses CMake. So the first thing we need to do is to configure the CMake on gradle file:
android {
...
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
...
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-std=c++14"
}
}
...
}
And the second step is to add the CMakeLists.txt file:
cmake_minimum_required(VERSION 3.4.1)
include_directories (
../../CPP/
)
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
../../CPP/Core.h
../../CPP/Core.cpp
)
find_library(
log-lib
log
)
target_link_libraries(
native-lib
${log-lib}
)
The CMake file is where you need to add the CPP files and header folders you will use on the project, on our example, we are adding the CPP folder and the Core.h/.cpp files. To know more about C/C++ configuration please read it.
Now the core code is part of our app it is time to create the bridge, to make the things more simple and organized we create a specific class named CoreWrapper to be our wrapper between JVM and CPP:
public class CoreWrapper {
public native String concatenateMyStringWithCppString(String myString);
static {
System.loadLibrary("native-lib");
}
}
Note this class has a native method and loads a native library named native-lib. This library is the one we create, in the end, the CPP code will become a shared object .so File embed in our APK, and the loadLibrary will load it. Finally, when you call the native method, the JVM will delegate the call to the loaded library.
Now the most strange part of Android integration is the JNI; We need a cpp file as follow, in our case "native-lib.cpp":
extern "C" {
JNIEXPORT jstring JNICALL Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString(JNIEnv *env, jobject /* this */, jstring myString) {
const char *utfString = env->GetStringUTFChars(myString, 0);
const char *textFromCppCore = concatenateMyStringWithCppString(utfString);
jstring javaString = env->NewStringUTF(textFromCppCore);
return javaString;
}
}
The first thing you will notice is the extern "C" this part is necessary to JNI work correctly with our CPP code and method linkages. You will also see some symbols JNI uses to works with JVM as JNIEXPORT and JNICALL. To you understand the meaning of those things, it is necessary to take a time and read it, for this tutorial purposes just consider these things as boilerplate.
One significant thing and usually the root of a lot of problems is the name of the method; it needs to follow the pattern "Java_package_class_method". Currently, Android studio has excellent support for it so it can generate this boilerplate automatically and show to you when it is correct or not named. On our example our method is named "Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString" it is because "ademar.androidioscppexample" is our package, so we replace the "." by "_", CoreWrapper is the class where we are linking the native method and "concatenateMyStringWithCppString" is the method name itself.
As we have the method correctly declared it is time to analyze the arguments, the first parameter is a pointer of JNIEnv it is the way we have access to JNI stuff, it is crucial to we make our conversions as you will see soon. The second is a jobject it is the instance of the object you had used to call this method. You can think it as the java "this", on our example we do not need to use it, but we still need to declare it. After this jobject, we are going to receive the arguments of the method. Because our method has only one argument - a String "myString", we have only a "jstring" with the same name. Also notice that our return type is also a jstring. It is because our Java method returns a String, for more information about Java/JNI types please read it.
The final step is to convert the JNI types to the types we use on CPP side. On our example, we are transforming the jstring to a const char * sending it converted to the CPP, getting the result and converting back to jstring. As all other steps on JNI, it is not hard; it is only boilerplated, all the work is done by the JNIEnv* argument we receive when we call the GetStringUTFChars and NewStringUTF. After it our code is ready to run on Android devices, lets take a look.
Approach described in the excellent answer above can be completely automated by Scapix Language Bridge which generates wrapper code on the fly directly from C++ headers. Here is an example:
Define your class in C++:
#include <scapix/bridge/object.h>
class contact : public scapix::bridge::object<contact>
{
public:
std::string name();
void send_message(const std::string& msg, std::shared_ptr<contact> from);
void add_tags(const std::vector<std::string>& tags);
void add_friends(std::vector<std::shared_ptr<contact>> friends);
};
And call it from Swift:
class ViewController: UIViewController {
func send(friend: Contact) {
let c = Contact()
contact.sendMessage("Hello", friend)
contact.addTags(["a","b","c"])
contact.addFriends([friend])
}
}
And from Java:
class View {
private contact = new Contact;
public void send(Contact friend) {
contact.sendMessage("Hello", friend);
contact.addTags({"a","b","c"});
contact.addFriends({friend});
}
}
In past years, we created a program that uses X25 protocol. It was made in C language and works fine for a Sun-Fire machine with Solaris 5.9.
Recently, we are working with java 6 in same machine, and we are trying to adapt that old program in C for working with java via jni.
So I have done some modifications to the old C program and created a shared library named x25lib.so
But I have found a runtime problem using jni and X25: When the C function is invoked from java via jni, the C code does not work in a same way that when it is invoked from another C program.
Concrete, using jni, the C code in shared library works fine until is invoked the system call connect(), then returns -1,
But invoking the same C code of my shared library from another C program returns 0 (ok)
In both cases, the C code in shared library doesn´t receive external parameters so the conditions are the same, I don´t understand if loading my "x25lib.so" shared library from java have a little difference that induce connect() in C fails.
using "truss" command from java I have found the error:
/2: connect(5, 0xFD878B75, 112, 1) Err#22 EINVAL
the same, but invoking the shared lib from another C program:
connect(4, 0xFFBFE794, 114, 1) = 0
So it works ok only with pure C,
Is there another consideration for using jni and X25 for solaris 5.9?
IMPORTANT: C Code in shared library is identical in both cases.
COMPILATION TIME:
a. Creating x25lib.so
cc -w -fd -G -Kpic subs.o -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib -lsockx25
-lsocket -lnsl -I"/SDK/jdk/include/" -I"/SDK/jdk/include/solaris/"
-o x25lib.so -h x25lib.so x25jni.c
b. Creating a test C program with that shared library:
cc -w x25lib.so -o x25test x25test.c
where `x25test.c` contains:
#include <stdio.h>
main()
{
java_x25();
}
c. Using java:
public class X25 {
static {
System.load("/home/x25lib.so");
}
public native void ejecutaComando();
}
public class TestX25 {
public static void main(String ... args) {
X25 x25 = new X25();
x25.ejecutaComando();
}
}
Then in C code shared library:
/*
* Class: X25
* Method: ejecutaComando
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_X25_ejecutaComando
(JNIEnv *env, jobject obj)
{
java_x25();
}
So finally both programs (java y C) call exactly the same C code in shared library:
java_x25()
Without parameters, so execute the same code.
Why works fine when is called from C, but fails when is called from java?
Thanks for any advice.
Thanks for your comments. I have found a solution while I was trying another approach: I decided not using jni, instead I adapted the old C program for listening for simple tcp connections from java and then could execute x25 code, but surprise, I got the same runtime error like using jni:
connect(5, 0xFD8789C5, 112, 1) Err#22 EINVAL
including a size of 112 instead 114, it was the same problem.
So I noticed that the problem was that I had compiled the new C program with "-lsocket" option before "-lsockx25", so that was a clue. Then I searched in google and I found a similar problem:
link to java X25 Bug ID:4077576
At the end of that article, it is mentioned the option LD_PRELOAD to force sockx25 library be loaded first. Finally the solution was at runtime:
bash$ export LD_PRELOAD=/opt/SUNWconn/lib/libsockx25.so
bash$ java TestX25
and then all is working fine using jni.
Reference for LD_PRELOAD: link to java tuning
Some observations (please post your code if you would like us to go deeper on this -- in particular the part that sets up the parameters to connect()):
Assuming X.25 over TCP(?):
From the man page EINVAL is returned from connect(3socket) "namelen is not the size of a valid address for the specified address family" where namelen is the sockaddr structure defined in <sys/socket_impl.h>. namelen is typically 16 (a 2-byte address family (I'd expect SOCK_STREAM) followed by 14 octets of address data). Your program returns namelen 112 or 114.
The address of name in your failing truss(1) output above 0xFD878B75 is odd (odd in the sense "not even"). Given Solaris' typical alignment requirements this seems strange. (SPARC or x86? What compiler and flags?). Perhaps a pointer or sizeof problem?
From your truss(1) output can see that threads are being used in the java invocation. Are your libraries thread-safe?