XploD
Posts: 35
Joined: Sat Mar 17, 2012 12:14 pm
Contact: Website

Pi4j alternative

Fri Mar 20, 2015 9:59 pm

Is there any alternative to Pi4j since this one is a total crap? First, it won't even work if I have LIRC started. Since my project will use IR remote and LCD + buttons and LEDs at the same time, this is unnaceptable. Second, my R-Pi random crashes (every few minutes) when using Pi4j. I didn't have these problems when I didn't use it. And third, it's too slow. Initialization takes a few seconds and and updating output takes to long. I have 12 LEDs and I need them to blink 50 ms but it's impossible. It takes more than 100 ms to update them.

XploD
Posts: 35
Joined: Sat Mar 17, 2012 12:14 pm
Contact: Website

Re: Pi4j alternative

Sun Mar 22, 2015 5:50 pm

I found a solution: I simply wrote a program in C using wiringPi and compiled it into .so native library and I use it in Java with JNI.

Butch
Posts: 9
Joined: Thu Nov 29, 2012 6:18 pm

Re: Pi4j alternative

Tue Mar 31, 2015 12:20 pm

I don't know where your problem is. I have no problems with pi4j. I have testet it with an 16 port IO Expander and send 3 bytes through i2c per command. In the test i switch 16 LEDs on (one by one) and the same way off. This is so fast, that i can just see every LED dimmed with a little flickering. The only thing that can be slow is when you use thread.wait(). The wakeup can use many more time than suspected. So i had to "active wait".

mihol
Posts: 23
Joined: Wed May 09, 2012 6:55 pm
Location: Germany

Re: Pi4j alternative

Wed Apr 01, 2015 12:46 pm

@Xplod, it would be good to see the facts (source code & measured results). Just ranting won't help anybody ;)

XploD
Posts: 35
Joined: Sat Mar 17, 2012 12:14 pm
Contact: Website

Re: Pi4j alternative

Thu May 14, 2015 10:24 am

Sorry about that, I'm the first one who hates when somebody finds solution and then forgets to write the solution itself, and now I did this myself :mrgreen: I can't perform tests since I don't use this currently and I have another distro running on my Pi (RuneAudio). But I can describe my situation and problems. First problem was it's incompatibility with LIRC. For some reason, Pi4j didn't work while LIRC was running and I had to use remote control and GPIO at the same time. This is just unnaceptable.

Next, I had to use 12 LEDs and lots of buttons. Since RPi didn't have enough GPIO pins for my needs, I used two 8-bit shift registers to control 12 LEDs with only 3 pins (a kind of serial connection). This means that everytime I had to change state of even one LED, I had to write to all 12 LEDs, or, since shift registers was 16 bits, I had to write to all 16 outputs. To write to each LED, I had to set DATA pin, and then CLOCK pin to HIGH, and then to LOW. This is 3 GPIO writes per output x 16 = 48 GPIO writes and at the end, I had to put SET signal to HIGH and then to LOW, so 50 GPIO writes in total, each time I had to change state of some LED. One Pi4j GPIO write took 1-3 ms, so multiplied by 50, this is 50 - 150 ms. Sometimes it took up to 200 ms. But I had to blink some LEDs in 50 ms interval, which was impossible due to this. After I started using C through JNI, 50 ms blinking worked like a charm. Furthermore, I tried even 10 ms, and it worked too. It's hard to see because it's too fast for human eye, but the LED was almost on but it was possible to see that it was blinking. So, WiringPi in C is obviously much faster than Pi4j in Java (even though Pi4j is actually a wrapper based on WiringPi).

I could write the whole program in C but since it was complex, it was much easier to use JNI and use only GPIO in C but buttons and all other in Java.

Here's the code:

wPiInitialize - initializing wiringPi, I had to separate this because if I initialize wiringPi everytime I want to write to LEDs, it gets stuck after a while.

wPiInitialize.h

Code: Select all

#include <jni.h>

#ifndef _Included_wPiInitialize
#define _Included_wPiInitialize
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_TrafficController_wPiInitialize
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
wPiInitialize.c

Code: Select all

#include <stdio.h>
#include <wiringPi.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "wPiInitialize.h"

// This function gets called from Java using JNI
// It initializes GPIO
JNIEXPORT void JNICALL Java_TrafficController_wPiInitialize (JNIEnv *env, jobject obj)
{
	// Initialize GPIO (using wiringPi library)
	wiringPiSetup () ;
	
	return;
}
updateLeds - program for writing to LEDs, it receives an integer from Java as parameter and then it uses the lowest 16 bits for 16 LEDs
Note: JNI works good and fast with simple parameters like integer, but AFAIK it gets slow when using, for example, big arrays as parameters.

updateLeds.h

Code: Select all

#include <jni.h>

#ifndef _Included_updateLeds
#define _Included_updateLeds
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_TrafficController_updateLeds
  (JNIEnv *, jobject, jint data);

#ifdef __cplusplus
}
#endif
#endif
updateLeds.c

Code: Select all

#include <stdio.h>
#include <wiringPi.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "updateLeds.h"

// Define pins for shift register
#define	DATA	0
#define	CLOCK	2
#define SET		1

// This function gets called from Java using JNI
// It receives an integer as a parameter where first 16 bits represent LED states
JNIEXPORT void JNICALL Java_TrafficController_updateLeds (JNIEnv *env, jobject obj, jint data)
{	
	// Declare pins as output
	pinMode (DATA, OUTPUT);
	pinMode (CLOCK, OUTPUT);
	pinMode (SET, OUTPUT);
	
	int i;
	
	// Iterate through first 16 bits of received integer
	for (i = 0; i <= 15; i++)
	{
		// Turn on or off LEDs according to value
		if (1&(data>>i)) digitalWrite (DATA, HIGH);
		else digitalWrite (DATA, LOW);
		
		// After each bit is sent, we have to sent one clock pulse
		digitalWrite (CLOCK, HIGH);
		digitalWrite (CLOCK, LOW);
	}
	
	// A the end, we have to send one set pulse to move data from shift register to output register
	digitalWrite (SET, HIGH);
	digitalWrite (SET, LOW);
	
	return;
}
Generating .so libraries You have to compile this C code to .so shared libraries, using GCC on your Pi. I forgot the exact command, but here is a tutorial for example, but you have to find the path to JDK on your Pi. Once you have .so libraries, we can proceed to Java.

Java - I can't give the whole code since it's huge, but I will give parts important for JNI:

TrafficController.java

Code: Select all

// IMPORTS, there's no need to import anything for JNI

public class TrafficController {
          // VARIABLE DECLARATIONS

          // Function prototypes for JNI (GPIO for updateing leds)
 	    public native void wPiInitialize();
          public native void updateLeds(int data);

          // Load SO libraries for JNI
          static {
                    System.load("/home/pi/programs/Lab/libwpi.so");
                    System.load("/home/pi/programs/Lab/libleds.so");
          }

          // The rest of the code ....
          // Now you can call wPiInitialize(); to inizialize WiringPi
          // And updateLeds(5); for example to send ......101 to turn on 0. and 2. LED
}
Note: the Java class is called TrafficController, and if you look at the function prototype in C code:

Code: Select all

JNIEXPORT void JNICALL Java_TrafficController_updateLeds  (JNIEnv *, jobject, jint data);
you can see that there is TraffcController as well so C must know which Java class will be calling it. the prototype is in the following format: JNIEXPORT return_type JNICALL Java_class_name_function_name (JNIEnv *, jobject, parameters);

Return to “Java”