B4J Question PI4J V2 Wrapper

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

I see that PI4J V2 now have only the DigitalInput and DigitalOutput classes exposed,
so starting from B4J opensource code on github I searched to implementsome other not exposed classes.

I want to implement some others interfaces like SPI, I2C and PWM.

I started to implement SPI interface, implemented SPI.Initialize and SPI.write, but I'm not sure if the code is correct, on Eclipse there are no errors, but actually
I don't have one Raspberry PI to test with some external SPI devices.

On PI4J Documentation I've foud it is powerful, just implement these classes in B4J permits to develop JavaFX applications (and libraries) to interact with external devices, IOExpanders, ADC, TFT, OLEDS, Shift Registers 74HC595 and more.

I'm an'electronic maker and these days I still experiment read a caliper over SPI and show readings on a TFT screen, I actually use a microcontroller, like ESP8266 and ESP32, but this can be done as well by a GUI app on a Raspberry that read the caliper from SPI bus. Note that in both cases need a voltage converter 3.3v-1.5v on SPI bus lines.

This is just an example, but you can do some sophisticated things. Using PWM DC motors and Servos can be controlled by code or by user interface in realtime.

Is someone interested to help to expand it and have Java acknowledge to help expand this library ?
I wrote some B4J and B4A libraries in java on Eclipse, but I'm not an expert.

The community that may want this need your help, and this add another good motivation to use B4J as well.

Here is my last java code with original code and an attempt to implement SPI output.
I even post two links where some users use PI4J V2 to control something over SPI.
https://github.com/Pi4J/pi4j-v2/discussions/167
https://pi4j.com/documentation/io-examples/spi/
Java:
package com.pi4j.b4j;

import com.pi4j.Pi4J;
import com.pi4j.io.gpio.digital.DigitalInput;
import com.pi4j.io.gpio.digital.DigitalInputConfigBuilder;
import com.pi4j.io.gpio.digital.DigitalOutput;
import com.pi4j.io.gpio.digital.DigitalOutputConfigBuilder;
import com.pi4j.io.gpio.digital.DigitalState;
import com.pi4j.io.gpio.digital.DigitalStateChangeEvent;
import com.pi4j.io.gpio.digital.DigitalStateChangeListener;
import com.pi4j.io.gpio.digital.PullResistance;

import com.pi4j.context.Context;

import com.pi4j.io.spi.Spi;
import com.pi4j.io.spi.SpiConfig;
//import com.pi4j.io.spi.SpiConfigBuilder;
import com.pi4j.library.pigpio.PiGpio;

import com.pi4j.io.i2c.I2C;
import com.pi4j.io.i2c.I2CConfig;

//import com.pi4j.plugin.pigpio.provider.gpio.digital.PiGpioDigitalInputProvider;
//import com.pi4j.plugin.pigpio.provider.gpio.digital.PiGpioDigitalOutputProvider;
//import com.pi4j.plugin.pigpio.provider.i2c.PiGpioI2CProvider;
//import com.pi4j.plugin.pigpio.provider.pwm.PiGpioPwmProvider;
//import com.pi4j.plugin.pigpio.provider.serial.PiGpioSerialProvider;
import com.pi4j.plugin.pigpio.provider.spi.PiGpioSpiProvider;

//import java.io.IOException;
import java.io.InputStream;

import anywheresoftware.b4a.AbsObjectWrapper;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.DependsOn;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;

@Version(1.1f)
@ShortName("Pi4J2")
@DependsOn(values= {"pi4j-plugin-raspberrypi-2.1.0", "pi4j-core-2.1.0", "slf4j-api-1.7.30", "slf4j-jdk14-1.7.25",
        "pi4j-plugin-pigpio-2.1.0", "pi4j-library-pigpio"})

public class Pi4JWrapper extends AbsObjectWrapper<Context>{
 
    protected static Spi spi = null;
 
    public void Initialize(String EventName) {
        setObject((Context) Pi4J.newAutoContext()); // Added Context cast
    }
 
    @ShortName("DigitalInput")
    @Events(values = {"StateChange (State As Boolean)"})
    public static class DigitalInputWrapper extends AbsObjectWrapper<DigitalInput> {
        /**
         * Initializes the DigitalInput.
         *Pi4J - Pi4J object.
         *EventName - Sets the sub that will handle the StateChange event.
         *Pin - Pin BCM address.
         *PullResistance - OFF, PULL_UP or PULL_DOWN
         *DebounceMicroSeconds - Debounce duration in microseconds.
         */
        public void Initialize(BA ba, Pi4JWrapper Pi4J, String EventName, int Pin, String PullResistance, long DebounceMicroSeconds) {
            DigitalInputConfigBuilder builder = DigitalInput.newConfigBuilder((com.pi4j.context.Context) Pi4J.getObject());// Added Context cast
            builder.address(Pin);
            builder.debounce(DebounceMicroSeconds).pull(Enum.valueOf(PullResistance.class, PullResistance)).provider("pigpio-digital-input");
            Intiailize2(ba, Pi4J, EventName, builder);
        }
        public void Intiailize2(BA ba, Pi4JWrapper Pi4J, String EventName, DigitalInputConfigBuilder ConfigurationBuilder) {
            final DigitalInput di = ((com.pi4j.context.Context) Pi4J.getObject()).create(ConfigurationBuilder);  // Added (com.pi4j.context.Context) cast
            setObject(di);
            final String eventName = EventName.toLowerCase(BA.cul);
            getObject().addListener(new DigitalStateChangeListener() {
     
                @Override
                public void onDigitalStateChange(@SuppressWarnings("rawtypes") DigitalStateChangeEvent event) {
                    ba.raiseEventFromDifferentThread(di, null, 0, eventName + "_statechange", false, new Object[] {
                            event.state() == DigitalState.HIGH});
                }
            });
        }
        /**
         * Gets the current pin state.
         */
        public boolean getState() {
            return getObject().state() == DigitalState.HIGH;
        }
    }
 
    @ShortName("DigitalOutput")
    public static class DigitalOutputWrapper extends AbsObjectWrapper<DigitalOutput> {
        /**
         * Initializes the DigitalOutput.
         *Pi4J - Pi4J object.
         *Pin - Pin BCM address.
         */
        public void Initialize(BA ba, Pi4JWrapper Pi4J, int Pin) {
 
            DigitalOutputConfigBuilder buttonConfig = DigitalOutput.newConfigBuilder((com.pi4j.context.Context) Pi4J.getObject())  // added cast
              .address(Pin)
              .shutdown(DigitalState.LOW)
              .initial(DigitalState.LOW)
              .provider("pigpio-digital-output");
 
            setObject(((com.pi4j.context.Context)Pi4J.getObject()).create(buttonConfig));  // Added (com.pi4j.context.Context) cast
        }
        /**
         * Gets or sets Sets the pin state.
         */
        public void setState(boolean s) {
            getObject().setState(s);
        }
        public boolean getState() {
            return getObject().state() == DigitalState.HIGH;
        }
    }
 
    @ShortName("SPI")
    @Events(values = {"DataReceived (Data() As Byte)"})
    public static class SPIInterfaceWrapper extends AbsObjectWrapper<Spi> {
        /**
         * Initializes the SPI port.
         *Pi4J - Pi4J object.
         *EventName - Sets the sub that will handle the DataReceived event.
         *Channel - The bus channel (eg. 0-1).
         *Baud - The bus speed in Hz
         *
         *'Example code
         *<code>
         *Dim pi4j As Pi4J2
         *Dim SPI As SPI
         *Dim Channel As Int = 0
         *Dim BaudRate As Int = 8000000
         *SPI.Initialize(pi4j, "SPI", Channel, BaudRate)
         *Dim Bytes = "This is a first SPI test with Raspberry SPI".getBytes("UTF-8")
         *SPI.write(Bytes & CRLF)</code>
         */
        public void Initialize(BA ba, Pi4JWrapper Pi4J, String EventName, int channel, int baud) {
 
             final PiGpio piGpio = PiGpio.newNativeInstance();
//                 com.pi4j.context.Context builder = com.pi4j.Pi4J.newContextBuilder()
//                            .noAutoDetect()
//                            .add(
//                                PiGpioDigitalInputProvider.newInstance(piGpio),
//                                PiGpioDigitalOutputProvider.newInstance(piGpio),
//                                PiGpioPwmProvider.newInstance(piGpio),
//                                PiGpioI2CProvider.newInstance(piGpio),
//                                PiGpioSerialProvider.newInstance(piGpio),
//                                PiGpioSpiProvider.newInstance(piGpio)
//                            )
//                            .build();
           
                 com.pi4j.context.Context builder = com.pi4j.Pi4J.newContextBuilder()
                            .noAutoDetect()
                            .add(
                                PiGpioSpiProvider.newInstance(piGpio)
                            )
                            .build();
     
                //Max7219 neu = new Max7219(builder.create(buildSpiConfig(builder, 0, 8000000)));
     
                //spi = builder.create(buildSpiConfig((Context) builder, 0, 8000000)));
                spi = builder.create(buildSpiConfig((Context) Pi4J.getObject(), channel, baud));
                System.out.println("SPI Configured");
     
                //setObject(((com.pi4j.context.Context)Pi4J.getObject()).create(buildSpiConfig((Context) Pi4J.getObject(), channel, baud)));
                setObject(spi);

                //byte bytes[] = {1, 2, 3, 4, 5, 6};
                //spi.write(bytes);            
            }
 
            private static SpiConfig  buildSpiConfig(Context pi4j, int channel, int baud) {
               return Spi.newConfigBuilder((com.pi4j.context.Context) pi4j)
                  .id("SPI" + channel)
                  .name("Matrix")
                  .address(channel)
                  .baud(baud)
                  .build();
           }
 
            public void write(byte data) {
                spi.write(data);
            }
 
            public void write2(char c) {
                spi.write(c);
            }
 
            public void write3(byte command, byte data) {
                spi.write(command, data);
            }
 
            public void write4(byte Data[]) {
                spi.write(Data);
            }
 
            public void write5(byte Data[], int Length) {
                spi.write(Data, Length);
            }
 
            public void write6(char c[], int Length) {
                spi.write(c, Length);
            }
 
            public void write7(InputStream is, int Length) {
                spi.write(is);
            }
 
    }
 
    @ShortName("I2C")
    @Events(values = {"DataReceived (Data() As Byte)"})
    public static class I2CInterfaceWrapper extends AbsObjectWrapper<I2C> {
 
    }
 
//    /**
//     * Override default providers which would otherwise be inherited from {@link RaspberryPiPlatform} with an empty list.
//     * This is required for manually controlling which providers are being loaded as part of {@link #buildNewContext()}.
//     *
//     * @return Empty provider list
//     */
//    protected String[] getProviders() {
//        return new String[]{};
//    }
 
}
 
Last edited:

peacemaker

Expert
Licensed User
Longtime User
i'm posting just to support you, the topic is interesting and needed, but i cannot help, no knowledge.
 
Upvote 0
Top