gjwo
gjwo

Reputation: 195

NoClassDefFoundError: com/pi4j/io/I2CFactory$UnsupportedBusNumberException

I am trying to run java code on a Raspberry Pi model 3, downloaded from a PC eclipse development environment to access a 9DoF device on the I2C bus using the pi4j library. I get the following error:

java -classpath .:classes:/opt/pi4j/lib/'*' -jar /home/pi
/artifacts/RPITank-1.0-SNAPSHOT.jar Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.NoClassDefFoundError: com/pi4j/io/i2c/I2CFa
ctory$UnsupportedBusNumberException at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) at java.lang.Class.privateGetMethodRecursive(Class.java:3048) at java.lang.Class.getMethod0(Class.java:3018) at java.lang.Class.getMethod(Class.java:1784) at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544 ) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526) Caused by: java.lang.ClassNotFoundException: com.pi4j.io.i2c.I2CFactory$Unsuppor
tedBusNumberException at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 7 more

This is the code

package main;

import java.io.IOException;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CFactory;

import devices.I2C.Pi4jI2CDevice;
import devices.sensorImplementations.MPU9250.MPU9250;

public class MPU9250Test {

    public static void main(String[] args)
    {
        I2CBus bus = null;
        System.out.println("Attempt to get Bus 1");
        try {
            final GpioController gpio = GpioFactory.getInstance();
            bus = I2CFactory.getInstance(I2CBus.BUS_1); 
            System.out.println("Got Bus, create devices");
            MPU9250 mpu9250 = new MPU9250(
                    new Pi4jI2CDevice(bus.getDevice(0x68)), // MPU9250 I2C device
                    new Pi4jI2CDevice(bus.getDevice(0x0C)), // ak8963 I2C 
                    100,                                    // sample rate
                    100);                                   // sample size
            Thread sensor = new Thread(mpu9250);
            sensor.start();

            Thread.sleep(10000);

            sensor.interrupt();

            for(int i = mpu9250.getAccelerometerReadingCount() -1; i>0; i--)
            {
                System.out.print("G: " + mpu9250.getRotationalAcceleration(i).toString());
                System.out.print(" A: " + mpu9250.getAcceleration(i).toString());
                System.out.println(" M: " + mpu9250.getGaussianData(i).toString());
            }
        } catch (I2CFactory.UnsupportedBusNumberException | InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }

}

I have checked that the device is visible on bus 1 using I2Cdetect -y 1, this shows a device at address 0x68 and 0x76.

I don't know if this is a problem with the execution environment or the code, any help would be welcome.

Further experimentation shows removing the exception handler isn't an option this is required at compile time. The exception class is described here http://pi4j.com/apidocs/com/pi4j/io/i2c/I2CFactory.UnsupportedBusNumberException.html

Upvotes: 0

Views: 2253

Answers (1)

gjwo
gjwo

Reputation: 195

The issue was that the project jar when transferred to the Raspberry Pi was not picking up its runtime links to the pi4j software preinstalled on the RPi the problem was solved via an issue on github here thanks to natdan.

The changes made to the project pom.xml were as follows:

Add the run time dependency to the dependencies

<dependencies>
<dependency>
    <groupId>com.pi4j</groupId>
    <artifactId>pi4j-core</artifactId>
    <version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>com.pi4j</groupId>
    <artifactId>pi4j-native</artifactId>
    <version>1.2-SNAPSHOT</version>
    <classifier>raspberrypi-dynamic</classifier>
    <type>so</type>
</dependency>

After further experimentation it turned out that this dependency was not required after all, so ignore the section above.

The class path was then added to the maven jar plugin configuration as a manifest entry:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.0.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <!--<classpathPrefix>${pi.pi4j.Directory}/</classpathPrefix>-->
                        <mainClass>${pi.main.class}</mainClass>
                    </manifest>
                    <manifestEntries>
                        <!-- Add the pi4j in runtime. -->
                        <Class-Path>${pi.pi4j.Directory}/pi4j-core.jar</Class-Path>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>

finally the classpath was removed from the java command in the antrun section

                            <!-- run the JAR file on the Raspberry Pi -->
                            <sshexec host="${pi.host}" port="${pi.port}" username="${pi.user}"
                                password="${pi.password}" trust="true" failonerror="false"
                                verbose="true"
                                command="java -jar ${pi.deployDirectory}/${project.build.finalName}.jar" />

Upvotes: 2

Related Questions