From 2c18e0eb2757b4ff3c6c0f26dc344338a98a5b2e Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Tue, 20 Aug 2019 20:35:19 -0400 Subject: [PATCH 01/15] updated gitignore --- .gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index 973be795d..19e8ee6fc 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,14 @@ Thumbs.db *.zip *.deb /nbactions.xml + +# PlatformIO specific IDE files +.pioenvs +.piolibdeps +.pio + +# Microsoft Visual Studio Code IDE files +.vscode +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json From d43e954af2e0d81dfca0a5d843a3e8bf504f1258 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Tue, 20 Aug 2019 21:12:52 -0400 Subject: [PATCH 02/15] added experimental DigitalOutput builder for evaluation/review. --- .../pi4j/io/gpio/digital/DigitalOutput.java | 4 + .../io/gpio/digital/DigitalOutputBuilder.java | 7 +- .../impl/DefaultDigitalOutputBuilder.java | 82 ++++++++++---- .../main/java/com/pi4j/platform/Platform.java | 16 +++ .../DigitalOutputExampleUsingNewBuilder.java | 107 ++++++++++++++++++ .../com/pi4j/plugin/pigpio/PiGpioPlugin.java | 2 +- 6 files changed, 190 insertions(+), 28 deletions(-) create mode 100644 pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutput.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutput.java index ab18903eb..94da81c76 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutput.java +++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutput.java @@ -27,6 +27,7 @@ * #L% */ +import com.pi4j.context.Context; import com.pi4j.io.Output; import com.pi4j.io.exception.IOException; @@ -39,6 +40,9 @@ public interface DigitalOutput extends Digital callback) throws IOException; diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBuilder.java index b694e8901..5a2ab5914 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBuilder.java @@ -30,8 +30,7 @@ import com.pi4j.context.Context; import com.pi4j.io.gpio.digital.impl.DefaultDigitalOutputBuilder; import com.pi4j.platform.Platform; - -import java.security.Provider; +import com.pi4j.provider.Provider; public interface DigitalOutputBuilder { @@ -48,8 +47,8 @@ public interface DigitalOutputBuilder { DigitalOutputBuilder provider(Class providerClass); static DigitalOutputBuilder newInstance(Context context) { - return DefaultDigitalOutputBuilder.newInstance(); + return DefaultDigitalOutputBuilder.newInstance(context); } - DigitalOutput build(); + DigitalOutput build() throws Exception; } diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java index 80ff8f93a..9b4c32724 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java @@ -27,80 +27,116 @@ * #L% */ -import com.pi4j.io.gpio.digital.DigitalOutput; -import com.pi4j.io.gpio.digital.DigitalOutputBuilder; -import com.pi4j.io.gpio.digital.DigitalState; +import com.pi4j.context.Context; +import com.pi4j.io.gpio.digital.*; import com.pi4j.platform.Platform; +import com.pi4j.util.StringUtil; +import com.pi4j.provider.Provider; -import java.security.Provider; public class DefaultDigitalOutputBuilder implements DigitalOutputBuilder { + private final Context context; + private final DigitalOutputConfigBuilder builder; + + private String platformId = null; + private Class platformClass = null; + private String providerId = null; + private Class providerClass = null; + + public static DigitalOutputBuilder newInstance(Context context) { + return new DefaultDigitalOutputBuilder(context); + } + /** * PRIVATE CONSTRUCTOR */ - protected DefaultDigitalOutputBuilder(){ + protected DefaultDigitalOutputBuilder(Context context) { super(); + this.context = context; + this.builder = DigitalOutputConfigBuilder.newInstance(); } @Override public DigitalOutputBuilder id(String id) { - return null; + this.builder.id(id); + return this; } @Override public DigitalOutputBuilder name(String name) { - return null; + this.builder.name(name); + return this; } @Override public DigitalOutputBuilder description(String description) { - return null; + this.builder.description(description); + return this; } @Override public DigitalOutputBuilder address(Integer address) { - return null; + this.builder.address(address); + return this; } @Override public DigitalOutputBuilder shutdown(DigitalState state) { - return null; + this.builder.shutdown(state); + return this; } @Override public DigitalOutputBuilder initial(DigitalState state) { - return null; + this.builder.initial(state); + return this; } @Override public DigitalOutputBuilder platform(String platformId) { - return null; + this.platformId = platformId; + return this; } @Override public DigitalOutputBuilder platform(Class platformClass) { - return null; + this.platformClass = platformClass; + return this; } @Override public DigitalOutputBuilder provider(String providerId) { - return null; + this.providerId = providerId; + return this; } @Override public DigitalOutputBuilder provider(Class providerClass) { - return null; - } - - public static DigitalOutputBuilder newInstance() { - return new DefaultDigitalOutputBuilder(); + this.providerClass = providerClass; + return this; } @Override - public DigitalOutput build() { - return null; + public DigitalOutput build() throws Exception { + + // create I/O instance config + DigitalOutputConfig config = this.builder.build(); + + if (StringUtil.isNotNullOrEmpty(this.providerId)) { + return (DigitalOutput) context.provider(this.providerId).create(config); + } + if (this.providerClass != null) { + return (DigitalOutput) context.provider(this.providerClass).create(config); + } + if (StringUtil.isNotNullOrEmpty(this.platformId)) { + return context.platforms().get(this.platformId).dout().create(config); + } + if (this.platformClass != null) { + return context.platforms().get(this.platformClass).dout().create(config); + } + + // use default digital output provider + return context.dout().create(config); } - - } diff --git a/pi4j-api/src/main/java/com/pi4j/platform/Platform.java b/pi4j-api/src/main/java/com/pi4j/platform/Platform.java index 17a9f77e6..a19c046c4 100644 --- a/pi4j-api/src/main/java/com/pi4j/platform/Platform.java +++ b/pi4j-api/src/main/java/com/pi4j/platform/Platform.java @@ -90,6 +90,22 @@ default T digitalOutput() throws ProviderExcep return this.provider(IOType.DIGITAL_OUTPUT); } + default T ain() throws ProviderException{ + return analogInput(); + } + + default T aout() throws ProviderException{ + return analogOutput(); + } + + default T din() throws ProviderException{ + return digitalInput(); + } + + default T dout() throws ProviderException{ + return digitalOutput(); + } + default T pwm() throws ProviderException{ return this.provider(IOType.PWM); } diff --git a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java new file mode 100644 index 000000000..9f2d38f38 --- /dev/null +++ b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java @@ -0,0 +1,107 @@ +package com.pi4j.example.gpio.digital; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: EXAMPLE :: Sample Code + * FILENAME : DigitalOutputExample.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.Pi4J; +import com.pi4j.io.gpio.digital.DigitalChangeListener; +import com.pi4j.io.gpio.digital.DigitalOutput; +import com.pi4j.io.gpio.digital.DigitalState; +import com.pi4j.plugin.mock.Mock; +import com.pi4j.util.Console; + +import java.util.concurrent.TimeUnit; + +public class DigitalOutputExampleUsingNewBuilder { + + public static int DIGITAL_OUTPUT_PIN = 4; + + public DigitalOutputExampleUsingNewBuilder() { + } + + public static void main(String[] args) throws Exception { + + // create Pi4J console wrapper/helper + // (This is a utility class to abstract some of the boilerplate stdin/stdout code) + final var console = new Console(); + + // print program title/header + console.title("<-- The Pi4J Project -->", "Basic Digital Output Example"); + + // allow for user to exit program using CTRL-C + console.promptForExit(); + + // Initialize Pi4J with an auto context + // An auto context includes AUTO-DETECT BINDINGS enabled + // which will load all detected Pi4J extension libraries + // (Platforms and Providers) in the class path + var pi4j = Pi4J.newAutoContext(); + + // create a digital output instance using the digital output builder + var output = DigitalOutput.newBuilder(pi4j) + .address(DIGITAL_OUTPUT_PIN) + .id("DIGITAL-OUTPUT-PIN-4") + .name("My Digital Output Pin") + .shutdown(DigitalState.HIGH) + .platform(Mock.PLATFORM_ID) + .build(); + + // setup a digital output listener to listen for any state changes on the digital output + output.addListener((DigitalChangeListener) event -> { + System.out.println(event); + }); + + // lets invoke some changes on the digital output + output.state(DigitalState.HIGH) + .state(DigitalState.LOW) + .state(DigitalState.HIGH) + .state(DigitalState.LOW); + + // lets toggle the digital output state a few times + output.toggle() + .toggle() + .toggle(); + + + // another friendly method of setting output state + output.high() + .low(); + + // lets read the digital output state + System.out.print("CURRENT DIGITAL OUTPUT [" + output + "] STATE IS ["); + System.out.println(output.state() + "]"); + + // pulse to HIGH state for 3 seconds + System.out.println("PULSING OUTPUT STATE TO HIGH FOR 3 SECONDS"); + output.pulse(3, TimeUnit.SECONDS, DigitalState.HIGH); + System.out.println("PULSING OUTPUT STATE COMPLETE"); + + // shutdown Pi4J + console.println("ATTEMPTING TO SHUTDOWN/TERMINATE THIS PROGRAM"); + pi4j.shutdown(); + } +} diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java index e15b60de7..99d764689 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java @@ -110,6 +110,6 @@ public void initialize(PluginService service) throws IOException { @Override public void shutdown(Context context) throws IOException { // shutdown the PiGpio library - piGpio.terminate(); + if(piGpio != null) piGpio.terminate(); } } From 94a7905aa0a61575a46bc0d071cf9ae4e349af49 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Wed, 21 Aug 2019 13:21:46 -0400 Subject: [PATCH 03/15] added Serial config & builders --- .../java/com/pi4j/config/DeviceConfig.java | 2 +- .../com/pi4j/config/DeviceConfigBuilder.java | 2 +- .../pi4j/config/impl/DeviceConfigBase.java | 3 +- .../config/impl/DeviceConfigBuilderBase.java | 5 +- .../main/java/com/pi4j/io/serial/Baud.java | 72 ++++++++++ .../java/com/pi4j/io/serial/DataBits.java | 66 +++++++++ .../pi4j/io/serial/DefaultSerialConfig.java | 59 ++++++++ .../java/com/pi4j/io/serial/FlowControl.java | 68 +++++++++ .../main/java/com/pi4j/io/serial/Parity.java | 79 +++++++++++ .../main/java/com/pi4j/io/serial/Serial.java | 55 ++------ .../java/com/pi4j/io/serial/SerialBase.java | 12 +- .../java/com/pi4j/io/serial/SerialConfig.java | 41 +++--- .../pi4j/io/serial/SerialConfigBuilder.java | 130 ++++++++++++++++++ .../com/pi4j/io/serial/SerialProvider.java | 41 +++++- .../java/com/pi4j/io/serial/StopBits.java | 62 +++++++++ .../io/serial/impl/DefaultSerialConfig.java | 123 +++++++++++++++++ .../impl/DefaultSerialConfigBuilder.java | 83 +++++++++++ .../pi4j/io/serial/impl/SerialFactory.java | 102 -------------- .../src/main/java/com/pi4j/io/spi/Spi.java | 35 +---- .../java/com/pi4j/io/spi/SpiProvider.java | 41 +++++- .../java/com/pi4j/io/spi/impl/SpiFactory.java | 89 ------------ .../pi4j/example/serial/SerialExample.java | 92 +++++++++++++ .../provider/serial/RpiSerial.java | 9 ++ 23 files changed, 976 insertions(+), 295 deletions(-) create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java create mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java delete mode 100644 pi4j-api/src/main/java/com/pi4j/io/serial/impl/SerialFactory.java delete mode 100644 pi4j-api/src/main/java/com/pi4j/io/spi/impl/SpiFactory.java create mode 100644 pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java diff --git a/pi4j-api/src/main/java/com/pi4j/config/DeviceConfig.java b/pi4j-api/src/main/java/com/pi4j/config/DeviceConfig.java index 2c56a9125..cecfaaf90 100644 --- a/pi4j-api/src/main/java/com/pi4j/config/DeviceConfig.java +++ b/pi4j-api/src/main/java/com/pi4j/config/DeviceConfig.java @@ -27,7 +27,7 @@ * #L% */ -public interface DeviceConfig extends AddressConfig { +public interface DeviceConfig extends Config { String DEVICE_KEY = "device"; String device(); diff --git a/pi4j-api/src/main/java/com/pi4j/config/DeviceConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/config/DeviceConfigBuilder.java index ecbe713a5..0ca83b1d7 100644 --- a/pi4j-api/src/main/java/com/pi4j/config/DeviceConfigBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/config/DeviceConfigBuilder.java @@ -27,6 +27,6 @@ * #L% */ -public interface DeviceConfigBuilder extends AddressConfigBuilder { +public interface DeviceConfigBuilder extends ConfigBuilder { BUILDER_TYPE device(String device); } diff --git a/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBase.java b/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBase.java index 149899873..26ee7b3d8 100644 --- a/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBase.java +++ b/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBase.java @@ -27,13 +27,14 @@ * #L% */ +import com.pi4j.config.ConfigBase; import com.pi4j.config.DeviceConfig; import com.pi4j.config.exception.ConfigMissingRequiredKeyException; import java.util.Map; public abstract class DeviceConfigBase> - extends AddressConfigBase + extends ConfigBase implements DeviceConfig { // private configuration variables diff --git a/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java b/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java index e1c223547..ac516c530 100644 --- a/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java +++ b/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java @@ -28,11 +28,12 @@ */ import com.pi4j.config.AddressConfigBuilder; +import com.pi4j.config.ConfigBuilder; import com.pi4j.config.DeviceConfig; import com.pi4j.config.DeviceConfigBuilder; -public abstract class DeviceConfigBuilderBase - extends AddressConfigBuilderBase +public abstract class DeviceConfigBuilderBase + extends ConfigBuilderBase implements DeviceConfigBuilder { /** diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java new file mode 100644 index 000000000..ddce7310d --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java @@ -0,0 +1,72 @@ +package com.pi4j.io.serial; + +/* + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: Java Library (Core) + * FILENAME : Baud.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +public enum Baud { + + _50(50), + _75(75), + _110(110), + _134(134), + _150(150), + _200(200), + _300(300), + _600(600), + _1200(1200), + _1800(1800), + _2400(2400), + _4800(4800), + _9600(9600), + _19200(19200), + _38400(38400), + _57600(57600), + _115200(115200), + _230400(230400); + + private int baud = 0; + + private Baud(int baud){ + this.baud = baud; + } + + public int getValue(){ + return this.baud; + } + public int value(){ + return this.baud; + } + + public static Baud getInstance(int baud_rate){ + for(Baud b : Baud.values()){ + if(b.getValue() == baud_rate){ + return b; + } + } + return null; + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java b/pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java new file mode 100644 index 000000000..639338c8e --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java @@ -0,0 +1,66 @@ +package com.pi4j.io.serial; + +/* + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: Java Library (Core) + * FILENAME : DataBits.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +public enum DataBits { + + _5(5), + _6(6), + _7(7), + _8(8); + + private int dataBits = 0; + + private DataBits(int dataBits){ + this.dataBits = dataBits; + } + + public int getValue(){ + return this.dataBits; + } + public int value(){ + return this.dataBits; + } + + public static DataBits getInstance(int data_bits){ + for(DataBits db : DataBits.values()){ + if(db.getValue() == data_bits){ + return db; + } + } + return null; + } + + public static DataBits parse(String parity) { + if(parity.equalsIgnoreCase("5")) return DataBits._5; + if(parity.equalsIgnoreCase("6")) return DataBits._6; + if(parity.equalsIgnoreCase("7")) return DataBits._7; + if(parity.equalsIgnoreCase("8")) return DataBits._8; + return DataBits._8; + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java b/pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java new file mode 100644 index 000000000..a1409fda6 --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java @@ -0,0 +1,59 @@ +package com.pi4j.io.serial; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) + * FILENAME : SerialConfig.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.config.impl.DeviceConfigBase; +import com.pi4j.io.IOConfig; + +public class DefaultSerialConfig extends DeviceConfigBase implements IOConfig { + + int baud = Serial.DEFAULT_BAUD; + + public DefaultSerialConfig(){ + //super(Serial.DEFAULT_DEVICE); + super(); + } + + public DefaultSerialConfig(String device) { + //super(device); + } + + public DefaultSerialConfig(String device, int baud) { + //super(device); + this.baud = baud; + } + + public int baud() { return this.baud; }; + public DefaultSerialConfig baud(int baud) { this.baud = baud; return this; } + + @Override + public String toString(){ + return String.format("[device=%s; baud=%d]", device(), baud()); + } + +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java b/pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java new file mode 100644 index 000000000..9e4722da4 --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java @@ -0,0 +1,68 @@ +package com.pi4j.io.serial; + +/* + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: Java Library (Core) + * FILENAME : FlowControl.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +public enum FlowControl { + + NONE(0), + HARDWARE(1), + SOFTWARE(2); + + private int index = 0; + + private FlowControl(int index){ + this.index = index; + } + + public int getIndex(){ + return this.index; + } + + public static FlowControl getInstance(String flow_control) { + return FlowControl.valueOf(flow_control.toUpperCase()); + } + + public static FlowControl getInstance(int control){ + for(FlowControl fc : FlowControl.values()){ + if(fc.getIndex() == control){ + return fc; + } + } + return null; + } + + public static FlowControl parse(String parity) { + if(parity.equalsIgnoreCase("0")) return FlowControl.NONE; + if(parity.equalsIgnoreCase("1")) return FlowControl.HARDWARE; + if(parity.equalsIgnoreCase("2")) return FlowControl.SOFTWARE; + if(parity.toLowerCase().startsWith("n")) return FlowControl.NONE; + if(parity.toLowerCase().startsWith("h")) return FlowControl.HARDWARE; + if(parity.toLowerCase().startsWith("s")) return FlowControl.SOFTWARE; + return FlowControl.NONE; + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java new file mode 100644 index 000000000..b6543a003 --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java @@ -0,0 +1,79 @@ +package com.pi4j.io.serial; + +/* + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: Java Library (Core) + * FILENAME : Parity.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.io.gpio.digital.PullResistance; + +public enum Parity { + + NONE(0), + ODD(1), + EVEN(2), + + // NOT ALL UNIX SYSTEM SUPPORT 'MARK' PARITY; THIS IS EXPERIMENTAL + MARK(3), + + //NOT ALL UNIX SYSTEM SUPPORT 'SPACE' PARITY; THIS IS EXPERIMENTAL + SPACE(4); + + private int index = 0; + + private Parity(int index){ + this.index = index; + } + + public int getIndex(){ + return this.index; + } + + public static Parity getInstance(String parity) { + return Parity.valueOf(parity.toUpperCase()); + } + + public static Parity getInstance(int parity){ + for(Parity p : Parity.values()){ + if(p.getIndex() == parity){ + return p; + } + } + return null; + } + public static Parity parse(String parity) { + if(parity.equalsIgnoreCase("0")) return Parity.NONE; + if(parity.equalsIgnoreCase("1")) return Parity.ODD; + if(parity.equalsIgnoreCase("2")) return Parity.EVEN; + if(parity.equalsIgnoreCase("3")) return Parity.MARK; + if(parity.equalsIgnoreCase("4")) return Parity.SPACE; + if(parity.toLowerCase().startsWith("n")) return Parity.NONE; + if(parity.toLowerCase().startsWith("o")) return Parity.ODD; + if(parity.toLowerCase().startsWith("e")) return Parity.EVEN; + if(parity.toLowerCase().startsWith("m")) return Parity.MARK; + if(parity.toLowerCase().startsWith("s")) return Parity.SPACE; + return Parity.NONE; + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java index 075db2586..6dca75440 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java @@ -27,58 +27,23 @@ * #L% */ -import com.pi4j.context.Context; import com.pi4j.io.IO; -import com.pi4j.io.serial.impl.SerialFactory; -import com.pi4j.provider.exception.ProviderException; +import com.pi4j.io.pwm.PwmConfigBuilder; import java.io.IOException; public interface Serial extends IO, AutoCloseable { - static final String ID = "SERIAL"; + int DEFAULT_BAUD = 9600; + DataBits DEFAULT_DATA_BITS = DataBits._8; + Parity DEFAULT_PARITY = Parity.NONE; + StopBits DEFAULT_STOP_BITS = StopBits._1; + FlowControl DEFAULT_FLOW_CONTROL = FlowControl.NONE; - static final int DEFAULT_BAUD = 9600; - static final String DEFAULT_DEVICE = "{DEFAULT}"; - - static Serial instance(Context context, SerialConfig config) throws ProviderException { - return SerialFactory.instance(context, config); - } - - static Serial instance(Context context, String device) throws ProviderException { - return SerialFactory.instance(context, device); - } - - static Serial instance(Context context, String device, int baud) throws ProviderException { - return SerialFactory.instance(context, device, baud); - } - - static Serial instance(Context context, String providerId, String device) throws ProviderException { - return SerialFactory.instance(context, providerId, device); - } - - static Serial instance(Context context, String providerId, String device, int baud) throws ProviderException { - return SerialFactory.instance(context, providerId, device); + static SerialConfigBuilder newConfigBuilder(){ + return SerialConfigBuilder.newInstance(); } - static Serial instance(Context context, String providerId, SerialConfig config) throws ProviderException { - return SerialFactory.instance(context, providerId, config); - } - - static Serial instance(SerialProvider provider, String device) throws ProviderException { - return SerialFactory.instance(provider, device); - } - - static Serial instance(SerialProvider provider, String device, int baud) throws ProviderException { - return SerialFactory.instance(provider, device); - } - - static Serial instance(SerialProvider provider, SerialConfig config) throws ProviderException { - return SerialFactory.instance(provider, config); - } - - - public void open() throws IOException; - public void close() throws IOException; - public void send(CharSequence data); + void open() throws IOException; + void close() throws IOException; } diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java index b729e1b51..ecd461e26 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java @@ -32,6 +32,13 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.Collection; public abstract class SerialBase extends IOBase implements Serial { @@ -51,9 +58,4 @@ public void open() throws IOException { public void close() throws IOException { logger.trace("invoked 'closed()'"); } - - @Override - public void send(CharSequence data) { - logger.trace("invoked 'send({})'", data); - } } diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfig.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfig.java index 12af6cef1..b6c844061 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfig.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfig.java @@ -27,33 +27,38 @@ * #L% */ -import com.pi4j.config.impl.DeviceConfigBase; +import com.pi4j.config.DeviceConfig; import com.pi4j.io.IOConfig; -public class SerialConfig extends DeviceConfigBase implements IOConfig { +public interface SerialConfig extends DeviceConfig, IOConfig { + String BAUD_KEY = "baud"; + String STOP_BITS_KEY = "stop-bits"; + String DATA_BITS_KEY = "data-bits"; + String PARITY_KEY = "parity"; + String FLOW_CONTROL_KEY = "flow-control"; - int baud = Serial.DEFAULT_BAUD; - - public SerialConfig(){ - //super(Serial.DEFAULT_DEVICE); - super(); + Integer baud(); + default Integer getBaud() { + return baud(); } - public SerialConfig(String device) { - //super(device); + StopBits stopBits(); + default StopBits getStopBits() { + return stopBits(); } - public SerialConfig(String device, int baud) { - //super(device); - this.baud = baud; + DataBits dataBits(); + default DataBits getDataBits() { + return dataBits(); } - public int baud() { return this.baud; }; - public SerialConfig baud(int baud) { this.baud = baud; return this; } - - @Override - public String toString(){ - return String.format("[device=%s; baud=%d]", device(), baud()); + Parity parity(); + default Parity getParity() { + return parity(); } + FlowControl flowControl(); + default FlowControl getFlowControl(){ + return flowControl(); + } } diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java new file mode 100644 index 000000000..d4ee5e35f --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java @@ -0,0 +1,130 @@ +package com.pi4j.io.serial; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) + * FILENAME : PwmConfigBuilder.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.config.DeviceConfigBuilder; +import com.pi4j.config.impl.DeviceConfigBuilderBase; +import com.pi4j.io.gpio.GpioConfigBuilder; +import com.pi4j.io.pwm.PwmConfig; +import com.pi4j.io.pwm.PwmPreset; +import com.pi4j.io.pwm.PwmType; +import com.pi4j.io.pwm.impl.DefaultPwmConfigBuilder; +import com.pi4j.io.serial.impl.DefaultSerialConfigBuilder; + +public interface SerialConfigBuilder extends DeviceConfigBuilder { + static SerialConfigBuilder newInstance() { + return DefaultSerialConfigBuilder.newInstance(); + } + + SerialConfigBuilder baud(Integer rate); + default SerialConfigBuilder baud(Baud rate){ + return baud(rate.value()); + } + + SerialConfigBuilder dataBits(DataBits bits); + default SerialConfigBuilder dataBits(Integer bits){ + return dataBits(DataBits.getInstance(bits)); + } + + SerialConfigBuilder parity(Parity parity); + default SerialConfigBuilder parity(int parity){ + return parity(Parity.getInstance(parity)); + } + + SerialConfigBuilder stopBits(StopBits bits); + default SerialConfigBuilder stopBits(Integer bits){ + return stopBits(StopBits.getInstance(bits)); + } + + SerialConfigBuilder flowControl(FlowControl control); + default SerialConfigBuilder flowControl(Integer control){ + return flowControl(FlowControl.getInstance(control)); + } + + default SerialConfigBuilder baud_50() { return baud(Baud._50); } + default SerialConfigBuilder baud_75() { return baud(Baud._75); } + default SerialConfigBuilder baud_110() { return baud(Baud._110); } + default SerialConfigBuilder baud_134() { return baud(Baud._134); } + default SerialConfigBuilder baud_150() { return baud(Baud._150); } + default SerialConfigBuilder baud_200() { return baud(Baud._200); } + default SerialConfigBuilder baud_300() { return baud(Baud._300); } + default SerialConfigBuilder baud_600() { return baud(Baud._600); } + default SerialConfigBuilder baud_1200() { return baud(Baud._1200); } + default SerialConfigBuilder baud_1800() { return baud(Baud._1800); } + default SerialConfigBuilder baud_2400() { return baud(Baud._2400); } + default SerialConfigBuilder baud_4800() { return baud(Baud._4800); } + default SerialConfigBuilder baud_9600() { return baud(Baud._9600); } + default SerialConfigBuilder baud_19200() { return baud(Baud._19200); } + default SerialConfigBuilder baud_38400() { return baud(Baud._38400); } + default SerialConfigBuilder baud_57600() { return baud(Baud._57600); } + default SerialConfigBuilder baud_115200() { return baud(Baud._115200); } + default SerialConfigBuilder baud_230400() { return baud(Baud._230400); } + + default SerialConfigBuilder dataBits_5() { return dataBits(DataBits._5); } + default SerialConfigBuilder dataBits_6() { return dataBits(DataBits._6); } + default SerialConfigBuilder dataBits_7() { return dataBits(DataBits._7); } + default SerialConfigBuilder dataBits_8() { return dataBits(DataBits._8); } + + default SerialConfigBuilder parityNone() { return parity(Parity.NONE); } + default SerialConfigBuilder parityOdd() { return parity(Parity.ODD); } + default SerialConfigBuilder parityEven() { return parity(Parity.EVEN); } + default SerialConfigBuilder parityMark() { return parity(Parity.MARK); } + default SerialConfigBuilder paritySpace() { return parity(Parity.SPACE); } + + default SerialConfigBuilder flowNone() { return flowControl(FlowControl.NONE); } + default SerialConfigBuilder flowHardware(){ return flowControl(FlowControl.HARDWARE); } + default SerialConfigBuilder flowSoftware(){ return flowControl(FlowControl.SOFTWARE); } + + default SerialConfigBuilder stopBits_1() { return stopBits(StopBits._1); } + default SerialConfigBuilder stopBits_2() { return stopBits(StopBits._2); } + + default SerialConfigBuilder baud8N1(Baud baud) { + return baud8N1(baud.value()); + } + default SerialConfigBuilder baud8N1(Integer baud) { + baud(baud); + dataBits(DataBits._8); + parity(Parity.NONE); + stopBits(StopBits._1); + flowControl(FlowControl.NONE); + return this; + } + + default SerialConfigBuilder use_9600_N81() { + return baud8N1(Baud._9600); + } + default SerialConfigBuilder use_38400_N81() { + return baud8N1(Baud._38400); + } + default SerialConfigBuilder use_57600_N81() { + return baud8N1(Baud._57600); + } + default SerialConfigBuilder use_115200_N81() { + return baud8N1(Baud._115200); + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java index 1888c0760..b090db06a 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java @@ -27,9 +27,48 @@ * #L% */ +import com.pi4j.io.pwm.Pwm; +import com.pi4j.io.pwm.PwmConfigBuilder; import com.pi4j.provider.Provider; public interface SerialProvider extends Provider { - //Serial instance(SerialConfig config) throws Exception; + + default T create(SerialConfigBuilder builder) throws Exception { + return (T)create(builder.build()); + } + +// default T create(Integer address) throws Exception { +// var config = Serial.newConfigBuilder() +// .address(address) +// .build(); +// return (T)create(config); +// } +// +// default T create(Integer address, String id) throws Exception { +// var config = Serial.newConfigBuilder() +// .address(address) +// .id(id) +// .build(); +// return (T)create(config); +// } +// +// default T create(Integer address, String id, String name) throws Exception { +// var config = Serial.newConfigBuilder() +// .address(address) +// .id(id) +// .name(name) +// .build(); +// return (T)create(config); +// } +// +// default T create(Integer address, String id, String name, String description) throws Exception { +// var config = Serial.newConfigBuilder() +// .address(address) +// .id(id) +// .name(name) +// .description(description) +// .build(); +// return (T)create(config); +// } } diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java b/pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java new file mode 100644 index 000000000..2329b24cf --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java @@ -0,0 +1,62 @@ +package com.pi4j.io.serial; + +/* + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: Java Library (Core) + * FILENAME : StopBits.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +public enum StopBits { + + _1(1), + _2(2); + + private int stopBits = 0; + + private StopBits(int stopBits){ + this.stopBits = stopBits; + } + + public int getValue(){ + return this.stopBits; + } + public int value(){ + return this.stopBits; + } + + public static StopBits getInstance(int stop_bits){ + for(StopBits sb : StopBits.values()){ + if(sb.getValue() == stop_bits){ + return sb; + } + } + return null; + } + + public static StopBits parse(String parity) { + if(parity.equalsIgnoreCase("1")) return StopBits._1; + if(parity.equalsIgnoreCase("2")) return StopBits._2; + return StopBits._1; + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java new file mode 100644 index 000000000..d36d228f8 --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java @@ -0,0 +1,123 @@ +package com.pi4j.io.serial.impl; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) + * FILENAME : DefaultPwmConfig.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.config.impl.DeviceConfigBase; +import com.pi4j.io.gpio.digital.PullResistance; +import com.pi4j.io.serial.*; +import com.pi4j.util.StringUtil; + +import java.util.Map; + +public class DefaultSerialConfig + extends DeviceConfigBase + implements SerialConfig { + + // private configuration properties + protected final Integer baud; + protected final StopBits stopBits; + protected final DataBits dataBits; + protected final Parity parity; + protected final FlowControl flowControl; + + // private configuration properties + protected PullResistance pullResistance = PullResistance.OFF; + + /** + * PRIVATE CONSTRUCTOR + * @param properties + */ + protected DefaultSerialConfig(Map properties){ + super(properties); + + // define default property values if any are missing (based on the required address value) + this.id = StringUtil.setIfNullOrEmpty(this.id, "SERIAL-" + this.device, true); + this.name = StringUtil.setIfNullOrEmpty(this.name, "SERIAL-" + this.device, true); + this.description = StringUtil.setIfNullOrEmpty(this.description, "SERIAL-" + this.device, true); + + // load optional BAUD RATE from properties + if(properties.containsKey(BAUD_KEY)){ + this.baud = StringUtil.parseInteger(properties.get(BAUD_KEY), Serial.DEFAULT_BAUD); + } else { + this.baud = Serial.DEFAULT_BAUD; + } + + // load optional DATA BITS from properties + if(properties.containsKey(DATA_BITS_KEY)){ + this.dataBits = DataBits.parse(properties.get(DATA_BITS_KEY)); + } else { + this.dataBits = Serial.DEFAULT_DATA_BITS; + } + + // load optional PARITY from properties + if(properties.containsKey(PARITY_KEY)){ + this.parity = Parity.parse(properties.get(PARITY_KEY)); + } else { + this.parity = Serial.DEFAULT_PARITY; + } + + // load optional STOP BITS from properties + if(properties.containsKey(STOP_BITS_KEY)){ + this.stopBits = StopBits.parse(properties.get(STOP_BITS_KEY)); + } else { + this.stopBits = Serial.DEFAULT_STOP_BITS; + } + + // load optional FLOW CONTROL from properties + if(properties.containsKey(FLOW_CONTROL_KEY)){ + this.flowControl = FlowControl.parse(properties.get(FLOW_CONTROL_KEY)); + } else { + this.flowControl = Serial.DEFAULT_FLOW_CONTROL; + } + } + + @Override + public Integer baud() { + return this.baud; + } + + @Override + public StopBits stopBits() { + return this.stopBits; + } + + @Override + public DataBits dataBits() { + return this.dataBits; + } + + @Override + public Parity parity() { + return this.parity; + } + + @Override + public FlowControl flowControl() { + return this.flowControl; + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java new file mode 100644 index 000000000..913c509c9 --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java @@ -0,0 +1,83 @@ +package com.pi4j.io.serial.impl; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) + * FILENAME : DefaultPwmConfigBuilder.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.config.impl.DeviceConfigBuilderBase; +import com.pi4j.io.serial.*; + +public class DefaultSerialConfigBuilder + extends DeviceConfigBuilderBase + implements SerialConfigBuilder { + + /** + * PRIVATE CONSTRUCTOR + */ + protected DefaultSerialConfigBuilder(){ + super(); + } + + public static SerialConfigBuilder newInstance() { + return new DefaultSerialConfigBuilder(); + } + + @Override + public SerialConfigBuilder baud(Integer rate) { + this.properties.put(SerialConfig.BAUD_KEY, rate.toString()); + return this; + } + + @Override + public SerialConfigBuilder dataBits(DataBits bits) { + this.properties.put(SerialConfig.DATA_BITS_KEY, Integer.toString(bits.value())); + return this; + } + + @Override + public SerialConfigBuilder parity(Parity parity) { + this.properties.put(SerialConfig.PARITY_KEY, parity.name()); + return this; + } + + @Override + public SerialConfigBuilder stopBits(StopBits bits) { + this.properties.put(SerialConfig.STOP_BITS_KEY, Integer.toString(bits.value())); + return this; + } + + @Override + public SerialConfigBuilder flowControl(FlowControl control) { + this.properties.put(SerialConfig.FLOW_CONTROL_KEY, control.name()); + return this; + } + + @Override + public SerialConfig build() { + SerialConfig config = new DefaultSerialConfig(this.properties); + return config; + } +} diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/SerialFactory.java b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/SerialFactory.java deleted file mode 100644 index d8d13a6c4..000000000 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/SerialFactory.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.pi4j.io.serial.impl; - -/* - * #%L - * ********************************************************************** - * ORGANIZATION : Pi4J - * PROJECT : Pi4J :: LIBRARY :: Java Library (API) - * FILENAME : SerialFactory.java - * - * This file is part of the Pi4J project. More information about - * this project can be found here: https://pi4j.com/ - * ********************************************************************** - * %% - * Copyright (C) 2012 - 2019 Pi4J - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.pi4j.context.Context; -import com.pi4j.io.serial.Serial; -import com.pi4j.io.serial.SerialConfig; -import com.pi4j.io.serial.SerialProvider; -import com.pi4j.io.spi.Spi; -import com.pi4j.provider.exception.ProviderException; - -/** - * SPI factory - it returns instances of {@link Spi} interface. - * - * @author Robert Savage (http://www.savagehomeautomation.com) - */ -public class SerialFactory { - - // private constructor - private SerialFactory() { - // forbid object construction - } - - public static Serial instance(Context context, String device) throws ProviderException { - return instance(context, new SerialConfig(device)); - } - - public static Serial instance(Context context, String device, int baud) throws ProviderException { - return instance(context, new SerialConfig(device, baud)); - } - - public static Serial instance(Context context, SerialConfig config) throws ProviderException { - // get SPI instance using default provider - SerialProvider provider = context.serial(); - return instance(provider, config); - } - - public static Serial instance(Context context, String providerId, String device) throws ProviderException { - return instance(context, providerId, new SerialConfig(device)); - } - - public static Serial instance(Context context, String providerId, String device, int baud) throws ProviderException { - return instance(context, providerId, new SerialConfig(device, baud)); - } - - public static Serial instance(Context context, String providerId, SerialConfig config) throws ProviderException { - // if provided, lookup the specified io; else use the default io - if(providerId == null) { - return instance(context, config); - } - else{ - SerialProvider provider = context.providers().serial().get(providerId); - return instance(provider, config); - } - } - - public static Serial instance(SerialProvider provider, String device) throws ProviderException { - return instance(provider, new SerialConfig(device)); - } - - public static Serial instance(SerialProvider provider, String device, int baud) throws ProviderException { - return instance(provider, new SerialConfig(device, baud)); - } - - public static Serial instance(SerialProvider provider, SerialConfig config) throws ProviderException { - try { - // create a SPI instance using the io - return provider.create(config); - } catch(ProviderException pe){ - throw pe; - } catch (Exception e) { - //e.printStackTrace(); - throw new ProviderException(provider, e); - } - } -} diff --git a/pi4j-api/src/main/java/com/pi4j/io/spi/Spi.java b/pi4j-api/src/main/java/com/pi4j/io/spi/Spi.java index a0cf35f30..440df302f 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/spi/Spi.java +++ b/pi4j-api/src/main/java/com/pi4j/io/spi/Spi.java @@ -28,10 +28,7 @@ */ -import com.pi4j.context.Context; import com.pi4j.io.IO; -import com.pi4j.io.spi.impl.SpiFactory; -import com.pi4j.provider.exception.ProviderException; import java.io.IOException; import java.io.InputStream; @@ -41,34 +38,14 @@ public interface Spi extends IO { - static final String ID = "SPI"; - static final SpiMode DEFAULT_SPI_MODE = SpiMode.MODE_0; - static final int DEFAULT_SPI_SPEED = 1000000; // 1MHz (range is 500kHz - 32MHz) - static final int MAX_SUPPORTED_BYTES = 2048; + SpiMode DEFAULT_SPI_MODE = SpiMode.MODE_0; + int DEFAULT_SPI_SPEED = 1000000; // 1MHz (range is 500kHz - 32MHz) + int MAX_SUPPORTED_BYTES = 2048; - static Spi instance(Context context, SpiConfig config) throws ProviderException { - return SpiFactory.instance(context, config); - } +// static SpiConfigBuilder newConfigBuilder(){ +// return SpiConfigBuilder.newInstance(); +// } - static Spi instance(Context context, String device) throws ProviderException { - return SpiFactory.instance(context, device); - } - - static Spi instance(Context context, String providerId, String device) throws ProviderException { - return SpiFactory.instance(context, providerId, device); - } - - static Spi instance(Context context, String providerId, SpiConfig config) throws ProviderException { - return SpiFactory.instance(context, providerId, config); - } - - static Spi instance(SpiProvider provider, String device) throws ProviderException { - return SpiFactory.instance(provider, device); - } - - static Spi instance(SpiProvider provider, SpiConfig config) throws ProviderException { - return SpiFactory.instance(provider, config); - } /** * Attempts to read/write data through this SPI device diff --git a/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java b/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java index 5683ae8ba..654b4f8b8 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java +++ b/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java @@ -28,8 +28,47 @@ */ +import com.pi4j.io.serial.Serial; import com.pi4j.provider.Provider; public interface SpiProvider extends Provider { - //Spi instance(SpiConfig config) throws Exception; + +// default T create(SpiConfigBuilder builder) throws Exception { +// return (T)create(builder.build()); +// } + +// default T create(Integer address) throws Exception { +// var config = Spi.newConfigBuilder() +// .address(address) +// .build(); +// return (T)create(config); +// } +// +// default T create(Integer address, String id) throws Exception { +// var config = Spi.newConfigBuilder() +// .address(address) +// .id(id) +// .build(); +// return (T)create(config); +// } +// +// default T create(Integer address, String id, String name) throws Exception { +// var config = Spi.newConfigBuilder() +// .address(address) +// .id(id) +// .name(name) +// .build(); +// return (T)create(config); +// } +// +// default T create(Integer address, String id, String name, String description) throws Exception { +// var config = Spi.newConfigBuilder() +// .address(address) +// .id(id) +// .name(name) +// .description(description) +// .build(); +// return (T)create(config); +// } + } diff --git a/pi4j-api/src/main/java/com/pi4j/io/spi/impl/SpiFactory.java b/pi4j-api/src/main/java/com/pi4j/io/spi/impl/SpiFactory.java deleted file mode 100644 index ecef57277..000000000 --- a/pi4j-api/src/main/java/com/pi4j/io/spi/impl/SpiFactory.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.pi4j.io.spi.impl; - -/* - * #%L - * ********************************************************************** - * ORGANIZATION : Pi4J - * PROJECT : Pi4J :: LIBRARY :: Java Library (API) - * FILENAME : SpiFactory.java - * - * This file is part of the Pi4J project. More information about - * this project can be found here: https://pi4j.com/ - * ********************************************************************** - * %% - * Copyright (C) 2012 - 2019 Pi4J - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.pi4j.context.Context; -import com.pi4j.io.spi.Spi; -import com.pi4j.io.spi.SpiConfig; -import com.pi4j.io.spi.SpiProvider; -import com.pi4j.provider.exception.ProviderException; - -/** - * SPI factory - it returns instances of {@link Spi} interface. - * - * @author Robert Savage (http://www.savagehomeautomation.com) - */ -public class SpiFactory { - - // private constructor - private SpiFactory() { - // forbid object construction - } - - public static Spi instance(Context context, String device) throws ProviderException { - return instance(context, new SpiConfig(device)); - } - - public static Spi instance(Context context, SpiConfig config) throws ProviderException { - // get SPI instance using default platform IO provider - var provider = context.platform().spi(); - return instance(provider, config); - } - - public static Spi instance(Context context, String providerId, String device) throws ProviderException { - return instance(context, providerId, new SpiConfig(device)); - } - - public static Spi instance(Context context, String providerId, SpiConfig config) throws ProviderException { - // if provided, lookup the specified io; else use the default io - if(providerId == null) { - return instance(context, config); - } - else{ - var provider = context.providers().spi().get(providerId); - return instance(provider, config); - } - } - - public static Spi instance(SpiProvider provider, String device) throws ProviderException { - return instance(provider, new SpiConfig(device)); - } - - public static Spi instance(SpiProvider provider, SpiConfig config) throws ProviderException { - try { - // create a SPI instance using the io - return provider.create(config); - } catch(ProviderException pe){ - throw pe; - } catch (Exception e) { - //e.printStackTrace(); - throw new ProviderException(provider, e); - } - } -} diff --git a/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java b/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java new file mode 100644 index 000000000..179a26f76 --- /dev/null +++ b/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java @@ -0,0 +1,92 @@ +package com.pi4j.example.serial; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: EXAMPLE :: Sample Code + * FILENAME : I2cDeviceExample.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.Pi4J; +import com.pi4j.io.i2c.I2C; +import com.pi4j.io.serial.Serial; +import com.pi4j.util.Console; + +import java.nio.ByteBuffer; + +public class SerialExample { + + private static int I2C_BUS = 1; + private static int I2C_DEVICE = 0x04; + + public static void main(String[] args) throws Exception { + + // TODO :: REMOVE TEMPORARY PROPERTIES WHEN NATIVE PIGPIO LIB IS READY + // this temporary property is used to tell + // PIGPIO which remote Raspberry Pi to connect to + System.setProperty("pi4j.host", "rpi3bp.savage.lan"); + + // create Pi4J console wrapper/helper + // (This is a utility class to abstract some of the boilerplate stdin/stdout code) + final var console = new Console(); + + // print program title/header + console.title("<-- The Pi4J Project -->", "Basic Serial Communications Example"); + + // allow for user to exit program using CTRL-C + console.promptForExit(); + + // Initialize Pi4J with an auto context + // An auto context includes AUTO-DETECT BINDINGS enabled + // which will load all detected Pi4J extension libraries + // (Platforms and Providers) in the class path + var pi4j = Pi4J.newAutoContext(); + + // create SERIAL config + var config = Serial.newConfigBuilder() + .id("my-serial-port") + .name("My Serial Port") + .device("") + .use_9600_N81() + .build(); + + // use try-with-resources to auto-close SERIAL when complete + try (var serial = pi4j.serial().create(config);) { + + // open serial port communications + serial.open(); + + + // serial port will be closed when this block goes + // out of scope by the AutoCloseable interface on Serial + } + + // create a digital input instance using the default digital input provider + // wait (block) for user to exit program using CTRL-C + console.waitForExit(); + + // shutdown Pi4J + console.println("ATTEMPTING TO SHUTDOWN/TERMINATE THIS PROGRAM"); + pi4j.shutdown(); + } +} diff --git a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java index 95a500fe9..f6c0788ab 100644 --- a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java +++ b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java @@ -34,6 +34,15 @@ import com.pi4j.io.serial.SerialConfig; import com.pi4j.io.serial.SerialProvider; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.Collection; + public class RpiSerial extends SerialBase implements Serial { public RpiSerial(SerialProvider provider, SerialConfig config){ From cf36d40f0d31b35d67f54d2c3872b3c89c1925c9 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Wed, 21 Aug 2019 23:43:00 -0400 Subject: [PATCH 04/15] added Serial interface and impl for PIGPIO lib --- .../java/com/pi4j/library/pigpio/PiGpio.java | 2 +- .../com/pi4j/library/pigpio/PiGpioPacket.java | 21 +- .../com/pi4j/library/pigpio/PiGpio_I2C.java | 24 +- .../pi4j/library/pigpio/PiGpio_Serial.java | 131 ++++++++++ .../pi4j/library/pigpio/impl/PiGpioBase.java | 4 +- .../library/pigpio/impl/PiGpioSocketImpl.java | 140 +++++++++-- .../java/com/pi4j/library/pigpio/Main.java | 49 ++-- .../TestDigitalInputsUsingTestHarness.java | 22 +- .../TestDigitalOutputsUsingTestHarness.java | 2 +- .../test/i2c/TestI2cRawUsingTestHarness.java | 3 + .../pwm/TestSoftwarePwmUsingTestHarness.java | 1 + .../serial/TestSerialUsingTestHarness.java | 224 +++++++++++++++++ .../src/main/arduino/src/command/Commands.h | 2 + .../src/command/CommandsArgumentParser.h | 53 ++++ .../arduino/src/command/SerialEchoCommand.h | 98 ++++++++ .../src/main/arduino/src/main.cpp | 228 ++---------------- pi4j-test-harness/src/main/arduino/src/main.h | 2 + pi4j-test-harness/src/main/arduino/src/pi4j.h | 2 + .../pi4j/test/harness/ArduinoTestHarness.java | 50 +++- .../TestDigitalInputUsingTestHarness.java | 21 +- 20 files changed, 779 insertions(+), 300 deletions(-) create mode 100644 libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java create mode 100644 libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java create mode 100644 pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio.java index 793e5ca8e..104e3e2e6 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio.java @@ -33,7 +33,7 @@ import java.io.IOException; -public interface PiGpio extends PiGpio_I2C, PiGpio_GPIO, PiGpio_PWM { +public interface PiGpio extends PiGpio_I2C, PiGpio_GPIO, PiGpio_PWM, PiGpio_Serial { /** * Creates a PiGpio instance using TCP Socket communication for remote I/O access. diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java index db0e11fd8..5afdd1c9a 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java @@ -135,11 +135,24 @@ public int dataLength(){ public byte[] data(){ return this.data; } - public PiGpioPacket data(byte[] data){ + + public PiGpioPacket data(CharSequence data){ + return this.data(data.toString().getBytes(StandardCharsets.US_ASCII)); + } + + public PiGpioPacket data(byte[] data) { + return data(data, data.length); + } + + public PiGpioPacket data(byte[] data, int length) { + return data(data, 0, data.length); + } + + public PiGpioPacket data(byte[] data, int offset, int length){ // check for valid data - if(data != null && data.length > 0) { - this.p3 = data.length; - this.data = Arrays.copyOf(data, data.length); + if(data != null && data.length > 0 && length > 0) { + this.p3 = length; + this.data = Arrays.copyOfRange(data, offset, length); } else{ this.p3 = 0; diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java index 6199a375f..0dffa0ad1 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java @@ -68,11 +68,11 @@ default void i2cWriteBlockData(int handle, int register, ByteBuffer buffer, int default void i2cWriteBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException{ i2cWriteBlockData(handle, register, buffer, 0, length); } - default void i2cWriteBlockData(int handle, int register, String data) throws IOException{ + default void i2cWriteBlockData(int handle, int register, CharSequence data) throws IOException{ i2cWriteBlockData(handle, register, data, StandardCharsets.US_ASCII); } - default void i2cWriteBlockData(int handle, int register, String data, Charset charset) throws IOException{ - i2cWriteBlockData(handle, register, data.getBytes(charset)); + default void i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ + i2cWriteBlockData(handle, register, data.toString().getBytes(charset)); } byte[] i2cReadBlockData(int handle, int register) throws IOException; @@ -86,10 +86,10 @@ default String i2cBlockProcessCallToString(int handle, int register, byte[] data byte[] rx = i2cBlockProcessCall(handle, register, data); return new String(rx, StandardCharsets.US_ASCII); } - default byte[] i2cBlockProcessCall(int handle, int register, String data) throws IOException{ - return i2cBlockProcessCall(handle, register, data.getBytes(StandardCharsets.US_ASCII)); + default byte[] i2cBlockProcessCall(int handle, int register, CharSequence data) throws IOException{ + return i2cBlockProcessCall(handle, register, data.toString().getBytes(StandardCharsets.US_ASCII)); } - default String i2cBlockProcessCallToString(int handle, int register, String data) throws IOException{ + default String i2cBlockProcessCallToString(int handle, int register, CharSequence data) throws IOException{ byte[] rx = i2cBlockProcessCall(handle, register, data); return new String(rx, StandardCharsets.US_ASCII); } @@ -119,11 +119,11 @@ default void i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer, i default void i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException{ i2cWriteI2CBlockData(handle, register, buffer, 0, length); } - default void i2cWriteI2CBlockData(int handle, int register, String data) throws IOException{ + default void i2cWriteI2CBlockData(int handle, int register, CharSequence data) throws IOException{ i2cWriteI2CBlockData(handle, register, data, StandardCharsets.US_ASCII); } - default void i2cWriteI2CBlockData(int handle, int register, String data, Charset charset) throws IOException{ - i2cWriteI2CBlockData(handle, register, data.getBytes(charset)); + default void i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ + i2cWriteI2CBlockData(handle, register, data.toString().getBytes(charset)); } byte[] i2cReadDevice(int handle, int length) throws IOException; @@ -151,10 +151,10 @@ default void i2cWriteDevice(int handle, ByteBuffer buffer, int offset, int lengt Objects.checkFromIndexSize(offset, length, buffer.capacity()); i2cWriteDevice(handle, buffer.array(), offset, length); } - default void i2cWriteDevice(int handle, String data) throws IOException{ + default void i2cWriteDevice(int handle, CharSequence data) throws IOException{ i2cWriteDevice(handle, data, StandardCharsets.US_ASCII); } - default void i2cWriteDevice(int handle, String data, Charset charset) throws IOException{ - i2cWriteDevice(handle, data.getBytes(charset)); + default void i2cWriteDevice(int handle, CharSequence data, Charset charset) throws IOException{ + i2cWriteDevice(handle, data.toString().getBytes(charset)); } } diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java new file mode 100644 index 000000000..396ed7f53 --- /dev/null +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java @@ -0,0 +1,131 @@ +package com.pi4j.library.pigpio; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: LIBRARY :: PIGPIO Library + * FILENAME : PiGpio_I2C.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.IOException; + +public interface PiGpio_Serial { + + /** + * This function opens a serial device at a specified baud rate and with specified flags. + * The device name must start with "/dev/tty" or "/dev/serial". + * + * @param device the serial device to open (Example: "/dev/ttyAMA0") + * @param baud the baud rate in bits per second, see below + * The baud rate must be one of 50, 75, 110, 134, 150, 200, 300, 600, 1200, + * 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, or 230400. + * @param flags No flags are currently defined. This parameter should be set to zero. + * @return Returns a handle (>=0) if OK, otherwise PI_NO_HANDLE, or PI_SER_OPEN_FAILED. + */ + int serOpen(CharSequence device, int baud, int flags) throws IOException; + default int serOpen(CharSequence device, int baud) throws IOException { + return serOpen(device, baud, 0); + }; + + /** + * This function closes the serial device associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE. + */ + int serClose(int handle) throws IOException; + + + /** + * This function writes a single byte "value" to the serial port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param value byte value to write to serial port + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + */ + int serWriteByte(int handle, byte value) throws IOException; + + + /** + * This function reads a byte from the serial port associated with handle. + * If no data is ready PI_SER_READ_NO_DATA is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE, PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED. + */ + int serReadByte(int handle) throws IOException; + + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the array of bytes to write + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + */ + int serWrite(int handle, byte[] data, int offset, int length) throws IOException; + default int serWrite(int handle, byte[] data) throws IOException{ + return serWrite(handle, data, 0, data.length); + } + default int serWrite(int handle, byte[] data, int length) throws IOException{ + return serWrite(handle, data, 0, length); + } + + /** + * This function reads up count bytes from the the serial port associated with handle and + * writes them to the buffer parameter. If no data is ready, zero is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer a byte array to receive the read data + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + */ + int serRead(int handle, byte[] buffer, int offset, int length) throws IOException; + default int serRead(int handle, byte[] buffer) throws IOException{ + return serRead(handle, buffer, 0, buffer.length); + } + default int serRead(int handle, byte[] buffer, int length) throws IOException{ + return serRead(handle, buffer, 0, length); + } + + /** + * This function returns the number of bytes available to be read from the device associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns the number of bytes of data available (>=0) if OK, otherwise PI_BAD_HANDLE. + */ + int serDataAvailable(int handle) throws IOException; + + + /** + * This function will drain the current serial receive buffer of any lingering bytes. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns the number of bytes of data drained (>=0) if OK, otherwise PI_BAD_HANDLE. + */ + int serDrain(int handle) throws IOException; +} diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioBase.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioBase.java index 9175ae91d..5ecc59f5a 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioBase.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioBase.java @@ -142,10 +142,10 @@ protected void validateResult(long value, boolean throwException) throws IOExcep } } - protected void validateI2cHandle(int handle) throws IOException { + protected void validateHandle(int handle) throws IOException { // validate I2C handle if(handle < 0) { - throw new IOException("PIGPIO ERROR: INVALID I2C HANDLE [" + handle + "]; Valid range: >0"); + throw new IOException("PIGPIO ERROR: INVALID I2C/SPI/SERIAL HANDLE [" + handle + "]; Valid range: >0"); } } diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java index 80998f003..fede4296c 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java @@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Arrays; import static com.pi4j.library.pigpio.PiGpioCmd.*; import static com.pi4j.library.pigpio.PiGpioConst.DEFAULT_HOST; @@ -221,7 +222,7 @@ public String gpioHardwareRevisionString() throws IOException { public void gpioSetPullUpDown(int pin, PiGpioPud pud) throws IOException { logger.trace("[GPIO::PUD-SET] -> PIN: {}; PUD={}({});", pin, pud.name(), pud.value()); validatePin(pin); - PiGpioPacket result = sendCommand(MODES, pin, pud.value()); + PiGpioPacket result = sendCommand(PUD, pin, pud.value()); logger.trace("[GPIO::PUD-SET] <- PIN: {}; PUD={}({}); SUCCESS={}", pud.name(), pud.value(), result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_GPIO or PI_BAD_MODE. } @@ -633,7 +634,7 @@ public int i2cOpen(int bus, int device) throws IOException { @Override public void i2cClose(int handle) throws IOException { logger.trace("[I2C::CLOSE] -> HANDLE={}, Close I2C Bus", handle); - validateI2cHandle(handle); + validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CC, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::CLOSE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); @@ -643,7 +644,7 @@ public void i2cClose(int handle) throws IOException { @Override public void i2cWriteQuick(int handle, boolean bit) throws IOException { logger.trace("[I2C::WRITE] -> HANDLE={}; R/W Bit [{}]", handle, bit ? 1 : 0); - validateI2cHandle(handle); + validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CWQ, handle, bit ? 1 : 0); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); @@ -653,7 +654,7 @@ public void i2cWriteQuick(int handle, boolean bit) throws IOException { @Override public void i2cWriteByte(int handle, byte value) throws IOException { logger.trace("[I2C::WRITE] -> HANDLE={}; Byte [{}]", handle, Byte.toUnsignedInt(value)); - validateI2cHandle(handle); + validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CWS, handle, Byte.toUnsignedInt(value)); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); @@ -663,7 +664,7 @@ public void i2cWriteByte(int handle, byte value) throws IOException { @Override public int i2cReadByte(int handle) throws IOException { logger.trace("[I2C::READ] -> [{}]; Byte", handle); - validateI2cHandle(handle); + validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CRS, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); @@ -674,7 +675,7 @@ public int i2cReadByte(int handle) throws IOException { @Override public void i2cWriteByteData(int handle, int register, byte value) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Byte [{}]", handle ,register, Byte.toUnsignedInt(value)); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CWB, handle, register).data(Byte.toUnsignedInt(value)); PiGpioPacket rx = sendPacket(tx); @@ -685,7 +686,7 @@ public void i2cWriteByteData(int handle, int register, byte value) throws IOExce @Override public void i2cWriteWordData(int handle, int register, int value) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Word [{}]", handle ,register, value); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CWW, handle, register).data(value); PiGpioPacket rx = sendPacket(tx); @@ -696,7 +697,7 @@ public void i2cWriteWordData(int handle, int register, int value) throws IOExcep @Override public int i2cReadByteData(int handle, int register) throws IOException { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Byte", handle ,register); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRB, handle, register); PiGpioPacket rx = sendPacket(tx); @@ -708,7 +709,7 @@ public int i2cReadByteData(int handle, int register) throws IOException { @Override public int i2cReadWordData(int handle, int register) throws IOException { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Word", handle ,register); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRW, handle, register); PiGpioPacket rx = sendPacket(tx); @@ -720,7 +721,7 @@ public int i2cReadWordData(int handle, int register) throws IOException { @Override public int i2cProcessCall(int handle, int register, int value) throws IOException { logger.trace("[I2C::W/R] -> [{}]; Register [{}]; Word [{}]", handle ,register, value); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CPC, handle, register).data(value); PiGpioPacket rx = sendPacket(tx); @@ -732,7 +733,7 @@ public int i2cProcessCall(int handle, int register, int value) throws IOExceptio @Override public void i2cWriteBlockData(int handle, int register, byte[] data) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Block [{} bytes]", handle ,register, data.length); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); validateI2cBlockLength(data.length); PiGpioPacket tx = new PiGpioPacket(I2CWK, handle, register, data); @@ -744,7 +745,7 @@ public void i2cWriteBlockData(int handle, int register, byte[] data) throws IOEx @Override public byte[] i2cReadBlockData(int handle, int register) throws IOException { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Block", handle ,register); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRK, handle, register); PiGpioPacket rx = sendPacket(tx); @@ -755,7 +756,7 @@ public byte[] i2cReadBlockData(int handle, int register) throws IOException { @Override public byte[] i2cBlockProcessCall(int handle, int register, byte[] data) throws IOException { logger.trace("[I2C::W/R] -> [{}]; Register [{}]; Block [{} bytes]", handle ,register, data.length); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); validateI2cBlockLength(data.length); PiGpioPacket tx = new PiGpioPacket(I2CPK, handle, register, data); @@ -768,7 +769,7 @@ public byte[] i2cBlockProcessCall(int handle, int register, byte[] data) throws @Override public byte[] i2cReadI2CBlockData(int handle, int register, int length) throws IOException { logger.trace("[I2C::READ] -> [{}]; Register [{}]; I2C Block [{} bytes]", handle ,register, length); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRI, handle, register).data(length); PiGpioPacket rx = sendPacket(tx); @@ -780,7 +781,7 @@ public byte[] i2cReadI2CBlockData(int handle, int register, int length) throws I @Override public void i2cWriteI2CBlockData(int handle, int register, byte[] data) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; I2C Block [{} bytes]", handle ,register, data.length); - validateI2cHandle(handle); + validateHandle(handle); validateI2cRegister(register); validateI2cBlockLength(data.length); PiGpioPacket tx = new PiGpioPacket(I2CWI, handle, register, data); @@ -792,7 +793,7 @@ public void i2cWriteI2CBlockData(int handle, int register, byte[] data) throws I @Override public byte[] i2cReadDevice(int handle, int length) throws IOException { logger.trace("[I2C::READ] -> [{}]; I2C Raw Read [{} bytes]", handle, length); - validateI2cHandle(handle); + validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CRD, handle, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); @@ -803,7 +804,7 @@ public byte[] i2cReadDevice(int handle, int length) throws IOException { @Override public int i2cWriteDevice(int handle, byte[] data) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; I2C Raw Write [{} bytes]", handle, data.length); - validateI2cHandle(handle); + validateHandle(handle); //validateI2cDataLength(data.length); PiGpioPacket tx = new PiGpioPacket(I2CWD, handle, 0, data); PiGpioPacket rx = sendPacket(tx); @@ -811,4 +812,109 @@ public int i2cWriteDevice(int handle, byte[] data) throws IOException { validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. return -1; } + + @Override + public int serOpen(CharSequence device, int baud, int flags) throws IOException { + logger.trace("[SERIAL::OPEN] -> Open Serial Port [{}] at Baud Rate [{}]", device, baud); + PiGpioPacket tx = new PiGpioPacket(SERO, baud, flags).data(device); + PiGpioPacket rx = sendPacket(tx); + int handle = rx.result(); + logger.trace("[SERIAL::OPEN] <- HANDLE={}; SUCCESS={}", handle, rx.success()); + validateResult(rx, false); + return handle; + } + + @Override + public int serClose(int handle) throws IOException { + logger.trace("[SERIAL::CLOSE] -> HANDLE={}, Close Serial Port", handle); + validateHandle(handle); + PiGpioPacket tx = new PiGpioPacket(SERC, handle); + PiGpioPacket rx = sendPacket(tx); + logger.trace("[SERIAL::CLOSE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); + validateResult(rx, false); + return rx.result(); + } + + @Override + public int serWriteByte(int handle, byte value) throws IOException { + logger.trace("[SERIAL::WRITE] -> HANDLE={}; Byte [{}]", handle, Byte.toUnsignedInt(value)); + validateHandle(handle); + PiGpioPacket tx = new PiGpioPacket(SERWB, handle, Byte.toUnsignedInt(value)); + PiGpioPacket rx = sendPacket(tx); + logger.trace("[SERIAL::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); + validateResult(rx, false); + return 0; + } + + @Override + public int serReadByte(int handle) throws IOException { + logger.trace("[SERIAL::READ] -> [{}]; Byte", handle); + validateHandle(handle); + PiGpioPacket tx = new PiGpioPacket(SERRB, handle); + PiGpioPacket rx = sendPacket(tx); + logger.trace("[SERIAL::READ] <- HANDLE={}; SUCCESS={}", handle, rx.p3()); + validateResult(rx, false); + return rx.result(); + } + + @Override + public int serWrite(int handle, byte[] data, int offset, int length) throws IOException { + logger.trace("[SERIAL::WRITE] -> [{}]; Serial Write [{} bytes]", handle, data.length); + validateHandle(handle); + PiGpioPacket tx = new PiGpioPacket(SERW, handle).data(data, offset, length); + PiGpioPacket rx = sendPacket(tx); + logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); + validateResult(rx, false); + return rx.result(); + } + + @Override + public int serRead(int handle, byte[] buffer, int offset, int length) throws IOException { + logger.trace("[SERIAL::READ] -> [{}]; Serial Read [{} bytes]", handle, length); + validateHandle(handle); + PiGpioPacket tx = new PiGpioPacket(SERR, handle, length); + PiGpioPacket rx = sendPacket(tx); + logger.trace("[SERIAL::READ] <- HANDLE={}; SUCCESS={}; BYTES-READ={}", handle, rx.success(), rx.dataLength()); + validateResult(rx, false); + if(rx.success()) { + System.arraycopy(rx.data(), 0, buffer, 0, rx.result()); + } + return rx.result(); + } + + @Override + public int serDataAvailable(int handle) throws IOException { + logger.trace("[SERIAL::AVAIL] -> Get number of bytes available to read"); + PiGpioPacket tx = new PiGpioPacket(SERDA, handle); + PiGpioPacket rx = sendPacket(tx); + int available = rx.result(); + logger.trace("[SERIAL::AVAIL] <- HANDLE={}; SUCCESS={}; AVAILABLE={}", handle, rx.success(), available); + validateResult(rx, false); + return available; + } + + /** + * This function will drain the current serial receive buffer of any lingering bytes. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns the number of bytes of data drained (>=0) if OK, otherwise PI_BAD_HANDLE. + */ + public int serDrain(int handle) throws IOException{ + logger.trace("[SERIAL::DRAIN] -> Drain any remaining bytes in serial RX buffer"); + + // get number of bytes available + PiGpioPacket tx = new PiGpioPacket(SERDA, handle); + PiGpioPacket rx = sendPacket(tx); + validateResult(rx, false); + int available = rx.result(); + + // if any bytes are available, then drain them now + if(available > 0){ + tx = new PiGpioPacket(SERR, handle, available); + rx = sendPacket(tx); + validateResult(rx, false); + } + logger.trace("[SERIAL::DRAIN] <- HANDLE={}; SUCCESS={}; DRAINED={}", handle, rx.success(), rx.result()); + return available; + } } diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java index dede20f2e..b37a66679 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java @@ -40,21 +40,26 @@ public static void main(String[] args) throws Exception { pig.initialize(); - // set pin ALT0 modes for I2C BUS<1> usage on RPI3B - pig.gpioSetMode(2, PiGpioMode.ALT0); - pig.gpioSetMode(3, PiGpioMode.ALT0); + pig.gpioSetMode(5, PiGpioMode.OUTPUT); - for(int x = 0; x < 100; x++) { - try { - pig.i2cClose(x); - } - catch (IOException e){ - continue; - } - } - int handle = pig.i2cOpen(1, 0x04); + +// // set pin ALT0 modes for I2C BUS<1> usage on RPI3B +// pig.gpioSetMode(2, PiGpioMode.ALT0); +// pig.gpioSetMode(3, PiGpioMode.ALT0); + + +// for(int x = 0; x < 100; x++) { +// try { +// pig.i2cClose(x); +// } +// catch (IOException e){ +// continue; +// } +// } +// +// int handle = pig.i2cOpen(1, 0x04); //pig.initialize(); @@ -92,14 +97,14 @@ public static void main(String[] args) throws Exception { // byte[] rx = pig.i2cReadI2CBlockData(handle, 2, 32); // System.out.println("[BLOCK] <" + rx.length + "> " + Arrays.toString(rx)); // - - int max = 32; - byte[] data = new byte[max]; - for(int i = 0; i < max; i++) { - data[i] = (byte)i; - } - - pig.i2cWriteDevice(handle, data); +// +// int max = 32; +// byte[] data = new byte[max]; +// for(int i = 0; i < max; i++) { +// data[i] = (byte)i; +// } +// +// pig.i2cWriteDevice(handle, data); //Thread.sleep(200); //byte rx[] = pig.i2cReadDevice(handle, data.length); @@ -119,8 +124,8 @@ public static void main(String[] args) throws Exception { // // pig.gpioWrite(4, PiGpioState.LOW); - // CLOSE - pig.i2cClose(handle); +// // CLOSE +// pig.i2cClose(handle); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java index 6be0802c1..3dfb525a1 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java @@ -53,6 +53,8 @@ public class TestDigitalInputsUsingTestHarness { @BeforeAll public static void initialize() { + System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); + System.out.println(); System.out.println("************************************************************************"); System.out.println("INITIALIZE TEST (" + TestDigitalInputsUsingTestHarness.class.getName() + ")"); @@ -129,17 +131,11 @@ public void testGpioDigitalPullUpDown() throws IOException { for(int pin = 2; pin <= 19; pin++){ // the following inputs are skipped because they always fail; possible - // because they are tied to other things that override the pull-up/down - if(pin == 5) continue; - if(pin == 6) continue; - if(pin == 9) continue; - if(pin == 10) continue; - if(pin == 11) continue; - if(pin == 12) continue; - if(pin == 13) continue; - if(pin == 16) continue; - if(pin == 18) continue; - if(pin == 19) continue; + // because they are tied to other things that override the software + // configurable pull-up/down resistors + if(pin == 2) continue; // RPi I2C PINS have on-board pull-up resistors + if(pin == 3) continue; // RPi I2C PINS have on-board pull-up resistors + testDigitalInputPullUpDown(pin); } } @@ -159,7 +155,7 @@ public void testDigitalInputPin(int pin) throws IOException{ // do not use internal pull down resistors; // these seem to overpower the HIGH signal from the Arduino - pigpio.gpioSetPullUpDown(pin, PiGpioPud.OFF); + pigpio.gpioSetPullUpDown(pin, PiGpioPud.DOWN); // get input pin state from SoC (RaspberryPi) PiGpioState state = pigpio.gpioRead(pin); @@ -219,7 +215,7 @@ public void testDigitalInputPullUpDown(int pin) throws IOException { System.out.println("----------------------------------------"); // configure pin as an input pin on the test harness - harness.setInputPin(pin, true); + harness.setInputPin(pin, false); // configure input pin on test SoC (RaspberryPi) pigpio.gpioSetMode(pin, PiGpioMode.INPUT); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java index 08a0b130c..545d12212 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java @@ -109,7 +109,7 @@ public void testGpioDigitalOutputs() throws IOException { // iterate over pins and perform test on each // TODO :: IMPLEMENT CORRECT SET OF TEST PINS - for(int pin = 2; pin <= 12; pin++){ + for(int pin = 2; pin <= 19; pin++){ testDigitalOutputPin(pin); } } diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java index 366d75f21..ce0122f61 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java @@ -41,6 +41,7 @@ import java.util.UUID; @DisplayName("PIGPIO Library :: Test I2C Raw Communication") +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class TestI2cRawUsingTestHarness { private static int I2C_BUS = 1; @@ -134,6 +135,7 @@ public void afterEach() throws IOException { @Test @DisplayName("I2C :: Test SINGLE-BYTE (W/R)") + @Order(1) public void testI2CSingleByteTxRx() throws IOException, InterruptedException { System.out.println(); System.out.println("----------------------------------------"); @@ -160,6 +162,7 @@ public void testI2CSingleByteTxRx() throws IOException, InterruptedException { @Test @DisplayName("I2C :: Test MULTI-BYTE (W/R)") + @Order(2) public void testI2CMultiByteTxRx() throws IOException, InterruptedException { System.out.println(); System.out.println("----------------------------------------"); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java index 98e29aeee..42fccc9d8 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java @@ -188,6 +188,7 @@ public void testPwm(int frequency, int dutyCycle) throws IOException, Interrupte Assert.assertEquals("PWM FREQUENCY MISMATCH", actualFrequency, readFrequency); Assert.assertEquals("PWM DUTY-CYCLE MISMATCH", dutyCycle, readDutyCycle); + Thread.sleep(50); // test once .. if(measureFrequency(p, actualFrequency) == false){ diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java new file mode 100644 index 000000000..270093171 --- /dev/null +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java @@ -0,0 +1,224 @@ +package com.pi4j.library.pigpio.test.serial; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: LIBRARY :: PIGPIO Library + * FILENAME : TestI2cRawUsingTestHarness.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.pi4j.library.pigpio.PiGpio; +import com.pi4j.library.pigpio.PiGpioMode; +import com.pi4j.library.pigpio.util.StringUtil; +import com.pi4j.test.harness.ArduinoTestHarness; +import com.pi4j.test.harness.TestHarnessInfo; +import com.pi4j.test.harness.TestHarnessPins; +import org.junit.Assert; +import org.junit.jupiter.api.*; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Formatter; +import java.util.Random; +import java.util.UUID; + +@DisplayName("PIGPIO Library :: Test Serial Communication") +public class TestSerialUsingTestHarness { + + private static String SERIAL_DEVICE = "/dev/ttyS0"; + private static int BAUD_RATE = 9600; + private static int TEST_HARNESS_UART = 3; + + private PiGpio pigpio; + private int handle; + + @BeforeAll + public static void initialize() { + System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); + + System.out.println(); + System.out.println("************************************************************************"); + System.out.println("INITIALIZE TEST (" + TestSerialUsingTestHarness.class.getName() + ")"); + System.out.println("************************************************************************"); + System.out.println(); + + try { + // create test harness and PIGPIO instances + ArduinoTestHarness harness = new ArduinoTestHarness(System.getProperty("pi4j.test.harness.port", "tty.usbmodem142301")); + + // initialize test harness and PIGPIO instances + harness.initialize(); + + // get test harness info + TestHarnessInfo info = harness.getInfo(); + System.out.println("... we are connected to test harness:"); + System.out.println("----------------------------------------"); + System.out.println("NAME : " + info.name); + System.out.println("VERSION : " + info.version); + System.out.println("DATE : " + info.date); + System.out.println("COPYRIGHT : " + info.copyright); + System.out.println("----------------------------------------"); + +// // reset all pins on test harness before proceeding with this test +// TestHarnessPins reset = harness.reset(); +// System.out.println(); +// System.out.println("RESET ALL PINS ON TEST HARNESS; (" + reset.total + " pin reset)"); + + // enable the Serial Echo (Loopback) function on the test harness for these tests + harness.enableSerialEcho(TEST_HARNESS_UART, BAUD_RATE); + + // terminate connection to test harness + harness.terminate(); + } catch (IOException e){ + e.printStackTrace(); + } + } + + @AfterAll + public static void terminate() throws IOException { + System.out.println(); + System.out.println("************************************************************************"); + System.out.println("TERMINATE TEST (" + TestSerialUsingTestHarness.class.getName() + ") "); + System.out.println("************************************************************************"); + System.out.println(); + } + + @BeforeEach + public void beforeEach() throws IOException { + // create test harness and PIGPIO instances + pigpio = PiGpio.newSocketInstance(System.getProperty("pi4j.pigpio.host", "rpi3bp.savage.lan"), + System.getProperty("pi4j.pigpio.port", "8888")); + + // initialize test harness and PIGPIO instances + pigpio.initialize(); + + // set pin ALT5 modes for SERIAL RX & TX PINS on RPI3B + pigpio.gpioSetMode(14, PiGpioMode.ALT5); + pigpio.gpioSetMode(15, PiGpioMode.ALT5); + + // OPEN SERIAL PORT + handle = pigpio.serOpen(SERIAL_DEVICE, BAUD_RATE); + } + + @AfterEach + public void afterEach() throws IOException { + + // CLOSE SERIAL PORT + pigpio.serClose(handle); + + // terminate test harness and PIGPIO instances + pigpio.terminate(); + } + + @Test + @DisplayName("SERIAL :: Test SINGLE-BYTE (W/R)") + public void testSerialSingleByteTxRx() throws IOException, InterruptedException { + System.out.println(); + System.out.println("--------------------------------------------"); + System.out.println("TEST SERIAL PORT SINGLE BYTE RAW READ/WRITE"); + System.out.println("--------------------------------------------"); + + // drain any pending bytes in buffer + pigpio.serDrain(handle); + + // iterate over BYTE range of values, WRITE the byte then immediately + // READ back the byte value and compare to make sure they are the same values. + for(int b = 0; b < 256; b++) { + System.out.println("[TEST WRITE/READ SINGLE BYTE]"); + // WRITE :: SINGLE RAW BYTE + System.out.println(" (WRITE) >> VALUE = 0x" + Integer.toHexString(b)); + pigpio.serWriteByte(handle, (byte)b); + + // READ :: NUMBER OF BYTES AVAILABLE TO READ + int available = pigpio.serDataAvailable(handle); + System.out.println(" (READ) << AVAIL = " + available); + Assert.assertEquals("SERIAL BYTE VALUE MISMATCH", 1, available); + + // READ :: SINGLE RAW BYTE + int rx = pigpio.serReadByte(handle); + System.out.println(" (READ) << VALUE = 0x" + Integer.toHexString(rx)); + Assert.assertEquals("SERIAL BYTE VALUE MISMATCH", b, rx); + System.out.println(); + } + } + + @Test + @DisplayName("SERIAL :: Test MULTI-BYTE (W/R)") + public void testSerialMultiByteTxRx() throws IOException, InterruptedException { + System.out.println(); + System.out.println("----------------------------------------"); + System.out.println("TEST SERIAL MULTI-BYTE READ/WRITE"); + System.out.println("----------------------------------------"); + + // iterate over series of test values, WRITE the byte then immediately + // READ back the byte value and compare to make sure they are the same values. + for(int x = 0; x < 50; x++) { + System.out.println("[TEST WRITE/READ MULTI-BYTE]"); + + // drain any pending bytes in buffer + pigpio.serDrain(handle); + + // Arduino max serial buffer length is 32 + // create a random series of bytes up to 32 bytes long + Random r = new Random(); + int len = r.nextInt((32 - 4) + 1) + 4; + byte[] testData = new byte[len]; + r.nextBytes(testData); + + // WRITE :: MULTI-BYTE + System.out.println(" (WRITE) >> VALUE = " + byteToHex(testData)); + pigpio.serWrite(handle, testData); + + // take a breath while buffer catches up + Thread.sleep(50); + + // READ :: NUMBER OF BYTES AVAILABLE TO READ + int available = pigpio.serDataAvailable(handle); + System.out.println(" (READ) << AVAIL = " + available); + Assert.assertEquals("SERIAL READ AVAIL MISMATCH", testData.length, available); + + // READ :: MULTI-BYTE + byte[] readBuffer = new byte[available]; + int bytesRead = pigpio.serRead(handle, readBuffer, available); + System.out.println(" (READ) << BYTES READ = " + bytesRead); + System.out.println(" (READ) << VALUE = " + byteToHex(readBuffer)); + //Thread.sleep(50); + + Assert.assertArrayEquals("SERIAL MULTI-BYTE VALUE MISMATCH", testData, readBuffer); + } + } + + private String byteToHex(final byte[] hash) + { + Formatter formatter = new Formatter(); + for (byte b : hash) { + formatter.format("%02x ", b); + } + String result = "[0x" + formatter.toString().trim() + "]"; + formatter.close(); + return result; + } +} diff --git a/pi4j-test-harness/src/main/arduino/src/command/Commands.h b/pi4j-test-harness/src/main/arduino/src/command/Commands.h index 4340d56c3..03255825b 100644 --- a/pi4j-test-harness/src/main/arduino/src/command/Commands.h +++ b/pi4j-test-harness/src/main/arduino/src/command/Commands.h @@ -40,6 +40,7 @@ #include "PinsCommand.h" #include "RebootCommand.h" #include "ResetCommand.h" +#include "SerialEchoCommand.h" /** @@ -62,6 +63,7 @@ void AddInteractiveCommands(SerialCommands& processor){ processor.AddCommand(&PinCommand); processor.AddCommand(&PinsCommand); processor.AddCommand(&PinShortCommand); + processor.AddCommand(&SerialEchoCommand); } #endif // PI4J_COMMANDS_H diff --git a/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h b/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h index 41fe13085..63d7a4d67 100644 --- a/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h +++ b/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h @@ -66,6 +66,12 @@ int GetCommandPinArgument(SerialCommands* sender){ if(pin == 3){ return 21; } + if(pin == 14){ + return 15; + } + if(pin == 15){ + return 14; + } } @@ -266,6 +272,51 @@ int GetCommandI2cDeviceArgument(SerialCommands* sender){ return device; } +/** + * GET SERIAL PORT VALUE FROM COMMANDS ARGUMENTS + */ +int GetCommandSerialPortArgument(SerialCommands* sender){ + char* port_str = sender->Next(); + if (port_str == NULL){ + return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument + } + + // validate numeric string + if(!StringUtil::isNumeric(port_str)){ + return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument + } + int port = atoi(port_str); + + // validate device + if(port != 2 && port != 3){ + return ERROR_UNSUPPORTED_SERIAL_PORT; + } + + return port; +} + +/** + * GET SERIAL BAUD RATE VALUE FROM COMMANDS ARGUMENTS + */ +int GetCommandSerialBaudArgument(SerialCommands* sender){ + char* baud_str = sender->Next(); + if (baud_str == NULL){ + return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument + } + + // validate numeric string + if(!StringUtil::isNumeric(baud_str)){ + return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument + } + int baud = atoi(baud_str); + + // validate device + if(baud < 0 || baud > 230400){ + return ERROR_UNSUPPORTED_SERIAL_BAUD_RATE; + } + + return baud; +} String GetCommandArgumentError(int error){ switch(error){ @@ -275,6 +326,8 @@ String GetCommandArgumentError(int error){ case ERROR_INVALID_PIN_RESTRICTED : {return "INVALID PIN NUMBER; RESTRICTED PIN"; break;} case ERROR_INVALID_I2C_BUS_OUT_OF_RANGE : {return "INVALID I2C BUS; UNSUPPORTED BUS"; break;} case ERROR_INVALID_I2C_DEVICE_OUT_OF_RANGE : {return "INVALID I2C DEVICE; OUT OF ACCEPTED RANGE"; break;} + case ERROR_UNSUPPORTED_SERIAL_PORT : {return "INVALID SERIAL PORT; UNSUPPORTED PORT NUMBER"; break;} + case ERROR_UNSUPPORTED_SERIAL_BAUD_RATE : {return "INVALID SERIAL BAUD RATE; UNSUPPORTED BAUD"; break;} default: return "UNKNOWN ARGUMENT ERROR"; } } diff --git a/pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h b/pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h new file mode 100644 index 000000000..1489e979e --- /dev/null +++ b/pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h @@ -0,0 +1,98 @@ +/* + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: TEST :: Arduino Test Harness + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * + * Copyright (C) 2012 - 2019 Pi4J + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * ********************************************************************** + */ + +#ifndef PI4J_COMMAND_SERIAL_H +#define PI4J_COMMAND_SERIAL_H + +#include +#include +#include +#include +#include "CommandsArgumentParser.h" +#include "main.h" + +// create SERIAL command invocation handler +void serial_command_execute(SerialCommands* sender){ + DynamicJsonDocument doc(256); + JsonObject response = doc.to(); + + // get BAUD bus + int port = GetCommandSerialPortArgument(sender); + + // get BAUD bus + int baud = GetCommandSerialBaudArgument(sender); + + // handle bus argument errors + if(port < 0) { + response["id"] = "error"; + response["errno"] = port; + response["arg"] = "port"; + response["msg"] = GetCommandArgumentError(port); + } + + // handle BAUD argument errors + else if(baud < 0) { + response["id"] = "error"; + response["errno"] = baud; + response["arg"] = "baud"; + response["msg"] = GetCommandArgumentError(baud); + } + + else{ + response["id"] = "serial"; + response["port"] = port; + response["baud"] = baud; + + // end any existing serial echo + if(serialEcho != nullptr){ + serialEcho->end(); + } + + // setup which I2C bus to enable + if(port == 3){ + serialEcho = &Serial3; // setup SERIAL UART3 + } else if(port == 2){ + serialEcho = &Serial2; // setup SERIAL UART2 + } else { + serialEcho = nullptr; + } + + // start seria lecho + if(serialEcho != nullptr && baud > 0){ + serialEcho->begin(baud); + } + } + + // output response + serializeJson(doc, *sender->GetSerial()); + sender->GetSerial()->println(); +} + +// create SERIAL command variable +SerialCommand SerialEchoCommand = SerialCommand("serial", serial_command_execute); + +#endif //PI4J_COMMAND_SERIAL_H diff --git a/pi4j-test-harness/src/main/arduino/src/main.cpp b/pi4j-test-harness/src/main/arduino/src/main.cpp index bf2ef390c..7291d6966 100644 --- a/pi4j-test-harness/src/main/arduino/src/main.cpp +++ b/pi4j-test-harness/src/main/arduino/src/main.cpp @@ -30,6 +30,7 @@ #include "pins.h" #include + // ------------------------------------------------------------------------------------------------------------------------------ // INTERACTIVE COMMAND PROCESSOR AND COMMANDS // ------------------------------------------------------------------------------------------------------------------------------ @@ -97,7 +98,6 @@ void inititalize(){ // Wire.onReceive(receiveI2CData); // Wire.onRequest(sendI2CData); // i2cCache.wire = &Wire; - } void reset(){ @@ -137,6 +137,11 @@ void reset(){ Wire.end(); Wire1.end(); + // termiante all SERIAL communication pins + if(serialEcho != nullptr){ + serialEcho->end(); + } + // include summary totals response["total"] = total; response["inputs"] = inputs; @@ -172,8 +177,17 @@ void loop() { // serializeJson(doc, console); // console.println(); // } - // } + // } // } + + if(serialEcho != nullptr){ + if (serialEcho->available()){ + int byt = serialEcho->read(); + //Serial.print("[SERIAL-ECHO] "); + //Serial.println(byt); + serialEcho->write(byt); // ECHO DATA BACK TO CALLER + } + } } /** @@ -207,216 +221,6 @@ void reboot() { } -// // callback for received data -// void receiveI2CDataSMBus(int byteCount){ - -// console.print("<-- I2C RX Byte Count: "); -// console.println(byteCount); -// console.println(byteCount); -// console.println(byteCount); - -// // process bytes received -// if(byteCount > 0){ - -// // create a receive data buffer -// uint8_t buffer[36] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; - -// // read all available bytes from the I2C bus -// byteCount = Wire.readBytes(buffer, byteCount); - -// console.print(" BYTES READ "); -// console.print(byteCount); -// //console.println(); - -// console.print(" :: "); -// for(int i = 0; i < byteCount; i++){ -// console.print(buffer[i]); -// console.print(", "); -// } -// console.println(); - -// // if the first byte is greater than 10, then treat this as a raw data byte write operation -// if(byteCount == 1 && buffer[0] >= 10){ -// // ------------------------------------------- -// // WRITING RAW BYTE VALUES -// // ------------------------------------------- -// console.print(" WRITING RAW BYTE: "); -// console.println((int)buffer[0]); -// i2cCache.length = 1; -// i2cCache.buffer[0] = buffer[0]; -// } - -// // if the first byte is between 0 and 9, then treat this as a SMBus registry data access operation -// else if(buffer[0] >= 0 && buffer[0] < 10){ - -// // regsiter address is the first byte -// int address = buffer[0]; - -// console.print(" REGISTER "); -// console.print(buffer[0]); -// console.println(); - -// return; - - -// // if we only received a single byte, then this is a READ operation -// if(byteCount == 1){ -// // ------------------------------------------- -// // REQUEST RECEIVED FOR READING A REGISTER -// // ------------------------------------------- -// uint16_t length = i2cCache.reg[address].length; - -// console.print(" REQUEST RECEIVED TO READ REGISTER: "); -// console.print(address); -// console.print("; ("); -// console.print(length); -// console.println(" bytes)"); -// return; -// // copy register data length to read buffer length -// i2cCache.length = length; - -// // copy the data from this register to the read buffer -// for(int i = 0; i < length; i++){ -// i2cCache.buffer[i] = i2cCache.reg[address].data[i]; -// } -// } - -// // if we received multiple bytes, then this is a WRITE operation -// else{ -// // ------------------------------------------- -// // WRITE REGISTER DATA -// // ------------------------------------------- - -// // get the data lenght from the number bytes available subtracting address (first) byte -// uint16_t length = byteCount - 1; - -// // only maximum of 32 bytes are supported; bounds check the data length -// if(length > 32) length = 32; - -// // update I2C register in the cache with the recevied data length -// i2cCache.reg[address].length = length; -// i2cCache.length = length; - -// console.print(" WRITING REGISTER: "); -// console.print(address); -// console.print("; BYTES="); -// console.println(length); - -// // // process data recevied -// // for(int i = 0; i < length; i++){ -// // // copy the received data to this register's storage buffer -// // i2cCache.reg[address].data[i] = buffer[i+1]; - -// // // copy the data from this register to the read buffer -// // i2cCache.buffer[i] = buffer[i+1]; -// // } -// } -// } -// else { -// console.print(" UNSUPPORTED REGISTER ADDRESS: "); -// console.print(buffer[0]); -// console.println(); -// } -// } - -// // drain anything remaining in buffer -// // while(Wire.available()){ -// // Wire.read(); -// // } -// return; - - - - -// // handle single byte values -// if(Wire.available() == 1){ -// int c = Wire.read(); // receive a byte as character - -// if(c > 10){ -// // WRITING RAW BYTE VALUES -// i2cCache.length = 1; -// i2cCache.buffer[0] = c; - -// console.print(" WRITING RAW BYTE: "); -// console.println((int)c); - -// } -// else{ -// // READING A REGISTER -// int address = c; - -// // bail out if address is unsupported; drain buffer -// if(address < 0 || address >= 10){ -// // while(Wire.available()) -// // Wire.read(); -// } - -// console.print(" READING REGISTER: "); -// console.println(address); - -// // copy register data to read buffer -// i2cCache.length = i2cCache.reg[address].length; -// if(i2cCache.length > 0){ -// console.print(" COPYING REGISTER TO READ BUFFER: ("); -// console.print(i2cCache.length); -// console.println(" bytes)"); -// memcpy(i2cCache.buffer, i2cCache.reg[address].data, i2cCache.length); -// } -// } -// } -// else { -// // WRITING A REGISTER -// int address = Wire.read(); // get register address - -// // bail out if address is unsupported; drain buffer -// if(address < 0 || address >= 10){ -// //if(Wire.available()) -// //Wire.read(Wire.av); -// } - -// // get number of bytes still available to read -// int bytesRemaining = Wire.available(); - -// // maximum of 32 bytes supported -// if(bytesRemaining > 32) bytesRemaining = 32; - -// // update I2C cache with data length -// i2cCache.reg[address].length = bytesRemaining; -// i2cCache.length = bytesRemaining; - -// console.print(" WRITING REGISTER: "); -// console.print(address); -// console.print("; BYTES="); -// console.println(bytesRemaining); - -// if(bytesRemaining > 0){ -// //Wire.readBytes(i2cCache.reg[address].data, i2cCache.reg[address].length) ; -// // for(int i = 0; i < bytesRemaining; i++){ -// // char b = Wire.read(); -// // i2cCache.reg[address].data[i] = b; -// // i2cCache.buffer[i] = b; -// // console.print("WRITING VALUE BYTE: "); -// // console.print((uint)b); -// // console.println(); -// // } - -// console.print("WRITING VALUE: "); -// //console.printHex(i2cCache.reg[address].data, bytesRemaining); -// console.println(); -// } -// } - -// // // display ready/running message -// // DynamicJsonDocument doc(512); -// // JsonObject response = doc.to(); -// // response["id"] = "i2c"; -// // response["value"] = i2cValue; -// // serializeJson(doc, console); -// // console.println(); -// } - - - // callback for sending data void sendI2CData(){ uint8_t address = i2cCache.address; diff --git a/pi4j-test-harness/src/main/arduino/src/main.h b/pi4j-test-harness/src/main/arduino/src/main.h index b787af0b2..3a321d3ff 100644 --- a/pi4j-test-harness/src/main/arduino/src/main.h +++ b/pi4j-test-harness/src/main/arduino/src/main.h @@ -106,4 +106,6 @@ struct I2cCache { I2cCache i2cCache; +HardwareSerial* serialEcho = nullptr; + #endif //PI4J_MAIN_H \ No newline at end of file diff --git a/pi4j-test-harness/src/main/arduino/src/pi4j.h b/pi4j-test-harness/src/main/arduino/src/pi4j.h index d300c2707..8140c6561 100644 --- a/pi4j-test-harness/src/main/arduino/src/pi4j.h +++ b/pi4j-test-harness/src/main/arduino/src/pi4j.h @@ -147,6 +147,8 @@ #define ERROR_INVALID_PIN_DISABLED -5 #define ERROR_INVALID_I2C_BUS_OUT_OF_RANGE -11 #define ERROR_INVALID_I2C_DEVICE_OUT_OF_RANGE -12 +#define ERROR_UNSUPPORTED_SERIAL_PORT -13 +#define ERROR_UNSUPPORTED_SERIAL_BAUD_RATE -14 #define ERROR_UNSUPPORTED_COMMAND -99 diff --git a/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java b/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java index 5e2bda79e..b7cb69b5a 100644 --- a/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java +++ b/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java @@ -60,15 +60,25 @@ public ArduinoTestHarness(String comport) throws IOException { com.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED); // configure read timeout - com.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 100, 0); + com.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 200, 0); } public TestHarnessPins reset() throws IOException { +// send("reboot"); +// try { +// Thread.sleep(500); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } send("reset"); TestHarnessPins response = read(TestHarnessPins.class); return response; } + public void reboot() throws IOException { + send("reboot"); + } + public TestHarnessInfo getInfo() throws IOException { send("info"); TestHarnessInfo response = read(TestHarnessInfo.class); @@ -126,6 +136,12 @@ public TestHarnessFrequency getFrequency(int pin) throws IOException { return response; } + public TestHarnessResponse enableSerialEcho(int port, int baudRate) throws IOException { + send(String.format("serial %d %d", port, baudRate)); + TestHarnessResponse response = read(TestHarnessResponse.class); + return response; + } + public void send(String command) throws IOException { // validate serial port is connected @@ -141,7 +157,24 @@ public void send(String command) throws IOException { } protected T read(Class type) throws IOException { + + List responses = read(); + + try { + if (responses.isEmpty()) { + Thread.sleep(1000); + responses = read(); + } + if (responses.isEmpty()) { + Thread.sleep(1000); + responses = read(); + } + } + catch (Exception e){ + e.printStackTrace(); + } + TestHarnessError err = null; for (var response : responses){ if(TestHarnessError.class.isInstance(response)){ @@ -158,11 +191,24 @@ else if(type.isInstance(response)){ } protected List read() throws IOException { + List responses = new ArrayList<>(); // validate serial port is connected if(!com.isOpen()) throw new IOException("Serial port is not open;"); - List responses = new ArrayList<>(); + int counter = 0; + try { + while (com.bytesAvailable() <= 0) { + counter++; + if(counter > 20) + return responses; + Thread.sleep(50); + } + } + catch (Exception e){ + e.printStackTrace(); + } + Scanner in = new Scanner(com.getInputStream()); while(in.hasNextLine()){ var received = in.nextLine(); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java index daedca105..fab44911b 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java @@ -197,19 +197,6 @@ public void testDigitalInputsPullUp() throws Exception { for(int p = 2; p < 20; p++) { - // the following inputs are skipped because they always fail; possible - // because they are tied to other things that override the pull-up/down - if(p == 5) continue; - if(p == 6) continue; - if(p == 9) continue; - if(p == 10) continue; - if(p == 11) continue; - if(p == 12) continue; - if(p == 13) continue; - if(p == 16) continue; - if(p == 18) continue; - if(p == 19) continue; - // create Digital Input instance config var config = DigitalInput.newConfigBuilder() .id("my-din-pin-" + p) @@ -241,6 +228,12 @@ public void testDigitalInputsPullDown() throws Exception { for(int p = 2; p < 20; p++) { + // the following inputs are skipped because they always fail; possible + // because they are tied to other things that override the software + // configurable pull-up/down resistors + if(p == 2) continue; // RPi I2C PINS have on-board pull-up resistors + if(p == 3) continue; // RPi I2C PINS have on-board pull-up resistors + // create Digital Input instance config var config = DigitalInput.newConfigBuilder() .id("my-din-pin-" + p) @@ -253,7 +246,7 @@ public void testDigitalInputsPullDown() throws Exception { DigitalInput din = pi4j.create(config); // configure input pin and read value/state on testing harness - harness.setInputPin(p, true); + harness.setInputPin(p, false); int pull = harness.getPin(p).value; System.out.println("(PIN #" + p + ") >> PULL = " + pull); From 241cc2442c7f67e39db35de65b15e381ec3f3791 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Thu, 22 Aug 2019 10:12:53 -0400 Subject: [PATCH 05/15] working on Serial interface and impl for PIGPIO lib --- .../pi4j/library/pigpio/PiGpio_Serial.java | 2 +- .../java/com/pi4j/library/pigpio/Main.java | 9 +++- .../test/i2c/TestI2cRawUsingTestHarness.java | 6 +-- .../pwm/TestHardwarePwmUsingTestHarness.java | 50 ++++++++++--------- .../pwm/TestSoftwarePwmUsingTestHarness.java | 12 +++-- .../serial/TestSerialUsingTestHarness.java | 10 ++-- .../main/java/com/pi4j/io/serial/Baud.java | 2 +- .../java/com/pi4j/io/serial/DataBits.java | 2 +- .../pi4j/io/serial/DefaultSerialConfig.java | 2 +- .../java/com/pi4j/io/serial/FlowControl.java | 2 +- .../main/java/com/pi4j/io/serial/Parity.java | 2 +- .../pi4j/io/serial/SerialConfigBuilder.java | 2 +- .../java/com/pi4j/io/serial/StopBits.java | 2 +- .../io/serial/impl/DefaultSerialConfig.java | 2 +- .../impl/DefaultSerialConfigBuilder.java | 2 +- .../DigitalOutputExampleUsingNewBuilder.java | 2 +- .../pi4j/example/serial/SerialExample.java | 2 +- .../src/command/CommandsArgumentParser.h | 8 +-- .../arduino/src/command/SerialEchoCommand.h | 18 +++++-- .../pi4j/test/harness/ArduinoTestHarness.java | 7 +++ 20 files changed, 86 insertions(+), 58 deletions(-) diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java index 396ed7f53..d7069a1ce 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: LIBRARY :: PIGPIO Library - * FILENAME : PiGpio_I2C.java + * FILENAME : PiGpio_Serial.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java index b37a66679..90c5aeb74 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java @@ -41,7 +41,7 @@ public static void main(String[] args) throws Exception { pig.initialize(); - pig.gpioSetMode(5, PiGpioMode.OUTPUT); + //pig.gpioSetMode(5, PiGpioMode.OUTPUT); @@ -64,7 +64,12 @@ public static void main(String[] args) throws Exception { //pig.initialize(); //pig.gpioSetPWMfrequency(4, 5000); - pig.gpioHardwarePWM(13, 100, 500000); + + + pig.gpioHardwarePWM(13, 50000000, 500000); + + pig.gpioSetPWMfrequency(2, 830); + pig.gpioPWM(2, 128); //var frequency = pig.gpioGetPWMfrequency(4); //System.out.println("FREQUENCY: " + frequency); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java index ce0122f61..ee18732d5 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java @@ -171,7 +171,7 @@ public void testI2CMultiByteTxRx() throws IOException, InterruptedException { // iterate over series of test values, WRITE the byte then immediately // READ back the byte value and compare to make sure they are the same values. - for(int x = 0; x < 100; x++) { + for(int x = 0; x < 50; x++) { System.out.println("[TEST WRITE/READ MULTI-BYTE]"); String value = UUID.randomUUID().toString().substring(0, 8); @@ -179,12 +179,12 @@ public void testI2CMultiByteTxRx() throws IOException, InterruptedException { // WRITE :: RAW MULTI-BYTE System.out.println(" (WRITE) >> VALUE = " + value); pigpio.i2cWriteDevice(handle, value); - Thread.sleep(5); + Thread.sleep(20); // READ :: RAW MULTI-BYTE String rx = pigpio.i2cReadDeviceToString(handle, value.length()); System.out.println(" (READ) << VALUE = " + rx); - Thread.sleep(5); + Thread.sleep(20); Assert.assertEquals("I2C MULTI-BYTE VALUE MISMATCH", value, rx); } diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java index 1a38942a7..28a052821 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java @@ -69,20 +69,20 @@ public static void initialize() { // initialize test harness and PIGPIO instances harness.initialize(); - // get test harness info - TestHarnessInfo info = harness.getInfo(); - System.out.println("... we are connected to test harness:"); - System.out.println("----------------------------------------"); - System.out.println("NAME : " + info.name); - System.out.println("VERSION : " + info.version); - System.out.println("DATE : " + info.date); - System.out.println("COPYRIGHT : " + info.copyright); - System.out.println("----------------------------------------"); - - // reset all pins on test harness before proceeding with this test - TestHarnessPins reset = harness.reset(); - System.out.println(); - System.out.println("RESET ALL PINS ON TEST HARNESS; (" + reset.total + " pin reset)"); +// // get test harness info +// TestHarnessInfo info = harness.getInfo(); +// System.out.println("... we are connected to test harness:"); +// System.out.println("----------------------------------------"); +// System.out.println("NAME : " + info.name); +// System.out.println("VERSION : " + info.version); +// System.out.println("DATE : " + info.date); +// System.out.println("COPYRIGHT : " + info.copyright); +// System.out.println("----------------------------------------"); +// +// // reset all pins on test harness before proceeding with this test +// TestHarnessPins reset = harness.reset(); +// System.out.println(); +// System.out.println("RESET ALL PINS ON TEST HARNESS; (" + reset.total + " pin reset)"); } catch (IOException e){ e.printStackTrace(); @@ -186,7 +186,7 @@ public void testPwmAt100000Hertz() throws IOException, InterruptedException { } public void testPwm(PiGpioMode mode, int[] pins, int frequency) throws IOException, InterruptedException { - testPwm(mode, pins, frequency, 35); // 35% duty-cycle by default + testPwm(mode, pins, frequency, 50); // 50% duty-cycle by default } public void testPwm(PiGpioMode mode, int[] pins, int frequency, int dutyCycle) throws IOException, InterruptedException { System.out.println(); @@ -203,12 +203,12 @@ public void testPwm(PiGpioMode mode, int[] pins, int frequency, int dutyCycle) t System.out.println("[TEST HARDWARE PWM] :: PIN=" + p + " <" + mode.name() + ">"); // hardware PWM duty cycle scaling - dutyCycle = dutyCycle * 10000; + int dc = dutyCycle * 10000; // write PWM frequency and duty-cycle - pigpio.gpioHardwarePWM(p, frequency, dutyCycle); + pigpio.gpioHardwarePWM(p, frequency, dc); System.out.println(" (WRITE) >> PWM FREQUENCY = " + frequency); - System.out.println(" (WRITE) >> PWM DUTY-CYCLE = " + dutyCycle); + System.out.println(" (WRITE) >> PWM DUTY-CYCLE = " + dc); // test once .. if(measureFrequency(p, frequency) == false){ @@ -234,13 +234,15 @@ public void testPwm(PiGpioMode mode, int[] pins, int frequency, int dutyCycle) t private boolean measureFrequency(int pin, int frequency) throws IOException { TestHarnessFrequency measured = harness.getFrequency(pin); - System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency); - // we allow a 75% margin of error, the testing harness uses a simple pulse counter to crudely - // measure the PWM signal, its not very accurate but should provide sufficient validation testing - // just to verify the applied PWM signal is close to the expected frequency - // calculate margin of error offset value - long marginOfError = Math.round(frequency * .75); + float deviation = (measured.frequency - frequency) * 100/(float)frequency; + System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency + "; (EXPECTED=" + frequency + "; DEVIATION: " + deviation + "%)"); + + // we allow a 30% margin of error, the testing harness uses a simple pulse counter to crudely + // measure the PWM signal, its not very accurate and we don't take enough samples to get a + // better average, but it should provide sufficient validation testing just to verify the + // applied PWM signal is close to the expected frequency calculate margin of error offset value + long marginOfError = Math.round(frequency * .30); // test measured value against HI/LOW offsets to determine acceptable range if(measured.frequency < frequency-marginOfError) return false; diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java index 42fccc9d8..ad187a02c 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java @@ -159,7 +159,7 @@ public void testPwmAt10000Hertz() throws IOException, InterruptedException { } public void testPwm(int frequency) throws IOException, InterruptedException { - testPwm(frequency, 80); // 80% duty-cycle by default + testPwm(frequency, 128); // 50% duty-cycle by default } public void testPwm(int frequency, int dutyCycle) throws IOException, InterruptedException { System.out.println(); @@ -188,7 +188,7 @@ public void testPwm(int frequency, int dutyCycle) throws IOException, Interrupte Assert.assertEquals("PWM FREQUENCY MISMATCH", actualFrequency, readFrequency); Assert.assertEquals("PWM DUTY-CYCLE MISMATCH", dutyCycle, readDutyCycle); - Thread.sleep(50); + Thread.sleep(100); // test once .. if(measureFrequency(p, actualFrequency) == false){ @@ -214,13 +214,15 @@ public void testPwm(int frequency, int dutyCycle) throws IOException, Interrupte private boolean measureFrequency(int pin, int frequency) throws IOException { TestHarnessFrequency measured = harness.getFrequency(pin); - System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency); - // we allow a 60% margin of error, the testing harness uses a simple pulse counter to crudely + float deviation = (measured.frequency - frequency) * 100/(float)frequency; + System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency + "; (EXPECTED=" + frequency + "; DEVIATION: " + deviation + "%)"); + + // we allow a 25% margin of error, the testing harness uses a simple pulse counter to crudely // measure the PWM signal, its not very accurate but should provide sufficient validation testing // just to verify the applied PWM signal is close to the expected frequency // calculate margin of error offset value - long marginOfError = Math.round(frequency * .60); + long marginOfError = Math.round(frequency * 25); // test measured value against HI/LOW offsets to determine acceptable range if(measured.frequency < frequency-marginOfError) return false; diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java index 270093171..633ef5030 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: LIBRARY :: PIGPIO Library - * FILENAME : TestI2cRawUsingTestHarness.java + * FILENAME : TestSerialUsingTestHarness.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ @@ -83,9 +83,9 @@ public static void initialize() { System.out.println("----------------------------------------"); // // reset all pins on test harness before proceeding with this test -// TestHarnessPins reset = harness.reset(); -// System.out.println(); -// System.out.println("RESET ALL PINS ON TEST HARNESS; (" + reset.total + " pin reset)"); + TestHarnessPins reset = harness.reset(); + System.out.println(); + System.out.println("RESET ALL PINS ON TEST HARNESS; (" + reset.total + " pin reset)"); // enable the Serial Echo (Loopback) function on the test harness for these tests harness.enableSerialEcho(TEST_HARNESS_UART, BAUD_RATE); @@ -193,7 +193,7 @@ public void testSerialMultiByteTxRx() throws IOException, InterruptedException { pigpio.serWrite(handle, testData); // take a breath while buffer catches up - Thread.sleep(50); + Thread.sleep(100); // READ :: NUMBER OF BYTES AVAILABLE TO READ int available = pigpio.serDataAvailable(handle); diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java index ddce7310d..c509e7212 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Baud.java @@ -4,7 +4,7 @@ * #%L * ********************************************************************** * ORGANIZATION : Pi4J - * PROJECT : Pi4J :: Java Library (Core) + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) * FILENAME : Baud.java * * This file is part of the Pi4J project. More information about diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java b/pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java index 639338c8e..67df36dba 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/DataBits.java @@ -4,7 +4,7 @@ * #%L * ********************************************************************** * ORGANIZATION : Pi4J - * PROJECT : Pi4J :: Java Library (Core) + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) * FILENAME : DataBits.java * * This file is part of the Pi4J project. More information about diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java b/pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java index a1409fda6..5e70dadf4 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/DefaultSerialConfig.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: LIBRARY :: Java Library (API) - * FILENAME : SerialConfig.java + * FILENAME : DefaultSerialConfig.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java b/pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java index 9e4722da4..0e5b5f597 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/FlowControl.java @@ -4,7 +4,7 @@ * #%L * ********************************************************************** * ORGANIZATION : Pi4J - * PROJECT : Pi4J :: Java Library (Core) + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) * FILENAME : FlowControl.java * * This file is part of the Pi4J project. More information about diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java index b6543a003..1fcb3497c 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java @@ -4,7 +4,7 @@ * #%L * ********************************************************************** * ORGANIZATION : Pi4J - * PROJECT : Pi4J :: Java Library (Core) + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) * FILENAME : Parity.java * * This file is part of the Pi4J project. More information about diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java index d4ee5e35f..7ff2b6f3f 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: LIBRARY :: Java Library (API) - * FILENAME : PwmConfigBuilder.java + * FILENAME : SerialConfigBuilder.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java b/pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java index 2329b24cf..919307bda 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/StopBits.java @@ -4,7 +4,7 @@ * #%L * ********************************************************************** * ORGANIZATION : Pi4J - * PROJECT : Pi4J :: Java Library (Core) + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) * FILENAME : StopBits.java * * This file is part of the Pi4J project. More information about diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java index d36d228f8..3742a314f 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfig.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: LIBRARY :: Java Library (API) - * FILENAME : DefaultPwmConfig.java + * FILENAME : DefaultSerialConfig.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java index 913c509c9..2776b3ea5 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/impl/DefaultSerialConfigBuilder.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: LIBRARY :: Java Library (API) - * FILENAME : DefaultPwmConfigBuilder.java + * FILENAME : DefaultSerialConfigBuilder.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ diff --git a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java index 9f2d38f38..190f98e9b 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java +++ b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputExampleUsingNewBuilder.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: EXAMPLE :: Sample Code - * FILENAME : DigitalOutputExample.java + * FILENAME : DigitalOutputExampleUsingNewBuilder.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ diff --git a/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java b/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java index 179a26f76..36729ddb0 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java +++ b/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: EXAMPLE :: Sample Code - * FILENAME : I2cDeviceExample.java + * FILENAME : SerialExample.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ diff --git a/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h b/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h index 63d7a4d67..a34ab070e 100644 --- a/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h +++ b/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h @@ -288,11 +288,11 @@ int GetCommandSerialPortArgument(SerialCommands* sender){ int port = atoi(port_str); // validate device - if(port != 2 && port != 3){ - return ERROR_UNSUPPORTED_SERIAL_PORT; - } + if(port == 0) return port; + if(port == 3) return port; - return port; + // unsupported port + return ERROR_UNSUPPORTED_SERIAL_PORT; } /** diff --git a/pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h b/pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h index 1489e979e..762a35e91 100644 --- a/pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h +++ b/pi4j-test-harness/src/main/arduino/src/command/SerialEchoCommand.h @@ -70,15 +70,27 @@ void serial_command_execute(SerialCommands* sender){ // end any existing serial echo if(serialEcho != nullptr){ serialEcho->end(); + serialEcho = nullptr; } // setup which I2C bus to enable if(port == 3){ serialEcho = &Serial3; // setup SERIAL UART3 - } else if(port == 2){ - serialEcho = &Serial2; // setup SERIAL UART2 + PIO_Configure( + g_APinDescription[PINS_USART3].pPort, + g_APinDescription[PINS_USART3].ulPinType, + g_APinDescription[PINS_USART3].ulPin, + g_APinDescription[PINS_USART3].ulPinConfiguration); + + } else if(port == 0){ + serialEcho = &Serial; // setup SERIAL UART0 + PIO_Configure( + g_APinDescription[PINS_USART0].pPort, + g_APinDescription[PINS_USART0].ulPinType, + g_APinDescription[PINS_USART0].ulPin, + g_APinDescription[PINS_USART0].ulPinConfiguration); } else { - serialEcho = nullptr; + serialEcho = nullptr; } // start seria lecho diff --git a/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java b/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java index b7cb69b5a..1c5f5df0e 100644 --- a/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java +++ b/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java @@ -193,6 +193,13 @@ else if(type.isInstance(response)){ protected List read() throws IOException { List responses = new ArrayList<>(); + try { + Thread.sleep(50); + } + catch (Exception e){ + e.printStackTrace(); + } + // validate serial port is connected if(!com.isOpen()) throw new IOException("Serial port is not open;"); From adbe627f48c46d7457dc351618a5d6e98ff1f64e Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Thu, 22 Aug 2019 14:16:51 -0400 Subject: [PATCH 06/15] completed Serial PIGPIO lib imlp; updated I2C PIGPIO lib interaces and impl; added javadoc for I2C and Serial PIGPIO lib interaces; --- .../com/pi4j/library/pigpio/PiGpio_I2C.java | 1273 ++++++++++++++++- .../pi4j/library/pigpio/PiGpio_Serial.java | 246 +++- .../library/pigpio/impl/PiGpioSocketImpl.java | 412 +++++- .../java/com/pi4j/library/pigpio/Main.java | 2 - .../test/i2c/TestI2cRawUsingTestHarness.java | 16 +- .../test/i2c/TestI2cUsingTestHarness.java | 53 +- .../pwm/TestHardwarePwmUsingTestHarness.java | 2 - .../serial/TestSerialUsingTestHarness.java | 4 - .../config/impl/DeviceConfigBuilderBase.java | 1 - .../impl/DefaultDigitalOutputBuilder.java | 2 +- .../main/java/com/pi4j/io/serial/Parity.java | 2 - .../main/java/com/pi4j/io/serial/Serial.java | 1 - .../java/com/pi4j/io/serial/SerialBase.java | 7 - .../pi4j/io/serial/SerialConfigBuilder.java | 6 - .../com/pi4j/io/serial/SerialProvider.java | 2 - .../java/com/pi4j/io/spi/SpiProvider.java | 1 - .../plugin/pigpio/provider/i2c/PiGpioI2C.java | 10 +- 17 files changed, 1854 insertions(+), 186 deletions(-) diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java index 0dffa0ad1..220a70080 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java @@ -33,128 +33,1245 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Objects; public interface PiGpio_I2C { - int i2cOpen(int bus, int device) throws IOException; - void i2cClose(int handle) throws IOException; - void i2cWriteQuick(int handle, boolean bit) throws IOException; - void i2cWriteByte(int handle, byte value) throws IOException; + /** + * Opens a I2C device on a given I2C bus for communications. + * This returns a handle for the device at the address on the I2C bus. + * Physically buses 0 and 1 are available on the Pi. + * Higher numbered buses will be available if a kernel supported bus multiplexor is being used. + * + * The GPIO used are given in the following table. + * SDA SCL + * I2C0 0 1 + * I2C1 2 3 + * + * @param bus the I2C bus address to open/access for reading and writing. (>=0) + * @param device the I2C device address to open/access for reading and writing. (0-0x7F) + * @param flags no flags are currently defined. This parameter should be set to zero. + * @return Returns a handle (>=0) if OK, otherwise PI_BAD_I2C_BUS, PI_BAD_I2C_ADDR, PI_BAD_FLAGS, PI_NO_HANDLE, or PI_I2C_OPEN_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cOpen" + */ + int i2cOpen(int bus, int device, int flags) throws IOException; + + /** + * Opens a I2C device on a given I2C bus for communications. + * This returns a handle for the device at the address on the I2C bus. + * Physically buses 0 and 1 are available on the Pi. + * Higher numbered buses will be available if a kernel supported bus multiplexor is being used. + * + * The GPIO used are given in the following table. + * SDA SCL + * I2C0 0 1 + * I2C1 2 3 + * + * @param bus the I2C bus address to open/access for reading and writing. (>=0) + * @param device the I2C device address to open/access for reading and writing. (0-0x7F) + * @return Returns a handle (>=0) if OK, otherwise PI_BAD_I2C_BUS, PI_BAD_I2C_ADDR, PI_BAD_FLAGS, PI_NO_HANDLE, or PI_I2C_OPEN_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cOpen" + */ + default int i2cOpen(int bus, int device) throws IOException{ + return i2cOpen(bus, device, 0); + } + + /** + * This closes the I2C device associated with the handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cClose" + */ + int i2cClose(int handle) throws IOException; + + /** + * This sends a single bit (in the Rd/Wr bit) to the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param bit 0-1, the value to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteQuick" + */ + int i2cWriteQuick(int handle, boolean bit) throws IOException; + + /** + * This sends a single byte to the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param value raw byte value (0-0xFF) to write to I2C device + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteByte" + */ + int i2cWriteByte(int handle, byte value) throws IOException; + + /** + * This reads a single byte from the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @return Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadByte" + */ int i2cReadByte(int handle) throws IOException; - void i2cWriteByteData(int handle, int register, byte value) throws IOException; - void i2cWriteWordData(int handle, int register, int value) throws IOException; + + /** + * This writes a single byte to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param value raw byte value (0-0xFF) to write to I2C device + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteByteData" + */ + int i2cWriteByteData(int handle, int register, byte value) throws IOException; + + /** + * This writes a single 16 bit word to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param value raw word (2-byte) value (0-0xFFFF) to write to I2C device + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteWordData" + */ + int i2cWriteWordData(int handle, int register, int value) throws IOException; + + /** + * This reads a single byte from the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @return Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadByteData" + */ int i2cReadByteData(int handle, int register) throws IOException; + + /** + * This reads a single 16 bit word from the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @return Returns the word (2-byte value) read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadWordData" + */ int i2cReadWordData(int handle, int register) throws IOException; + + /** + * This writes 16 bits of data to the specified register of the device associated with + * handle and reads 16 bits of data in return. (in a single transaction) + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to and read from. (0-255) + * @param value raw word (2-byte) value (0-0xFFFF) to write to I2C device + * @return Returns the word read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cProcessCall" + */ int i2cProcessCall(int handle, int register, int value) throws IOException; - void i2cWriteBlockData(int handle, int register, byte[] data) throws IOException; + /** + * This writes up to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the array of bytes to write + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + int i2cWriteBlockData(int handle, int register, byte[] data, int offset, int length) throws IOException; + + /** + * This writes up to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the array of bytes to write + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, byte[] data, int length) throws IOException{ + return i2cWriteBlockData(handle, register, data, 0, length); + } + + /** + * This writes up to 32 bytes to the specified I2c register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the array of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, byte[] data) throws IOException{ + return i2cWriteBlockData(handle, register, data, data.length); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param buffer the byte buffer of data to write + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, ByteBuffer buffer, int offset, int length) throws IOException{ + return i2cWriteBlockData(handle, register, buffer.array(), offset, length); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param buffer the byte buffer of data to write + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException{ + return i2cWriteBlockData(handle, register, buffer, 0, length); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param buffer the byte buffer of data to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, ByteBuffer buffer) throws IOException{ + return i2cWriteBlockData(handle, register, buffer, buffer.capacity()); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the character/string data to write + * @param charset the character set/type used to decode the character sequence/string to bytes + * @param offset the starting offset position in the provided data to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset, int offset, int length) throws IOException{ + return i2cWriteBlockData(handle, register, data.toString().getBytes(charset), offset, length); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the character/string data to write + * @param charset the character set/type used to decode the character sequence/string to bytes + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset, int length) throws IOException{ + return i2cWriteBlockData(handle, register, data, charset,0, length); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the character/string data to write + * @param charset the character set/type used to decode the character sequence/string to bytes + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ + return i2cWriteBlockData(handle, register, data, charset, data.length()); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the ASCII character/string data to write + * @param offset the starting offset position in the provided data to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, CharSequence data, int offset, int length) throws IOException{ + return i2cWriteBlockData(handle, register, data.toString().getBytes(StandardCharsets.US_ASCII), offset, length); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the ASCII character/string data to write + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, CharSequence data, int length) throws IOException{ + return i2cWriteBlockData(handle, register, data, 0, length); + } + + /** + * This writes up to 32 bytes to the specified I2C register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the ASCII character/string data to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ + default int i2cWriteBlockData(int handle, int register, CharSequence data) throws IOException{ + return i2cWriteBlockData(handle, register, data, data.length()); + } + + /** + * This reads a block of up to 32 bytes from the specified register of the device associated with handle. + * The amount of returned data is set by the device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadBlockData" + */ + int i2cReadBlockData(int handle, int register, byte[] buffer, int offset, int length) throws IOException; + + /** + * This reads a block of up to 32 bytes from the specified register of the device associated with handle. + * The amount of returned data is set by the device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array to receive the read data + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadBlockData" + */ + default int i2cReadBlockData(int handle, int register, byte[] buffer, int length) throws IOException { + return i2cReadBlockData(handle, register, buffer, 0, length); + } + + /** + * This reads a block of up to 32 bytes from the specified register of the device associated with handle. + * The amount of returned data is set by the device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array to receive the read data + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadBlockData" + */ + default int i2cReadBlockData(int handle, int register, byte[] buffer) throws IOException { + return i2cReadBlockData(handle, register, buffer, buffer.length); + } + + /** + * This reads a block of up to 32 bytes from the specified register of the device associated with handle. + * The amount of returned data is set by the device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadBlockData" + */ + default int i2cReadBlockData(int handle, int register, ByteBuffer buffer, int offset, int length) throws IOException{ + return i2cReadBlockData(handle, register, buffer.array(), 0, length); + } + + /** + * This reads a block of up to 32 bytes from the specified register of the device associated with handle. + * The amount of returned data is set by the device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadBlockData" + */ + default int i2cReadBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException { + return i2cReadBlockData(handle, register, buffer, 0, length); + } + + /** + * This reads a block of up to 32 bytes from the specified register of the device associated with handle. + * The amount of returned data is set by the device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadBlockData" + */ + default int i2cReadBlockData(int handle, int register, ByteBuffer buffer) throws IOException { + return i2cReadBlockData(handle, register, buffer, buffer.capacity()); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte array containing data to write + * @param writeOffset the starting offset position in the provided byte array to start writing from. + * @param writeLength the number of bytes to write (maximum 32 bytes supported) + * @param read a byte array to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @param readOffset the starting offset position in the provided read array/buffer to start copying the data bytes read. + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + int i2cBlockProcessCall(int handle, int register, byte[] write, int writeOffset, int writeLength, byte[] read, int readOffset) throws IOException; + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte array containing data to write + * @param writeOffset the starting offset position in the provided byte array to start writing from. + * @param writeLength the number of bytes to write (maximum 32 bytes supported) + * @param read a byte array to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, byte[] write, int writeOffset, int writeLength, byte[] read) throws IOException{ + return i2cBlockProcessCall(handle, register, write, writeOffset, writeLength, read, 0); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte array containing data to write + * @param writeLength the number of bytes to write (maximum 32 bytes supported) + * @param read a byte array to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, byte[] write, int writeLength, byte[] read) throws IOException{ + return i2cBlockProcessCall(handle, register, write, 0, writeLength, read, 0); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte array containing data to write + * @param read a byte array to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, byte[] write, byte[] read) throws IOException{ + return i2cBlockProcessCall(handle, register, write, 0, write.length, read, 0); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param data a single byte array/buffer containing data to write and the array contents will be + * overwritten with the data read from the I2C device register. + * @param offset the starting offset position in the provided byte array to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, byte[] data, int offset, int length) throws IOException{ + return i2cBlockProcessCall(handle, register, data, offset, length, data, offset); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param data a single byte array/buffer containing data to write and the array contents will be + * overwritten with the data read from the I2C device register. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, byte[] data, int length) throws IOException { + return i2cBlockProcessCall(handle, register, data, 0, length); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param data a single byte array/buffer containing data to write and the array contents will be + * overwritten with the data read from the I2C device register. + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, byte[] data) throws IOException { + return i2cBlockProcessCall(handle, register, data, data.length); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte buffer containing data to write + * @param writeOffset the starting offset position in the provided byte buffer to start writing from. + * @param writeLength the number of bytes to write (maximum 32 bytes supported) + * @param read a byte buffer to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @param readOffset the starting offset position in the provided read buffer to start copying the data bytes read. + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, ByteBuffer write, int writeOffset, int writeLength, ByteBuffer read, int readOffset) throws IOException{ + return i2cBlockProcessCall(handle, register, write.array(), writeOffset, writeLength, read.array(), readOffset); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte buffer containing data to write + * @param writeOffset the starting offset position in the provided byte buffer to start writing from. + * @param writeLength the number of bytes to write (maximum 32 bytes supported) + * @param read a byte buffer to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, ByteBuffer write, int writeOffset, int writeLength, ByteBuffer read) throws IOException{ + return i2cBlockProcessCall(handle, register, write, writeOffset, writeLength, read, 0); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte buffer containing data to write + * @param writeLength the number of bytes to write (maximum 32 bytes supported) + * @param read a byte buffer to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, ByteBuffer write, int writeLength, ByteBuffer read) throws IOException{ + return i2cBlockProcessCall(handle, register, write, 0, writeLength, read, 0); + } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param write a byte buffer containing data to write + * @param read a byte buffer to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, ByteBuffer write, ByteBuffer read) throws IOException{ + return i2cBlockProcessCall(handle, register, write, 0, write.capacity(), read, 0); + } - default void i2cWriteBlockData(int handle, int register, byte[] data, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, data.length); - byte[] temp = Arrays.copyOfRange(data, offset, length); - i2cWriteBlockData(handle, register, temp); + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param data a single byte array/buffer containing data to write and the array contents will be + * overwritten with the data read from the I2C device register. + * @param offset the starting offset position in the provided byte array to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, ByteBuffer data, int offset, int length) throws IOException{ + return i2cBlockProcessCall(handle, register, data, offset, length, data, offset); } - default void i2cWriteBlockData(int handle, int register, byte[] data, int length) throws IOException{ - i2cWriteBlockData(handle, register, data, 0 ,length); + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param data a single byte array/buffer containing data to write and the array contents will be + * overwritten with the data read from the I2C device register. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, ByteBuffer data, int length) throws IOException { + return i2cBlockProcessCall(handle, register, data, 0, length); } - default void i2cWriteBlockData(int handle, int register, ByteBuffer buffer) throws IOException{ - i2cWriteBlockData(handle, register, buffer.array()); + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to/read from. (0-255) + * @param data a single byte array/buffer containing data to write and the array contents will be + * overwritten with the data read from the I2C device register. + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ + default int i2cBlockProcessCall(int handle, int register, ByteBuffer data) throws IOException { + return i2cBlockProcessCall(handle, register, data, data.capacity()); } - default void i2cWriteBlockData(int handle, int register, ByteBuffer buffer, int offset, int length) throws IOException{ - i2cWriteBlockData(handle, register, buffer.array(), offset, length); + + /** + * This reads count bytes from the specified register of the device associated with handle . + * The maximum length of data that can be read is 32 bytes. + * The minimum length of data that can be read is 1 byte. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array (pre-allocated) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read (1-32) + * @return Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadI2CBlockData" + */ + int i2cReadI2CBlockData(int handle, int register, byte[] buffer, int offset, int length) throws IOException; + + /** + * This reads count bytes from the specified register of the device associated with handle . + * The maximum length of data that can be read is 32 bytes. + * The minimum length of data that can be read is 1 byte. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array (pre-allocated) to receive the read data + * @param length the maximum number of bytes to read (1-32) + * @return Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadI2CBlockData" + */ + default int i2cReadI2CBlockData(int handle, int register, byte[] buffer, int length) throws IOException{ + return i2cReadI2CBlockData(handle, register, buffer, 0, length); } - default void i2cWriteBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException{ - i2cWriteBlockData(handle, register, buffer, 0, length); + + /** + * This reads count bytes from the specified register of the device associated with handle . + * The maximum length of data that can be read is 32 bytes. + * The minimum length of data that can be read is 1 byte. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array (pre-allocated) to receive the read data + * @return Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadI2CBlockData" + */ + default int i2cReadI2CBlockData(int handle, int register, byte[] buffer) throws IOException{ + return i2cReadI2CBlockData(handle, register, buffer, buffer.length); + } + + /** + * This reads count bytes from the specified register of the device associated with handle . + * The maximum length of data that can be read is 32 bytes. + * The minimum length of data that can be read is 1 byte. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read (1-32) + * @return Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadI2CBlockData" + */ + default int i2cReadI2CBlockData(int handle, int register, ByteBuffer buffer, int offset, int length) throws IOException{ + return i2cReadI2CBlockData(handle, register, buffer.array(), offset, length); } - default void i2cWriteBlockData(int handle, int register, CharSequence data) throws IOException{ - i2cWriteBlockData(handle, register, data, StandardCharsets.US_ASCII); + + /** + * This reads count bytes from the specified register of the device associated with handle . + * The maximum length of data that can be read is 32 bytes. + * The minimum length of data that can be read is 1 byte. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @param length the maximum number of bytes to read (1-32) + * @return Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadI2CBlockData" + */ + default int i2cReadI2CBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException{ + return i2cReadI2CBlockData(handle, register, buffer, 0, length); + } + + /** + * This reads count bytes from the specified register of the device associated with handle . + * The maximum length of data that can be read is 32 bytes. + * The minimum length of data that can be read is 1 byte. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @return Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadI2CBlockData" + */ + default int i2cReadI2CBlockData(int handle, int register, ByteBuffer buffer) throws IOException{ + return i2cReadI2CBlockData(handle, register, buffer, buffer.capacity()); + } + + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data a byte array containing the data to write to the I2C device register + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + int i2cWriteI2CBlockData(int handle, int register, byte[] data, int offset, int length) throws IOException; + + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data a byte array containing the data to write to the I2C device register + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, byte[] data, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data, 0, length); } - default void i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ - i2cWriteBlockData(handle, register, data.toString().getBytes(charset)); + + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data a byte array containing the data to write to the I2C device register + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, byte[] data) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data, data.length); } - byte[] i2cReadBlockData(int handle, int register) throws IOException; - default String i2cReadBlockDataToString(int handle, int register) throws IOException{ - byte[] rx = i2cReadBlockData(handle, register); - return new String(rx, StandardCharsets.US_ASCII); + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param buffer a byte buffer containing the data to write to the I2C device register + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer, int offset, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, buffer.array(), offset, length); } - byte[] i2cBlockProcessCall(int handle, int register, byte[] data) throws IOException; - default String i2cBlockProcessCallToString(int handle, int register, byte[] data) throws IOException{ - byte[] rx = i2cBlockProcessCall(handle, register, data); - return new String(rx, StandardCharsets.US_ASCII); + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param buffer a byte buffer containing the data to write to the I2C device register + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, buffer, 0, length); } - default byte[] i2cBlockProcessCall(int handle, int register, CharSequence data) throws IOException{ - return i2cBlockProcessCall(handle, register, data.toString().getBytes(StandardCharsets.US_ASCII)); + + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param buffer a byte buffer containing the data to write to the I2C device register + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer) throws IOException{ + return i2cWriteI2CBlockData(handle, register, buffer, buffer.capacity()); } - default String i2cBlockProcessCallToString(int handle, int register, CharSequence data) throws IOException{ - byte[] rx = i2cBlockProcessCall(handle, register, data); - return new String(rx, StandardCharsets.US_ASCII); + + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data a byte array containing the data to write to the I2C device register + * @param charset the character set/type used to encode the character sequence/string to bytes + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset, int offset, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data.toString().getBytes(charset), offset, length); } - byte[] i2cReadI2CBlockData(int handle, int register, int length) throws IOException; - default String i2cReadI2CBlockDataToString(int handle, int register, int length) throws IOException{ - byte[] rx = i2cReadI2CBlockData(handle, register, length); - return new String(rx, StandardCharsets.US_ASCII); + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data a byte array containing the data to write to the I2C device register + * @param charset the character set/type used to encode the character sequence/string to bytes + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data, charset, 0, length); } - void i2cWriteI2CBlockData(int handle, int register, byte[] data) throws IOException; + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data a byte array containing the data to write to the I2C device register + * @param charset the character set/type used to encode the character sequence/string to bytes + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data, charset, data.length()); + } - default void i2cWriteI2CBlockData(int handle, int register, byte[] data, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, data.length); - byte[] temp = Arrays.copyOfRange(data, offset, length); - i2cWriteI2CBlockData(handle, register, temp); + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data an ASCII string containing the data to write to the I2C device register + * @param offset the starting offset position in the provided character sequence/string to start writing from. + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, int offset, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data.toString().getBytes(StandardCharsets.US_ASCII), offset, length); } - default void i2cWriteI2CBlockData(int handle, int register, byte[] data, int length) throws IOException{ - i2cWriteI2CBlockData(handle, register, data, 0 ,length); + + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data an ASCII string containing the data to write to the I2C device register + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data, 0, length); } - default void i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer) throws IOException{ - i2cWriteI2CBlockData(handle, register, buffer.array()); + + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data an ASCII string containing the data to write to the I2C device register + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ + default int i2cWriteI2CBlockData(int handle, int register, CharSequence data) throws IOException{ + return i2cWriteI2CBlockData(handle, register, data, data.length()); } - default void i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer, int offset, int length) throws IOException{ - i2cWriteI2CBlockData(handle, register, buffer.array(), offset, length); + + /** + * This reads count bytes from the raw device into byte buffer array. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer a byte array (pre-allocated) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read (1-32) + * @return Returns number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadDevice" + */ + int i2cReadDevice(int handle, byte[] buffer, int offset, int length) throws IOException; + + /** + * This reads count bytes from the raw device into byte buffer array. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer a byte array (pre-allocated) to receive the read data + * @param length the maximum number of bytes to read (1-32) + * @return Returns number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadDevice" + */ + default int i2cReadDevice(int handle, byte[] buffer, int length) throws IOException{ + return i2cReadDevice(handle, buffer, 0, length); } - default void i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer, int length) throws IOException{ - i2cWriteI2CBlockData(handle, register, buffer, 0, length); + + /** + * This reads count bytes from the raw device into byte buffer array. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer a byte array (pre-allocated) to receive the read data + * @return Returns number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadDevice" + */ + default int i2cReadDevice(int handle, byte[] buffer) throws IOException{ + return i2cReadDevice(handle, buffer, buffer.length); } - default void i2cWriteI2CBlockData(int handle, int register, CharSequence data) throws IOException{ - i2cWriteI2CBlockData(handle, register, data, StandardCharsets.US_ASCII); + + /** + * This reads count bytes from the raw device into byte buffer. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read (1-32) + * @return Returns number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadDevice" + */ + default int i2cReadDevice(int handle, ByteBuffer buffer, int offset, int length) throws IOException{ + return i2cReadDevice(handle, buffer.array(), offset, length); } - default void i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ - i2cWriteI2CBlockData(handle, register, data.toString().getBytes(charset)); + + /** + * This reads count bytes from the raw device into byte buffer. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @param length the maximum number of bytes to read (1-32) + * @return Returns number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadDevice" + */ + default int i2cReadDevice(int handle, ByteBuffer buffer, int length) throws IOException{ + return i2cReadDevice(handle, buffer, 0, length); } - byte[] i2cReadDevice(int handle, int length) throws IOException; - default String i2cReadDeviceToString(int handle, int length) throws IOException{ - byte[] rx = i2cReadDevice(handle, length); - return new String(rx, StandardCharsets.US_ASCII); + /** + * This reads count bytes from the raw device into byte buffer. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer a byte buffer (pre-allocated) to receive the read data + * @return Returns number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadDevice" + */ + default int i2cReadDevice(int handle, ByteBuffer buffer) throws IOException{ + return i2cReadDevice(handle, buffer, buffer.capacity()); } - int i2cWriteDevice(int handle, byte[] data) throws IOException; + /** + * This writes the length of bytes from the provided data array to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the array of bytes to write + * @param offset the starting offset position in the provided array/buffer to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + int i2cWriteDevice(int handle, byte[] data, int offset, int length) throws IOException; + + /** + * This writes the length of bytes from the provided data array to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the array of bytes to write + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ default int i2cWriteDevice(int handle, byte[] data, int length) throws IOException{ return i2cWriteDevice(handle, data, 0, length); } - default int i2cWriteDevice(int handle, byte[] data, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, data.length); - return i2cWriteDevice(handle, Arrays.copyOfRange(data, offset, length)); + + /** + * This writes the length of bytes from the provided data array to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the array of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, byte[] data) throws IOException{ + return i2cWriteDevice(handle, data, data.length); + } + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer the byte buffer of data to write + * @param offset the starting offset position in the provided array/buffer to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, ByteBuffer buffer, int offset, int length) throws IOException{ + return i2cWriteDevice(handle, buffer.array(), offset ,length); } - default void i2cWriteDevice(int handle, ByteBuffer buffer) throws IOException{ - i2cWriteDevice(handle, buffer.array()); + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer the byte buffer of data to write + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, ByteBuffer buffer, int length) throws IOException{ + return i2cWriteDevice(handle, buffer, 0 ,length); } - default void i2cWriteDevice(int handle, ByteBuffer buffer, int length) throws IOException{ - i2cWriteDevice(handle, buffer, 0, length); + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer the byte buffer of data to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, ByteBuffer buffer) throws IOException{ + return i2cWriteDevice(handle, buffer, buffer.capacity()); } - default void i2cWriteDevice(int handle, ByteBuffer buffer, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, buffer.capacity()); - i2cWriteDevice(handle, buffer.array(), offset, length); + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the character sequence or string of data to write to the I2C device + * @param charset the character set/type used to encode the character sequence/string to bytes + * @param offset the starting offset position in the provided character sequence/string to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, CharSequence data, Charset charset, int offset, int length) throws IOException{ + return i2cWriteDevice(handle, data.toString().getBytes(charset), offset ,length); } - default void i2cWriteDevice(int handle, CharSequence data) throws IOException{ - i2cWriteDevice(handle, data, StandardCharsets.US_ASCII); + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the character sequence or string of data to write to the I2C device + * @param charset the character set/type used to encode the character sequence/string to bytes + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, CharSequence data, Charset charset, int length) throws IOException{ + return i2cWriteDevice(handle, data, charset, 0, length); + } + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the character sequence or string of data to write to the I2C device + * @param charset the character set/type used to encode the character sequence/string to bytes + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, CharSequence data, Charset charset) throws IOException{ + return i2cWriteDevice(handle, data, charset, data.length()); } - default void i2cWriteDevice(int handle, CharSequence data, Charset charset) throws IOException{ - i2cWriteDevice(handle, data.toString().getBytes(charset)); + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the character sequence or string of data to write to the I2C device + * @param offset the starting offset position in the provided character sequence/string to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, CharSequence data, int offset, int length) throws IOException{ + return i2cWriteDevice(handle, data.toString().getBytes(StandardCharsets.US_ASCII), offset ,length); + } + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the character sequence or string of data to write to the I2C device + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, CharSequence data, int length) throws IOException{ + return i2cWriteDevice(handle, data, 0, length); + } + + /** + * This writes the length of bytes from the provided byte buffer to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the character sequence or string of data to write to the I2C device + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ + default int i2cWriteDevice(int handle, CharSequence data) throws IOException{ + return i2cWriteDevice(handle, data, data.length()); } } diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java index d7069a1ce..ef860f6a7 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java @@ -30,6 +30,9 @@ */ import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; public interface PiGpio_Serial { @@ -43,8 +46,21 @@ public interface PiGpio_Serial { * 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, or 230400. * @param flags No flags are currently defined. This parameter should be set to zero. * @return Returns a handle (>=0) if OK, otherwise PI_NO_HANDLE, or PI_SER_OPEN_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serOpen" */ int serOpen(CharSequence device, int baud, int flags) throws IOException; + + /** + * This function opens a serial device at a specified baud rate and with specified flags. + * The device name must start with "/dev/tty" or "/dev/serial". + * + * @param device the serial device to open (Example: "/dev/ttyAMA0") + * @param baud the baud rate in bits per second, see below + * The baud rate must be one of 50, 75, 110, 134, 150, 200, 300, 600, 1200, + * 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, or 230400. + * @return Returns a handle (>=0) if OK, otherwise PI_NO_HANDLE, or PI_SER_OPEN_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serOpen" + */ default int serOpen(CharSequence device, int baud) throws IOException { return serOpen(device, baud, 0); }; @@ -54,45 +70,197 @@ default int serOpen(CharSequence device, int baud) throws IOException { * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) * @return Returns 0 if OK, otherwise PI_BAD_HANDLE. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serClose" */ int serClose(int handle) throws IOException; - /** * This function writes a single byte "value" to the serial port associated with handle. * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) * @param value byte value to write to serial port * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWriteByte" */ int serWriteByte(int handle, byte value) throws IOException; - /** * This function reads a byte from the serial port associated with handle. * If no data is ready PI_SER_READ_NO_DATA is returned. * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) * @return Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE, PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serReadByte" */ int serReadByte(int handle) throws IOException; - /** * This function writes multiple bytes from the buffer array ('data') to the the serial * port associated with handle. * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) * @param data the array of bytes to write + * @param offset the starting offset position in the provided buffer to start writing from. * @param length the number of bytes to write * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" */ int serWrite(int handle, byte[] data, int offset, int length) throws IOException; + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the array of bytes to write + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, byte[] data, int length) throws IOException{ + return serWrite(handle, data, 0, length); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the array of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ default int serWrite(int handle, byte[] data) throws IOException{ return serWrite(handle, data, 0, data.length); } - default int serWrite(int handle, byte[] data, int length) throws IOException{ - return serWrite(handle, data, 0, length); + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer the byte buffer of data to write + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, ByteBuffer buffer, int offset, int length) throws IOException{ + return serWrite(handle, buffer.array(), offset, length); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer the byte buffer of data to write + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, ByteBuffer buffer, int length) throws IOException{ + return serWrite(handle, buffer, 0, length); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer the byte buffer of data to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, ByteBuffer buffer) throws IOException{ + return serWrite(handle, buffer, 0, buffer.capacity()); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the character/string data to write + * @param charset the character set/type used to decode the character sequence/string to bytes + * @param offset the starting offset position in the provided data to start writing from. + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, CharSequence data, Charset charset, int offset, int length) throws IOException{ + return serWrite(handle, data.toString().getBytes(charset), offset, length); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the character/string data to write + * @param charset the character set/type used to decode the character sequence/string to bytes + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, CharSequence data, Charset charset, int length) throws IOException{ + return serWrite(handle, data, charset, 0, length); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the character/string data to write + * @param charset the character set/type used to decode the character sequence/string to bytes + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, CharSequence data, Charset charset) throws IOException{ + return serWrite(handle, data, charset,0, data.length()); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the ASCII character/string data to write + * @param offset the starting offset position in the provided data to start writing from. + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, CharSequence data, int offset, int length) throws IOException{ + return serWrite(handle, data, StandardCharsets.US_ASCII, offset, length); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the ASCII character/string data to write + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, CharSequence data, int length) throws IOException{ + return serWrite(handle, data, StandardCharsets.US_ASCII, length); + } + + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the ASCII character/string data to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ + default int serWrite(int handle, CharSequence data) throws IOException{ + return serWrite(handle, data, StandardCharsets.US_ASCII); } /** @@ -101,22 +269,88 @@ default int serWrite(int handle, byte[] data, int length) throws IOException{ * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) * @param buffer a byte array to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. * @param length the maximum number of bytes to read * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serRead" */ int serRead(int handle, byte[] buffer, int offset, int length) throws IOException; + + /** + * This function reads up count bytes from the the serial port associated with handle and + * writes them to the buffer parameter. If no data is ready, zero is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer a byte array to receive the read data + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serRead" + */ + default int serRead(int handle, byte[] buffer, int length) throws IOException{ + return serRead(handle, buffer, 0, length); + } + + /** + * This function reads up count bytes from the the serial port associated with handle and + * writes them to the buffer parameter. If no data is ready, zero is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer a byte array to receive the read data + * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serRead" + */ default int serRead(int handle, byte[] buffer) throws IOException{ return serRead(handle, buffer, 0, buffer.length); } - default int serRead(int handle, byte[] buffer, int length) throws IOException{ + + /** + * This function reads up count bytes from the the serial port associated with handle and + * writes them to the buffer parameter. If no data is ready, zero is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer a byte buffer (with pre-allocated capacity) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serRead" + */ + default int serRead(int handle, ByteBuffer buffer, int offset, int length) throws IOException{ + return serRead(handle, buffer.array(), offset, length); + } + + /** + * This function reads up count bytes from the the serial port associated with handle and + * writes them to the buffer parameter. If no data is ready, zero is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer a byte buffer (with pre-allocated capacity) to receive the read data + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serRead" + */ + default int serRead(int handle, ByteBuffer buffer, int length) throws IOException{ return serRead(handle, buffer, 0, length); } + /** + * This function reads up count bytes from the the serial port associated with handle and + * writes them to the buffer parameter. If no data is ready, zero is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer a byte buffer (with pre-allocated capacity) to receive the read data + * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serRead" + */ + default int serRead(int handle, ByteBuffer buffer) throws IOException{ + return serRead(handle, buffer, 0, buffer.capacity()); + } + /** * This function returns the number of bytes available to be read from the device associated with handle. * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) * @return Returns the number of bytes of data available (>=0) if OK, otherwise PI_BAD_HANDLE. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serDataAvailable" */ int serDataAvailable(int handle) throws IOException; diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java index fede4296c..04276a72e 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java @@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -import java.util.Arrays; +import java.util.Objects; import static com.pi4j.library.pigpio.PiGpioCmd.*; import static com.pi4j.library.pigpio.PiGpioConst.DEFAULT_HOST; @@ -210,6 +210,12 @@ public String gpioHardwareRevisionString() throws IOException { return revisionString; } + // ***************************************************************************************************** + // ***************************************************************************************************** + // GPIO IMPLEMENTATION + // ***************************************************************************************************** + // ***************************************************************************************************** + /** * Sets or clears resistor pull ups or downs on the GPIO. * @@ -301,6 +307,12 @@ public void gpioWrite(int pin, PiGpioState state) throws IOException { validateResult(result); // Returns 0 if OK, otherwise PI_BAD_GPIO or PI_BAD_LEVEL. } + // ***************************************************************************************************** + // ***************************************************************************************************** + // PWM IMPLEMENTATION + // ***************************************************************************************************** + // ***************************************************************************************************** + /** * Starts PWM on the GPIO, dutycycle between 0 (off) and range (fully on). Range defaults to 255. * @@ -551,6 +563,12 @@ public void gpioHardwarePWM(int pin, int frequency, int dutyCycle) throws IOExce validateResult(rx); // Returns the numerically closest frequency if OK, otherwise PI_BAD_USER_GPIO. } + // ***************************************************************************************************** + // ***************************************************************************************************** + // DELAY/SLEEP/TIMER IMPLEMENTATION + // ***************************************************************************************************** + // ***************************************************************************************************** + /** * Delays for at least the number of microseconds specified by micros. * (Delays of 100 microseconds or less use busy waits.) @@ -618,49 +636,110 @@ public long gpioTick() throws IOException { return tick; } + // ***************************************************************************************************** + // ***************************************************************************************************** + // I2C IMPLEMENTATION + // ***************************************************************************************************** + // ***************************************************************************************************** + + /** + * Opens a I2C device on a I2C bus for communications. + * This returns a handle for the device at the address on the I2C bus. + * Physically buses 0 and 1 are available on the Pi. + * Higher numbered buses will be available if a kernel supported bus multiplexor is being used. + * + * The GPIO used are given in the following table. + * SDA SCL + * I2C0 0 1 + * I2C1 2 3 + * + * @param bus the I2C bus address to open/access for reading and writing. (>=0) + * @param device the I2C device address to open/access for reading and writing. (0-0x7F) + * @param flags no flags are currently defined. This parameter should be set to zero. + * @return Returns a handle (>=0) if OK, otherwise PI_BAD_I2C_BUS, PI_BAD_I2C_ADDR, PI_BAD_FLAGS, PI_NO_HANDLE, or PI_I2C_OPEN_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cOpen" + */ @Override - public int i2cOpen(int bus, int device) throws IOException { + public int i2cOpen(int bus, int device, int flags) throws IOException { logger.trace("[I2C::OPEN] -> Open I2C Bus [{}] and Device [{}]", bus, device); validateI2cBus(bus); validateI2cDeviceAddress(device); - PiGpioPacket tx = new PiGpioPacket(I2CO, bus, device); + PiGpioPacket tx = new PiGpioPacket(I2CO, bus, device).data(flags); PiGpioPacket rx = sendPacket(tx); int handle = rx.result(); logger.trace("[I2C::OPEN] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); return handle; } + /** + * This closes the I2C device associated with the handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cClose" + */ @Override - public void i2cClose(int handle) throws IOException { + public int i2cClose(int handle) throws IOException { logger.trace("[I2C::CLOSE] -> HANDLE={}, Close I2C Bus", handle); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CC, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::CLOSE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); + return rx.result(); } + /** + * This sends a single bit (in the Rd/Wr bit) to the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param bit 0-1, the value to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteQuick" + */ @Override - public void i2cWriteQuick(int handle, boolean bit) throws IOException { + public int i2cWriteQuick(int handle, boolean bit) throws IOException { logger.trace("[I2C::WRITE] -> HANDLE={}; R/W Bit [{}]", handle, bit ? 1 : 0); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CWQ, handle, bit ? 1 : 0); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); + return rx.result(); } + /** + * This sends a single byte to the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param value raw byte value (0-0xFF) to write to I2C device + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteByte" + */ @Override - public void i2cWriteByte(int handle, byte value) throws IOException { + public int i2cWriteByte(int handle, byte value) throws IOException { logger.trace("[I2C::WRITE] -> HANDLE={}; Byte [{}]", handle, Byte.toUnsignedInt(value)); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CWS, handle, Byte.toUnsignedInt(value)); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); + return rx.result(); } + /** + * This reads a single byte from the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @return Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadByte" + */ @Override public int i2cReadByte(int handle) throws IOException { logger.trace("[I2C::READ] -> [{}]; Byte", handle); @@ -668,32 +747,63 @@ public int i2cReadByte(int handle) throws IOException { PiGpioPacket tx = new PiGpioPacket(I2CRS, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, false); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); return rx.result(); } + /** + * This writes a single byte to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register i2cReg: 0-255, the register to write + * @param value raw byte value (0-0xFF) to write to I2C device + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteByteData" + */ @Override - public void i2cWriteByteData(int handle, int register, byte value) throws IOException { + public int i2cWriteByteData(int handle, int register, byte value) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Byte [{}]", handle ,register, Byte.toUnsignedInt(value)); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CWB, handle, register).data(Byte.toUnsignedInt(value)); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); + return rx.result(); } + /** + * This writes a single 16 bit word to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param value raw word (2-byte) value (0-0xFFFF) to write to I2C device + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteWordData" + */ @Override - public void i2cWriteWordData(int handle, int register, int value) throws IOException { + public int i2cWriteWordData(int handle, int register, int value) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Word [{}]", handle ,register, value); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CWW, handle, register).data(value); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); + return rx.result(); } + /** + * This reads a single byte from the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @return Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadByteData" + */ @Override public int i2cReadByteData(int handle, int register) throws IOException { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Byte", handle ,register); @@ -702,10 +812,19 @@ public int i2cReadByteData(int handle, int register) throws IOException { PiGpioPacket tx = new PiGpioPacket(I2CRB, handle, register); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, false); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); return rx.result(); } + /** + * This reads a single 16 bit word from the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @return Returns the word (2-byte value) read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadWordData" + */ @Override public int i2cReadWordData(int handle, int register) throws IOException { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Word", handle ,register); @@ -714,10 +833,21 @@ public int i2cReadWordData(int handle, int register) throws IOException { PiGpioPacket tx = new PiGpioPacket(I2CRW, handle, register); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, false); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); return rx.result(); } + /** + * This writes 16 bits of data to the specified register of the device associated with + * handle and reads 16 bits of data in return. (in a single transaction) + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to and read from. (0-255) + * @param value raw word (2-byte) value (0-0xFFFF) to write to I2C device + * @return Returns the word read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cProcessCall" + */ @Override public int i2cProcessCall(int handle, int register, int value) throws IOException { logger.trace("[I2C::W/R] -> [{}]; Register [{}]; Word [{}]", handle ,register, value); @@ -726,93 +856,228 @@ public int i2cProcessCall(int handle, int register, int value) throws IOExceptio PiGpioPacket tx = new PiGpioPacket(I2CPC, handle, register).data(value); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::W/R] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, false); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); return rx.result(); } + /** + * This writes up to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data the array of bytes to write + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" + */ @Override - public void i2cWriteBlockData(int handle, int register, byte[] data) throws IOException { + public int i2cWriteBlockData(int handle, int register, byte[] data, int offset, int length) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Block [{} bytes]", handle ,register, data.length); + Objects.checkFromIndexSize(offset, length, data.length); validateHandle(handle); validateI2cRegister(register); - validateI2cBlockLength(data.length); - PiGpioPacket tx = new PiGpioPacket(I2CWK, handle, register, data); + validateI2cBlockLength(length); + PiGpioPacket tx = new PiGpioPacket(I2CWK, handle, register).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); + return rx.result(); } + /** + * This reads a block of up to 32 bytes from the specified register of the device associated with handle. + * The amount of returned data is set by the device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + */ @Override - public byte[] i2cReadBlockData(int handle, int register) throws IOException { + public int i2cReadBlockData(int handle, int register, byte[] buffer, int offset, int length) throws IOException { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Block", handle ,register); + Objects.checkFromIndexSize(offset, length, buffer.length); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRK, handle, register); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, true); // Upon success nothing is returned. On error a negative status code will be returned. - return rx.data(); + if(rx.success()) { + System.arraycopy(rx.data(), 0, buffer, offset, rx.result()); + } + return rx.result(); } + + /** + * This writes data bytes to the specified register of the device associated with handle and reads a + * device specified number of bytes of data in return. + * + * The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. + * The total number of bytes sent/received must be 32 or less. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param write a byte array containing data to write + * @param writeOffset the starting offset position in the provided byte array to start writing from. + * @param writeLength the number of bytes to write (maximum 32 bytes supported) + * @param read a byte array to receive the read data; note the size must be pre-allocated and must be at + * is determined by the actual I2C device (a pre-allocated array/buffer of 32 bytes is safe) + * @param readOffset the starting offset position in the provided read array/buffer to start copying the data bytes read. + * @return Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cBlockProcessCall" + */ @Override - public byte[] i2cBlockProcessCall(int handle, int register, byte[] data) throws IOException { - logger.trace("[I2C::W/R] -> [{}]; Register [{}]; Block [{} bytes]", handle ,register, data.length); + public int i2cBlockProcessCall(int handle, int register, + byte[] write, int writeOffset, int writeLength, + byte[] read, int readOffset) throws IOException { + logger.trace("[I2C::W/R] -> [{}]; Register [{}]; Block [{} bytes]", handle ,register, writeLength); + Objects.checkFromIndexSize(writeOffset, writeLength, write.length); validateHandle(handle); validateI2cRegister(register); - validateI2cBlockLength(data.length); - PiGpioPacket tx = new PiGpioPacket(I2CPK, handle, register, data); + validateI2cBlockLength(writeLength); + + // write/read from I2C device + PiGpioPacket tx = new PiGpioPacket(I2CPK, handle, register).data(write, writeOffset, writeLength); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::W/R] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, true); // Upon success nothing is returned. On error a negative status code will be returned. - return rx.data(); + validateResult(rx, false); + + // copy data bytes to provided "read" array/buffer + if(rx.success()) { + int readLength = rx.result(); + // make sure the read array has sufficient space to store the bytes returned + Objects.checkFromIndexSize(readOffset, readLength, read.length); + System.arraycopy(rx.data(), 0, read, readOffset, readLength); + } + return rx.result(); } + /** + * This reads count bytes from the specified register of the device associated with handle . + * The maximum length of data that can be read is 32 bytes. + * The minimum length of data that can be read is 1 byte. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to read from. (0-255) + * @param buffer a byte array (pre-allocated) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read (1-32) + * @return Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadI2CBlockData" + */ @Override - public byte[] i2cReadI2CBlockData(int handle, int register, int length) throws IOException { + public int i2cReadI2CBlockData(int handle, int register, byte[] buffer, int offset, int length) throws IOException{ logger.trace("[I2C::READ] -> [{}]; Register [{}]; I2C Block [{} bytes]", handle ,register, length); + Objects.checkFromIndexSize(offset, length, buffer.length); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRI, handle, register).data(length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, true); // Upon success nothing is returned. On error a negative status code will be returned. - return rx.data(); + validateResult(rx, false); + if(rx.success()) { + System.arraycopy(rx.data(), 0, buffer, offset, rx.result()); + } + return rx.result(); } + /** + * This writes 1 to 32 bytes to the specified register of the device associated with handle. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param register the I2C register address to write to. (0-255) + * @param data a byte array containing the data to write to the I2C device register + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the maximum number of bytes to read (1-32) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" + */ @Override - public void i2cWriteI2CBlockData(int handle, int register, byte[] data) throws IOException { + public int i2cWriteI2CBlockData(int handle, int register, byte[] data, int offset, int length) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; I2C Block [{} bytes]", handle ,register, data.length); validateHandle(handle); validateI2cRegister(register); validateI2cBlockLength(data.length); - PiGpioPacket tx = new PiGpioPacket(I2CWI, handle, register, data); + PiGpioPacket tx = new PiGpioPacket(I2CWI, handle, register).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. + validateResult(rx, false); + return rx.result(); } + /** + * This reads count bytes from the raw device into byte buffer array. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param buffer a byte array (pre-allocated) to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read (1-32) + * @return Returns number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_READ_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cReadDevice" + */ @Override - public byte[] i2cReadDevice(int handle, int length) throws IOException { + public int i2cReadDevice(int handle, byte[] buffer, int offset, int length) throws IOException { logger.trace("[I2C::READ] -> [{}]; I2C Raw Read [{} bytes]", handle, length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CRD, handle, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx, false); // Upon success nothing is returned. On error a negative status code will be returned. - return rx.data(); + validateResult(rx, false); + if(rx.success()) { + System.arraycopy(rx.data(), 0, buffer, offset, rx.result()); + } + return rx.result(); } + /** + * This writes the length of bytes from the provided data array to the raw I2C device. + * + * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) + * @param data the array of bytes to write + * @param offset the starting offset position in the provided array/buffer to start writing from. + * @param length the number of bytes to write (maximum 32 bytes supported) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. + * @throws IOException + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" + */ @Override - public int i2cWriteDevice(int handle, byte[] data) throws IOException { + public int i2cWriteDevice(int handle, byte[] data, int offset, int length) throws IOException { logger.trace("[I2C::WRITE] -> [{}]; I2C Raw Write [{} bytes]", handle, data.length); validateHandle(handle); - //validateI2cDataLength(data.length); - PiGpioPacket tx = new PiGpioPacket(I2CWD, handle, 0, data); + PiGpioPacket tx = new PiGpioPacket(I2CWD, handle).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); - validateResult(rx); // Upon success nothing is returned. On error a negative status code will be returned. - return -1; + validateResult(rx, false); + return rx.result(); } + // ***************************************************************************************************** + // ***************************************************************************************************** + // SERIAL IMPLEMENTATION + // ***************************************************************************************************** + // ***************************************************************************************************** + + /** + * This function opens a serial device at a specified baud rate and with specified flags. + * The device name must start with "/dev/tty" or "/dev/serial". + * + * @param device the serial device to open (Example: "/dev/ttyAMA0") + * @param baud the baud rate in bits per second, see below + * The baud rate must be one of 50, 75, 110, 134, 150, 200, 300, 600, 1200, + * 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, or 230400. + * @param flags No flags are currently defined. This parameter should be set to zero. + * @return Returns a handle (>=0) if OK, otherwise PI_NO_HANDLE, or PI_SER_OPEN_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serOpen" + */ @Override public int serOpen(CharSequence device, int baud, int flags) throws IOException { logger.trace("[SERIAL::OPEN] -> Open Serial Port [{}] at Baud Rate [{}]", device, baud); @@ -824,6 +1089,13 @@ public int serOpen(CharSequence device, int baud, int flags) throws IOException return handle; } + /** + * This function closes the serial device associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serClose" + */ @Override public int serClose(int handle) throws IOException { logger.trace("[SERIAL::CLOSE] -> HANDLE={}, Close Serial Port", handle); @@ -835,6 +1107,14 @@ public int serClose(int handle) throws IOException { return rx.result(); } + /** + * This function writes a single byte "value" to the serial port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param value byte value to write to serial port + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWriteByte" + */ @Override public int serWriteByte(int handle, byte value) throws IOException { logger.trace("[SERIAL::WRITE] -> HANDLE={}; Byte [{}]", handle, Byte.toUnsignedInt(value)); @@ -846,6 +1126,14 @@ public int serWriteByte(int handle, byte value) throws IOException { return 0; } + /** + * This function reads a byte from the serial port associated with handle. + * If no data is ready PI_SER_READ_NO_DATA is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE, PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serReadByte" + */ @Override public int serReadByte(int handle) throws IOException { logger.trace("[SERIAL::READ] -> [{}]; Byte", handle); @@ -857,9 +1145,21 @@ public int serReadByte(int handle) throws IOException { return rx.result(); } + /** + * This function writes multiple bytes from the buffer array ('data') to the the serial + * port associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param data the array of bytes to write + * @param offset the starting offset position in the provided buffer to start writing from. + * @param length the number of bytes to write + * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" + */ @Override public int serWrite(int handle, byte[] data, int offset, int length) throws IOException { logger.trace("[SERIAL::WRITE] -> [{}]; Serial Write [{} bytes]", handle, data.length); + Objects.checkFromIndexSize(offset, length, data.length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SERW, handle).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); @@ -868,20 +1168,39 @@ public int serWrite(int handle, byte[] data, int offset, int length) throws IOEx return rx.result(); } + /** + * This function reads up count bytes from the the serial port associated with handle and + * writes them to the buffer parameter. If no data is ready, zero is returned. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @param buffer a byte array to receive the read data + * @param offset the starting offset position in the provided buffer to start copying the data bytes read. + * @param length the maximum number of bytes to read + * @return Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_READ_NO_DATA. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serRead" + */ @Override public int serRead(int handle, byte[] buffer, int offset, int length) throws IOException { logger.trace("[SERIAL::READ] -> [{}]; Serial Read [{} bytes]", handle, length); + Objects.checkFromIndexSize(offset, length, buffer.length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SERR, handle, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[SERIAL::READ] <- HANDLE={}; SUCCESS={}; BYTES-READ={}", handle, rx.success(), rx.dataLength()); validateResult(rx, false); if(rx.success()) { - System.arraycopy(rx.data(), 0, buffer, 0, rx.result()); + System.arraycopy(rx.data(), 0, buffer, offset, rx.result()); } return rx.result(); } + /** + * This function returns the number of bytes available to be read from the device associated with handle. + * + * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) + * @return Returns the number of bytes of data available (>=0) if OK, otherwise PI_BAD_HANDLE. + * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serDataAvailable" + */ @Override public int serDataAvailable(int handle) throws IOException { logger.trace("[SERIAL::AVAIL] -> Get number of bytes available to read"); @@ -899,6 +1218,7 @@ public int serDataAvailable(int handle) throws IOException { * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) * @return Returns the number of bytes of data drained (>=0) if OK, otherwise PI_BAD_HANDLE. */ + @Override public int serDrain(int handle) throws IOException{ logger.trace("[SERIAL::DRAIN] -> Drain any remaining bytes in serial RX buffer"); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java index 90c5aeb74..6ca2fac1e 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/Main.java @@ -28,8 +28,6 @@ * #L% */ -import java.io.IOException; - public class Main { diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java index ee18732d5..b61a9ece9 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cRawUsingTestHarness.java @@ -182,11 +182,19 @@ public void testI2CMultiByteTxRx() throws IOException, InterruptedException { Thread.sleep(20); // READ :: RAW MULTI-BYTE - String rx = pigpio.i2cReadDeviceToString(handle, value.length()); - System.out.println(" (READ) << VALUE = " + rx); - Thread.sleep(20); + byte[] buffer = new byte[value.length()]; + var result = pigpio.i2cReadDevice(handle, buffer); + + System.out.println(" (READ) << RESULT = " + result); + if(result > 0) { + String resultString = new String(buffer); + System.out.println(" (READ) << VALUE = " + resultString); + Assert.assertEquals("I2C MULTI-BYTE VALUE MISMATCH", value, resultString); + } else { + Assert.fail("I2C READ FAILED: " + result); + } - Assert.assertEquals("I2C MULTI-BYTE VALUE MISMATCH", value, rx); + Thread.sleep(20); } } } diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cUsingTestHarness.java index a9a44234f..91f35e074 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/i2c/TestI2cUsingTestHarness.java @@ -38,7 +38,9 @@ import org.junit.jupiter.api.*; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import java.util.Random; import java.util.UUID; @@ -310,15 +312,21 @@ public void testI2CProcessBlockTxRx() throws IOException, InterruptedException { Thread.sleep(10); System.out.println("[TEST PROCESS BLOCK] :: REGISTER=" + register); - String generatedValue = UUID.randomUUID().toString().substring(0, 10); - System.out.println(" (WRITE) >> VALUE = " + generatedValue); + // create a random test array of bytes between 5 and 25 bytes in length + Random r = new Random(); + byte[] writeBuffer = new byte[r.nextInt(20) + 5]; + r.nextBytes(writeBuffer); + System.out.println(" (WRITE) >> VALUE = " + Arrays.toString(writeBuffer)); // WRITE/READ :: BLOCK TO REGISTER - String returnedValue = pigpio.i2cBlockProcessCallToString(handle, register, generatedValue); - System.out.println(" (READ) << VALUE = " + returnedValue); + byte[] readBuffer = new byte[writeBuffer.length]; + var result = pigpio.i2cBlockProcessCall(handle, register, writeBuffer, readBuffer); + + System.out.println(" (READ) << RESULT = " + result); + System.out.println(" (READ) << VALUE = " + Arrays.toString(readBuffer)); // validate read value match with expected value that was written to this register - Assert.assertEquals("I2C BLOCK VALUE MISMATCH", generatedValue, returnedValue); + Assert.assertArrayEquals("I2C BLOCK VALUE MISMATCH", writeBuffer, readBuffer); } } @@ -350,27 +358,42 @@ public void testI2CBlockI2CDataTxRx() throws IOException, InterruptedException, for(int register = 0; register < MAX_REGISTERS; register++) { System.out.println("[TEST READ BLOCK] :: REGISTER=" + register + "; LENGTH=" + values[register].length()); + String valueString = ""; + // READ :: BLOCK - Thread.sleep(50); - String value = pigpio.i2cReadI2CBlockDataToString(handle, register, values[register].length()); - System.out.println(" (READ) << VALUE = " + value + "; (EXPECTED=" + values[register] + ")"); + Thread.sleep(100); + byte[] buffer = new byte[values[register].length()]; + int result = pigpio.i2cReadI2CBlockData(handle, register, buffer); + System.out.println(" (READ) << RESULT = " + result); + if(result > 0) { + valueString = new String(buffer, StandardCharsets.US_ASCII); + System.out.println(" (READ) << VALUE = " + valueString + "; (EXPECTED=" + values[register] + ")"); + } // attempt #2 - if(!values[register].equals(value)){ + if(!values[register].equals(valueString)){ Thread.sleep(100); - value = pigpio.i2cReadI2CBlockDataToString(handle, register, values[register].length()); - System.out.println(" (READ) << VALUE = " + value + "; (EXPECTED=" + values[register] + ") "); + result = pigpio.i2cReadI2CBlockData(handle, register, buffer); + System.out.println(" (READ) << RESULT = " + result); + if(result > 0) { + valueString = new String(buffer, StandardCharsets.US_ASCII); + System.out.println(" (READ) << VALUE = " + valueString + "; (EXPECTED=" + values[register] + ")"); + } } // attempt #3 - if(!values[register].equals(value)){ + if(!values[register].equals(valueString)){ Thread.sleep(500); - value = pigpio.i2cReadI2CBlockDataToString(handle, register, values[register].length()); - System.out.println(" (READ) << VALUE = " + value + "; (EXPECTED=" + values[register] + ") "); + result = pigpio.i2cReadI2CBlockData(handle, register, buffer); + System.out.println(" (READ) << RESULT = " + result); + if(result > 0) { + valueString = new String(buffer, StandardCharsets.US_ASCII); + System.out.println(" (READ) << VALUE = " + valueString + "; (EXPECTED=" + values[register] + ")"); + } } // validate read value match with expected value that was writted to this register - Assert.assertEquals("I2C BLOCK VALUE MISMATCH", values[register], value); + Assert.assertEquals("I2C BLOCK VALUE MISMATCH", values[register], valueString); } } } diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java index 28a052821..719ba04ae 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestHardwarePwmUsingTestHarness.java @@ -33,8 +33,6 @@ import com.pi4j.library.pigpio.PiGpioMode; import com.pi4j.test.harness.ArduinoTestHarness; import com.pi4j.test.harness.TestHarnessFrequency; -import com.pi4j.test.harness.TestHarnessInfo; -import com.pi4j.test.harness.TestHarnessPins; import org.junit.Assert; import org.junit.jupiter.api.*; diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java index 633ef5030..bd63789d7 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java @@ -31,7 +31,6 @@ import com.pi4j.library.pigpio.PiGpio; import com.pi4j.library.pigpio.PiGpioMode; -import com.pi4j.library.pigpio.util.StringUtil; import com.pi4j.test.harness.ArduinoTestHarness; import com.pi4j.test.harness.TestHarnessInfo; import com.pi4j.test.harness.TestHarnessPins; @@ -39,11 +38,8 @@ import org.junit.jupiter.api.*; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.Formatter; import java.util.Random; -import java.util.UUID; @DisplayName("PIGPIO Library :: Test Serial Communication") public class TestSerialUsingTestHarness { diff --git a/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java b/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java index ac516c530..66a76cc87 100644 --- a/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java +++ b/pi4j-api/src/main/java/com/pi4j/config/impl/DeviceConfigBuilderBase.java @@ -27,7 +27,6 @@ * #L% */ -import com.pi4j.config.AddressConfigBuilder; import com.pi4j.config.ConfigBuilder; import com.pi4j.config.DeviceConfig; import com.pi4j.config.DeviceConfigBuilder; diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java index 9b4c32724..d3eb669f2 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/impl/DefaultDigitalOutputBuilder.java @@ -30,8 +30,8 @@ import com.pi4j.context.Context; import com.pi4j.io.gpio.digital.*; import com.pi4j.platform.Platform; -import com.pi4j.util.StringUtil; import com.pi4j.provider.Provider; +import com.pi4j.util.StringUtil; public class DefaultDigitalOutputBuilder implements DigitalOutputBuilder { diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java index 1fcb3497c..19c33d89b 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Parity.java @@ -27,8 +27,6 @@ * #L% */ -import com.pi4j.io.gpio.digital.PullResistance; - public enum Parity { NONE(0), diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java index 6dca75440..e1f20204b 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java @@ -28,7 +28,6 @@ */ import com.pi4j.io.IO; -import com.pi4j.io.pwm.PwmConfigBuilder; import java.io.IOException; diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java index ecd461e26..8c9fca74f 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java @@ -32,13 +32,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.util.Collection; public abstract class SerialBase extends IOBase implements Serial { diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java index 7ff2b6f3f..c477ab4c4 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialConfigBuilder.java @@ -28,12 +28,6 @@ */ import com.pi4j.config.DeviceConfigBuilder; -import com.pi4j.config.impl.DeviceConfigBuilderBase; -import com.pi4j.io.gpio.GpioConfigBuilder; -import com.pi4j.io.pwm.PwmConfig; -import com.pi4j.io.pwm.PwmPreset; -import com.pi4j.io.pwm.PwmType; -import com.pi4j.io.pwm.impl.DefaultPwmConfigBuilder; import com.pi4j.io.serial.impl.DefaultSerialConfigBuilder; public interface SerialConfigBuilder extends DeviceConfigBuilder { diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java index b090db06a..e7f81db68 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialProvider.java @@ -27,8 +27,6 @@ * #L% */ -import com.pi4j.io.pwm.Pwm; -import com.pi4j.io.pwm.PwmConfigBuilder; import com.pi4j.provider.Provider; diff --git a/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java b/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java index 654b4f8b8..fe533903d 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java +++ b/pi4j-api/src/main/java/com/pi4j/io/spi/SpiProvider.java @@ -28,7 +28,6 @@ */ -import com.pi4j.io.serial.Serial; import com.pi4j.provider.Provider; public interface SpiProvider extends Provider { diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java index 4032ce663..0e1fa2f96 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java @@ -115,10 +115,7 @@ public int read() throws IOException{ @Override public int read(ByteBuffer buffer, int offset, int length) throws IOException{ Objects.checkFromIndexSize(offset, length, buffer.capacity()); - byte[] data = piGpio.i2cReadDevice(this.handle, length); - if(data.length > 0) - buffer.put(data, offset, length); - return length; + return piGpio.i2cReadDevice(this.handle, buffer, offset, length); } // ------------------------------------------------------------------- @@ -149,10 +146,7 @@ public int readRegister(int register) throws IOException { @Override public int readRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException { Objects.checkFromIndexSize(offset, length, buffer.capacity()); - byte data[] = piGpio.i2cReadI2CBlockData(this.handle, register, length); - if(data.length > 0) - buffer.put(data, offset, length); - return length; + return piGpio.i2cReadI2CBlockData(this.handle, register, buffer, offset, length); } @Override From 2694680fe343e8663bab0ed8bfdb30f22484db32 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Fri, 23 Aug 2019 09:18:50 -0400 Subject: [PATCH 07/15] updated IODataWriter interface for combined Serial and I2C; fixed a number of hardware test harness issues --- .../com/pi4j/library/pigpio/PiGpioPacket.java | 22 +- .../com/pi4j/library/pigpio/PiGpio_I2C.java | 48 +- .../pi4j/library/pigpio/PiGpio_Serial.java | 20 +- .../library/pigpio/impl/PiGpioSocketImpl.java | 14 +- .../TestDigitalInputsUsingTestHarness.java | 2 +- .../TestDigitalOutputsUsingTestHarness.java | 2 + .../pwm/TestSoftwarePwmUsingTestHarness.java | 5 + .../serial/TestSerialUsingTestHarness.java | 4 +- .../main/java/com/pi4j/io/IODataReader.java | 29 +- .../main/java/com/pi4j/io/IODataWriter.java | 426 ++++++++++++++-- .../java/com/pi4j/io/i2c/I2CRegister.java | 9 + .../pi4j/io/i2c/I2CRegisterDataWriter.java | 480 ++++++++++++++++-- .../pi4j/io/i2c/impl/DefaultI2CRegister.java | 26 +- .../main/java/com/pi4j/io/serial/Serial.java | 18 +- .../java/com/pi4j/io/serial/SerialBase.java | 7 + .../pi4j/example/i2c/I2cRawDeviceExample.java | 6 - .../pi4j/example/serial/SerialExample.java | 3 - .../arduino/src/command/FrequencyCommand.h | 6 +- .../src/main/arduino/src/main.cpp | 18 +- .../pi4j/test/harness/ArduinoTestHarness.java | 32 +- .../plugin/mock/provider/i2c/MockI2C.java | 38 +- .../mock/provider/serial/MockSerial.java | 120 +++++ .../com/pi4j/plugin/pigpio/PiGpioPlugin.java | 2 + .../plugin/pigpio/provider/i2c/PiGpioI2C.java | 24 +- .../pigpio/provider/serial/PiGpioSerial.java | 127 +++++ .../provider/serial/PiGpioSerialProvider.java | 42 ++ .../serial/PiGpioSerialProviderImpl.java | 51 ++ .../TestDigitalInputUsingTestHarness.java | 2 +- .../TestDigitalOutputUsingTestHarness.java | 2 +- .../i2c/TestI2cRawUsingTestHarness.java | 18 +- .../pigpio/i2c/TestI2cUsingTestHarness.java | 2 +- .../pwm/TestHardwarePwmUsingTestHarness.java | 2 +- .../pwm/TestSoftwarePwmUsingTestHarness.java | 2 +- .../serial/TestSerialUsingTestHarness.java | 255 ++++++++++ .../raspberrypi/provider/i2c/RpiI2C.java | 14 +- .../provider/serial/RpiSerial.java | 32 +- 36 files changed, 1663 insertions(+), 247 deletions(-) create mode 100644 plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java create mode 100644 plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProvider.java create mode 100644 plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProviderImpl.java create mode 100644 plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java index 5afdd1c9a..9204fdf3e 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java @@ -221,10 +221,19 @@ public static PiGpioPacket decode(byte[] data) throws IOException { .p3(p3); // set RAW P3 value // apply any extra payload data (if available) - if(rx.hasRemaining()){ - var temp = new byte[rx.remaining()]; - rx.get(temp); - packet.data(temp); + int remaining = rx.remaining(); + + // bounds check remaining byte count + if(p3 < remaining) remaining = p3; + + //System.out.println("HAS-REMAINING: " + remaining); + if(remaining > 0){ + var temp = new byte[remaining]; + rx.get(temp, 0, remaining); + //System.out.println("[REMAINING ]" + Arrays.toString(temp)); + //packet.data(temp); + packet.data = Arrays.copyOf(temp, remaining); + //System.out.println("[DATA SIZE ]" + packet.dataLength()); } return packet; } @@ -240,7 +249,7 @@ public static byte[] encode(PiGpioPacket packet){ buffer.putInt((packet.p1())); // buffer.putInt((packet.p2())); // buffer.putInt((packet.p3())); // - if(packet.hasData()) { + if(packet.data != null && packet.data.length > 0) { buffer.put(packet.data()); // } @@ -250,7 +259,8 @@ public static byte[] encode(PiGpioPacket packet){ @Override public String toString(){ - if(hasData()) + //if(this.data != null && this.data.length > 0) + if(p3() > 0) return String.format("CMD=%s(%d); P1=%d; P2=%d; P3=%d; PAYLOAD=[0x%s]", cmd().name(), cmd().value(), p1(), p2(), p3(), StringUtil.toHexString(data())); else return String.format("CMD=%s(%d); P1=%d; P2=%d; P3=%d", cmd().name(), cmd().value(), p1(), p2(), p3()); diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java index 220a70080..baf182690 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_I2C.java @@ -271,15 +271,15 @@ default int i2cWriteBlockData(int handle, int register, ByteBuffer buffer) throw * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) * @param register the I2C register address to write to. (0-255) - * @param data the character/string data to write * @param charset the character set/type used to decode the character sequence/string to bytes + * @param data the character/string data to write * @param offset the starting offset position in the provided data to start writing from. * @param length the number of bytes to write (maximum 32 bytes supported) * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" */ - default int i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset, int offset, int length) throws IOException{ + default int i2cWriteBlockData(int handle, int register, Charset charset, CharSequence data, int offset, int length) throws IOException{ return i2cWriteBlockData(handle, register, data.toString().getBytes(charset), offset, length); } @@ -288,15 +288,15 @@ default int i2cWriteBlockData(int handle, int register, CharSequence data, Chars * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) * @param register the I2C register address to write to. (0-255) - * @param data the character/string data to write * @param charset the character set/type used to decode the character sequence/string to bytes + * @param data the character/string data to write * @param length the number of bytes to write (maximum 32 bytes supported) * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" */ - default int i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset, int length) throws IOException{ - return i2cWriteBlockData(handle, register, data, charset,0, length); + default int i2cWriteBlockData(int handle, int register, Charset charset, CharSequence data, int length) throws IOException{ + return i2cWriteBlockData(handle, register, charset, data, 0, length); } /** @@ -304,14 +304,14 @@ default int i2cWriteBlockData(int handle, int register, CharSequence data, Chars * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) * @param register the I2C register address to write to. (0-255) - * @param data the character/string data to write * @param charset the character set/type used to decode the character sequence/string to bytes + * @param data the character/string data to write * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteBlockData" */ - default int i2cWriteBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ - return i2cWriteBlockData(handle, register, data, charset, data.length()); + default int i2cWriteBlockData(int handle, int register, Charset charset, CharSequence data) throws IOException{ + return i2cWriteBlockData(handle, register, charset, data, data.length()); } /** @@ -936,15 +936,15 @@ default int i2cWriteI2CBlockData(int handle, int register, ByteBuffer buffer) th * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) * @param register the I2C register address to write to. (0-255) - * @param data a byte array containing the data to write to the I2C device register * @param charset the character set/type used to encode the character sequence/string to bytes + * @param data a byte array containing the data to write to the I2C device register * @param offset the starting offset position in the provided buffer to start writing from. * @param length the maximum number of bytes to read (1-32) * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" */ - default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset, int offset, int length) throws IOException{ + default int i2cWriteI2CBlockData(int handle, int register, Charset charset, CharSequence data, int offset, int length) throws IOException{ return i2cWriteI2CBlockData(handle, register, data.toString().getBytes(charset), offset, length); } @@ -953,15 +953,15 @@ default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Ch * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) * @param register the I2C register address to write to. (0-255) - * @param data a byte array containing the data to write to the I2C device register * @param charset the character set/type used to encode the character sequence/string to bytes + * @param data a byte array containing the data to write to the I2C device register * @param length the maximum number of bytes to read (1-32) * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" */ - default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset, int length) throws IOException{ - return i2cWriteI2CBlockData(handle, register, data, charset, 0, length); + default int i2cWriteI2CBlockData(int handle, int register, Charset charset, CharSequence data, int length) throws IOException{ + return i2cWriteI2CBlockData(handle, register, charset, data, 0, length); } /** @@ -969,14 +969,14 @@ default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Ch * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) * @param register the I2C register address to write to. (0-255) - * @param data a byte array containing the data to write to the I2C device register * @param charset the character set/type used to encode the character sequence/string to bytes + * @param data a byte array containing the data to write to the I2C device register * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteI2CBlockData" */ - default int i2cWriteI2CBlockData(int handle, int register, CharSequence data, Charset charset) throws IOException{ - return i2cWriteI2CBlockData(handle, register, data, charset, data.length()); + default int i2cWriteI2CBlockData(int handle, int register, Charset charset, CharSequence data) throws IOException{ + return i2cWriteI2CBlockData(handle, register, charset, data, data.length()); } /** @@ -1192,15 +1192,15 @@ default int i2cWriteDevice(int handle, ByteBuffer buffer) throws IOException{ * This writes the length of bytes from the provided byte buffer to the raw I2C device. * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) - * @param data the character sequence or string of data to write to the I2C device * @param charset the character set/type used to encode the character sequence/string to bytes + * @param data the character sequence or string of data to write to the I2C device * @param offset the starting offset position in the provided character sequence/string to start writing from. * @param length the number of bytes to write (maximum 32 bytes supported) * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" */ - default int i2cWriteDevice(int handle, CharSequence data, Charset charset, int offset, int length) throws IOException{ + default int i2cWriteDevice(int handle, Charset charset, CharSequence data, int offset, int length) throws IOException{ return i2cWriteDevice(handle, data.toString().getBytes(charset), offset ,length); } @@ -1208,29 +1208,29 @@ default int i2cWriteDevice(int handle, CharSequence data, Charset charset, int o * This writes the length of bytes from the provided byte buffer to the raw I2C device. * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) - * @param data the character sequence or string of data to write to the I2C device * @param charset the character set/type used to encode the character sequence/string to bytes + * @param data the character sequence or string of data to write to the I2C device * @param length the number of bytes to write (maximum 32 bytes supported) * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" */ - default int i2cWriteDevice(int handle, CharSequence data, Charset charset, int length) throws IOException{ - return i2cWriteDevice(handle, data, charset, 0, length); + default int i2cWriteDevice(int handle, Charset charset, CharSequence data, int length) throws IOException{ + return i2cWriteDevice(handle, charset, data, 0, length); } /** * This writes the length of bytes from the provided byte buffer to the raw I2C device. * * @param handle the open I2C device handle; (>=0, as returned by a call to i2cOpen) - * @param data the character sequence or string of data to write to the I2C device * @param charset the character set/type used to encode the character sequence/string to bytes + * @param data the character sequence or string of data to write to the I2C device * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_I2C_WRITE_FAILED. * @throws IOException * @see "http://abyz.me.uk/rpi/pigpio/cif.html#i2cWriteDevice" */ - default int i2cWriteDevice(int handle, CharSequence data, Charset charset) throws IOException{ - return i2cWriteDevice(handle, data, charset, data.length()); + default int i2cWriteDevice(int handle, Charset charset, CharSequence data) throws IOException{ + return i2cWriteDevice(handle, charset, data, data.length()); } /** diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java index ef860f6a7..0639a4d38 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpio_Serial.java @@ -181,14 +181,14 @@ default int serWrite(int handle, ByteBuffer buffer) throws IOException{ * port associated with handle. * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) - * @param data the character/string data to write * @param charset the character set/type used to decode the character sequence/string to bytes + * @param data the character/string data to write * @param offset the starting offset position in the provided data to start writing from. * @param length the number of bytes to write * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" */ - default int serWrite(int handle, CharSequence data, Charset charset, int offset, int length) throws IOException{ + default int serWrite(int handle, Charset charset, CharSequence data, int offset, int length) throws IOException{ return serWrite(handle, data.toString().getBytes(charset), offset, length); } @@ -197,14 +197,14 @@ default int serWrite(int handle, CharSequence data, Charset charset, int offset, * port associated with handle. * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) - * @param data the character/string data to write * @param charset the character set/type used to decode the character sequence/string to bytes + * @param data the character/string data to write * @param length the number of bytes to write * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" */ - default int serWrite(int handle, CharSequence data, Charset charset, int length) throws IOException{ - return serWrite(handle, data, charset, 0, length); + default int serWrite(int handle, Charset charset, CharSequence data, int length) throws IOException{ + return serWrite(handle, charset, data, 0, length); } /** @@ -212,13 +212,13 @@ default int serWrite(int handle, CharSequence data, Charset charset, int length) * port associated with handle. * * @param handle the open serial device handle; (>=0, as returned by a call to serOpen) - * @param data the character/string data to write * @param charset the character set/type used to decode the character sequence/string to bytes + * @param data the character/string data to write * @return Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or PI_SER_WRITE_FAILED. * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" */ default int serWrite(int handle, CharSequence data, Charset charset) throws IOException{ - return serWrite(handle, data, charset,0, data.length()); + return serWrite(handle, charset, data, 0, data.length()); } /** @@ -233,7 +233,7 @@ default int serWrite(int handle, CharSequence data, Charset charset) throws IOEx * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" */ default int serWrite(int handle, CharSequence data, int offset, int length) throws IOException{ - return serWrite(handle, data, StandardCharsets.US_ASCII, offset, length); + return serWrite(handle, StandardCharsets.US_ASCII, data, offset, length); } /** @@ -247,7 +247,7 @@ default int serWrite(int handle, CharSequence data, int offset, int length) thro * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" */ default int serWrite(int handle, CharSequence data, int length) throws IOException{ - return serWrite(handle, data, StandardCharsets.US_ASCII, length); + return serWrite(handle, data, length); } /** @@ -260,7 +260,7 @@ default int serWrite(int handle, CharSequence data, int length) throws IOExcepti * @see "http://abyz.me.uk/rpi/pigpio/cif.html#serWrite" */ default int serWrite(int handle, CharSequence data) throws IOException{ - return serWrite(handle, data, StandardCharsets.US_ASCII); + return serWrite(handle, data, data.length()); } /** diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java index 04276a72e..d807302fe 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/impl/PiGpioSocketImpl.java @@ -982,8 +982,20 @@ public int i2cReadI2CBlockData(int handle, int register, byte[] buffer, int offs PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); + + logger.trace("[I2C::READ] <- DATA SIZE={}", rx.result()); + logger.trace("[I2C::READ] <- DATA LENGTH={}", rx.dataLength()); + logger.trace("[I2C::READ] <- BUFFER SIZE={}", rx.data()); + logger.trace("[I2C::READ] <- OFFSET={}", offset); + if(rx.success()) { - System.arraycopy(rx.data(), 0, buffer, offset, rx.result()); + try { + System.arraycopy(rx.data(), 0, buffer, offset, rx.result()); + } + catch (ArrayIndexOutOfBoundsException a){ + a.printStackTrace(); + } + } return rx.result(); } diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java index 3dfb525a1..c87958380 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalInputsUsingTestHarness.java @@ -53,7 +53,7 @@ public class TestDigitalInputsUsingTestHarness { @BeforeAll public static void initialize() { - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java index 545d12212..534691cae 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/gpio/TestDigitalOutputsUsingTestHarness.java @@ -53,6 +53,8 @@ public class TestDigitalOutputsUsingTestHarness { @BeforeAll public static void initialize() { + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); + System.out.println(); System.out.println("************************************************************************"); System.out.println("INITIALIZE TEST (" + TestDigitalOutputsUsingTestHarness.class.getName() + ")"); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java index ad187a02c..7a5cb4e3c 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/pwm/TestSoftwarePwmUsingTestHarness.java @@ -30,6 +30,7 @@ */ import com.pi4j.library.pigpio.PiGpio; +import com.pi4j.library.pigpio.PiGpioMode; import com.pi4j.test.harness.ArduinoTestHarness; import com.pi4j.test.harness.TestHarnessFrequency; import com.pi4j.test.harness.TestHarnessInfo; @@ -168,6 +169,10 @@ public void testPwm(int frequency, int dutyCycle) throws IOException, Interrupte System.out.println("----------------------------------------"); for(int p = 2; p < 20; p++) { + + // set pin to output pin + pigpio.gpioSetMode(p, PiGpioMode.OUTPUT); + System.out.println(); System.out.println("[TEST SOFT PWM] :: PIN=" + p); int actualFrequency = pigpio.gpioSetPWMfrequency(p, frequency); diff --git a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java index bd63789d7..60b2e6748 100644 --- a/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java +++ b/libraries/pi4j-library-pigpio/src/test/java/com/pi4j/library/pigpio/test/serial/TestSerialUsingTestHarness.java @@ -53,7 +53,7 @@ public class TestSerialUsingTestHarness { @BeforeAll public static void initialize() { - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); @@ -78,7 +78,7 @@ public static void initialize() { System.out.println("COPYRIGHT : " + info.copyright); System.out.println("----------------------------------------"); -// // reset all pins on test harness before proceeding with this test + // reset all pins on test harness before proceeding with this test TestHarnessPins reset = harness.reset(); System.out.println(); System.out.println("RESET ALL PINS ON TEST HARNESS; (" + reset.total + " pin reset)"); diff --git a/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java b/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java index 2898640fb..66a508b82 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java +++ b/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java @@ -48,24 +48,41 @@ */ public interface IODataReader { + // ------------------------------------------------------------------------------------ + // SINGLE BYTE + // ------------------------------------------------------------------------------------ + int read() throws IOException; - int read(ByteBuffer buffer, int offset, int length) throws IOException; - // ------------------------------------------------------------------------------------------------------------ - default int read(byte[] buffer, int offset, int length) throws IOException{ - ByteBuffer bb = ByteBuffer.wrap(buffer); - return read(bb, offset, length); - } + // ------------------------------------------------------------------------------------ + // BYTE ARRAY + // ------------------------------------------------------------------------------------ + + int read(byte[] buffer, int offset, int length) throws IOException; + default int read(byte[] buffer, int length) throws IOException{ return read(buffer, 0, length); } + default int read(byte[] buffer) throws IOException{ return read(buffer, 0, buffer.length); } + + // ------------------------------------------------------------------------------------------------------------ + + // ------------------------------------------------------------------------------------ + // BYTE BUFFER + // ------------------------------------------------------------------------------------ + + default int read(ByteBuffer buffer, int offset, int length) throws IOException{ + return read(buffer.array(), offset, length); + } + default int read(ByteBuffer buffer, int length) throws IOException{ return read(buffer, 0, length); } + default int read(ByteBuffer buffer) throws IOException{ return read(buffer, 0, buffer.capacity()); } diff --git a/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java b/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java index 9e4a2e843..50655a70c 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java +++ b/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java @@ -27,13 +27,15 @@ * #L% */ +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.Objects; +import java.util.Collection; /** * Data Writer Interface for Pi4J Data Communications @@ -46,81 +48,111 @@ */ public interface IODataWriter { + // ------------------------------------------------------------------------------------ + // SINGLE BYTE + // ------------------------------------------------------------------------------------ + /** * Write a single raw byte value. * * @param b byte to be written * @throws IOException thrown on write error */ - void write(byte b) throws IOException; + int write(byte b) throws IOException; /** - * Write a buffer of byte values with given offset (starting position) and length in the provided data buffer. + * Write a single raw byte value. * - * @param buffer byte buffer of data to be written + * @param b integer value that will be cast to a byte and written + * @throws IOException thrown on write error + */ + default int write(int b) throws IOException{ + return write((byte)b); + } + + // ------------------------------------------------------------------------------------ + // BYTE ARRAY + // ------------------------------------------------------------------------------------ + + /** + * Write an array of byte values with given offset (starting position) and length in the provided data array. + * + * @param data data array of bytes to be written * @param offset offset in data buffer to start at * @param length number of bytes to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - int write(ByteBuffer buffer, int offset, int length) throws IOException; + int write(byte[] data, int offset, int length) throws IOException; /** - * Write a single raw byte value. + * Write an array of byte values starting with the first byte in the array up to the provided length. * - * @param b byte to be written + * @param data data array of bytes to be written + * @param length number of bytes to be written + * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default void write(int b) throws IOException{ - write((byte)b); + default int write(byte[] data, int length) throws IOException{ + return write(data, 0, length); } /** - * Write a single word value (16-bit) to the raw I2C device. + * Write an array of byte values (all bytes in array). * - * @param word 16-bit word value to be written + * @param data data array of bytes to be written + * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default void writeWord(int word) throws IOException{ - byte[] buffer = new byte[] { (byte)(word >> 8), (byte)word }; - this.write(buffer); + default int write(byte ... data) throws IOException { + return write(data, 0, data.length); } /** - * Write an array of byte values with given offset (starting position) and length in the provided data array. + * Write multiple byte arrays. * * @param data data array of bytes to be written - * @param offset offset in data buffer to start at - * @param length number of bytes to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int write(byte[] data, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, data.length); - return write(ByteBuffer.wrap(data), offset, length); + default int write(byte[] ... data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (byte[] ba : data) { + os.write(ba); + } + return write(os.toByteArray()); } /** - * Write an array of byte values starting with the first byte in the array up to the provided length. + * Write a collection of byte arrays. * - * @param data data array of bytes to be written - * @param length number of bytes to be written + * @param data collection of byte array of data to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int write(byte[] data, int length) throws IOException{ - return write(data, 0, length); + default int write(Collection data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (byte[] ba : data) { + os.write(ba); + } + return write(os.toByteArray()); } + // ------------------------------------------------------------------------------------ + // BYTE BUFFER + // ------------------------------------------------------------------------------------ + /** - * Write an array of byte values (all bytes in array). + * Write a buffer of byte values with given offset (starting position) and length in the provided data buffer. * - * @param data data array of bytes to be written + * @param buffer byte buffer of data to be written + * @param offset offset in data buffer to start at + * @param length number of bytes to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int write(byte[] data) throws IOException{ - return write(data, 0, data.length); + default int write(ByteBuffer buffer, int offset, int length) throws IOException{ + return write(buffer.array(), offset, length); } /** @@ -132,20 +164,42 @@ default int write(byte[] data) throws IOException{ * @throws IOException thrown on write error */ default int write(ByteBuffer buffer, int length) throws IOException{ - return write(buffer, 0, length); + return write(buffer, buffer.position(), length); } /** * Write a buffer of byte values (all bytes in buffer). * - * @param buffer byte buffer of data to be written + * (The byte buffer is read from the current position up to the 'limit' value, not the 'capacity'. + * You may need to rewind() or flip() the byte buffer if you have just written to it.) + * + * @param buffer byte buffer of data to be written (from current position to limit) * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ default int write(ByteBuffer buffer) throws IOException{ - return write(buffer, 0, buffer.capacity()); + return write(buffer, buffer.remaining()); + } + + /** + * Write multiple byte buffers of data. + * + * @param buffer byte buffer of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(ByteBuffer ... buffer) throws IOException{ + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (ByteBuffer bb : buffer) { + os.write(bb.array()); + } + return write(os.toByteArray()); } + // ------------------------------------------------------------------------------------ + // INPUT STREAM + // ------------------------------------------------------------------------------------ + /** * Write a buffer of byte values (all bytes in buffer). * @@ -158,14 +212,34 @@ default int write(InputStream stream) throws IOException{ } /** - * Writes an ASCII data string. + * Write a buffer of byte values (all bytes in buffer). + * + * @param stream stream of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(InputStream ... stream) throws IOException{ + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (InputStream is : stream) { + os.write(is.readAllBytes()); + } + return write(os.toByteArray()); + } + + // ------------------------------------------------------------------------------------ + // CHARACTER SEQUENCE (Strings) + // ------------------------------------------------------------------------------------ + + /** + * Writes a data string with specified character set (encoding). * * @param data string data (US_ASCII) to be written + * @param charset character set to use for byte encoding * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int write(String data) throws IOException{ - return write(data, StandardCharsets.US_ASCII); + default int write(Charset charset, CharSequence data) throws IOException{ + return write(data.toString().getBytes(charset)); } /** @@ -176,10 +250,288 @@ default int write(String data) throws IOException{ * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int write(String data, Charset charset) throws IOException{ - return write(data.getBytes(charset)); + default int write(Charset charset, CharSequence ... data) throws IOException{ + StringBuilder builder = new StringBuilder(); + for(var d : data){ + builder.append(d); + } + return write(charset, builder); + } + + /** + * Write a collection of ASCII character sequences + * with specified character set (encoding). + * + * @param charset character set to use for byte encoding + * @param data collection of character sequences of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, Collection ... data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (Collection csc : data) { + for (CharSequence cs : csc) { + os.write(cs.toString().getBytes(charset)); + } + } + return write(os.toByteArray()); + } + + /** + * Writes an ASCII data string/character sequence. + * + * @param data string data (US_ASCII) to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(CharSequence data) throws IOException{ + return write(StandardCharsets.US_ASCII, data); } + /** + * Writes multiple ASCII data strings/character sequences. + * + * @param data string data (US_ASCII) to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(CharSequence ... data) throws IOException{ + return write(StandardCharsets.US_ASCII, data); + } + + /** + * Write a collection of ASCII character sequences. + * + * @param data collection of character sequences of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Collection ... data) throws IOException { + return write(StandardCharsets.US_ASCII, data); + } + + // ------------------------------------------------------------------------------------ + // CHARACTER ARRAYS + // ------------------------------------------------------------------------------------ + + /** + * Writes an ASCII based character array (1 or more chars) with + * a given offset and length. + * + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(char[] data, int offset, int length) throws IOException { + return write(StandardCharsets.US_ASCII, data, offset, length); + } + + /** + * Writes an ASCII based character array (1 or more chars) with + * a given length starting from the 0 index position. + * + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(char[] data, int length) throws IOException { + return write(StandardCharsets.US_ASCII, data, length); + } + + /** + * Writes an ASCII based character array (1 or more chars). + * + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(char ... data) throws IOException{ + return write(StandardCharsets.US_ASCII, data); + } + + /** + * Writes a character based array with a given offset and length. + * Specify the encoding to be used to encode the chars into bytes. + * + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, char[] data, int offset, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, offset, length)); + return write(bb.array()); + } + + /** + * Writes a character based array starting at the first index with a given length. + * Specify the encoding to be used to encode the chars into bytes. + * + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, char[] data, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, 0, length)); + return write(bb.array()); + } + + /** + * Writes a character array (1 or more chars). + * + * @param data character array (1 or more chars) to be written + * @param charset character set to use for byte encoding + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, char ... data) throws IOException{ + ByteBuffer bb = charset.encode(CharBuffer.wrap(data)); + return write(bb.array()); + } + + /** + * Write a collection of character arrays. Specify the encoding + * to be used to encode the chars into bytes. + * + * @param data collection of character sequences of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, Collection data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (char[] ca : data) { + ByteBuffer bb = charset.encode(CharBuffer.wrap(ca)); + os.write(bb.array()); + } + return write(os.toByteArray()); + } + + // ------------------------------------------------------------------------------------ + // CHARACTER BUFFERS + // ------------------------------------------------------------------------------------ + + /** + * Writes an ASCII based character buffer with a given offset and length. + * + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(CharBuffer data, int offset, int length) throws IOException { + return write(StandardCharsets.US_ASCII, data, offset, length); + } + + /** + * Writes an ASCII based character buffer starting at first index to a given length. + * + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(CharBuffer data, int length) throws IOException { + return write(StandardCharsets.US_ASCII, data, length); + } + + /** + * Writes an ASCII based character buffer. + * + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(CharBuffer data) throws IOException { + return write(StandardCharsets.US_ASCII, data); + } + + /** + * Writes an ASCII based character buffer. + * + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(CharBuffer ... data) throws IOException { + return write(StandardCharsets.US_ASCII, data); + } + + /** + * Writes an ASCII based character buffer with a given offset and length + * using a specified character set to encode the chars into bytes. + * + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, CharBuffer data, int offset, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, offset, length)); + return write(bb.array()); + } + + /** + * Writes an ASCII based character buffer starting at first index to a + * given length using a specified character set to encode the chars into bytes. + * + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, CharBuffer data, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, 0, length)); + return write(bb.array()); + } + + /** + * Writes an ASCII based character buffer using a specified + * character set to encode the chars into bytes. + * + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, CharBuffer data) throws IOException { + ByteBuffer bb = charset.encode(data); + return write(bb.array()); + } + + /** + * Writes an ASCII based character buffer using a specified + * character set to encode the chars into bytes. + * + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int write(Charset charset, CharBuffer ... data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (CharBuffer cb : data) { + ByteBuffer bb = charset.encode(cb); + os.write(bb.array()); + } + return write(os.toByteArray()); + } + + + // ------------------------------------------------------------------------------------ + // OUTPUT STREAM + // ------------------------------------------------------------------------------------ + /** * Get an output stream to write data to * @return new output stream instance to write to diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java index 66c306c77..4b817cdaf 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java +++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java @@ -48,6 +48,15 @@ default int address(){ return getAddress(); } + /** + * Write a single word value (16-bit) to the I2C device register. + * + * @param word 16-bit word value to be written + * @return The number of bytes written, possibly zero; typically 2 + * @throws IOException thrown on write error + */ + void writeWord(int word) throws IOException; + /** * Write a single word value (16-bit) to the I2C device register * and immediately reads back a 16-bit word value. diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java index 65e92ebc4..ab48a22c2 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java +++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java @@ -27,12 +27,14 @@ * #L% */ +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.Objects; +import java.util.Collection; /** * I2C Register Data Writer Interface for Pi4J Data Communications @@ -45,6 +47,11 @@ */ public interface I2CRegisterDataWriter { + + // ------------------------------------------------------------------------------------ + // SINGLE BYTE + // ------------------------------------------------------------------------------------ + /** * Write a single raw byte (8-bit) value to the I2C device register. * @@ -52,19 +59,24 @@ public interface I2CRegisterDataWriter { * @param b byte to be written * @throws IOException thrown on write error */ - void writeRegister(int register, byte b) throws IOException; + int writeRegister(int register, byte b) throws IOException; /** * Write a single raw byte (8-bit) value to the I2C device register. + * (The integer value provided will be cast to a byte thus only using the lowest 8 bits) * * @param register the register address to write to * @param b byte to be written; the provided Integer wll be cast to a Byte. * @throws IOException thrown on write error */ - default void writeRegister(int register, int b) throws IOException{ - writeRegister(register, (byte)b); + default int writeRegister(int register, int b) throws IOException{ + return writeRegister(register, (byte)b); } + // ------------------------------------------------------------------------------------ + // SINGLE WORD (2-byte) + // ------------------------------------------------------------------------------------ + /** * Write a single word value (16-bit) to the I2C device register. * @@ -72,22 +84,14 @@ default void writeRegister(int register, int b) throws IOException{ * @param word 16-bit word value to be written * @throws IOException thrown on write error */ - default void writeRegisterWord(int register, int word) throws IOException{ + default int writeRegisterWord(int register, int word) throws IOException{ byte[] buffer = new byte[] { (byte)(word >> 8), (byte)word }; - this.writeRegister(register, buffer); + return this.writeRegister(register, buffer); } - /** - * This method writes all bytes included in the given buffer directly to the i2c device. - * - * @param register the register address to write to - * @param buffer byte buffer of data to be written to the i2c device in one go - * @param offset offset in buffer - * @param length number of bytes to be written - * @return The number of bytes written, possibly zero - * @throws IOException thrown on write error - */ - int writeRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException; + // ------------------------------------------------------------------------------------ + // BYTE ARRAY + // ------------------------------------------------------------------------------------ /** * Write a array of byte values with given offset (starting position) @@ -100,13 +104,11 @@ default void writeRegisterWord(int register, int word) throws IOException{ * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, byte[] data, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, data.length); - return writeRegister(register, ByteBuffer.wrap(data), offset, length); - } + int writeRegister(int register, byte[] data, int offset, int length) throws IOException; /** - * Write a array of byte values starting with the first byte in the array up to the provided length. + * Write an array of byte values starting with the first byte in the array + * up to the provided length to a specific I2C device register. * * @param register the register address to write to * @param data data array of bytes to be written @@ -119,32 +121,94 @@ default int writeRegister(int register, byte[] data, int length) throws IOExcept } /** - * This method writes all bytes included in the given buffer directly to the i2c device. + * Write an array of byte values to a specific I2C device register. * * @param register the register address to write to * @param data data to be written to the i2c device in one go * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, byte[] data) throws IOException{ + default int writeRegister(int register, byte ... data) throws IOException { return writeRegister(register, data, 0, data.length); } /** - * This method writes all bytes included in the given buffer directly to the i2c device. + * Write multiple byte arrays of data to a specific I2C device register. + * + * @param register the register address to write to + * @param data data to be written to the i2c device in one go + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, byte[] ... data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (byte[] ba : data) { + os.write(ba); + } + return writeRegister(register, os.toByteArray()); + } + + /** + * Write a collection of byte arrays of data to a specific I2C device register. + * + * @param register the register address to write to + * @param data data to be written to the i2c device in one go + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Collection data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (byte[] ba : data) { + os.write(ba); + } + return writeRegister(register, os.toByteArray()); + } + + // ------------------------------------------------------------------------------------ + // BYTE BUFFER + // ------------------------------------------------------------------------------------ + + /** + * Write a buffer of byte values starting from a given offset index in the + * array up to the provided length to a specific I2C device register. * * @param register the register address to write to * @param buffer byte buffer of data to be written to the i2c device in one go + * @param offset offset in buffer + * @param length number of bytes to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, ByteBuffer buffer, int length) throws IOException{ - return writeRegister(register, buffer, 0, length); + default int writeRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException{ + return writeRegister(register, buffer.array(), offset, length); } + /** + * Write a buffer of byte values starting with the first byte in the array + * up to the provided length to a specific I2C device register. + * + * @param buffer byte buffer of data to be written + * @param length number of bytes to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + + /** + * Write a buffer of byte values starting from the first byte in the buffer + * up to the provided length to a specific I2C device register. + * + * @param register the register address to write to + * @param buffer byte buffer of data to be written to the i2c device in one go + * @param length number of bytes to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, ByteBuffer buffer, int length) throws IOException{ + return writeRegister(register, buffer, buffer.position(), length); + } /** - * This method writes all bytes included in the given buffer directly to the i2c device. + * Write a buffer of byte values (all bytes in buffer) to a specific I2C device register. * * @param register the register address to write to * @param buffer byte buffer of data to be written to the i2c device in one go @@ -152,14 +216,34 @@ default int writeRegister(int register, ByteBuffer buffer, int length) throws IO * @throws IOException thrown on write error */ default int writeRegister(int register, ByteBuffer buffer) throws IOException{ - return writeRegister(register, buffer, 0, buffer.capacity()); + return writeRegister(register, buffer, buffer.remaining()); + } + + /** + * Write multiple byte buffers to a specific I2C device register. + * + * @param register the register address to write to + * @param buffer byte buffer of data to be written to the i2c device in one go + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, ByteBuffer ... buffer) throws IOException{ + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (ByteBuffer bb : buffer) { + os.write(bb.array()); + } + return writeRegister(register, os.toByteArray()); } + // ------------------------------------------------------------------------------------ + // INPUT STREAM + // ------------------------------------------------------------------------------------ + /** - * This method writes all bytes included in the given buffer directly to the i2c device. + * Write a stream of data bytes to a specific I2C device register. * * @param register the register address to write to - * @param stream stream of data to be written to the i2c device in one go + * @param stream stream of data to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ @@ -168,26 +252,344 @@ default int writeRegister(int register, InputStream stream) throws IOException{ } /** - * This method writes all bytes included in the given buffer directly to the i2c device. + * Write multiple streams of data bytes to a specific I2C device register. + * + * @param register the register address to write to + * @param stream stream of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, InputStream ... stream) throws IOException{ + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (InputStream is : stream) { + os.write(is.readAllBytes()); + } + return writeRegister(register, os.toByteArray()); + } + + // ------------------------------------------------------------------------------------ + // CHARACTER SEQUENCE (Strings) + // ------------------------------------------------------------------------------------ + + /** + * Writes a data string with specified character set (encoding) + * to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data string data (US_ASCII) to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, CharSequence data) throws IOException{ + return writeRegister(register, data.toString().getBytes(charset)); + } + + /** + * Writes a data string with specified character set (encoding) + * to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data string data (US_ASCII) to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, CharSequence ... data) throws IOException{ + StringBuilder builder = new StringBuilder(); + for(var d : data){ + builder.append(d); + } + return writeRegister(register, charset, builder); + } + + /** + * Write a collection of ASCII character sequences with specified + * character set (encoding) to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data collection of character sequences of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, Collection ... data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (Collection csc : data) { + for (CharSequence cs : csc) { + os.write(cs.toString().getBytes(charset)); + } + } + return writeRegister(register, os.toByteArray()); + } + + /** + * Writes an ASCII data string/character sequence to a specific I2C device register. + * + * @param register the register address to write to + * @param data string data (US_ASCII) to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, CharSequence data) throws IOException{ + return writeRegister(register, StandardCharsets.US_ASCII, data); + } + + /** + * Writes multiple ASCII data strings/character sequences to a specific I2C device register. + * + * @param register the register address to write to + * @param data string data (US_ASCII) to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, CharSequence ... data) throws IOException{ + return writeRegister(register, StandardCharsets.US_ASCII, data); + } + + /** + * Write a collection of ASCII character sequences to a specific I2C device register. * * @param register the register address to write to - * @param data string data to be written to the i2c device in one go + * @param data collection of character sequences of data to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, String data) throws IOException{ - return writeRegister(register, data.getBytes(StandardCharsets.US_ASCII)); + default int writeRegister(int register, Collection ... data) throws IOException { + return writeRegister(register, StandardCharsets.US_ASCII, data); + } + + // ------------------------------------------------------------------------------------ + // CHARACTER ARRAYS + // ------------------------------------------------------------------------------------ + + /** + * Writes an ASCII based character array (1 or more chars) with + * a given offset and length to a specific I2C device register. + * + * @param register the register address to write to + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, char[] data, int offset, int length) throws IOException { + return writeRegister(register, StandardCharsets.US_ASCII, data, offset, length); + } + + /** + * Writes an ASCII based character array (1 or more chars) with a given length + * starting from the 0 index position to a specific I2C device register. + * + * @param register the register address to write to + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, char[] data, int length) throws IOException { + return writeRegister(register, StandardCharsets.US_ASCII, data, length); + } + + /** + * Writes an ASCII based character array (1 or more chars) to a specific I2C device register. + * + * @param register the register address to write to + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, char ... data) throws IOException{ + return writeRegister(register, StandardCharsets.US_ASCII, data); } /** - * This method writes all bytes included in the given buffer directly to the i2c device. + * Writes a character based array with a given offset and length. Specify the encoding + * to be used to encode the chars into bytes to a specific I2C device register. * * @param register the register address to write to - * @param data string data to be written to the i2c device in one go + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, char[] data, int offset, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, offset, length)); + return writeRegister(register, bb.array()); + } + + /** + * Writes a character based array starting at the first index with a given length. Specify + * the encoding to be used to encode the chars into bytes to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, char[] data, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, 0, length)); + return writeRegister(register, bb.array()); + } + + /** + * Writes a character array (1 or more chars) to a specific I2C device register. + * + * @param register the register address to write to + * @param data character array (1 or more chars) to be written + * @param charset character set to use for byte encoding * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, String data, Charset charset) throws IOException{ - return writeRegister(register, data.getBytes(charset)); + default int writeRegister(int register, Charset charset, char ... data) throws IOException{ + ByteBuffer bb = charset.encode(CharBuffer.wrap(data)); + return writeRegister(register, bb.array()); + } + + /** + * Write a collection of character arrays. Specify the encoding to be + * used to encode the chars into bytes to a specific I2C device register. + * + * @param register the register address to write to + * @param data collection of character sequences of data to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, Collection data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (char[] ca : data) { + ByteBuffer bb = charset.encode(CharBuffer.wrap(ca)); + os.write(bb.array()); + } + return writeRegister(register, os.toByteArray()); + } + + // ------------------------------------------------------------------------------------ + // CHARACTER BUFFERS + // ------------------------------------------------------------------------------------ + + /** + * Writes an ASCII based character buffer with a given offset + * and length to a specific I2C device register. + * + * @param register the register address to write to + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, CharBuffer data, int offset, int length) throws IOException { + return writeRegister(register, StandardCharsets.US_ASCII, data, offset, length); + } + + /** + * Writes an ASCII based character buffer starting at first + * index to a given length to a specific I2C device register. + * + * @param register the register address to write to + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, CharBuffer data, int length) throws IOException { + return writeRegister(register, StandardCharsets.US_ASCII, data, length); + } + + /** + * Writes an ASCII based character buffer to a specific I2C device register. + * + * @param register the register address to write to + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, CharBuffer data) throws IOException { + return writeRegister(register, StandardCharsets.US_ASCII, data); + } + + /** + * Writes an ASCII based character buffer to a specific I2C device register. + * + * @param register the register address to write to + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, CharBuffer ... data) throws IOException { + return writeRegister(register, StandardCharsets.US_ASCII, data); + } + + /** + * Writes an ASCII based character buffer with a given offset and length using a specified + * character set to encode the chars into bytes to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param offset offset in data character array to start at + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, CharBuffer data, int offset, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, offset, length)); + return writeRegister(register, bb.array()); + } + + /** + * Writes an ASCII based character buffer starting at first index to a given length using + * a specified character set to encode the chars into bytes to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @param length number of character in character array to be written + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, CharBuffer data, int length) throws IOException { + ByteBuffer bb = charset.encode(CharBuffer.wrap(data, 0, length)); + return writeRegister(register, bb.array()); + } + + /** + * Writes an ASCII based character buffer using a specified character set + * to encode the chars into bytes to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, CharBuffer data) throws IOException { + ByteBuffer bb = charset.encode(data); + return writeRegister(register, bb.array()); + } + + /** + * Writes an ASCII based character buffer using a specified character + * set to encode the chars into bytes to a specific I2C device register. + * + * @param register the register address to write to + * @param charset character set to use for byte encoding + * @param data ASCII character array used for data write + * @return The number of bytes (not characters) written, possibly zero + * @throws IOException thrown on write error + */ + default int writeRegister(int register, Charset charset, CharBuffer ... data) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (CharBuffer cb : data) { + ByteBuffer bb = charset.encode(cb); + os.write(bb.array()); + } + return writeRegister(register, os.toByteArray()); } } diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java index 3a557ad88..0b6b61e75 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java +++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java @@ -32,7 +32,6 @@ import com.pi4j.io.i2c.I2CRegister; import java.io.IOException; -import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Objects; @@ -52,8 +51,8 @@ public int getAddress() { } @Override - public void write(byte b) throws IOException { - this.i2c.writeRegister(this.address, b); + public int write(byte b) throws IOException { + return this.i2c.writeRegister(this.address, b); } /** @@ -68,6 +67,12 @@ public void writeWord(int word) throws IOException{ this.i2c.writeRegisterWord(this.address, word); } + @Override + public int write(byte[] data, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, data.length); + return this.i2c.writeRegister(this.address, data, offset, length); + } + @Override public int readWord() throws IOException, IOReadException { return this.i2c.readRegisterWord(this.address); @@ -78,25 +83,14 @@ public int writeReadWord(int word) throws IOException, IOReadException { return this.i2c.writeReadRegisterWord(this.address, word); } - @Override - public int write(ByteBuffer buffer, int offset, int length) throws IOException { - Objects.checkFromIndexSize(offset, length, buffer.capacity()); - return this.i2c.writeRegister(this.address, buffer, offset, length); - } - - @Override - public int write(String data, Charset charset) throws IOException { - return this.i2c.writeRegister(this.address, data, charset); - } - @Override public int read() throws IOException { return this.i2c.readRegister(this.address); } @Override - public int read(ByteBuffer buffer, int offset, int length) throws IOException { - Objects.checkFromIndexSize(offset, length, buffer.capacity()); + public int read(byte[] buffer, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, buffer.length); return this.i2c.readRegister(this.address, buffer, offset, length); } diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java index e1f20204b..e710f830f 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java @@ -28,10 +28,12 @@ */ import com.pi4j.io.IO; +import com.pi4j.io.IODataReader; +import com.pi4j.io.IODataWriter; import java.io.IOException; -public interface Serial extends IO, AutoCloseable { +public interface Serial extends IO, AutoCloseable, IODataWriter, IODataReader { int DEFAULT_BAUD = 9600; DataBits DEFAULT_DATA_BITS = DataBits._8; @@ -43,6 +45,20 @@ static SerialConfigBuilder newConfigBuilder(){ return SerialConfigBuilder.newInstance(); } + /** + * Serial Device Communication State is OPEN + * @return The Serial device communication state + */ + boolean isOpen(); + + + /** + * Get the number of data bytes available in the serial receive buffer + * @return + */ + int available() throws IOException; + + void open() throws IOException; void close() throws IOException; } diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java index 8c9fca74f..1e89a15df 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/SerialBase.java @@ -36,12 +36,18 @@ public abstract class SerialBase extends IOBase implements Serial { Logger logger = LoggerFactory.getLogger(this.getClass()); + protected boolean isOpen = false; public SerialBase(SerialProvider provider, SerialConfig config){ super(provider, config); logger.trace("created instance with config: {}", config); } + @Override + public boolean isOpen() { + return this.isOpen; + } + @Override public void open() throws IOException { logger.trace("invoked 'open()'"); @@ -50,5 +56,6 @@ public void open() throws IOException { @Override public void close() throws IOException { logger.trace("invoked 'closed()'"); + this.isOpen = false; } } diff --git a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java index 79038740c..21f81e7aa 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java +++ b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java @@ -75,12 +75,6 @@ public static void main(String[] args) throws Exception { // <-- read a single (8-bit) byte value from the raw I2C device (not to a register) byte readByte = i2c.readByte(); - // --> write a single (16-bit) word value to the raw I2C device (not to a register) - i2c.writeWord(0xFFFF); - - // <-- read a single (16-bit) word value from the raw I2C device (not to a register) - int readWord = i2c.readWord(); - // --> write an array of data bytes to the raw I2C device (not to a register) i2c.write(new byte[] { 0,1,2,3,4,5,6,7,8,9 }); diff --git a/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java b/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java index 36729ddb0..512837013 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java +++ b/pi4j-example/src/main/java/com/pi4j/example/serial/SerialExample.java @@ -28,12 +28,9 @@ */ import com.pi4j.Pi4J; -import com.pi4j.io.i2c.I2C; import com.pi4j.io.serial.Serial; import com.pi4j.util.Console; -import java.nio.ByteBuffer; - public class SerialExample { private static int I2C_BUS = 1; diff --git a/pi4j-test-harness/src/main/arduino/src/command/FrequencyCommand.h b/pi4j-test-harness/src/main/arduino/src/command/FrequencyCommand.h index 9a3e73345..b365d061d 100644 --- a/pi4j-test-harness/src/main/arduino/src/command/FrequencyCommand.h +++ b/pi4j-test-harness/src/main/arduino/src/command/FrequencyCommand.h @@ -44,13 +44,17 @@ void frequency_command_execute(SerialCommands* sender){ int pin = GetCommandPinArgument(sender); // handle pin argument errors - if(pin < 0 && pin != ERROR_INVALID_PIN_DISABLED) { + if(pin < 0) { response["id"] = "error"; response["errno"] = pin; response["arg"] = "pin"; response["msg"] = GetCommandArgumentError(pin); } else { + // make sure to disable any HIGH signals on the pin + pinMode(pin, OUTPUT); + digitalWrite(pin, LOW); + // make sure the reading pin is an input pin pinMode(pin, INPUT); pins[pin].enabled = true; diff --git a/pi4j-test-harness/src/main/arduino/src/main.cpp b/pi4j-test-harness/src/main/arduino/src/main.cpp index 7291d6966..ea926727c 100644 --- a/pi4j-test-harness/src/main/arduino/src/main.cpp +++ b/pi4j-test-harness/src/main/arduino/src/main.cpp @@ -107,6 +107,15 @@ void reset(){ response["id"] = "reset"; JsonArray pinscontainer = response.createNestedArray("pins"); + // terminate all I2C buses + Wire.end(); + Wire1.end(); + + // termiante all SERIAL communication pins + if(serialEcho != nullptr){ + serialEcho->end(); + } + // reset pins states int total, inputs, outputs; total = inputs = outputs = 0; @@ -133,15 +142,6 @@ void reset(){ // reset I2C cache i2cCache.reset(); - // terminate all I2C buses - Wire.end(); - Wire1.end(); - - // termiante all SERIAL communication pins - if(serialEcho != nullptr){ - serialEcho->end(); - } - // include summary totals response["total"] = total; response["inputs"] = inputs; diff --git a/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java b/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java index 1c5f5df0e..e743ebbf3 100644 --- a/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java +++ b/pi4j-test-harness/src/main/java/com/pi4j/test/harness/ArduinoTestHarness.java @@ -60,16 +60,10 @@ public ArduinoTestHarness(String comport) throws IOException { com.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED); // configure read timeout - com.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 200, 0); + com.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 50, 0); } public TestHarnessPins reset() throws IOException { -// send("reboot"); -// try { -// Thread.sleep(500); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } send("reset"); TestHarnessPins response = read(TestHarnessPins.class); return response; @@ -203,18 +197,18 @@ protected List read() throws IOException { // validate serial port is connected if(!com.isOpen()) throw new IOException("Serial port is not open;"); - int counter = 0; - try { - while (com.bytesAvailable() <= 0) { - counter++; - if(counter > 20) - return responses; - Thread.sleep(50); - } - } - catch (Exception e){ - e.printStackTrace(); - } +// int counter = 0; +// try { +// while (com.bytesAvailable() <= 0) { +// counter++; +// if(counter > 20) +// return responses; +// Thread.sleep(50); +// } +// } +// catch (Exception e){ +// e.printStackTrace(); +// } Scanner in = new Scanner(com.getInputStream()); while(in.hasNextLine()){ diff --git a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java index 131211771..e1c94aad3 100644 --- a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java +++ b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java @@ -80,7 +80,7 @@ public void close() throws IOException { // ------------------------------------------------------------------- @Override - public void write(byte b) throws IOException { + public int write(byte b) throws IOException { raw.add(b); System.out.print(" ["); System.out.print(Mock.I2C_PROVIDER_NAME); @@ -89,27 +89,28 @@ public void write(byte b) throws IOException { System.out.print("] :: WRITE(0x"); System.out.print(StringUtil.toHexString(b)); System.out.println(")"); + return 0; } @Override - public int write(ByteBuffer buffer, int offset, int length) throws IOException { - Objects.checkFromIndexSize(offset, length, buffer.capacity()); + public int write(byte[] data, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, data.length); for(int p = offset; p-offset < length; p++){ - raw.add(buffer.get(p)); // add to internal buffer + raw.add(data[p]); // add to internal buffer } System.out.print(" ["); System.out.print(Mock.I2C_PROVIDER_NAME); System.out.print("::"); System.out.print(this.id); System.out.print("] :: WRITE(0x"); - System.out.print(StringUtil.toHexString(buffer, offset, length)); + System.out.print(StringUtil.toHexString(data, offset, length)); System.out.println(")"); return length; } @Override - public int write(String data, Charset charset) throws IOException { - byte[] buffer = data.getBytes(charset); + public int write(Charset charset, CharSequence data) throws IOException { + byte[] buffer = data.toString().getBytes(charset); for(int p = 0; p < buffer.length; p++){ raw.add(buffer[p]); // add to internal buffer } @@ -142,15 +143,15 @@ public int read() throws IOException{ } @Override - public int read(ByteBuffer buffer, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, buffer.capacity()); + public int read(byte[] buffer, int offset, int length) throws IOException{ + Objects.checkFromIndexSize(offset, length, buffer.length); if(raw.isEmpty()) return -1; int counter = 0; for(int p = 0; p < length; p++) { - if(p+offset > buffer.capacity()) break; + if(p+offset > buffer.length) break; if(raw.isEmpty()) break;; - buffer.put(offset + p, raw.pop()); + buffer[offset + p] = raw.pop(); counter++; } @@ -191,7 +192,7 @@ public String readString(int length, Charset charset) throws IOException{ // ------------------------------------------------------------------- @Override - public void writeRegister(int register, byte b) throws IOException { + public int writeRegister(int register, byte b) throws IOException { if(registers[register] == null) registers[register] = new ArrayDeque(); registers[register].add(b); @@ -206,16 +207,17 @@ public void writeRegister(int register, byte b) throws IOException { System.out.print(", 0x"); System.out.print(StringUtil.toHexString(b)); System.out.println(")"); + return 0; } @Override - public int writeRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException { - Objects.checkFromIndexSize(offset, length, buffer.capacity()); + public int writeRegister(int register, byte[] data, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, data.length); // add to internal buffer if(registers[register] == null) registers[register] = new ArrayDeque(); for(int p = offset; p-offset < length; p++){ - registers[register].add(buffer.get(p)); + registers[register].add(data[p]); } System.out.print(" ["); @@ -226,17 +228,17 @@ public int writeRegister(int register, ByteBuffer buffer, int offset, int length System.out.print("REG="); System.out.print(register); System.out.print(", 0x"); - System.out.print(StringUtil.toHexString(buffer, offset, length)); + System.out.print(StringUtil.toHexString(data, offset, length)); System.out.println(")"); return length; } @Override - public int writeRegister(int register, String data, Charset charset) throws IOException{ + public int writeRegister(int register, Charset charset, CharSequence data) throws IOException{ if(registers[register] == null) registers[register] = new ArrayDeque(); - byte[] buffer = data.getBytes(charset); + byte[] buffer = data.toString().getBytes(charset); for(int p = 0; p < buffer.length; p++){ registers[register].add(buffer[p]); // add to internal buffer } diff --git a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java index 198fd52e2..b8d9b4844 100644 --- a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java +++ b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java @@ -33,10 +33,130 @@ import com.pi4j.io.serial.SerialBase; import com.pi4j.io.serial.SerialConfig; import com.pi4j.io.serial.SerialProvider; +import com.pi4j.plugin.mock.Mock; +import com.pi4j.util.StringUtil; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayDeque; +import java.util.Objects; public class MockSerial extends SerialBase implements Serial { + /** + * ATTENTION: The storage and management of the byte arrays + * are terribly inefficient and not intended for real-world + * usage. These are only intended to unit testing the + * Pi4J I2C APIs. + */ + protected ArrayDeque raw = new ArrayDeque<>(); + public MockSerial(SerialProvider provider, SerialConfig config){ super(provider, config); + System.out.print(" ["); + System.out.print(Mock.SERIAL_PROVIDER_NAME); + System.out.print("::"); + System.out.print(this.id); + System.out.print("] :: CLOSE(DEVICE=" + config.device() + "; BAUD=" + config.baud() + ")"); + System.out.println(); + } + + @Override + public int available() throws IOException { + return raw.size(); + } + + @Override + public void close() throws IOException { + System.out.print(" ["); + System.out.print(Mock.SERIAL_PROVIDER_NAME); + System.out.print("::"); + System.out.print(this.id); + System.out.print("] :: CLOSE(DEVICE=" + config.device() + "; BAUD=" + config.baud() + ")"); + System.out.println(); + super.close(); + } + + @Override + public int write(byte b) throws IOException { + raw.add(b); + System.out.print(" ["); + System.out.print(Mock.SERIAL_PROVIDER_NAME); + System.out.print("::"); + System.out.print(this.id); + System.out.print("] :: WRITE(0x"); + System.out.print(StringUtil.toHexString(b)); + System.out.println(")"); + return 0; + } + + @Override + public int write(byte[] data, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, data.length); + for(int p = offset; p-offset < length; p++){ + raw.add(data[p]); // add to internal buffer + } + System.out.print(" ["); + System.out.print(Mock.SERIAL_PROVIDER_NAME); + System.out.print("::"); + System.out.print(this.id); + System.out.print("] :: WRITE(0x"); + System.out.print(StringUtil.toHexString(data, offset, length)); + System.out.println(")"); + return length; + } + + @Override + public int write(Charset charset, CharSequence data) throws IOException { + byte[] buffer = data.toString().getBytes(charset); + for(int p = 0; p < buffer.length; p++){ + raw.add(buffer[p]); // add to internal buffer + } + System.out.print(" ["); + System.out.print(Mock.SERIAL_PROVIDER_NAME); + System.out.print("::"); + System.out.print(this.id); + System.out.print("] :: WRITE(\""); + System.out.print(data); + System.out.println("\")"); + return data.length(); + } + + @Override + public int read() throws IOException { + if(raw.isEmpty()) return -1; + byte b = raw.pop(); + System.out.print(" ["); + System.out.print(Mock.SERIAL_PROVIDER_NAME); + System.out.print("::"); + System.out.print(this.id); + System.out.print("] :: READ(0x"); + System.out.print(StringUtil.toHexString(b)); + System.out.println(")"); + return b; + } + + @Override + public int read(byte[] buffer, int offset, int length) throws IOException{ + Objects.checkFromIndexSize(offset, length, buffer.length); + + if(raw.isEmpty()) return -1; + int counter = 0; + for(int p = 0; p < length; p++) { + if(p+offset > buffer.length) break; + if(raw.isEmpty()) break;; + buffer[offset + p] = raw.pop(); + counter++; + } + + System.out.print(" ["); + System.out.print(Mock.SERIAL_PROVIDER_NAME); + System.out.print("::"); + System.out.print(this.id); + System.out.print("] :: READ(0x"); + System.out.print(StringUtil.toHexString(buffer, offset, length)); + System.out.println(")"); + + return counter; } } diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java index 99d764689..429637e7c 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/PiGpioPlugin.java @@ -37,6 +37,7 @@ 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.provider.Provider; import java.io.IOException; @@ -101,6 +102,7 @@ public void initialize(PluginService service) throws IOException { PiGpioDigitalOutputProvider.newInstance(piGpio), PiGpioPwmProvider.newInstance(piGpio), PiGpioI2CProvider.newInstance(piGpio), + PiGpioSerialProvider.newInstance(piGpio) }; // register all PiGpio I/O Providers with the plugin service diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java index 0e1fa2f96..aaa96f193 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java @@ -92,14 +92,14 @@ public void close() throws IOException { // ------------------------------------------------------------------- @Override - public void write(byte b) throws IOException { - piGpio.i2cWriteByte(this.handle, b);; + public int write(byte b) throws IOException { + return piGpio.i2cWriteByte(this.handle, b); } @Override - public int write(ByteBuffer buffer, int offset, int length) throws IOException { - Objects.checkFromIndexSize(offset, length, buffer.capacity()); - piGpio.i2cWriteDevice(this.handle, buffer, offset, length); + public int write(byte[] data, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, data.length); + piGpio.i2cWriteDevice(this.handle, data, offset, length); return length; } @@ -113,8 +113,8 @@ public int read() throws IOException{ } @Override - public int read(ByteBuffer buffer, int offset, int length) throws IOException{ - Objects.checkFromIndexSize(offset, length, buffer.capacity()); + public int read(byte[] buffer, int offset, int length) throws IOException{ + Objects.checkFromIndexSize(offset, length, buffer.length); return piGpio.i2cReadDevice(this.handle, buffer, offset, length); } @@ -123,14 +123,14 @@ public int read(ByteBuffer buffer, int offset, int length) throws IOException{ // ------------------------------------------------------------------- @Override - public void writeRegister(int register, byte b) throws IOException { - piGpio.i2cWriteByteData(this.handle, register, b); + public int writeRegister(int register, byte b) throws IOException { + return piGpio.i2cWriteByteData(this.handle, register, b); } @Override - public int writeRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException { - Objects.checkFromIndexSize(offset, length, buffer.capacity()); - piGpio.i2cWriteI2CBlockData(this.handle, register, buffer, offset, length); + public int writeRegister(int register, byte[] data, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, data.length); + piGpio.i2cWriteI2CBlockData(this.handle, register, data, offset, length); return length; } diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java new file mode 100644 index 000000000..5b05ad517 --- /dev/null +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java @@ -0,0 +1,127 @@ +package com.pi4j.plugin.pigpio.provider.serial; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: PLUGIN :: PIGPIO I/O Providers + * FILENAME : PiGpioSerial.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + + +import com.pi4j.context.Context; +import com.pi4j.exception.InitializeException; +import com.pi4j.io.serial.Serial; +import com.pi4j.io.serial.SerialBase; +import com.pi4j.io.serial.SerialConfig; +import com.pi4j.io.serial.SerialProvider; +import com.pi4j.library.pigpio.PiGpio; +import com.pi4j.library.pigpio.PiGpioMode; + +import java.io.IOException; + +public class PiGpioSerial extends SerialBase implements Serial { + + protected final PiGpio piGpio; + protected final int handle; + + public PiGpioSerial(PiGpio piGpio, SerialProvider provider, SerialConfig config) throws IOException { + super(provider, config); + + // set local reference instance + this.piGpio = piGpio; + + // TODO :: HANDLE SERIAL PIN CONFIG FOR RASPBERRY PI SERIAL PORTS + if(config.device().endsWith("ttyS0")) { + // set pin ALT5 modes for SERIAL RX & TX PINS on RPI3B + piGpio.gpioSetMode(14, PiGpioMode.ALT5); + piGpio.gpioSetMode(15, PiGpioMode.ALT5); + } + + // create SERIAL instance of PIGPIO SERIAL + this.handle = piGpio.serOpen(config.device(), config.baud()); + + // set open state flag + this.isOpen = true; + } + + @Override + public Serial initialize(Context context) throws InitializeException { + super.initialize(context); + return this; + } + + @Override + public int available() throws IOException { + return piGpio.serDataAvailable(this.handle); + } + + @Override + public void close() throws IOException { + piGpio.serClose(this.handle); + super.close(); + } + + // ------------------------------------------------------------------- + // DEVICE WRITE FUNCTIONS + // ------------------------------------------------------------------- + + @Override + public int write(byte b) throws IOException { + return piGpio.serWriteByte(this.handle, b); + } + + @Override + public int write(byte[] data, int offset, int length) throws IOException { + return piGpio.serWrite(this.handle, data, offset, length); + } + + + // ------------------------------------------------------------------- + // RAW DEVICE READ FUNCTIONS + // ------------------------------------------------------------------- + + @Override + public int read() throws IOException { + return piGpio.serReadByte(this.handle); + } + + @Override + public int read(byte[] buffer, int offset, int length) throws IOException { + return piGpio.serRead(this.handle, buffer, offset, length); + } + + +// @Override +// public int read() throws IOException{ +// return piGpio.i2cReadByte(this.handle); +// } +// +// @Override +// public int read(ByteBuffer buffer, int offset, int length) throws IOException{ +// Objects.checkFromIndexSize(offset, length, buffer.capacity()); +// return piGpio.i2cReadDevice(this.handle, buffer, offset, length); +// } + +} diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProvider.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProvider.java new file mode 100644 index 000000000..0aab05fc6 --- /dev/null +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProvider.java @@ -0,0 +1,42 @@ +package com.pi4j.plugin.pigpio.provider.serial; + +/* + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: PLUGIN :: PIGPIO I/O Providers + * FILENAME : PiGpioSerialProvider.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.pi4j.io.serial.SerialProvider; +import com.pi4j.library.pigpio.PiGpio; +import com.pi4j.plugin.pigpio.PiGpioPlugin; + +public interface PiGpioSerialProvider extends SerialProvider { + String NAME = PiGpioPlugin.SERIAL_PROVIDER_NAME; + String ID = PiGpioPlugin.SERIAL_PROVIDER_ID; + static PiGpioSerialProvider newInstance(PiGpio piGpio) { + return new PiGpioSerialProviderImpl(piGpio); + } +} diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProviderImpl.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProviderImpl.java new file mode 100644 index 000000000..1ea7f8af1 --- /dev/null +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerialProviderImpl.java @@ -0,0 +1,51 @@ +package com.pi4j.plugin.pigpio.provider.serial; + +/* + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: PLUGIN :: PIGPIO I/O Providers + * FILENAME : PiGpioSerialProviderImpl.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.pi4j.io.serial.Serial; +import com.pi4j.io.serial.SerialConfig; +import com.pi4j.io.serial.SerialProviderBase; +import com.pi4j.library.pigpio.PiGpio; + +public class PiGpioSerialProviderImpl extends SerialProviderBase implements PiGpioSerialProvider { + + final PiGpio piGpio; + + public PiGpioSerialProviderImpl(PiGpio piGpio){ + this.id = ID; + this.name = NAME; + this.piGpio = piGpio; + } + + @Override + public Serial create(SerialConfig config) throws Exception { + return new PiGpioSerial(piGpio,this, config); + } +} diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java index fab44911b..37f8a1d22 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalInputUsingTestHarness.java @@ -55,7 +55,7 @@ public class TestDigitalInputUsingTestHarness { @BeforeAll public static void initialize() { // configure logging output - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "INFO"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalOutputUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalOutputUsingTestHarness.java index d29781d67..1fd06a4a9 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalOutputUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/gpio/digital/TestDigitalOutputUsingTestHarness.java @@ -54,7 +54,7 @@ public class TestDigitalOutputUsingTestHarness { @BeforeAll public static void initialize() { // configure logging output - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "INFO"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java index 58e1973dd..cda15b25b 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java @@ -67,7 +67,7 @@ public class TestI2cRawUsingTestHarness { @BeforeAll public static void initialize() { // configure logging output - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "INFO"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); @@ -180,22 +180,6 @@ public void testI2CSingleByteRead() throws Exception { Assert.assertEquals(SAMPLE_BYTE, i2c.readByte()); } - @Test - @DisplayName("I2C :: Test WORD (WRITE)") - @Order(4) - public void testI2CSingleWordWrite() throws Exception { - // write a single word (16 bits) to the raw I2C device (not to a register) - i2c.writeWord(SAMPLE_WORD); - } - - @Test - @DisplayName("I2C :: Test WORD (READ)") - @Order(5) - public void testI2CSingleWordRead() throws Exception { - // read single word (16 bits) from the raw I2C device (not from a register) - Assert.assertEquals(SAMPLE_WORD, i2c.readWord()); - } - @Test @DisplayName("I2C :: Test BYTE-ARRAY (WRITE)") @Order(6) diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java index 0ad2331ff..fa605390b 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java @@ -62,7 +62,7 @@ public class TestI2cUsingTestHarness { @BeforeAll public static void initialize() { // configure logging output - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "INFO"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java index a4bfb8a83..11cc686c2 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java @@ -60,7 +60,7 @@ public class TestHardwarePwmUsingTestHarness { @BeforeAll public static void initialize() { // configure logging output - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "INFO"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java index 79eb61692..d1e99eba3 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java @@ -59,7 +59,7 @@ public class TestSoftwarePwmUsingTestHarness { @BeforeAll public static void initialize() { // configure logging output - System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "INFO"); + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); System.out.println(); System.out.println("************************************************************************"); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java new file mode 100644 index 000000000..a684eb60f --- /dev/null +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java @@ -0,0 +1,255 @@ +package com.pi4j.plugin.pigpio.serial; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: PLUGIN :: PIGPIO I/O Providers + * FILENAME : TestSerialUsingTestHarness.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.pi4j.Pi4J; +import com.pi4j.context.Context; +import com.pi4j.exception.LifecycleException; +import com.pi4j.exception.Pi4JException; +import com.pi4j.io.serial.Baud; +import com.pi4j.io.serial.Serial; +import com.pi4j.library.pigpio.PiGpio; +import com.pi4j.plugin.pigpio.provider.serial.PiGpioSerialProvider; +import com.pi4j.plugin.pigpio.provider.serial.PiGpioSerialProviderImpl; +import com.pi4j.test.harness.ArduinoTestHarness; +import com.pi4j.test.harness.TestHarnessInfo; +import com.pi4j.test.harness.TestHarnessPins; +import org.junit.Assert; +import org.junit.jupiter.api.*; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +@DisplayName("PIGPIO Plugin :: Test Serial Communication using Test Harness") +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestSerialUsingTestHarness { + + private static String SERIAL_DEVICE = "/dev/ttyS0"; + private static int BAUD_RATE = Baud._38400.value(); + private static int TEST_HARNESS_UART = 3; + + private static byte SAMPLE_BYTE = 0x0d; + private static int SAMPLE_WORD = 0xFFFA; + private static byte[] SAMPLE_BYTE_ARRAY = new byte[] { 0,1,2,3,4,5,6,7,8,9 }; + private static byte[] SAMPLE_BUFFER_ARRAY = new byte[] { 10,11,12,13,14,15,16,17,18,19 }; + private static ByteBuffer SAMPLE_BUFFER = ByteBuffer.wrap(SAMPLE_BUFFER_ARRAY); + private static String SAMPLE_STRING = "Hello World!"; + + private static PiGpio piGpio; + private static Context pi4j; + private static Serial serial; + + @BeforeAll + public static void initialize() { + // configure logging output + System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); + + System.out.println(); + System.out.println("************************************************************************"); + System.out.println("INITIALIZE TEST (" + TestSerialUsingTestHarness.class.getName() + ")"); + System.out.println("************************************************************************"); + System.out.println(); + + try { + // create test harness and PIGPIO instances + ArduinoTestHarness harness = new ArduinoTestHarness(System.getProperty("pi4j.test.harness.port", "tty.usbmodem142301")); + + // initialize test harness and PIGPIO instances + harness.initialize(); + + // get test harness info + TestHarnessInfo info = harness.getInfo(); + System.out.println("... we are connected to test harness:"); + System.out.println("----------------------------------------"); + System.out.println("NAME : " + info.name); + System.out.println("VERSION : " + info.version); + System.out.println("DATE : " + info.date); + System.out.println("COPYRIGHT : " + info.copyright); + System.out.println("----------------------------------------"); + + // reset all pins on test harness before proceeding with this test + TestHarnessPins reset = harness.reset(); + System.out.println(); + System.out.println("RESET ALL PINS ON TEST HARNESS; (" + reset.total + " pin reset)"); + + // enable the Serial Echo (Loopback) function on the test harness for these tests + harness.enableSerialEcho(TEST_HARNESS_UART, BAUD_RATE); + System.out.println(); + System.out.println("ENABLE SERIAL UART [" + TEST_HARNESS_UART + "] ON TEST HARNESS; BAUD=" + BAUD_RATE); + + // terminate connection to test harness + harness.terminate(); + + + // create SERIAL config + var config = Serial.newConfigBuilder() + .id("my-serial-port") + .name("My Serial Port") + .device(SERIAL_DEVICE) + .baud8N1(BAUD_RATE) + .build(); + + + // TODO :: THIS WILL NEED TO CHANGE WHEN NATIVE PIGPIO SUPPORT IS ADDED + piGpio = PiGpio.newSocketInstance("rpi3bp"); + + // initialize the PiGpio library + piGpio.initialize(); + + + // create SERIAL provider instance to test with + PiGpioSerialProvider provider = new PiGpioSerialProviderImpl(piGpio); + + // initialize Pi4J instance with this single provider + pi4j = Pi4J.newContextBuilder().add(provider).build(); + + // create serial instance + serial = pi4j.create(config); + + + } catch (IOException e){ + e.printStackTrace(); + } catch (Pi4JException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterAll + public static void terminate() throws IOException, LifecycleException { + System.out.println(); + System.out.println("************************************************************************"); + System.out.println("TERMINATE TEST (" + TestSerialUsingTestHarness.class.getName() + ") "); + System.out.println("************************************************************************"); + System.out.println(); + + // close down serial + //if(serial.isOpen()) + serial.close();; + + // terminate the PiGpio library + piGpio.terminate(); + + // shutdown Pi4J + pi4j.shutdown(); + } + + @BeforeEach + public void beforeEach() throws Exception { + + } + + @AfterEach + public void afterEach() throws Exception { + } + + @Test + @DisplayName("SERIAL :: Verify SERIAL Instance") + @Order(1) + public void testSerialInstance() throws Exception { + // ensure that the SERIAL instance is not null; + assertNotNull(serial); + + // ensure connection is open + assertTrue("SERIAL INSTANCE IS NOT OPEN", serial.isOpen()); + } + + @Test + @DisplayName("SERIAL :: Test BYTE (WRITE)") + @Order(2) + public void testSerialSingleByteWrite() throws Exception { + // write a single byte to the serial device + serial.write(SAMPLE_BYTE); + } + + @Test + @DisplayName("SERIAL :: Test BYTE (READ)") + @Order(3) + public void testSerialSingleByteRead() throws Exception { + // read single byte from the serial device + Assert.assertEquals(SAMPLE_BYTE, serial.readByte()); + } + + @Test + @DisplayName("SERIAL :: Test BYTE-ARRAY (WRITE)") + @Order(4) + public void testSerialByteArrayWrite() throws Exception { + // write an array of data bytes to the serial device + serial.write(SAMPLE_BYTE_ARRAY); + } + + @Test + @DisplayName("SERIAL :: Test BYTE-ARRAY (READ)") + @Order(5) + public void testSerialByteArrayRead() throws Exception { + // read an array of data bytes from the serial device + byte[] byteArray = serial.readArray(SAMPLE_BYTE_ARRAY.length); + Assert.assertArrayEquals(SAMPLE_BYTE_ARRAY, byteArray); + } + + @Test + @DisplayName("SERIAL :: Test BYTE-BUFFER (WRITE)") + @Order(6) + public void testSerialByteBufferWrite() throws Exception { + // write a buffer of data bytes to the serial device + serial.write(SAMPLE_BUFFER); + } + + @Test + @DisplayName("SERIAL :: Test BYTE-BUFFER (READ)") + @Order(7) + public void testSerialByteBufferRead() throws Exception { + // read a buffer of data bytes from the serial device + ByteBuffer buffer = serial.readBuffer(SAMPLE_BUFFER.capacity()); + Assert.assertArrayEquals(SAMPLE_BUFFER.array(), buffer.array()); + } + + @Test + @DisplayName("SERIAL :: Test ASCII STRING (WRITE)") + @Order(8) + public void testSerialAsciiStringWrite() throws Exception { + // write a string of data to the serial device + serial.write(SAMPLE_STRING); + } + + @Test + @DisplayName("SERIAL :: Test ASCII STRING (READ)") + @Order(9) + public void testSerialAsciiStringRead() throws Exception { + // read a string of data from the serial device + String testString = serial.readString(SAMPLE_STRING.length()); + Assert.assertEquals(SAMPLE_STRING, testString); + } + +} diff --git a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java index de98e2948..c704755a9 100644 --- a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java +++ b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java @@ -50,17 +50,17 @@ public int read() throws IOException { } @Override - public int read(ByteBuffer buffer, int offset, int length) throws IOException { + public int read(byte[] buffer, int offset, int length) throws IOException { return 0; } @Override - public void write(byte b) throws IOException { - + public int write(byte b) throws IOException { + return 0; } @Override - public int write(ByteBuffer buffer, int offset, int length) throws IOException { + public int write(byte[] data, int offset, int length) throws IOException { return 0; } @@ -75,12 +75,12 @@ public int readRegister(int register, ByteBuffer buffer, int offset, int length) } @Override - public void writeRegister(int register, byte b) throws IOException { - + public int writeRegister(int register, byte b) throws IOException { + return 0; } @Override - public int writeRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException { + public int writeRegister(int register, byte[] data, int offset, int length) throws IOException { return 0; } } diff --git a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java index f6c0788ab..a22f25c6d 100644 --- a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java +++ b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/serial/RpiSerial.java @@ -35,17 +35,35 @@ import com.pi4j.io.serial.SerialProvider; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.util.Collection; public class RpiSerial extends SerialBase implements Serial { public RpiSerial(SerialProvider provider, SerialConfig config){ super(provider, config); } + + @Override + public int write(byte b) throws IOException { + return 0; + } + + @Override + public int write(byte[] data, int offset, int length) throws IOException { + return 0; + } + + @Override + public int read() throws IOException { + return 0; + } + + @Override + public int read(byte[] buffer, int offset, int length) throws IOException { + return 0; + } + + @Override + public int available() throws IOException { + return 0; + } } From 34de4f2c3aa9427d1b43106ecb22e0b598a18c63 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Fri, 23 Aug 2019 11:50:39 -0400 Subject: [PATCH 08/15] updated PWM interfaces to accept duty-cycle percentage only; abstracting real value and removing ranges. added JavaDoc for Pwm* interfaces. --- .../com/pi4j/annotation/AddPwmPreset.java | 2 +- .../java/com/pi4j/annotation/DutyCycle.java | 4 +- .../com/pi4j/annotation/InitialValue.java | 2 +- .../AnalogOutputRegistrationProcessor.java | 2 +- .../register/PwmRegistrationProcessor.java | 7 - .../src/main/java/com/pi4j/io/pwm/Pwm.java | 312 ++++++++++++++++-- .../main/java/com/pi4j/io/pwm/PwmBase.java | 31 +- .../main/java/com/pi4j/io/pwm/PwmConfig.java | 168 ++++++++-- .../com/pi4j/io/pwm/PwmConfigBuilder.java | 77 ++++- .../main/java/com/pi4j/io/pwm/PwmPreset.java | 81 ++++- .../com/pi4j/io/pwm/PwmPresetBuilder.java | 35 +- .../pi4j/io/pwm/impl/DefaultPwmConfig.java | 62 ++-- .../io/pwm/impl/DefaultPwmConfigBuilder.java | 47 ++- .../pi4j/io/pwm/impl/DefaultPwmPreset.java | 18 +- .../io/pwm/impl/DefaultPwmPresetBuilder.java | 12 +- .../PwmExampleUsingDependencyInjection.java | 17 +- .../pwm/PwmExampleUsingHardwarePwm.java | 14 +- .../pwm/PwmExampleUsingSoftwarePwm.java | 10 +- .../pi4j/example/pwm/PwmPresetsExample.java | 25 +- .../pigpio/provider/pwm/PiGpioPwmBase.java | 14 +- .../provider/pwm/PiGpioPwmHardware.java | 32 +- .../provider/pwm/PiGpioPwmSoftware.java | 36 +- .../pwm/TestHardwarePwmUsingTestHarness.java | 17 +- .../pwm/TestSoftwarePwmUsingTestHarness.java | 19 +- 24 files changed, 777 insertions(+), 267 deletions(-) diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/AddPwmPreset.java b/pi4j-api/src/main/java/com/pi4j/annotation/AddPwmPreset.java index ff693f508..2acf7d738 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/AddPwmPreset.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/AddPwmPreset.java @@ -35,5 +35,5 @@ public @interface AddPwmPreset { String name(); int frequency() default -1; - int dutyCycle() default -1; + float dutyCycle() default -1; } diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/DutyCycle.java b/pi4j-api/src/main/java/com/pi4j/annotation/DutyCycle.java index 964fd3f82..644121395 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/DutyCycle.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/DutyCycle.java @@ -35,7 +35,5 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface DutyCycle { - int value() default -1; - int percent() default -1; - int range() default -1; + float value() default -1; } diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/InitialValue.java b/pi4j-api/src/main/java/com/pi4j/annotation/InitialValue.java index 1d9d6356b..9a1a9461f 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/InitialValue.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/InitialValue.java @@ -35,5 +35,5 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface InitialValue { - int value(); + double value(); } diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/AnalogOutputRegistrationProcessor.java b/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/AnalogOutputRegistrationProcessor.java index f47141347..cc6792c7b 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/AnalogOutputRegistrationProcessor.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/AnalogOutputRegistrationProcessor.java @@ -109,7 +109,7 @@ public AnalogOutput process(Context context, Object instance, Register annotatio InitialValue initialValue = null; if (field.isAnnotationPresent(InitialValue.class)) { initialValue = field.getAnnotation(InitialValue.class); - if (initialValue != null) builder.initial(initialValue.value()); + if (initialValue != null) builder.initial((int)Math.round(initialValue.value())); } StepValue stepValue = null; diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java b/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java index 1d9d83f24..1b4342c33 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java @@ -116,16 +116,9 @@ public Pwm process(Context context, Object instance, Register annotation, Field if (field.isAnnotationPresent(DutyCycle.class)) { dutyCycle = field.getAnnotation(DutyCycle.class); if (dutyCycle != null){ - if(dutyCycle.value() >= 0) { builder.dutyCycle(dutyCycle.value()); } - if(dutyCycle.range() >= 0) { - builder.range(dutyCycle.range()); - } - if(dutyCycle.percent() >= 0) { - //builder.dutyCycle(dutyCycle.range()); - } } } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/Pwm.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/Pwm.java index f9a7b1881..6952d25df 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/Pwm.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/Pwm.java @@ -38,27 +38,89 @@ static PwmConfigBuilder newConfigBuilder(){ return PwmConfigBuilder.newInstance(); } + /** + * Get the GPIO pin number/address of this PWM instance. + * + * @return gpio pin number/address + */ default int getAddress(){ return config().address(); } + + /** + * Get the GPIO pin number/address of this PWM instance. + * + * @return gpio pin number/address + */ default int address(){ return getAddress(); } + /** + * Get the PWM signal ON/ENABLED state. + * + * @return returns 'true' if the PWM signal is in the ON state; else returns 'false' + */ boolean isOn(); + + /** + * Get the PWM signal OFF/DISABLED state. + * + * @return returns 'true' if the PWM signal is in the OFF state; else returns 'false' + */ + default boolean isOff(){ + return !isOn(); + } + + /** + * Turn the PWM signal [ON] using the configured frequency and duty-cycle. + * + * @return returns this PWM instance + * @throws IOException + */ Pwm on() throws IOException; + + /** + * Turn the PWM signal [OFF] by applying a zero frequency and zero duty-cycle to the PWM pin. + * + * @return + * @throws IOException + */ Pwm off() throws IOException; + /** + * Get the PWM type of this PWM instance. (Hardware/Software) + * @return the PWM type of this PWM instance. + */ default PwmType pwmType(){ return config().getPwmType(); } + + /** + * Get the PWM type of this PWM instance. (Hardware/Software) + * @return the PWM type of this PWM instance. + */ default PwmType getPwmType(){ return pwmType(); } - default Pwm on(int dutyCycle) throws IOException{ - if(dutyCycle > 0) { - setDutyCycle(dutyCycle); + /** + * Turn the PWM signal [ON] using a specified duty-cycle (%) + * at the pre-configured frequency (Hz). + * + * @param dutyCycle The duty-cycle value is a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * The duty-cycle range is valid from 0 to 100 including factional + * values. (Values above 50% mean the signal will remain HIGH more + * time than LOW.) + * @return returns this PWM instance + * @throws IOException + */ + default Pwm on(Number dutyCycle) throws IOException{ + if(dutyCycle.floatValue() > 0) { + setDutyCycle(dutyCycle.floatValue()); return on(); } else{ @@ -66,9 +128,31 @@ default Pwm on(int dutyCycle) throws IOException{ } } - default Pwm on(int dutyCycle, int frequency) throws IOException{ - if(dutyCycle > 0 && frequency > 0) { - setDutyCycle(dutyCycle); + /** + * Turn the PWM signal [ON] using a specified duty-cycle (%) + * at the pre-configured frequency (Hz). + * + * @param dutyCycle The duty-cycle value is a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * The duty-cycle range is valid from 0 to 100 including factional + * values. (Values above 50% mean the signal will remain HIGH more + * time than LOW.) + * @param frequency The desired frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should attempt to output. Please + * note that certain PWM signal generators may be limited to + * specific frequency bands and may not generate all possible explicit + * frequency values. Immediately after calling this method, you can + * check the 'Pwm::actualFrequency()' or 'Pwm::getActualFrequency()' + * properties to determine what frequency the PWM generator actually + * applied. + * @return returns this PWM instance + * @throws IOException + */ + default Pwm on(Number dutyCycle, int frequency) throws IOException{ + if(dutyCycle.floatValue() > 0 && frequency > 0) { + setDutyCycle(dutyCycle.floatValue()); setFrequency(frequency); return on(); } @@ -77,50 +161,222 @@ default Pwm on(int dutyCycle, int frequency) throws IOException{ } } - default boolean isOff(){ - return !isOn(); - } + /** + * Get the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. (Values above 50% mean the signal will remain + * HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @return duty-cycle value expressed as a percentage (rage: 0-100) + * @throws IOException + */ + float getDutyCycle() throws IOException; - default float getDutyCyclePercent() throws IOException{ - return getDutyCycle() * 100 / getRange(); - } - default float dutyCyclePercent() throws IOException { return getDutyCyclePercent();} + /** + * Get the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. (Values above 50% mean the signal will remain + * HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @return duty-cycle value expressed as a percentage (rage: 0-100) + * @throws IOException + */ + default float dutyCycle() throws IOException { return getDutyCycle();} + + /** + * Set the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. This method will not update a live PWM signal, + * but rather stage the duty-cycle value for subsequent call to the + * 'Pwm::On()' method. Call 'Pwm::On()' if you wish to make a live/ + * immediate change to the duty-cycle on an existing PWM signal. + * (Values above 50% mean the signal will remain HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @param dutyCycle duty-cycle value expressed as a percentage (rage: 0-100) + * @throws IOException + */ + void setDutyCycle(Number dutyCycle) throws IOException; - int getDutyCycle() throws IOException; - default int dutyCycle() throws IOException { return getDutyCycle();} + /** + * Set the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. This method will not update a live PWM signal, + * but rather stage the duty-cycle value for subsequent call to the + * 'Pwm::On()' method. Call 'Pwm::On()' if you wish to make a live/ + * immediate change to the duty-cycle on an existing PWM signal. + * (Values above 50% mean the signal will remain HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @param dutyCycle duty-cycle value expressed as a percentage (rage: 0-100) + * @return returns this PWM instance + * @throws IOException + */ + default Pwm dutyCycle(Number dutyCycle) throws IOException { setDutyCycle(dutyCycle); return this; } + /** + * Get the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should attempt to output when the PWM signal + * is turned 'ON'. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(..) method, you can check the + * 'Pwm::frequency()' or 'Pwm::getFrequency()' properties to determine what + * frequency the PWM generator actually applied. + * + * @return the configured frequency (Hz) that is used when turning the + * PWM signal to the 'ON' state. + * @throws IOException + */ int getFrequency() throws IOException; + + /** + * Get the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should attempt to output when the PWM signal + * is turned 'ON'. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(...)' method, you can check the + * 'Pwm::frequency()' or 'Pwm::getFrequency()' properties to determine what + * frequency the PWM generator actually applied. + * + * @return the configured frequency (Hz) that is used when turning the + * PWM signal to the 'ON' state. + * @throws IOException + */ default int frequency() throws IOException { return getFrequency();} - void setDutyCycle(int dutyCycle) throws IOException; - default Pwm dutyCycle(int dutyCycle) throws IOException { setDutyCycle(dutyCycle); return this; } + /** + * Get the actual frequency value in Hertz (number of cycles per second) + * applied by the PWM signal generator after the PWM signal is turned 'ON'. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(...)' method, you can call this + * method to determine what frequency the PWM generator actually applied. + * + * @return the actual frequency (Hz) applied by the PWM generator when the + * PWM signal is set to the 'ON' state. + * @throws IOException + */ + int getActualFrequency() throws IOException; - default void setDutyCyclePercent(float percent) throws IOException{ - int dutyCycle = Math.round(this.range() * percent / 100); - setDutyCycle(dutyCycle); - } - default Pwm dutyCyclePercent(int percent) throws IOException { setDutyCyclePercent(percent); return this; } + /** + * Get the actual frequency value in Hertz (number of cycles per second) + * applied by the PWM signal generator after the PWM signal is turned 'ON'. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(...)' method, you can call this + * method to determine what frequency the PWM generator actually applied. + * + * @return the actual frequency (Hz) applied by the PWM generator when the + * PWM signal is set to the 'ON' state. + * @throws IOException + */ + default int actualFrequency() throws IOException { return getActualFrequency();} + /** + * Set the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should use when the PWM signal is turned 'ON'. + * + * Note: This method will not update a live PWM signal, but rather stage the + * frequency value for subsequent call to the 'Pwm::On()' method. Call 'Pwm::On()' + * if you wish to make a live/immediate change to the duty-cycle on an existing + * PWM signal. + * + * @param frequency the number of cycles per second (Hertz) + * @throws IOException + */ void setFrequency(int frequency) throws IOException; - default Pwm frequency(int frequency) throws IOException { setFrequency(frequency); return this; } - - int getRange() throws IOException; - default int range() throws IOException { return getRange();} - void setRange(int range) throws IOException; - default Pwm range(int range) throws IOException { setRange(range); return this; } + /** + * Set the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should use when the PWM signal is turned 'ON'. + * + * Note: This method will not update a live PWM signal, but rather stage the + * frequency value for subsequent call to the 'Pwm::On()' method. Call 'Pwm::On()' + * if you wish to make a live/immediate change to the duty-cycle on an existing + * PWM signal. + * + * @param frequency the number of cycles per second (Hertz) + * @return returns this PWM instance + * @throws IOException + */ + default Pwm frequency(int frequency) throws IOException { setFrequency(frequency); return this; } + /** + * Get all the PwmPreset instances assigned to this PWM instance. + * @return a map of PwmPresets indexed/cataloged by preset name. + */ Map getPresets(); + + /** + * Get all the PwmPreset assigned to this PWM instance. + * @return a map of PwmPreset indexed/cataloged by preset name. + */ default Map presets(){ return getPresets(); } + /** + * Get a single PwmPreset from this PWM instance by the preset's name. + * @param name preset name string + * @return a single PwmPreset instance + */ PwmPreset getPreset(String name); + + /** + * Get a single PwmPreset from this PWM instance by the preset's name. + * @param name preset name string + * @return a single PwmPreset instance + */ default PwmPreset preset(String name){ return getPreset(name); } + /** + * Delete/remove a PwmPreset by name from this PWM instance. + * + * @param name preset name string + * @return the deleted PWM Preset instance + */ PwmPreset deletePreset(String name); + + /** + * Add a new PwmPreset to this PWM instance. You can create new PWM + * preset instance using the 'PwmPreset::newBuilder(name)' static + * factory method. + * + * @param preset a pre-configured PwmPreset instance + * @return this PWM instance + */ Pwm addPreset(PwmPreset preset); + + /** + * Apply/recall a PwmPreset by name to this PWM instance. + * This will update the PWM signal with the configured + * PWM frequency and duty-cycle defined in the preset object. + * + * @param name preset name string + * @return the deleted PWM Preset instance + * @throws IOException + */ Pwm applyPreset(String name) throws IOException; } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmBase.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmBase.java index a3ba689e6..7c573812f 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmBase.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmBase.java @@ -39,9 +39,8 @@ public abstract class PwmBase extends IOBase implements Pwm { - protected int range = -1; - protected int frequency = -1; - protected int dutyCycle = -1; + protected int frequency = 100; + protected float dutyCycle = 50; protected boolean onState = false; protected Map presets = Collections.synchronizedMap(new HashMap<>()); @@ -56,7 +55,7 @@ public PwmBase(PwmProvider provider, PwmConfig config) { } @Override - public int getDutyCycle() throws IOException { + public float getDutyCycle() throws IOException { return this.dutyCycle; } @@ -66,23 +65,25 @@ public int getFrequency() throws IOException { } @Override - public void setDutyCycle(int dutyCycle) throws IOException { - this.dutyCycle = dutyCycle; + public int getActualFrequency() throws IOException { + return this.frequency; } @Override - public void setFrequency(int frequency) throws IOException { - this.frequency = frequency; - } + public void setDutyCycle(Number dutyCycle) throws IOException { + float dc = dutyCycle.floatValue(); - @Override - public int getRange() throws IOException { - return this.range; + // bounds check the duty-cycle value + if(dc < 0) dc = 0; + if(dc > 100) dc = 100; + + // update the duty-cycle member + this.dutyCycle = dc; } @Override - public void setRange(int range) throws IOException { - this.range = range; + public void setFrequency(int frequency) throws IOException { + this.frequency = frequency; } @Override @@ -156,7 +157,7 @@ public Pwm applyPreset(String name) throws IOException { if(presets.containsKey(key)) { PwmPreset preset = presets.get(key); if(preset.dutyCycle() != null) - setDutyCycle(preset.dutyCycle().intValue()); + setDutyCycle(preset.dutyCycle().floatValue()); if(preset.frequency() != null) setFrequency(preset.frequency().intValue()); on(); // update PWM signal now diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfig.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfig.java index 852124289..73b901570 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfig.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfig.java @@ -36,55 +36,177 @@ public interface PwmConfig extends GpioConfig, AddressConfig presets(); + + /** + * Get the configured PwmPresets assigned to this PWM instance. + * + * @return collection of PwmPresets + */ default Collection getPresets(){ return presets(); } - } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfigBuilder.java index b2dd3ad69..39f2454e5 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfigBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfigBuilder.java @@ -35,12 +35,79 @@ static PwmConfigBuilder newInstance() { return DefaultPwmConfigBuilder.newInstance(); } - PwmConfigBuilder range(Integer range); + /** + * Set the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should attempt to output when the PWM state + * is enabled. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(...)' method, you can check the + * 'Pwm::frequency()' or 'Pwm::getFrequency()' properties to determine what + * frequency the PWM generator actually applied. + * + * @param frequency the number of cycles per second (Hertz) + * @return this builder instance + */ PwmConfigBuilder frequency(Integer frequency); - PwmConfigBuilder dutyCycle(Integer dutyCycle); - PwmConfigBuilder dutyCyclePercent(Integer percent); + + /** + * Set the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. (Values above 50% mean the signal will + * remain HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @param dutyCycle duty-cycle value expressed as a percentage (rage: 0-100) + * @return this builder instance + */ + PwmConfigBuilder dutyCycle(Number dutyCycle); + + /** + * Set the PwmType of this PWM instance. (Hardware/Software) + * Please note that not all PWM providers support both hardware and software + * PWM generators. Please consult the documentation for your PWM provider + * to determine what support is available and what limitations may apply. + * + * @return this builder instance + */ PwmConfigBuilder pwmType(PwmType pwmType); - PwmConfigBuilder shutdown(Integer value); - PwmConfigBuilder initial(Integer value); + + /** + * Optionally configure a PWM duty-cycle value that should automatically + * be applied to the PWM instance when the Pi4J context is shutdown. + * This option can be helpful if you wish to do something like stop a PWM + * signal (by configuring this 'shutdown' value to zero) when your application + * is terminated an Pi4J is shutdown. + * + * @param dutyCycle duty-cycle value expressed as a percentage (rage: 0-100) + * @return this builder instance + */ + PwmConfigBuilder shutdown(Number dutyCycle); + + /** + * Optionally configure a PWM duty-cycle value that should automatically + * be applied to the PWM instance when this PWM instance is created and initialized. + * This option can be helpful if you wish to do something like set a default PWM + * signal (by configuring this 'initial' value to 50%) when your application + * creates the PWM instance. This just helps eliminate a second line of code + * to manually start the PWM signal for cases where you prefer it is auto-started. + * + * @param dutyCycle duty-cycle value expressed as a percentage (rage: 0-100) + * @return this builder instance + */ + PwmConfigBuilder initial(Number dutyCycle); + + /** + * Add one or more PwmPresets to this PWM instance. You can create new PWM + * preset instance using the 'PwmPreset::newBuilder(name)' static + * factory method. + * + * @param preset one or more pre-configured PwmPreset instances + * @return this builder instance + */ PwmConfigBuilder preset(PwmPreset ... preset); } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPreset.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPreset.java index 9131d3fca..95907b086 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPreset.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPreset.java @@ -29,23 +29,100 @@ import com.pi4j.io.pwm.impl.DefaultPwmPresetBuilder; +import java.io.IOException; + public interface PwmPreset { + /** + * Return a new PWM Preset builder; (static factory method) + * + * @param name the unique preset name assigned to the PWM preset instance being created. + * @return a new PWM preset builder instance. + */ static PwmPresetBuilder newBuilder(String name){ return DefaultPwmPresetBuilder.newInstance(name); } + /** + * Get the preset name assigned to this PWM preset instance. + * + * @return preset name + */ String name(); + + /** + * Get the preset name assigned to this PWM preset instance. + * + * @return preset name + */ default String getName() { return name(); } - Integer dutyCycle(); - default Integer getDutyCycle() { + /** + * Get the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. (Values above 50% mean the signal will + * remain HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @return duty-cycle value expressed as a percentage (rage: 0-100) + * @throws IOException + */ + Float dutyCycle(); + + /** + * Get the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. (Values above 50% mean the signal will + * remain HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @return duty-cycle value expressed as a percentage (rage: 0-100) + * @throws IOException + */ + default Float getDutyCycle() { return dutyCycle(); } + /** + * Get the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should attempt to output when this preset + * is applied to a PWM instance. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(...)' method, you can check the + * 'Pwm::frequency()' or 'Pwm::getFrequency()' properties to determine what + * frequency the PWM generator actually applied. + * + * @return the configured frequency (Hz) that is used when turning the + * PWM signal to the 'ON' state when applying this PWM preset. + * @throws IOException + */ Integer frequency(); + + /** + * Get the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should attempt to output when this preset + * is applied to a PWM instance. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(...)' method, you can check the + * 'Pwm::frequency()' or 'Pwm::getFrequency()' properties to determine what + * frequency the PWM generator actually applied. + * + * @return the configured frequency (Hz) that is used when turning the + * PWM signal to the 'ON' state when applying this PWM preset. + * @throws IOException + */ default Integer getFrequency() { return frequency(); } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPresetBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPresetBuilder.java index 145c6844b..a148876d5 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPresetBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPresetBuilder.java @@ -30,10 +30,43 @@ import com.pi4j.config.Builder; import com.pi4j.io.pwm.impl.DefaultPwmPresetBuilder; +import java.io.IOException; + public interface PwmPresetBuilder extends Builder { static PwmPresetBuilder newInstance(String name) { return DefaultPwmPresetBuilder.newInstance(name); } + + /** + * Set the duty-cycle value as a decimal value that represents the + * percentage of the ON vs OFF time of the PWM signal for each + * period. The duty-cycle range is valid from 0 to 100 including + * factional values. (Values above 50% mean the signal will + * remain HIGH more time than LOW.) + * + * Example: A value of 50 represents a duty-cycle where half of + * the time period the signal is LOW and the other half is HIGH. + * + * @param dutyCycle duty-cycle value expressed as a percentage (rage: 0-100) + * @return this builder instance + * @throws IOException + */ + PwmPresetBuilder dutyCycle(Number dutyCycle); + + /** + * Set the configured frequency value in Hertz (number of cycles per second) + * that the PWM signal generator should attempt to output when this preset + * is applied to a PWM instance. + * + * Please note that certain PWM signal generators may be limited to specific + * frequency bands and may not generate all possible explicit frequency values. + * After enabling the PWM signal using the 'on(...)' method, you can check the + * 'Pwm::frequency()' or 'Pwm::getFrequency()' properties to determine what + * frequency the PWM generator actually applied. + * + * @param frequency the number of cycles per second (Hertz) + * @return this builder instance + * @throws IOException + */ PwmPresetBuilder frequency(Integer frequency); - PwmPresetBuilder dutyCycle(Integer dutyCycle); } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfig.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfig.java index 945c1f10b..2dff6e4e8 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfig.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfig.java @@ -44,13 +44,11 @@ public class DefaultPwmConfig implements PwmConfig { // private configuration properties - protected Integer dutyCycle = null; - protected Integer dutyCyclePercent = null; - protected Integer range = null; + protected Float dutyCycle = null; protected Integer frequency = null; protected PwmType pwmType = PwmType.SOFTWARE; - protected Integer shutdownValue = null; - protected Integer initialValue = null; + protected Float shutdownValue = null; + protected Float initialValue = null; protected List presets = new ArrayList<>(); /** @@ -86,12 +84,7 @@ protected DefaultPwmConfig(Map properties){ // load optional pwm duty-cycle from properties if(properties.containsKey(DUTY_CYCLE_KEY)){ - this.dutyCycle = Integer.parseInt(properties.get(DUTY_CYCLE_KEY)); - } - - // load optional pwm duty-cycle from properties - if(properties.containsKey(DUTY_CYCLE_PERCENT_KEY)){ - this.dutyCyclePercent = Integer.parseInt(properties.get(DUTY_CYCLE_PERCENT_KEY)); + this.dutyCycle = Float.parseFloat(properties.get(DUTY_CYCLE_KEY)); } // load optional pwm frequency from properties @@ -99,11 +92,6 @@ protected DefaultPwmConfig(Map properties){ this.frequency = Integer.parseInt(properties.get(FREQUENCY_KEY)); } - // load optional pwm range from properties - if(properties.containsKey(RANGE_KEY)){ - this.range = Integer.parseInt(properties.get(RANGE_KEY)); - } - // load optional pwm type from properties if(properties.containsKey(PWM_TYPE_KEY)){ this.pwmType = PwmType.parse(properties.get(PWM_TYPE_KEY)); @@ -111,33 +99,28 @@ protected DefaultPwmConfig(Map properties){ // load initial value property if(properties.containsKey(INITIAL_VALUE_KEY)){ - this.initialValue = Integer.parseInt(properties.get(INITIAL_VALUE_KEY)); + this.initialValue = Float.parseFloat(properties.get(INITIAL_VALUE_KEY)); } // load shutdown value property if(properties.containsKey(SHUTDOWN_VALUE_KEY)){ - this.shutdownValue = Integer.parseInt(properties.get(SHUTDOWN_VALUE_KEY)); + this.shutdownValue = Float.parseFloat(properties.get(SHUTDOWN_VALUE_KEY)); } // bounds checking - if(this.dutyCyclePercent != null && this.dutyCyclePercent > 100) - this.dutyCyclePercent = 100; + if(this.dutyCycle != null && this.dutyCycle > 100) + this.dutyCycle = 100f; // bounds checking - if(this.dutyCyclePercent != null && this.dutyCyclePercent < 0) - this.dutyCyclePercent = 0; + if(this.dutyCycle != null && this.dutyCycle < 0) + this.dutyCycle = 0f; } @Override - public Integer dutyCycle() { + public Float dutyCycle() { return this.dutyCycle; } - @Override - public Integer range() { - return this.range; - } - @Override public Integer frequency() { return this.frequency; @@ -149,31 +132,24 @@ public PwmType pwmType() { } @Override - public Integer shutdownValue(){ + public Float shutdownValue(){ return this.shutdownValue; } @Override - public Integer dutyCyclePercent(){ - // bounds checking - if(this.dutyCyclePercent != null && this.dutyCyclePercent > 100) - this.dutyCyclePercent = 100; - - // bounds checking - if(this.dutyCyclePercent != null && this.dutyCyclePercent < 0) - this.dutyCyclePercent = 0; + public PwmConfig shutdownValue(Number dutyCycle){ - return this.dutyCyclePercent; - } + // bounds check the duty-cycle value + float dc = dutyCycle.floatValue(); + if(dc < 0) dc = 0; + if(dc > 100) dc = 100; - @Override - public PwmConfig shutdownValue(Integer value){ - this.shutdownValue = value; + this.shutdownValue = dc; return this; } @Override - public Integer initialValue() { + public Float initialValue() { return this.initialValue; } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfigBuilder.java index e2dd120ad..98c26d470 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfigBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfigBuilder.java @@ -53,12 +53,6 @@ public static PwmConfigBuilder newInstance() { return new DefaultPwmConfigBuilder(); } - @Override - public PwmConfigBuilder range(Integer range) { - this.properties.put(PwmConfig.RANGE_KEY, range.toString()); - return this; - } - @Override public PwmConfigBuilder frequency(Integer frequency) { this.properties.put(PwmConfig.FREQUENCY_KEY, frequency.toString()); @@ -66,23 +60,13 @@ public PwmConfigBuilder frequency(Integer frequency) { } @Override - public PwmConfigBuilder dutyCycle(Integer dutyCycle) { - this.properties.put(PwmConfig.DUTY_CYCLE_KEY, dutyCycle.toString()); - return this; - } + public PwmConfigBuilder dutyCycle(Number dutyCycle) { + // bounds check the duty-cycle value + float dc = dutyCycle.floatValue(); + if(dc < 0) dc = 0; + if(dc > 100) dc = 100; - @Override - public PwmConfigBuilder dutyCyclePercent(Integer percent) { - - // bounds checking - if(percent != null && percent > 100) - percent = 100; - - // bounds checking - if(percent != null && percent < 0) - percent = 0; - - this.properties.put(PwmConfig.DUTY_CYCLE_PERCENT_KEY, percent.toString()); + this.properties.put(PwmConfig.DUTY_CYCLE_KEY, Float.toString(dc)); return this; } @@ -93,14 +77,25 @@ public PwmConfigBuilder pwmType(PwmType pwmType) { } @Override - public PwmConfigBuilder shutdown(Integer value) { - this.properties.put(PwmConfig.SHUTDOWN_VALUE_KEY, value.toString()); + public PwmConfigBuilder shutdown(Number dutyCycle) { + // bounds check the duty-cycle value + float dc = dutyCycle.floatValue(); + if(dc < 0) dc = 0; + if(dc > 100) dc = 100; + + this.properties.put(PwmConfig.SHUTDOWN_VALUE_KEY, Float.toString(dc)); return this; } @Override - public PwmConfigBuilder initial(Integer value) { - this.properties.put(PwmConfig.INITIAL_VALUE_KEY, value.toString()); + public PwmConfigBuilder initial(Number dutyCycle) { + + // bounds check the duty-cycle value + float dc = dutyCycle.floatValue(); + if(dc < 0) dc = 0; + if(dc > 100) dc = 100; + + this.properties.put(PwmConfig.INITIAL_VALUE_KEY, Float.toString(dc)); return this; } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java index 0bc312ea3..bdfc837e1 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java @@ -32,18 +32,24 @@ public class DefaultPwmPreset implements PwmPreset { protected final String name; - protected final Integer dutyCycle; + protected final Float dutyCycle; protected final Integer frequency; - public DefaultPwmPreset(String name, Integer dutyCycle){ + public DefaultPwmPreset(String name, Number dutyCycle){ this.name = name.toLowerCase().trim(); - this.dutyCycle = dutyCycle; + this.dutyCycle = dutyCycle.floatValue(); this.frequency = null; } - public DefaultPwmPreset(String name, Integer dutyCycle, Integer frequency){ + public DefaultPwmPreset(String name, Number dutyCycle, Integer frequency){ this.name = name.toLowerCase().trim(); - this.dutyCycle = dutyCycle; + + // bounds check the duty-cycle value + float dc = dutyCycle.floatValue(); + if(dc < 0) dc = 0; + if(dc > 100) dc = 100; + + this.dutyCycle = dc; this.frequency = frequency; } @@ -53,7 +59,7 @@ public String name() { } @Override - public Integer dutyCycle() { + public Float dutyCycle() { return this.dutyCycle; } diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPresetBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPresetBuilder.java index 09414fc3f..547cdbdc9 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPresetBuilder.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPresetBuilder.java @@ -31,7 +31,7 @@ import com.pi4j.io.pwm.PwmPresetBuilder; public class DefaultPwmPresetBuilder implements PwmPresetBuilder{ - protected Integer dutyCycle = null; + protected Float dutyCycle = null; protected Integer frequency = null; protected final String name; @@ -53,8 +53,14 @@ public PwmPresetBuilder frequency(Integer frequency) { } @Override - public PwmPresetBuilder dutyCycle(Integer dutyCycle) { - this.dutyCycle = dutyCycle; + public PwmPresetBuilder dutyCycle(Number dutyCycle) { + float dc = dutyCycle.floatValue(); + + // bounds check the duty-cycle value + if(dc < 0) dc = 0; + if(dc > 100) dc = 100; + + this.dutyCycle = dc; return this; } @Override diff --git a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java index 503fa90b1..e34e660c9 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java +++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java @@ -52,10 +52,10 @@ public static class RuntimeContainer implements Callable { @Address(2) // pin number 2 @ShutdownValue(0) @WithProvider(type=PiGpioPwmProvider.class) - @Frequency(5000) - @DutyCycle(range=1000, percent=50) - @AddPwmPreset(name = "one-quarter", dutyCycle = 250 ) - @AddPwmPreset(name = "three-quarter", dutyCycle = 750 ) + @Frequency(5000) // 5 KHz frequency + @DutyCycle(50) // 50% duty-cycle + @AddPwmPreset(name = "one-quarter", dutyCycle = 25.5f ) // 25% + @AddPwmPreset(name = "three-quarter", dutyCycle = 75.0f ) // 75% @AddPwmPreset(name = "1KHZ", frequency = 1000) @AddPwmPreset(name = "10KHZ", frequency = 10000) private Pwm pwm; @@ -100,8 +100,7 @@ public Void call() throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); console.println(); console.println(" ... WAITING 5 SECONDS TO APPLY PRESET: 10KHZ"); @@ -118,8 +117,7 @@ public Void call() throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); @@ -137,8 +135,7 @@ public Void call() throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); // shutdown Pi4J diff --git a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingHardwarePwm.java b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingHardwarePwm.java index 874c617e0..92b372a94 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingHardwarePwm.java +++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingHardwarePwm.java @@ -49,7 +49,7 @@ public static void main(String[] args) throws Exception { final var console = new Console(); // print program title/header - console.title("<-- The Pi4J Project -->", "PWM Example using Software-Emulated PWM"); + console.title("<-- The Pi4J Project -->", "PWM Example using Hardware PWM"); // allow for user to exit program using CTRL-C console.promptForExit(); @@ -79,13 +79,8 @@ public static void main(String[] args) throws Exception { //pwm.frequency(1000); // - // optionally override pre-configured duty-cycle value; - // this is in relation to the previously defined rage value - //pwm.setDutyCycle(500000); // hardware PWM range is 0-1M; this value is 50% of range - - // - // alternatively, you can also just simply set the duty-cycle as a percent value - pwm.setDutyCyclePercent(50); // 50% + // optionally override a pre-configured PWM duty-cycle (percent 0-100%) + pwm.dutyCycle(50); // 50% // enable the PWM signal pwm.on(); @@ -96,8 +91,7 @@ public static void main(String[] args) throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); // create a digital input instance using the default digital input provider diff --git a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingSoftwarePwm.java b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingSoftwarePwm.java index 19322a1ae..117e834e4 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingSoftwarePwm.java +++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingSoftwarePwm.java @@ -34,7 +34,7 @@ public class PwmExampleUsingSoftwarePwm { - public static int PWM_PIN = 4; + public static int PWM_PIN = 13; public static void main(String[] args) throws Exception { @@ -65,10 +65,9 @@ public static void main(String[] args) throws Exception { .name("My Test PWM Pin") .address(PWM_PIN) .frequency(1000) // optionally pre-configure the desired frequency to 1KHz - .range(255) // optionally pre-configure the desired duty-cycle range (0-255) - .dutyCycle(128) // optionally pre-configure the desired duty-cycle (50%) + .dutyCycle(50) // optionally pre-configure the desired duty-cycle (50%) .shutdown(0) // optionally pre-configure a shutdown duty-cycle value (on terminate) - //.initial(125) // optionally pre-configure an initial duty-cycle value (on startup) + //.initial(50) // optionally pre-configure an initial duty-cycle value (on startup) .build(); // use try-with-resources to auto-close I2C when complete @@ -101,8 +100,7 @@ public static void main(String[] args) throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); // create a digital input instance using the default digital input provider diff --git a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmPresetsExample.java b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmPresetsExample.java index 91d105ad1..574e57df2 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmPresetsExample.java +++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmPresetsExample.java @@ -63,10 +63,9 @@ public static void main(String[] args) throws Exception { .name("My Test PWM Pin") .address(PWM_PIN) .frequency(1000) // optionally pre-configure the desired frequency to 1KHz - .range(255) // optionally pre-configure the desired duty-cycle range (0-255) - .dutyCycle(128) // optionally pre-configure the desired duty-cycle (50%) + .dutyCycle(50) // optionally pre-configure the desired duty-cycle (50%) .shutdown(0) // optionally pre-configure a shutdown duty-cycle value (on terminate) - //.initial(125) // optionally pre-configure an initial duty-cycle value (on startup) + //.initial(50) // optionally pre-configure an initial duty-cycle value (on startup) .build(); // use try-with-resources to auto-close I2C when complete @@ -74,16 +73,16 @@ public static void main(String[] args) throws Exception { // add PWM presets pwm.addPreset(PwmPreset.newBuilder("one") - .frequency(5000) - .dutyCycle(128) + .frequency(5000) // 5 KHz + .dutyCycle(50) // 50% .build()); pwm.addPreset(PwmPreset.newBuilder("two") - .frequency(80) + .frequency(80) // 80 Hz .build()); pwm.addPreset(PwmPreset.newBuilder("three") - .dutyCycle(180) + .dutyCycle(75) // 75% .build()); @@ -117,8 +116,7 @@ public static void main(String[] args) throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); // wait 5 seconds then exit @@ -135,8 +133,7 @@ public static void main(String[] args) throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); @@ -154,8 +151,7 @@ public static void main(String[] args) throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); @@ -173,8 +169,7 @@ public static void main(String[] args) throws Exception { console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); - console.println(" - RANGE : 0-" + pwm.range()); - console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); // wait 5 seconds then exit diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmBase.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmBase.java index d05d80d2e..fbef1733e 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmBase.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmBase.java @@ -38,9 +38,21 @@ public abstract class PiGpioPwmBase extends PwmBase implements Pwm { protected final PiGpio piGpio; + protected final int range; + protected int actualFrequency = -1; - public PiGpioPwmBase(PiGpio piGpio, PwmProvider provider, PwmConfig config){ + public PiGpioPwmBase(PiGpio piGpio, PwmProvider provider, PwmConfig config, int range){ super(provider, config); this.piGpio = piGpio; + this.range = range; + } + + protected int calculateActualDutyCycle(float dutyCycle){ + return Math.round((this.range * dutyCycle) / 100); + } + + @Override + public int getActualFrequency() { + return this.actualFrequency; } } diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java index 2d9fb5209..e0f338393 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java @@ -39,8 +39,11 @@ public class PiGpioPwmHardware extends PiGpioPwmBase implements Pwm { + // fixed range for hardware PWM + public static int RANGE = 1000000; + public PiGpioPwmHardware(PiGpio piGpio, PwmProvider provider, PwmConfig config) throws IOException { - super(piGpio, provider, config); + super(piGpio, provider, config, RANGE); // 12 PWM channel 0 All models but A and B // 13 PWM channel 1 All models but A and B @@ -64,33 +67,32 @@ else if(this.address() == 18 || this.address() == 19) { // throw new IOException(" UNSUPPORTED HARDWARE PWM PIN: " + this.address()); // } + // get actual PWM frequency + this.actualFrequency = piGpio.gpioGetPWMfrequency(this.address()); + // get current frequency from config or from actual PWM pin if(config.frequency() != null){ this.frequency = config.frequency(); } else { - this.frequency = piGpio.gpioGetPWMfrequency(this.address()); + this.frequency = this.getActualFrequency(); } - // ignore any configured range values, - // fixed range for hardware PWM - this.range = 1000000; - // get current duty-cycle from config or set to default 50% if(config.dutyCycle() != null){ - this.dutyCycle = config.dutyCycle(); - } - else if(config.dutyCyclePercent() != null){ - dutyCyclePercent(config.dutyCyclePercent()); + this.dutyCycle(config.dutyCycle()); } else { // get updated duty-cycle value from PiGpio - this.dutyCycle = this.range / 2; // default duty-cycle is 50% of total range + this.dutyCycle = 50; // default duty-cycle is 50% of total range } } public Pwm on() throws IOException{ // set PWM frequency & duty-cycle; enable PWM signal - piGpio.gpioHardwarePWM(this.address(), this.frequency, this.dutyCycle); + piGpio.gpioHardwarePWM(this.address(), this.frequency, calculateActualDutyCycle(this.dutyCycle)); + + // get actual PWM frequency + this.actualFrequency = piGpio.gpioGetPWMfrequency(this.address()); // update tracking state this.onState = (this.frequency > 0 && this.dutyCycle > 0); @@ -108,10 +110,4 @@ public Pwm off() throws IOException{ return this; } - - @Override - public void setRange(int range) throws IOException { - // NOT SUPPORTED - throw new UnsupportedOperationException("Hardware PWM does not support custom ranges; rage will always be 0-1M"); - } } diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java index 447a55fbd..6a6d05f42 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java @@ -41,9 +41,11 @@ public class PiGpioPwmSoftware extends PiGpioPwmBase implements Pwm { + // fixed range for software PWM + public static int RANGE = 255; public PiGpioPwmSoftware(PiGpio piGpio, PwmProvider provider, PwmConfig config) throws IOException { - super(piGpio, provider, config); + super(piGpio, provider, config, RANGE); } @Override @@ -54,28 +56,25 @@ public Pwm initialize(Context context) throws InitializeException { // set pin mode to output piGpio.gpioSetMode(this.address(), PiGpioMode.OUTPUT); + // set PWM range (to fixed range) + piGpio.gpioSetPWMrange(this.address(), RANGE); + + // get actual PWM frequency + this.actualFrequency = piGpio.gpioGetPWMfrequency(this.address()); + // get current frequency from config or from actual PWM pin if (config.frequency() != null) { this.frequency = config.frequency(); } else { - this.frequency = piGpio.gpioGetPWMfrequency(this.address()); - } - - // get current range from config or from actual PWM pin - if (config.range() != null) { - this.range = config.range(); - } else { - this.range = piGpio.gpioGetPWMrange(this.address()); + this.frequency = this.actualFrequency; } // get current duty-cycle from config or set to default 50% if (config.dutyCycle() != null) { this.dutyCycle = config.dutyCycle(); - } else if (config.dutyCyclePercent() != null) { - dutyCyclePercent(config.dutyCyclePercent()); } else { // get updated duty-cycle value from PiGpio - this.dutyCycle = this.range / 2; // default duty-cycle is 50% of total range + this.dutyCycle = 50; // default duty-cycle is 50% of total range } } catch (IOException e){ @@ -87,18 +86,11 @@ public Pwm initialize(Context context) throws InitializeException { public Pwm on() throws IOException{ - // set PWM range - piGpio.gpioSetPWMrange(this.address(), range); - this.range = piGpio.gpioGetPWMrange(this.address()); - - // set PWM frequency - piGpio.gpioSetPWMfrequency(this.address(), frequency); + // set PWM frequency; return actual frequency + this.actualFrequency = piGpio.gpioSetPWMfrequency(this.address(), frequency); // set PWM duty-cycle and enable PWM - piGpio.gpioPWM(this.address(), this.dutyCycle); - - // get updated duty-cycle value from PiGpio - this.dutyCycle = piGpio.gpioGetPWMdutycycle(this.address()); + piGpio.gpioPWM(this.address(), calculateActualDutyCycle(this.dutyCycle)); // update tracking state this.onState = (this.frequency > 0 && this.dutyCycle > 0); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java index 11cc686c2..cbae1ac63 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestHardwarePwmUsingTestHarness.java @@ -172,7 +172,7 @@ public void testPwmAt10000Hertz() throws Exception { @Test @Order(6) - @DisplayName("PWM :: Test Hardware PWM @ 10000 Hz (10 KHz)") + @DisplayName("PWM :: Test Unsupported Hardware PWM Pin") public void testUnsupportedPin() throws Exception { // create PWM instance config @@ -232,15 +232,11 @@ public void testPwm(int frequency, int dutyCycle) throws Exception { System.out.println("[TEST HARDWARE PWM] :: PIN=" + p); // turn on PWM pulses with specified frequency and duty-cycle - pwm.dutyCyclePercent(dutyCycle) - .frequency(frequency) - .on(); + pwm.dutyCycle(dutyCycle).frequency(frequency).on(); System.out.println(" (PWM) >> SET FREQUENCY = " + frequency); System.out.println(" (PWM) >> SET DUTY-CYCLE = " + dutyCycle + "%"); System.out.println(" (PWM) << GET FREQUENCY = " + pwm.frequency()); - System.out.println(" (PWM) << GET DUTY-CYCLE = " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); - System.out.println(" (PWM) << GET RANGE MAX = " + pwm.range()); Thread.sleep(10); // test once .. @@ -266,15 +262,16 @@ public void testPwm(int frequency, int dutyCycle) throws Exception { } private boolean measureFrequency(Pwm pwm) throws IOException { - int frequency = pwm.frequency(); + int frequency = pwm.actualFrequency(); TestHarnessFrequency measured = harness.getFrequency(pwm.address()); - System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency); + float deviation = (measured.frequency - frequency) * 100/(float)frequency; + System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency + "; (EXPECTED=" + frequency + "; DEVIATION: " + deviation + "%)"); - // we allow a 60% margin of error, the testing harness uses a simple pulse counter to crudely + // we allow a 25% margin of error, the testing harness uses a simple pulse counter to crudely // measure the PWM signal, its not very accurate but should provide sufficient validation testing // just to verify the applied PWM signal is close to the expected frequency // calculate margin of error offset value - long marginOfError = Math.round(frequency * .60); + long marginOfError = Math.round(frequency * .25); // test measured value against HI/LOW offsets to determine acceptable range if(measured.frequency < frequency-marginOfError) return false; diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java index d1e99eba3..957c05cb1 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/pwm/TestSoftwarePwmUsingTestHarness.java @@ -194,13 +194,11 @@ public void testPwm(int frequency, int dutyCycle) throws Exception { System.out.println("[TEST SOFT PWM] :: PIN=" + p); // turn on PWM pulses with specified frequency and duty-cycle - pwm.dutyCyclePercent(dutyCycle).frequency(frequency).on(); + pwm.dutyCycle(dutyCycle).frequency(frequency).on(); - System.out.println(" (PWM) >> SET FREQUENCY = " + frequency); - System.out.println(" (PWM) >> SET DUTY-CYCLE = " + dutyCycle + "%"); - System.out.println(" (PWM) << GET FREQUENCY = " + pwm.frequency()); - System.out.println(" (PWM) << GET DUTY-CYCLE = " + pwm.dutyCycle() + " (" + pwm.dutyCyclePercent() + "%)"); - System.out.println(" (PWM) << GET RANGE MAX = " + pwm.range()); + System.out.println(" (PWM) >> SET DESIRED FREQUENCY = " + frequency); + System.out.println(" (PWM) >> SET DUTY-CYCLE PERCENT = " + dutyCycle + "%"); + System.out.println(" (PWM) << GET ACTUAL FREQUENCY = " + pwm.actualFrequency()); // test once .. if(measureFrequency(pwm) == false){ @@ -225,15 +223,16 @@ public void testPwm(int frequency, int dutyCycle) throws Exception { } private boolean measureFrequency(Pwm pwm) throws IOException { - int frequency = pwm.frequency(); + int frequency = pwm.actualFrequency(); TestHarnessFrequency measured = harness.getFrequency(pwm.address()); - System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency); + float deviation = (measured.frequency - frequency) * 100/(float)frequency; + System.out.println(" (TEST) << MEASURED FREQUENCY = " + measured.frequency + "; (EXPECTED=" + frequency + "; DEVIATION: " + deviation + "%)"); - // we allow a 60% margin of error, the testing harness uses a simple pulse counter to crudely + // we allow a 30% margin of error, the testing harness uses a simple pulse counter to crudely // measure the PWM signal, its not very accurate but should provide sufficient validation testing // just to verify the applied PWM signal is close to the expected frequency // calculate margin of error offset value - long marginOfError = Math.round(frequency * .60); + long marginOfError = Math.round(frequency * .30); // test measured value against HI/LOW offsets to determine acceptable range if(measured.frequency < frequency-marginOfError) return false; From fe3d1822887134d907b18a28139b670491642c6a Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Fri, 23 Aug 2019 12:44:46 -0400 Subject: [PATCH 09/15] minor PWM fixes; added annotation support for @WithPwmType --- .../java/com/pi4j/annotation/WithPwmType.java | 41 ++++++++ .../impl/DefaultAnnotationEngine.java | 5 +- .../register/PwmRegistrationProcessor.java | 6 ++ .../pi4j/io/pwm/impl/DefaultPwmPreset.java | 13 ++- .../PwmExampleUsingDependencyInjection.java | 46 ++++++--- .../provider/pwm/PiGpioPwmHardware.java | 93 +++++++++++-------- .../provider/pwm/PiGpioPwmSoftware.java | 7 +- 7 files changed, 152 insertions(+), 59 deletions(-) create mode 100644 pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java b/pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java new file mode 100644 index 000000000..82637e8b9 --- /dev/null +++ b/pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java @@ -0,0 +1,41 @@ +package com.pi4j.annotation; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: LIBRARY :: Java Library (API) + * FILENAME : WithProvider.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.io.pwm.PwmType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface WithPwmType { + PwmType value(); +} diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/impl/DefaultAnnotationEngine.java b/pi4j-api/src/main/java/com/pi4j/annotation/impl/DefaultAnnotationEngine.java index fc862679c..b3c330414 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/impl/DefaultAnnotationEngine.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/impl/DefaultAnnotationEngine.java @@ -31,6 +31,7 @@ import com.pi4j.annotation.Processor; import com.pi4j.annotation.exception.AnnotationException; import com.pi4j.context.Context; +import com.pi4j.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -280,7 +281,9 @@ private void processFieldAnnotations(Object instance, Field field, Annotation an } } catch (Exception e){ - StringBuilder message = new StringBuilder(e.getMessage()); + String msg = e.getMessage(); + if(StringUtil.isNullOrEmpty(msg)) msg = e.getClass().getName(); + StringBuilder message = new StringBuilder(msg); message.append(" <"); message.append("Annotation '@"); message.append(annotation.annotationType().getSimpleName()); diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java b/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java index 1b4342c33..accc9b928 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/processor/register/PwmRegistrationProcessor.java @@ -122,6 +122,12 @@ public Pwm process(Context context, Object instance, Register annotation, Field } } + WithPwmType pwmType = null; + if (field.isAnnotationPresent(WithPwmType.class)) { + pwmType = field.getAnnotation(WithPwmType.class); + if (pwmType != null) builder.pwmType(pwmType.value()); + } + AddPwmPresets pwmPresets = null; if (field.isAnnotationPresent(AddPwmPresets.class)) { pwmPresets = field.getAnnotation(AddPwmPresets.class); diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java index bdfc837e1..1363e3fef 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java +++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java @@ -45,11 +45,14 @@ public DefaultPwmPreset(String name, Number dutyCycle, Integer frequency){ this.name = name.toLowerCase().trim(); // bounds check the duty-cycle value - float dc = dutyCycle.floatValue(); - if(dc < 0) dc = 0; - if(dc > 100) dc = 100; - - this.dutyCycle = dc; + if(dutyCycle != null) { + float dc = dutyCycle.floatValue(); + if (dc < 0) dc = 0; + if (dc > 100) dc = 100; + this.dutyCycle = dc; + } else { + this.dutyCycle = null; + } this.frequency = frequency; } diff --git a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java index e34e660c9..e4a18a38e 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java +++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java @@ -31,6 +31,7 @@ import com.pi4j.annotation.*; import com.pi4j.context.Context; import com.pi4j.io.pwm.Pwm; +import com.pi4j.io.pwm.PwmType; import com.pi4j.plugin.pigpio.provider.pwm.PiGpioPwmProvider; import com.pi4j.util.Console; @@ -49,15 +50,17 @@ public static class RuntimeContainer implements Callable { // create a digital output instance using the default digital output provider @Register("My PWM Pin") - @Address(2) // pin number 2 - @ShutdownValue(0) + @Address(13) // pin number 13 @WithProvider(type=PiGpioPwmProvider.class) - @Frequency(5000) // 5 KHz frequency - @DutyCycle(50) // 50% duty-cycle + @WithPwmType(PwmType.HARDWARE) + @ShutdownValue(0) // 0% duty-cycle on shutdown + @InitialValue(10) // 10% duty-cycle on startup + @DutyCycle(50) // 50% duty-cycle by default (when called with 'on()') + @Frequency(500) // 500 Hz frequency used by default (until overwritten) @AddPwmPreset(name = "one-quarter", dutyCycle = 25.5f ) // 25% @AddPwmPreset(name = "three-quarter", dutyCycle = 75.0f ) // 75% @AddPwmPreset(name = "1KHZ", frequency = 1000) - @AddPwmPreset(name = "10KHZ", frequency = 10000) + @AddPwmPreset(name = "10KHZ", frequency = 10000, dutyCycle = 25.5f) private Pwm pwm; @Override @@ -89,13 +92,29 @@ public Void call() throws Exception { pi4j.describe().print(System.out); + console.println("[PWM I/O INSTANCE] : "); + pwm.describe().print(System.out); + console.println(); + console.println(" ... PWM SIGNAL SHOULD BE <--ON--> USING INITAL DUTY-CYCLE VALUE: " + pwm.config().initialValue().floatValue()); + console.println(); + console.println(" - GPIO PIN : " + pwm.address()); + console.println(" - PWM TYPE : " + pwm.pwmType()); + console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); + console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); + console.println(" - IS-ON : " + pwm.isOn()); + console.println(); + console.println(" ... WAITING 10 SECONDS TO CALL ON() METHOD"); + + // wait 10 seconds + Thread.sleep(10000); + // turn on the PWM pin pwm.on(); console.println("[PWM I/O INSTANCE] : "); pwm.describe().print(System.out); console.println(); - console.println(" ... PWM SIGNAL SHOULD BE <--ON-->"); + console.println(" ... PWM SIGNAL SHOULD BE <--ON--> USING CONFIGURED DUTY-CYCLE: " + pwm.config().dutyCycle().floatValue()); console.println(); console.println(" - GPIO PIN : " + pwm.address()); console.println(" - PWM TYPE : " + pwm.pwmType()); @@ -103,10 +122,10 @@ public Void call() throws Exception { console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); console.println(); - console.println(" ... WAITING 5 SECONDS TO APPLY PRESET: 10KHZ"); + console.println(" ... WAITING 10 SECONDS TO APPLY PRESET: 10KHZ"); - // wait 5 seconds then exit - Thread.sleep(5000); + // wait 10 seconds + Thread.sleep(10000); // turn off PWM pin pwm.applyPreset("10KHZ"); @@ -119,12 +138,11 @@ public Void call() throws Exception { console.println(" - FREQUENCY : " + pwm.frequency() + " Hz"); console.println(" - DUTY-CYCLE : " + pwm.dutyCycle() + "%"); console.println(" - IS-ON : " + pwm.isOn()); + console.println(); + console.println(" ... WAITING 10 SECONDS TO TURN PWM SIGNAL OFF"); - - console.println(" ... WAITING 5 SECONDS TO TURN PWM SIGNAL OFF"); - - // wait 5 seconds then exit - Thread.sleep(5000); + // wait 10 seconds + Thread.sleep(10000); // turn off PWM pin pwm.off(); diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java index e0f338393..295f5af5d 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmHardware.java @@ -29,6 +29,8 @@ * #L% */ +import com.pi4j.context.Context; +import com.pi4j.exception.InitializeException; import com.pi4j.io.pwm.Pwm; import com.pi4j.io.pwm.PwmConfig; import com.pi4j.io.pwm.PwmProvider; @@ -44,49 +46,65 @@ public class PiGpioPwmHardware extends PiGpioPwmBase implements Pwm { public PiGpioPwmHardware(PiGpio piGpio, PwmProvider provider, PwmConfig config) throws IOException { super(piGpio, provider, config, RANGE); + } -// 12 PWM channel 0 All models but A and B -// 13 PWM channel 1 All models but A and B -// 18 PWM channel 0 All models -// 19 PWM channel 1 All models but A and B - - // TODO :: SET PIN ALT MODES FOR HARDWARE PWM ON COMPUTE MODULE -// 40 PWM channel 0 Compute module only -// 41 PWM channel 1 Compute module only -// 45 PWM channel 1 Compute module only -// 52 PWM channel 0 Compute module only -// 53 PWM channel 1 Compute module only - - if(this.address() == 12 || this.address() == 13 || this.address() == 41 || this.address() == 42 || this.address() == 45) { - piGpio.gpioSetMode(this.address(), PiGpioMode.ALT0); + @Override + public Pwm initialize(Context context) throws InitializeException { + try { + + // TODO :: SET PIN ALT MODES FOR HARDWARE PWM ON COMPUTE MODULE + // 12 PWM channel 0 All models but A and B + // 13 PWM channel 1 All models but A and B + // 18 PWM channel 0 All models + // 19 PWM channel 1 All models but A and B + // 40 PWM channel 0 Compute module only + // 41 PWM channel 1 Compute module only + // 45 PWM channel 1 Compute module only + // 52 PWM channel 0 Compute module only + // 53 PWM channel 1 Compute module only + + if(this.address() == 12 || this.address() == 13 || this.address() == 41 || this.address() == 42 || this.address() == 45) { + piGpio.gpioSetMode(this.address(), PiGpioMode.ALT0); + } + else if(this.address() == 18 || this.address() == 19) { + piGpio.gpioSetMode(this.address(), PiGpioMode.ALT0); + } + // else{ + // throw new IOException(" UNSUPPORTED HARDWARE PWM PIN: " + this.address()); + // } + + // set pin mode to output + piGpio.gpioSetMode(this.address(), PiGpioMode.OUTPUT); + + // get actual PWM frequency + this.actualFrequency = piGpio.gpioGetPWMfrequency(this.address()); + + // get current frequency from config or from actual PWM pin + if (config.frequency() != null) { + this.frequency = config.frequency(); + } else { + this.frequency = this.actualFrequency; + } + + // initialize + super.initialize(context); + + // get current duty-cycle from config or set to default 50% + if (config.dutyCycle() != null) { + this.dutyCycle = config.dutyCycle(); + } else { + // get updated duty-cycle value from PiGpio + this.dutyCycle = 50; // default duty-cycle is 50% of total range + } } - else if(this.address() == 18 || this.address() == 19) { - piGpio.gpioSetMode(this.address(), PiGpioMode.ALT0); + catch (IOException e){ + throw new InitializeException(e); } -// else{ -// throw new IOException(" UNSUPPORTED HARDWARE PWM PIN: " + this.address()); -// } - - // get actual PWM frequency - this.actualFrequency = piGpio.gpioGetPWMfrequency(this.address()); - // get current frequency from config or from actual PWM pin - if(config.frequency() != null){ - this.frequency = config.frequency(); - } else { - this.frequency = this.getActualFrequency(); - } - - // get current duty-cycle from config or set to default 50% - if(config.dutyCycle() != null){ - this.dutyCycle(config.dutyCycle()); - } - else { - // get updated duty-cycle value from PiGpio - this.dutyCycle = 50; // default duty-cycle is 50% of total range - } + return this; } + @Override public Pwm on() throws IOException{ // set PWM frequency & duty-cycle; enable PWM signal piGpio.gpioHardwarePWM(this.address(), this.frequency, calculateActualDutyCycle(this.dutyCycle)); @@ -100,6 +118,7 @@ public Pwm on() throws IOException{ return this; } + @Override public Pwm off() throws IOException{ // set PWM duty-cycle and enable PWM diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java index 6a6d05f42..cb883d549 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/pwm/PiGpioPwmSoftware.java @@ -50,8 +50,6 @@ public PiGpioPwmSoftware(PiGpio piGpio, PwmProvider provider, PwmConfig config) @Override public Pwm initialize(Context context) throws InitializeException { - super.initialize(context); - try { // set pin mode to output piGpio.gpioSetMode(this.address(), PiGpioMode.OUTPUT); @@ -69,6 +67,9 @@ public Pwm initialize(Context context) throws InitializeException { this.frequency = this.actualFrequency; } + // initialize + super.initialize(context); + // get current duty-cycle from config or set to default 50% if (config.dutyCycle() != null) { this.dutyCycle = config.dutyCycle(); @@ -84,6 +85,7 @@ public Pwm initialize(Context context) throws InitializeException { return this; } + @Override public Pwm on() throws IOException{ // set PWM frequency; return actual frequency @@ -98,6 +100,7 @@ public Pwm on() throws IOException{ return this; } + @Override public Pwm off() throws IOException{ // set PWM duty-cycle and enable PWM From 627b0172d364d57996366bd2c59d52919ed97d15 Mon Sep 17 00:00:00 2001 From: Miro Wengner Date: Sat, 24 Aug 2019 13:15:15 +0200 Subject: [PATCH 10/15] annotation: docu correction --- pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java b/pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java index 82637e8b9..108bff4db 100644 --- a/pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java +++ b/pi4j-api/src/main/java/com/pi4j/annotation/WithPwmType.java @@ -5,7 +5,7 @@ * ********************************************************************** * ORGANIZATION : Pi4J * PROJECT : Pi4J :: LIBRARY :: Java Library (API) - * FILENAME : WithProvider.java + * FILENAME : WithPwmType.java * * This file is part of the Pi4J project. More information about * this project can be found here: https://pi4j.com/ From 0f00ba9d5729a0ffa517b33471c95a634a1d63ad Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Sun, 25 Aug 2019 16:36:26 -0400 Subject: [PATCH 11/15] fixed minor issue with impl of Arrays.copyOfRange(). --- .../src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java | 2 +- .../src/main/java/com/pi4j/library/pigpio/util/StringUtil.java | 2 +- pi4j-api/src/main/java/com/pi4j/util/StringUtil.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java index 9204fdf3e..2fb203248 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/PiGpioPacket.java @@ -152,7 +152,7 @@ public PiGpioPacket data(byte[] data, int offset, int length){ // check for valid data if(data != null && data.length > 0 && length > 0) { this.p3 = length; - this.data = Arrays.copyOfRange(data, offset, length); + this.data = Arrays.copyOfRange(data, offset, offset+length); } else{ this.p3 = 0; diff --git a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/util/StringUtil.java b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/util/StringUtil.java index 2aa30b587..adfd485a6 100644 --- a/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/util/StringUtil.java +++ b/libraries/pi4j-library-pigpio/src/main/java/com/pi4j/library/pigpio/util/StringUtil.java @@ -303,7 +303,7 @@ public static void appendHexString(StringBuilder builder, ByteBuffer buffer, int } public static String toHexString(ByteBuffer buffer, int offset, int length){ StringBuilder sb = new StringBuilder(); - appendHexString(sb, buffer, offset, length); + appendHexString(sb, buffer, offset, offset+length); return sb.toString().trim(); } diff --git a/pi4j-api/src/main/java/com/pi4j/util/StringUtil.java b/pi4j-api/src/main/java/com/pi4j/util/StringUtil.java index 325ac3336..f6d909025 100644 --- a/pi4j-api/src/main/java/com/pi4j/util/StringUtil.java +++ b/pi4j-api/src/main/java/com/pi4j/util/StringUtil.java @@ -288,7 +288,7 @@ public static String toHexString(ByteBuffer buffer){ } public static void appendHexString(StringBuilder builder, byte[] bytes, int offset, int length){ - appendHexString(builder, Arrays.copyOfRange(bytes, offset, length)); + appendHexString(builder, Arrays.copyOfRange(bytes, offset, offset+length)); } public static String toHexString(byte[] bytes, int offset, int length){ StringBuilder sb = new StringBuilder(); From 3436295644cdf0d53b39aa112cb69c716c8f4ac3 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Sun, 25 Aug 2019 16:37:47 -0400 Subject: [PATCH 12/15] minor cleanup --- .../main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java | 1 + pi4j-test/src/main/java/com/pi4j/test/Main.java | 2 -- .../java/com/pi4j/plugin/mock/provider/serial/MockSerial.java | 4 ++-- plugins/pi4j-plugin-pigpio/src/main/java/module-info.java | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java index 21f81e7aa..40454474b 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java +++ b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java @@ -39,6 +39,7 @@ public class I2cRawDeviceExample { private static int I2C_DEVICE = 0x04; public static void main(String[] args) throws Exception { + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); // TODO :: REMOVE TEMPORARY PROPERTIES WHEN NATIVE PIGPIO LIB IS READY // this temporary property is used to tell diff --git a/pi4j-test/src/main/java/com/pi4j/test/Main.java b/pi4j-test/src/main/java/com/pi4j/test/Main.java index 954b1abb2..973742678 100644 --- a/pi4j-test/src/main/java/com/pi4j/test/Main.java +++ b/pi4j-test/src/main/java/com/pi4j/test/Main.java @@ -69,7 +69,6 @@ public static void main(String[] args) throws Exception { var din1 = pi4j.dout().create(11); var ain1 = pi4j.ain().create(21, "test-analog-input-provider"); - var input = pi4j.ain().create(98); input.name("My Analog Input #1"); @@ -84,7 +83,6 @@ public static void main(String[] args) throws Exception { System.out.println(event.value()); }); - output1.addListener((AnalogChangeListener) event -> { System.out.print("ANALOG OUTPUT ["); System.out.print(event.source().address()); diff --git a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java index b8d9b4844..186069135 100644 --- a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java +++ b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/serial/MockSerial.java @@ -130,7 +130,7 @@ public int read() throws IOException { System.out.print(Mock.SERIAL_PROVIDER_NAME); System.out.print("::"); System.out.print(this.id); - System.out.print("] :: READ(0x"); + System.out.print("] :: READ (0x"); System.out.print(StringUtil.toHexString(b)); System.out.println(")"); return b; @@ -153,7 +153,7 @@ public int read(byte[] buffer, int offset, int length) throws IOException{ System.out.print(Mock.SERIAL_PROVIDER_NAME); System.out.print("::"); System.out.print(this.id); - System.out.print("] :: READ(0x"); + System.out.print("] :: READ (0x"); System.out.print(StringUtil.toHexString(buffer, offset, length)); System.out.println(")"); diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/module-info.java b/plugins/pi4j-plugin-pigpio/src/main/java/module-info.java index 41df43e35..ff6f62606 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/module-info.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/module-info.java @@ -34,10 +34,10 @@ uses com.pi4j.extension.Plugin; exports com.pi4j.plugin.pigpio; - //exports com.pi4j.plugin.pigpio.provider.gpio.digital; + exports com.pi4j.plugin.pigpio.provider.gpio.digital; //exports com.pi4j.plugin.pigpio.provider.gpio.analog; exports com.pi4j.plugin.pigpio.provider.pwm; - //exports com.pi4j.plugin.pigpio.provider.serial; + exports com.pi4j.plugin.pigpio.provider.serial; //exports com.pi4j.plugin.pigpio.provider.spi; exports com.pi4j.plugin.pigpio.provider.i2c; From aa01336cbce8f6d76621d023df3e4a802c32156c Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Sun, 25 Aug 2019 16:41:00 -0400 Subject: [PATCH 13/15] added "drain()" method and impl for Serial I/O interface --- .../main/java/com/pi4j/io/serial/Serial.java | 16 ++++++++++++++++ .../pigpio/provider/serial/PiGpioSerial.java | 18 +++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java index e710f830f..cb82d5c09 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java +++ b/pi4j-api/src/main/java/com/pi4j/io/serial/Serial.java @@ -58,6 +58,22 @@ static SerialConfigBuilder newConfigBuilder(){ */ int available() throws IOException; + /** + * This function will drain the current serial receive buffer of any lingering bytes. + * + * @return Returns the number of bytes of data drained (>=0) if OK, otherwise a negative error code. + */ + default int drain() throws IOException{ + // get number of bytes available + int avail = this.available(); + if(avail > 0) { + byte[] temp = new byte[avail]; + return this.read(temp); + } + else{ + return 0; + } + } void open() throws IOException; void close() throws IOException; diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java index 5b05ad517..d1ba6f707 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/serial/PiGpioSerial.java @@ -112,16 +112,12 @@ public int read(byte[] buffer, int offset, int length) throws IOException { return piGpio.serRead(this.handle, buffer, offset, length); } + // ------------------------------------------------------------------- + // MISC I/O FUNCTIONS + // ------------------------------------------------------------------- -// @Override -// public int read() throws IOException{ -// return piGpio.i2cReadByte(this.handle); -// } -// -// @Override -// public int read(ByteBuffer buffer, int offset, int length) throws IOException{ -// Objects.checkFromIndexSize(offset, length, buffer.capacity()); -// return piGpio.i2cReadDevice(this.handle, buffer, offset, length); -// } - + @Override + public int drain() throws IOException{ + return piGpio.serDrain(this.handle); + } } From 1bb063343fd5653240410a6f0c2f914ada15deeb Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Sun, 25 Aug 2019 16:41:55 -0400 Subject: [PATCH 14/15] updated IODataWriter and I2CRegisterDataWriter to handle relative positioning in ByteBuffer and CharBuffer --- .../main/java/com/pi4j/io/IODataWriter.java | 193 ++++++++++++++---- .../pi4j/io/i2c/I2CRegisterDataWriter.java | 160 +++++++++++++-- 2 files changed, 299 insertions(+), 54 deletions(-) diff --git a/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java b/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java index 50655a70c..43e446bb3 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java +++ b/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java @@ -145,6 +145,14 @@ default int write(Collection data) throws IOException { /** * Write a buffer of byte values with given offset (starting position) and length in the provided data buffer. * + * NOTE: The buffer's internal position tracking is no + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only read the number of + * bytes up to the buffers' available space. + * * @param buffer byte buffer of data to be written * @param offset offset in data buffer to start at * @param length number of bytes to be written @@ -152,38 +160,76 @@ default int write(Collection data) throws IOException { * @throws IOException thrown on write error */ default int write(ByteBuffer buffer, int offset, int length) throws IOException{ + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } return write(buffer.array(), offset, length); } /** * Write a buffer of byte values starting with the first byte in the array up to the provided length. * + * NOTE: The contents from the byte buffer is read + * from the current position index up to the length + * requested or up to the buffer's remaining limit; + * whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we + * will automatically flip the buffer to begin reading + * data from the zero position up to the buffer's limit. + * * @param buffer byte buffer of data to be written * @param length number of bytes to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ default int write(ByteBuffer buffer, int length) throws IOException{ + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // bounds check the requested length; only allow reading up to the remaining space in the buffer + if(length > buffer.remaining()) length = buffer.remaining(); + + // write contents from the buffer starting at the current position up the the specified length return write(buffer, buffer.position(), length); } /** * Write a buffer of byte values (all bytes in buffer). * - * (The byte buffer is read from the current position up to the 'limit' value, not the 'capacity'. - * You may need to rewind() or flip() the byte buffer if you have just written to it.) + * NOTE: The contents from the byte buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. * * @param buffer byte buffer of data to be written (from current position to limit) * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ default int write(ByteBuffer buffer) throws IOException{ - return write(buffer, buffer.remaining()); + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // write contents from the buffer starting at the current position up the the remaining buffer size + return write(buffer, buffer.position(), buffer.remaining()); } /** * Write multiple byte buffers of data. * + * NOTE: The contents from each byte buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param buffer byte buffer of data to be written * @return The number of bytes written, possibly zero * @throws IOException thrown on write error @@ -191,6 +237,11 @@ default int write(ByteBuffer buffer) throws IOException{ default int write(ByteBuffer ... buffer) throws IOException{ ByteArrayOutputStream os = new ByteArrayOutputStream(); for (ByteBuffer bb : buffer) { + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(bb.position() == bb.limit()) bb.flip(); + + // write the byte array to the byte output stream os.write(bb.array()); } return write(os.toByteArray()); @@ -201,7 +252,7 @@ default int write(ByteBuffer ... buffer) throws IOException{ // ------------------------------------------------------------------------------------ /** - * Write a buffer of byte values (all bytes in buffer). + * Write a stream of data (all bytes available in input stream). * * @param stream stream of data to be written * @return The number of bytes written, possibly zero @@ -212,7 +263,19 @@ default int write(InputStream stream) throws IOException{ } /** - * Write a buffer of byte values (all bytes in buffer). + * Write a stream of stream of data up to the length (number of bytes) specified. + * + * @param stream stream of data to be written + * @param length number of bytes to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(InputStream stream, int length) throws IOException{ + return write(stream.readNBytes(length)); + } + + /** + * Write multiple streams of data (all bytes available in each input stream). * * @param stream stream of data to be written * @return The number of bytes written, possibly zero @@ -420,108 +483,164 @@ default int write(Charset charset, Collection data) throws IOException { /** * Writes an ASCII based character buffer with a given offset and length. * - * @param data ASCII character array used for data write + * @param buffer ASCII character buffer used for data write * @param offset offset in data character array to start at * @param length number of character in character array to be written * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(CharBuffer data, int offset, int length) throws IOException { - return write(StandardCharsets.US_ASCII, data, offset, length); + default int write(CharBuffer buffer, int offset, int length) throws IOException { + return write(StandardCharsets.US_ASCII, buffer, offset, length); } /** * Writes an ASCII based character buffer starting at first index to a given length. * - * @param data ASCII character array used for data write + * @param buffer ASCII character buffer used for data write * @param length number of character in character array to be written * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(CharBuffer data, int length) throws IOException { - return write(StandardCharsets.US_ASCII, data, length); + default int write(CharBuffer buffer, int length) throws IOException { + return write(StandardCharsets.US_ASCII, buffer, length); } /** * Writes an ASCII based character buffer. * - * @param data ASCII character array used for data write + * @param buffer ASCII character buffer used for data write * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(CharBuffer data) throws IOException { - return write(StandardCharsets.US_ASCII, data); + default int write(CharBuffer buffer) throws IOException { + return write(StandardCharsets.US_ASCII, buffer); } /** - * Writes an ASCII based character buffer. + * Writes multiple ASCII based character buffers. * - * @param data ASCII character array used for data write + * @param buffer ASCII character buffer used for data write * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(CharBuffer ... data) throws IOException { - return write(StandardCharsets.US_ASCII, data); + default int write(CharBuffer ... buffer) throws IOException { + return write(StandardCharsets.US_ASCII, buffer); } /** - * Writes an ASCII based character buffer with a given offset and length + * Writes a character buffer with a given offset and length * using a specified character set to encode the chars into bytes. * + * NOTE: The buffer's internal position tracking is no + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only read the number of + * characters up to the buffers' available space. + * * @param charset character set to use for byte encoding - * @param data ASCII character array used for data write + * @param buffer character buffer used for data write * @param offset offset in data character array to start at * @param length number of character in character array to be written * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(Charset charset, CharBuffer data, int offset, int length) throws IOException { - ByteBuffer bb = charset.encode(CharBuffer.wrap(data, offset, length)); + default int write(Charset charset, CharBuffer buffer, int offset, int length) throws IOException { + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } + + // convert the character array to a byte array and write the byte array + ByteBuffer bb = charset.encode(CharBuffer.wrap(buffer.array(), offset, length)); return write(bb.array()); } /** - * Writes an ASCII based character buffer starting at first index to a + * Writes a character buffer starting at first index to a * given length using a specified character set to encode the chars into bytes. * + * NOTE: The contents from the character buffer is read + * from the current position index up to the length + * requested or up to the buffer's remaining limit; + * whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we + * will automatically flip the buffer to begin reading + * data from the zero position up to the buffer's limit. + * * @param charset character set to use for byte encoding - * @param data ASCII character array used for data write + * @param buffer character buffer used for data write * @param length number of character in character array to be written * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(Charset charset, CharBuffer data, int length) throws IOException { - ByteBuffer bb = charset.encode(CharBuffer.wrap(data, 0, length)); - return write(bb.array()); + default int write(Charset charset, CharBuffer buffer, int length) throws IOException { + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // bounds check the requested length; only allow reading up to the remaining space in the buffer + if(length > buffer.remaining()) length = buffer.remaining(); + + // write contents from the buffer starting at the current position up the the specified length + return write(charset, buffer, buffer.position(), length); } /** - * Writes an ASCII based character buffer using a specified + * Writes character buffer using a specified * character set to encode the chars into bytes. * + * NOTE: The contents from the character buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param charset character set to use for byte encoding - * @param data ASCII character array used for data write + * @param buffer character buffer used for data write * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(Charset charset, CharBuffer data) throws IOException { - ByteBuffer bb = charset.encode(data); - return write(bb.array()); + default int write(Charset charset, CharBuffer buffer) throws IOException { + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // write contents from the buffer starting at the current position up the the remaining buffer size + return write(charset, buffer, buffer.position(), buffer.remaining()); } /** - * Writes an ASCII based character buffer using a specified + * Writes multiple character buffers using a specified * character set to encode the chars into bytes. * + * NOTE: The contents from each character buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param charset character set to use for byte encoding - * @param data ASCII character array used for data write + * @param buffer character buffer used for data write * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int write(Charset charset, CharBuffer ... data) throws IOException { + default int write(Charset charset, CharBuffer ... buffer) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); - for (CharBuffer cb : data) { - ByteBuffer bb = charset.encode(cb); + for (CharBuffer cb : buffer) { + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(cb.position() == cb.limit()) cb.flip(); + + // encode the contents of the character buffer from the current position up to the limit + ByteBuffer bb = charset.encode(CharBuffer.wrap(cb.array(), cb.position(), cb.remaining())); + + // write the encoded byte buffer to the byte array output stream os.write(bb.array()); } return write(os.toByteArray()); diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java index ab48a22c2..36aa8a4af 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java +++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java @@ -172,6 +172,14 @@ default int writeRegister(int register, Collection data) throws IOExcept * Write a buffer of byte values starting from a given offset index in the * array up to the provided length to a specific I2C device register. * + * NOTE: The buffer's internal position tracking is no + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only read the number of + * bytes up to the buffers' available space. + * * @param register the register address to write to * @param buffer byte buffer of data to be written to the i2c device in one go * @param offset offset in buffer @@ -180,6 +188,10 @@ default int writeRegister(int register, Collection data) throws IOExcept * @throws IOException thrown on write error */ default int writeRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException{ + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } return writeRegister(register, buffer.array(), offset, length); } @@ -197,6 +209,14 @@ default int writeRegister(int register, ByteBuffer buffer, int offset, int lengt * Write a buffer of byte values starting from the first byte in the buffer * up to the provided length to a specific I2C device register. * + * NOTE: The contents from the byte buffer is read + * from the current position index up to the length + * requested or up to the buffer's remaining limit; + * whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we + * will automatically flip the buffer to begin reading + * data from the zero position up to the buffer's limit. + * * @param register the register address to write to * @param buffer byte buffer of data to be written to the i2c device in one go * @param length number of bytes to be written @@ -204,24 +224,54 @@ default int writeRegister(int register, ByteBuffer buffer, int offset, int lengt * @throws IOException thrown on write error */ default int writeRegister(int register, ByteBuffer buffer, int length) throws IOException{ + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // bounds check the requested length; only allow reading up to the remaining space in the buffer + if(length > buffer.remaining()) length = buffer.remaining(); + + // write contents from the buffer starting at the current position up the the specified length return writeRegister(register, buffer, buffer.position(), length); + } /** * Write a buffer of byte values (all bytes in buffer) to a specific I2C device register. * + * NOTE: The contents from the byte buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param register the register address to write to * @param buffer byte buffer of data to be written to the i2c device in one go * @return The number of bytes written, possibly zero * @throws IOException thrown on write error */ default int writeRegister(int register, ByteBuffer buffer) throws IOException{ - return writeRegister(register, buffer, buffer.remaining()); + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // write contents from the buffer starting at the current position up the the remaining buffer size + return writeRegister(register, buffer, buffer.position(), buffer.remaining()); } /** * Write multiple byte buffers to a specific I2C device register. * + * NOTE: The contents from each byte buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param register the register address to write to * @param buffer byte buffer of data to be written to the i2c device in one go * @return The number of bytes written, possibly zero @@ -230,6 +280,12 @@ default int writeRegister(int register, ByteBuffer buffer) throws IOException{ default int writeRegister(int register, ByteBuffer ... buffer) throws IOException{ ByteArrayOutputStream os = new ByteArrayOutputStream(); for (ByteBuffer bb : buffer) { + + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(bb.position() == bb.limit()) bb.flip(); + + // write the byte array to the byte output stream os.write(bb.array()); } return writeRegister(register, os.toByteArray()); @@ -251,6 +307,20 @@ default int writeRegister(int register, InputStream stream) throws IOException{ return writeRegister(register, stream.readAllBytes()); } + /** + * Write a stream of stream of data up to the length (number of bytes) + * specified to a specific I2C device register. + * + * @param register the register address to write to + * @param stream stream of data to be written + * @param length number of bytes to be written + * @return The number of bytes written, possibly zero + * @throws IOException thrown on write error + */ + default int write(int register, InputStream stream, int length) throws IOException{ + return writeRegister(register, stream.readNBytes(length)); + } + /** * Write multiple streams of data bytes to a specific I2C device register. * @@ -527,57 +597,106 @@ default int writeRegister(int register, CharBuffer ... data) throws IOException } /** - * Writes an ASCII based character buffer with a given offset and length using a specified + * Writes a character buffer with a given offset and length using a specified * character set to encode the chars into bytes to a specific I2C device register. * + * NOTE: The buffer's internal position tracking is no + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only read the number of + * characters up to the buffers' available space. + * * @param register the register address to write to * @param charset character set to use for byte encoding - * @param data ASCII character array used for data write + * @param buffer character buffer used for data write * @param offset offset in data character array to start at * @param length number of character in character array to be written * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, Charset charset, CharBuffer data, int offset, int length) throws IOException { - ByteBuffer bb = charset.encode(CharBuffer.wrap(data, offset, length)); + default int writeRegister(int register, Charset charset, CharBuffer buffer, int offset, int length) throws IOException { + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } + + // convert the character array to a byte array and write the byte array + ByteBuffer bb = charset.encode(CharBuffer.wrap(buffer.array(), offset, length)); return writeRegister(register, bb.array()); } /** - * Writes an ASCII based character buffer starting at first index to a given length using + * Write a character buffer starting at first index to a given length using * a specified character set to encode the chars into bytes to a specific I2C device register. * + * NOTE: The contents from the character buffer is read + * from the current position index up to the length + * requested or up to the buffer's remaining limit; + * whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we + * will automatically flip the buffer to begin reading + * data from the zero position up to the buffer's limit. + * * @param register the register address to write to * @param charset character set to use for byte encoding - * @param data ASCII character array used for data write + * @param buffer character buffer used for data write * @param length number of character in character array to be written * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, Charset charset, CharBuffer data, int length) throws IOException { - ByteBuffer bb = charset.encode(CharBuffer.wrap(data, 0, length)); - return writeRegister(register, bb.array()); + default int writeRegister(int register, Charset charset, CharBuffer buffer, int length) throws IOException { + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // bounds check the requested length; only allow reading up to the remaining space in the buffer + if(length > buffer.remaining()) length = buffer.remaining(); + + // write contents from the buffer starting at the current position up the the specified length + return writeRegister(register, charset, buffer, buffer.position(), length); } /** - * Writes an ASCII based character buffer using a specified character set + * Write a character buffer using a specified character set * to encode the chars into bytes to a specific I2C device register. * + * NOTE: The contents from the character buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param register the register address to write to * @param charset character set to use for byte encoding - * @param data ASCII character array used for data write + * @param buffer character array used for data write * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error */ - default int writeRegister(int register, Charset charset, CharBuffer data) throws IOException { - ByteBuffer bb = charset.encode(data); - return writeRegister(register, bb.array()); + default int writeRegister(int register, Charset charset, CharBuffer buffer) throws IOException { + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(buffer.position() == buffer.limit()) buffer.flip(); + + // write contents from the buffer starting at the current position up the the remaining buffer size + return writeRegister(register, charset, buffer, buffer.position(), buffer.remaining()); } /** - * Writes an ASCII based character buffer using a specified character + * Writes multiple character buffers using a specified character * set to encode the chars into bytes to a specific I2C device register. * + * NOTE: The contents from each character buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param register the register address to write to * @param charset character set to use for byte encoding * @param data ASCII character array used for data write @@ -587,7 +706,14 @@ default int writeRegister(int register, Charset charset, CharBuffer data) throws default int writeRegister(int register, Charset charset, CharBuffer ... data) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); for (CharBuffer cb : data) { - ByteBuffer bb = charset.encode(cb); + // if the buffer position is already at the buffer limit, then flip the buffer for + //reading data from the buffer at the starting position to write to the I/O device + if(cb.position() == cb.limit()) cb.flip(); + + // encode the contents of the character buffer from the current position up to the limit + ByteBuffer bb = charset.encode(CharBuffer.wrap(cb.array(), cb.position(), cb.remaining())); + + // write the encoded byte buffer to the byte array output stream os.write(bb.array()); } return writeRegister(register, os.toByteArray()); From 18c3ec31865e0775963ee364227d8370128dae11 Mon Sep 17 00:00:00 2001 From: Robert Savage Date: Sun, 25 Aug 2019 20:46:44 -0400 Subject: [PATCH 15/15] updated IODataReader interface for combined Serial and I2C; --- .../main/java/com/pi4j/io/IODataReader.java | 907 ++++++++++++++++- .../main/java/com/pi4j/io/IODataWriter.java | 36 +- .../java/com/pi4j/io/i2c/I2CRegister.java | 8 + .../pi4j/io/i2c/I2CRegisterDataReader.java | 918 +++++++++++++++++- .../pi4j/io/i2c/impl/DefaultI2CRegister.java | 4 +- .../src/main/java/com/pi4j/example/Main.java | 101 +- .../pi4j/example/i2c/I2cDeviceExample.java | 4 +- .../pi4j/example/i2c/I2cRawDeviceExample.java | 4 +- .../pi4j/test/io/serial/SerialDataTest.java | 377 +++++++ .../plugin/mock/provider/i2c/MockI2C.java | 11 +- .../plugin/pigpio/provider/i2c/PiGpioI2C.java | 5 +- .../i2c/TestI2cRawUsingTestHarness.java | 4 +- .../pigpio/i2c/TestI2cUsingTestHarness.java | 12 +- .../serial/TestSerialUsingTestHarness.java | 4 +- .../raspberrypi/provider/i2c/RpiI2C.java | 3 +- 15 files changed, 2286 insertions(+), 112 deletions(-) create mode 100644 pi4j-test/src/test/java/com/pi4j/test/io/serial/SerialDataTest.java diff --git a/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java b/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java index 66a508b82..9edec127d 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java +++ b/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -46,12 +47,21 @@ * Daniel Sendula, * RasPelikan */ -public interface IODataReader { +public interface IODataReader extends Readable { // ------------------------------------------------------------------------------------ // SINGLE BYTE // ------------------------------------------------------------------------------------ + /** + * Read a single raw byte (8-bit) value from the I/O device. + * + * @return If successful, a zero or positive integer value representing the byte value (0-255) + * is returned. If a read error was encountered, a negative error code may be returned. + * @throws IOException In some cases, an IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not thrown as exceptions. + */ int read() throws IOException; @@ -59,92 +69,898 @@ public interface IODataReader { // BYTE ARRAY // ------------------------------------------------------------------------------------ + /** + * Read data from the I/O device into the provided byte array at the given + * offset and up to the specified data length (number of bytes). + * + * @param buffer the byte array/buffer the read data will be copied/inserted into + * @param offset the offset index in the data buffer to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ int read(byte[] buffer, int offset, int length) throws IOException; + /** + * Read data from the I/O device into the provided byte array starting at the zero + * index (first byte) and up to the specified data length (number of bytes). + * + * @param buffer the byte array/buffer the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int read(byte[] buffer, int length) throws IOException{ return read(buffer, 0, length); } + /** + * Read data from the I/O device into the provided byte array starting at the zero + * index (first byte) and up to the available space in the buffer/array. + * + * @param buffer the byte array/buffer the read data will be copied/inserted into + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int read(byte[] buffer) throws IOException{ - return read(buffer, 0, buffer.length); + return read(buffer, buffer.length); } - // ------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------ // BYTE BUFFER // ------------------------------------------------------------------------------------ + /** + * Read data from the I/O device into the provided byte buffer at the given + * offset and up to the specified data length (number of bytes). + * + * NOTE: The buffer's internal position tracking is not + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only write the number of + * bytes up to the buffers' available space. + * + * @param buffer the byte buffer the read data will be copied/inserted into + * @param offset the offset index in the data buffer to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int read(ByteBuffer buffer, int offset, int length) throws IOException{ - return read(buffer.array(), offset, length); + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } + + // create a temporary byte array to read in the length of data bytes + byte[] temp = new byte[length]; + int actualLength = read(temp, 0 ,length); + + // return any error codes ( < 0) + if(actualLength < 0) return actualLength; + + // perform bounds checking on number of bytes read versus the length requested + if(actualLength < length) length = actualLength; + + // copy the data from the temporary byte array into the return buffer at the given offset + buffer.position(offset); + buffer.put(temp, 0, length); + + // return actual number of bytes read + return length; } + /** + * Read data from the I/O device into the provided byte buffer starting + * with the first byte in the array up to the provided length. + * + * NOTE: The data bytes read from the I/O device are copied/ + * inserted into the byte buffer starting at the current + * position index up to the length requested or up to the + * buffer's remaining limit; whichever is is lower . If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param buffer the byte buffer the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int read(ByteBuffer buffer, int length) throws IOException{ - return read(buffer, 0, length); + // if the buffer position is already at the buffer limit, then rewind the buffer for + // writing new data into the buffer read from the I/O device + if(buffer.position() == buffer.limit()) buffer.rewind(); + + // bounds check the requested length; only allow reading up to the remaining space in the buffer + if(length > buffer.remaining()) length = buffer.remaining(); + + // read the buffer starting at the current position up the the specified length + return read(buffer, buffer.position(), length); } + /** + * Read data from the I/O device into the provided byte buffer starting with + * the first byte in the array up to available space remaining in the buffer. + * + * NOTE: The data bytes read from the I/O device are copied/ + * inserted into the byte buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param buffer byte buffer of data where data read from the I/O device + * will be copied (from current position to limit) + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int read(ByteBuffer buffer) throws IOException{ - return read(buffer, 0, buffer.capacity()); + // if the buffer position is already at the buffer limit, then rewind the buffer for + // writing new data into the buffer read from the I/O device + if(buffer.position() == buffer.limit()) buffer.rewind(); + + // read the buffer starting at the current position and fill up to the remaining size + return read(buffer, buffer.position(), buffer.remaining()); } - // ------------------------------------------------------------------------------------------------------------ - default String readString(int length, Charset charset) throws IOException, IOReadException { - byte[] temp = new byte[length]; - int actual = read(temp, 0, length); - if(actual < 0) throw new IOReadException(actual); - return new String(temp, 0, actual, charset); + // ------------------------------------------------------------------------------------ + // CHAR ARRAY + // ------------------------------------------------------------------------------------ + + /** + * Read character data from the I/O device into the provided character array at the given + * offset and up to the specified data length (number of characters). Specify the character + * set to be used to decode the bytes into chars. + * + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @param offset the offset index in the character array to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(Charset charset, char[] buffer, int offset, int length) throws IOException{ + // determine the maximum number of bytes that may be needed for this character set + // and create a byte array to temporarily read the raw data from the I/O device + int maxBytes = (int)charset.newDecoder().maxCharsPerByte() * length; + byte[] rx = new byte[maxBytes]; + + // read data from I/O device into temporary byte buffer + int actualLength = read(rx, maxBytes); + + // return any error codes ( < 0) + if(actualLength < 0) return actualLength; + + // decode byte array into char buffer + CharBuffer cb = charset.decode(ByteBuffer.wrap(rx)); + + // perform bounds checking on number of bytes read versus the length requested + if(actualLength < length) length = actualLength; + + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.length-offset)){ + length = buffer.length-offset; + } + + // stuff the decoded characters into the provided char array + cb.get(buffer, offset, length); + + // return number of bytes read + return actualLength; + } + + /** + * Read data from the I/O device into the provided character array starting + * with the first byte in the array up to the provided length. Specify the + * character set to be used to decode the bytes into chars. + * + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(Charset charset, char[] buffer, int length) throws IOException{ + return read(buffer, 0, length); + } + + /** + * Read data from the I/O device into the provided character array starting at the zero + * index (first byte) and up to the available space in the buffer/array. Specify the + * character set to be used to decode the bytes into chars. + * + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(Charset charset, char[] buffer) throws IOException{ + return read(buffer, buffer.length); + } + + /** + * Read ASCII character data from the I/O device into the provided character array at the given + * offset and up to the specified data length (number of characters). + * ASCII is the internal character set used to decode the bytes into chars. + * + * @param buffer the character array the read data will be copied/inserted into + * @param offset the offset index in the character array to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(char[] buffer, int offset, int length) throws IOException{ + return read(StandardCharsets.US_ASCII, buffer, offset, length); + } + + /** + * Read ASCII data from the I/O device into the provided character array starting + * with the first byte in the array up to the provided length. + * ASCII is the internal character set used to decode the bytes into chars. + * + * @param buffer the character array the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(char[] buffer, int length) throws IOException{ + return read(StandardCharsets.US_ASCII, buffer, length); + } + + /** + * Read ASCII data from the I/O device into the provided character array starting at the zero + * index (first byte) and up to the available space in the buffer/array. + * ASCII is the internal character set used to decode the bytes into chars. + * + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(char[] buffer) throws IOException{ + return read(StandardCharsets.US_ASCII, buffer, buffer.length); + } + + + // ------------------------------------------------------------------------------------ + // CHAR BUFFER + // ------------------------------------------------------------------------------------ + + /** + * Read character data from the I/O device into the provided character buffer at the given + * offset and up to the specified data length (number of characters). Specify the character + * set to be used to decode the bytes into chars. + * + * NOTE: The buffer's internal position tracking is not + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only write the number of + * characters up to the buffers' available space. + * + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @param offset the offset index in the character buffer to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(Charset charset, CharBuffer buffer, int offset, int length) throws IOException{ + // validate length argument + if(length <=0) throw new IOException("Invalid read request; length must be greater than zero."); + + // determine the maximum number of bytes that may be needed for this character set + // and create a byte array to temporarily read the raw data from the I/O device + int maxBytes = (int)charset.newDecoder().maxCharsPerByte() * length; + byte[] rx = new byte[maxBytes]; + + // read data from I/O device into temporary byte buffer + int actualLength = read(rx, maxBytes); + + // return any error codes ( < 0) + if(actualLength < 0) return actualLength; + + // decode byte array into char buffer + CharBuffer cb = charset.decode(ByteBuffer.wrap(rx)); + + // perform bounds checking on number of bytes read versus the length requested + if(actualLength < length) length = actualLength; + + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } + + // set the buffer position to the provided offset index + buffer.position(offset); + + // stuff the decoded characters into the provided CharBuffer + buffer.put(cb.array(), 0, length); + + // return number of characters put into the array + return actualLength; + } + + /** + * Read character data from the I/O device into the provided character buffer starting + * at the zero index (first position) up to the specified data length (number of characters). + * Specify the character set to be used to decode the bytes into chars. + * + * NOTE: The data characters read and decoded from the I/O device are + * copied/inserted into the character buffer starting at the current + * position index up to the length requested or up to the buffer's + * remaining limit; whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we will automatically + * rewind the buffer to begin writing data from the zero position up to + * the buffer's limit. + * + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(Charset charset, CharBuffer buffer, int length) throws IOException{ + // if the buffer position is already at the buffer limit, then rewind the buffer for reading + if(buffer.position() == buffer.limit()) buffer.rewind(); + + return read(buffer, buffer.position(), length); + } + + /** + * Read character data from the I/O device into the provided character buffer starting + * at the zero index (first position) up to available space remaining in the buffer. + * Specify the character set to be used to decode the bytes into chars. + * + * NOTE: The data characters read from the I/O device are copied/ + * inserted into the character buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(Charset charset, CharBuffer buffer) throws IOException{ + // if the buffer position is already at the buffer limit, then rewind the buffer for reading + if(buffer.position() == buffer.limit()) buffer.rewind(); + + // read the buffer starting at the current position and fill up to the remaining size + return read(buffer, buffer.position(), buffer.remaining()); + } + + /** + * Read ASCII character data from the I/O device into the provided character buffer at the given + * offset and up to the specified data length (number of characters). ASCII is the internal + * character set used to decode the bytes into chars. + * + * NOTE: The buffer's internal position tracking is not + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only write the number of + * characters up to the buffers' available space. + * + * @param buffer the character array the read data will be copied/inserted into + * @param offset the offset index in the character buffer to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(CharBuffer buffer, int offset, int length) throws IOException{ + return read(StandardCharsets.US_ASCII, buffer, offset, length); + } + + /** + * Read ASCII character data from the I/O device into the provided character buffer starting + * at the zero index (first position) up to the specified data length (number of characters). + * ASCII is the internal character set used to decode the bytes into chars. + * + * NOTE: The data characters read and decoded from the I/O device are + * copied/inserted into the character buffer starting at the current + * position index up to the length requested or up to the buffer's + * remaining limit; whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we will automatically + * rewind the buffer to begin writing data from the zero position up to + * the buffer's limit. + * + * @param buffer the character array the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(CharBuffer buffer, int length) throws IOException{ + return read(StandardCharsets.US_ASCII, buffer, length); } - default String readString(int length) throws IOException, IOReadException { - return readString(length, StandardCharsets.US_ASCII); + /** + * Read ASCII character data from the I/O device into the provided character buffer starting + * at the zero index (first position) up to available space remaining in the buffer. + * ASCII is the internal character set used to decode the bytes into chars. + * + * NOTE: The data characters read from the I/O device are copied/ + * inserted into the character buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int read(CharBuffer buffer) throws IOException{ + return read(StandardCharsets.US_ASCII, buffer); } + + // ------------------------------------------------------------------------------------ + // AUXILIARY CONVENIENCE METHODS + // ------------------------------------------------------------------------------------ + /** - * Read a single byte value (16-bit) from the raw I2C device (not a register). + * Read a single raw byte (8-bit) value from the I/O device. * - * @return The 16-bit word value - * @throws IOException thrown on write error + * @return The 8-bit byte value + * @throws IOException In all error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. */ default byte readByte() throws IOException{ int actual = read(); - if(actual < 0) { - System.out.println(actual); - throw new IOException("I2C READ ERROR; " + actual); - } + if(actual < 0) throw new IOException("I2C READ ERROR; " + actual); return (byte)actual; } /** - * Read a single word value (16-bit) from the raw I2C device (not a register). + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new byte array. The 'offset' parameter allows you to skip + * a certain number of bytes in the read data an excludes them from the returned + * data byte array. + * + * Note: the resulting byte array size will be at most the 'length' - 'offset'. + * + * @param offset the offset index in the data read to start copying read data + * @param length the number of bytes to read + * @return a new byte array containing the data bytes read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default byte[] readNBytes(int offset, int length) throws IOException, IOReadException { + if (length <= 0) { + throw new IllegalArgumentException("length <= 0"); + } + if (offset < 0) { + throw new IllegalArgumentException("offset < 0"); + } + if (length < offset) { + throw new IllegalArgumentException("length < offset"); + } + int bufferSize = length-offset; + byte[] temp = new byte[bufferSize]; + int actual = read(temp, offset, length); + if(actual < 0) throw new IOReadException(actual); + return Arrays.copyOf(temp, actual); + } + + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new byte array. * - * @return The 16-bit word value - * @throws IOException thrown on write error + * @param length the number of bytes to read + * @return a new byte array containing the data bytes read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. */ - default int readWord() throws IOException, IOReadException { - byte[] buffer = new byte[2]; - int actual = read(buffer); - if(actual < 2) throw new IOReadException(actual); - return ((buffer[0] & 0xff) << 8) | (buffer[1] & 0xff); + default byte[] readNBytes(int length) throws IOException, IOReadException { + return readNBytes(0 ,length); } - default ByteBuffer readBuffer(int length) throws IOException, IOReadException { - byte[] temp = new byte[length]; - int actual = read(temp, 0, length); + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new ByteBuffer. The 'offset' parameter allows you to skip + * a certain number of bytes in the read data and excludes them from the returned + * data ByteBuffer. + * + * Note: the resulting byte buffer size will be at most the 'length' - 'offset'. + * + * @param offset the offset index in the data read to start copying read data + * @param length the number of bytes to read + * @return a new ByteBuffer containing the data bytes read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default ByteBuffer readByteBuffer(int offset, int length) throws IOException, IOReadException { + if (length <= 0) { + throw new IllegalArgumentException("length <= 0"); + } + if (offset < 0) { + throw new IllegalArgumentException("offset < 0"); + } + if (length < offset) { + throw new IllegalArgumentException("length < offset"); + } + int bufferSize = length-offset; + byte[] temp = new byte[bufferSize]; + int actual = read(temp, offset, length); if(actual < 0) throw new IOReadException(actual); return ByteBuffer.wrap(temp, 0, actual); } - default byte[] readArray(int length) throws IOException, IOReadException { - byte[] temp = new byte[length]; - int actual = read(temp, 0, length); + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new ByteBuffer. The 'offset' parameter allows you to skip + * a certain number of bytes in the read data and excludes them from the returned + * data ByteBuffer. + * + * @param length the number of bytes to read + * @return a new ByteBuffer containing the data bytes read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default ByteBuffer readByteBuffer(int length) throws IOException, IOReadException { + return readByteBuffer(0, length); + } + + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new character array. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character array. + * + * @param charset character set to use for byte decoding + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readCharArray(Charset charset, int offset, int numberOfBytes) throws IOException, IOReadException { + byte[] temp = new byte[numberOfBytes]; + int actual = read(temp, offset, numberOfBytes); if(actual < 0) throw new IOReadException(actual); - return Arrays.copyOf(temp, actual); + CharBuffer cb = charset.decode(ByteBuffer.wrap(temp, 0, actual)); + return cb.array(); + } + + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new character array. ASCII is the internal character + * set used to decode the bytes into chars. + * + * @param charset character set to use for byte decoding + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readCharArray(Charset charset, int numberOfBytes) throws IOException, IOReadException { + return readCharArray(charset, 0, numberOfBytes); + } + + /** + * Read ASCII data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new character array. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character buffer. ASCII is the internal character set used to decode the bytes into chars. + * + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readCharArray(int offset, int numberOfBytes) throws IOException, IOReadException { + return readCharArray(StandardCharsets.US_ASCII, offset, numberOfBytes); } + /** + * Read ASCII data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new character buffer. + * + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readCharArray(int numberOfBytes) throws IOException, IOReadException { + return readCharArray(0, numberOfBytes); + } + + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character buffer. + * + * @param charset character set to use for byte decoding + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readCharBuffer(Charset charset, int offset, int numberOfBytes) throws IOException, IOReadException { + byte[] temp = new byte[numberOfBytes]; + int actual = read(temp, offset, numberOfBytes); + if(actual < 0) throw new IOReadException(actual); + CharBuffer cb = charset.decode(ByteBuffer.wrap(temp, 0, actual)); + return cb.flip(); + } + + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. + * + * @param charset character set to use for byte decoding + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readCharBuffer(Charset charset, int numberOfBytes) throws IOException, IOReadException { + return readCharBuffer(charset, 0, numberOfBytes); + } + + /** + * Read ASCII data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character buffer. ASCII is the internal character set used to decode the bytes into chars. + * + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readCharBuffer(int offset, int numberOfBytes) throws IOException, IOReadException { + return readCharBuffer(StandardCharsets.US_ASCII, offset, numberOfBytes); + } + + /** + * Read ASCII data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. ASCII is the internal character + * set used to decode the bytes into chars. + * + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readCharBuffer(int numberOfBytes) throws IOException, IOReadException { + return readCharBuffer(0, numberOfBytes); + } + + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new String instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * string. + * + * @param charset character set to use for byte decoding + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readString(Charset charset, int offset, int numberOfBytes) throws IOException, IOReadException { + byte[] temp = new byte[numberOfBytes]; + int actual = read(temp, offset, numberOfBytes); + if(actual < 0) throw new IOReadException(actual); + return new String(temp, 0, actual, charset); + } + + /** + * Read data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new String instance. + * + * @param charset character set to use for byte decoding + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readString(Charset charset, int numberOfBytes) throws IOException, IOReadException { + return readString(charset, 0, numberOfBytes); + } + + /** + * Read ASCII data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new String instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * string. ASCII is the internal character set used to decode the bytes into chars. + * + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readString(int offset, int numberOfBytes) throws IOException, IOReadException { + return readString(StandardCharsets.US_ASCII, offset, numberOfBytes); + } + + /** + * Read ASCII data from the I/O device up to a specified length (number of bytes) and + * return the data read in a new String instance. ASCII is the internal character set + * used to decode the bytes into chars. + * + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I/O device. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readString(int numberOfBytes) throws IOException, IOReadException { + return readString(0, numberOfBytes); + } + + + // ------------------------------------------------------------------------------------ + // INPUT STREAM + // ------------------------------------------------------------------------------------ + + /** + * Get an InputStream to read data from the I/O device. + * @return InputStream instance + */ default InputStream getInputStream(){ var t = this; return new InputStream() { + +// @Override +// public int available () throws IOException { +// return t.available(); +// } + @Override public int read() throws IOException { return t.read(); @@ -155,9 +971,28 @@ public int read(byte[] b, int off, int len) throws IOException { Objects.checkFromIndexSize(off, len, b.length); return t.read(b, off, len); } + + @Override + public int readNBytes(byte[] b, int off, int len) throws IOException { + Objects.checkFromIndexSize(off, len, b.length); + return t.read(b, off, len); + } + + @Override + public byte[] readNBytes(int len) throws IOException { + try { + return t.readNBytes(len); + } catch (IOReadException e) { + throw new IOException(e); + } + } }; } + /** + * Get an InputStream to read data from the I/O device. + * @return InputStream instance + */ default InputStream in() { return getInputStream(); } diff --git a/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java b/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java index 43e446bb3..a4822236b 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java +++ b/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java @@ -145,7 +145,7 @@ default int write(Collection data) throws IOException { /** * Write a buffer of byte values with given offset (starting position) and length in the provided data buffer. * - * NOTE: The buffer's internal position tracking is no + * NOTE: The buffer's internal position tracking is not * used but rather only the explicit offset and * length provided. If the requested length is * greater than the buffers capacity (minus offset) @@ -483,6 +483,14 @@ default int write(Charset charset, Collection data) throws IOException { /** * Writes an ASCII based character buffer with a given offset and length. * + * NOTE: The buffer's internal position tracking is not + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only read the number of + * characters up to the buffers' available space. + * * @param buffer ASCII character buffer used for data write * @param offset offset in data character array to start at * @param length number of character in character array to be written @@ -496,6 +504,14 @@ default int write(CharBuffer buffer, int offset, int length) throws IOException /** * Writes an ASCII based character buffer starting at first index to a given length. * + * NOTE: The contents from the character buffer is read + * from the current position index up to the length + * requested or up to the buffer's remaining limit; + * whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we + * will automatically flip the buffer to begin reading + * data from the zero position up to the buffer's limit. + * * @param buffer ASCII character buffer used for data write * @param length number of character in character array to be written * @return The number of bytes (not characters) written, possibly zero @@ -508,6 +524,14 @@ default int write(CharBuffer buffer, int length) throws IOException { /** * Writes an ASCII based character buffer. * + * NOTE: The contents from the character buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param buffer ASCII character buffer used for data write * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error @@ -519,6 +543,14 @@ default int write(CharBuffer buffer) throws IOException { /** * Writes multiple ASCII based character buffers. * + * NOTE: The contents from each character buffer is read + * from the current position index up to the buffer's + * remaining limit. If the buffer's current position + * is already at the buffer's limit, then we will + * automatically flip the buffer to begin reading + * data from the zero position up to the buffer's + * limit. + * * @param buffer ASCII character buffer used for data write * @return The number of bytes (not characters) written, possibly zero * @throws IOException thrown on write error @@ -531,7 +563,7 @@ default int write(CharBuffer ... buffer) throws IOException { * Writes a character buffer with a given offset and length * using a specified character set to encode the chars into bytes. * - * NOTE: The buffer's internal position tracking is no + * NOTE: The buffer's internal position tracking is not * used but rather only the explicit offset and * length provided. If the requested length is * greater than the buffers capacity (minus offset) diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java index 4b817cdaf..dead46ced 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java +++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java @@ -57,6 +57,14 @@ default int address(){ */ void writeWord(int word) throws IOException; + /** + * Read a single word value (16-bit) to the I2C device register. + * + * @return If success, then returns 16-bit word value read from I2C register; else a negative error code. + * @throws IOException thrown on write error + */ + int readWord() throws IOException, IOReadException; + /** * Write a single word value (16-bit) to the I2C device register * and immediately reads back a 16-bit word value. diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReader.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReader.java index d4ff983eb..55da959f3 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReader.java +++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReader.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -46,67 +47,938 @@ */ public interface I2CRegisterDataReader { - // ------------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + // SINGLE BYTE + // ------------------------------------------------------------------------------------ + /** + * Read a single raw byte (8-bit) value from an I2C device register. + * + * @param register The I2C device register address to write to. + * @return If successful, a zero or positive integer value representing the byte value (0-255) + * is returned. If a read error was encountered, a negative error code may be returned. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ int readRegister(int register) throws IOException; - int readRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException; - // ------------------------------------------------------------------------------------------------------------ - default int readRegister(int register, byte[] buffer, int offset, int length) throws IOException{ - ByteBuffer bb = ByteBuffer.wrap(buffer); - return readRegister(register, bb, offset, length); - } + // ------------------------------------------------------------------------------------ + // BYTE ARRAY + // ------------------------------------------------------------------------------------ + + /** + * Read data from the I2C device register into the provided byte array at the given + * offset and up to the specified data length (number of bytes). + * + * @param register The I2C device register address to write to. + * @param buffer the byte array/buffer the read data will be copied/inserted into + * @param offset the offset index in the data buffer to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + int readRegister(int register, byte[] buffer, int offset, int length) throws IOException; + + /** + * Read data from the I2C device register into the provided byte array starting at the zero + * index (first byte) and up to the specified data length (number of bytes). + * + * @param register The I2C device register address to write to. + * @param buffer the byte array/buffer the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int readRegister(int register, byte[] buffer, int length) throws IOException{ return readRegister(register, buffer, 0, length); } + + /** + * Read data from the I2C device register into the provided byte array starting at the zero + * index (first byte) and up to the available space in the buffer. + * + * @param register The I2C device register address to write to. + * @param buffer the byte array/buffer the read data will be copied/inserted into + * @return If successful, return the number of bytes read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int readRegister(int register, byte[] buffer) throws IOException{ - return readRegister(register, buffer, 0, buffer.length); + return readRegister(register, buffer, buffer.length); + } + + + // ------------------------------------------------------------------------------------ + // BYTE BUFFER + // ------------------------------------------------------------------------------------ + + /** + * Read data from the I2C device register into the provided byte buffer at the given + * offset and up to the specified data length (number of bytes). + * + * NOTE: The buffer's internal position tracking is not + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only write the number of + * bytes up to the buffers' available space. + * + * @param register The I2C device register address to write to. + * @param buffer the byte buffer the read data will be copied/inserted into + * @param offset the offset index in the data buffer to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException{ + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } + + // create a temporary byte array to read in the length of data bytes + byte[] temp = new byte[length]; + int actualLength = readRegister(register, temp, 0 ,length); + + // return any error codes ( < 0) + if(actualLength < 0) return actualLength; + + // perform bounds checking on number of bytes read versus the length requested + if(actualLength < length) length = actualLength; + + // copy the data from the temporary byte array into the return buffer at the given offset + buffer.position(offset); + buffer.put(temp, 0, length); + + // return actual number of bytes read + return length; } + + /** + * Read data from the I2C device register into the provided byte buffer starting + * with the first byte in the array up to the provided length. + * + * NOTE: The data bytes read from the I2C device register are copied/ + * inserted into the byte buffer starting at the current + * position index up to the length requested or up to the + * buffer's remaining limit; whichever is is lower . If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param register The I2C device register address to write to. + * @param buffer the byte buffer the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int readRegister(int register, ByteBuffer buffer, int length) throws IOException{ - return readRegister(register, buffer, 0, length); + // if the buffer position is already at the buffer limit, then rewind the buffer for + // writing new data into the buffer read from the I/O device + if(buffer.position() == buffer.limit()) buffer.rewind(); + + // bounds check the requested length; only allow reading up to the remaining space in the buffer + if(length > buffer.remaining()) length = buffer.remaining(); + + // read the buffer starting at the current position up the the specified length + return readRegister(register, buffer, buffer.position(), length); } + + /** + * Read data from the I2C device register into the provided byte buffer starting with + * the first byte in the array up to available space remaining in the buffer. + * + * NOTE: The data bytes read from the I2C device register are copied/ + * inserted into the byte buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param register The I2C device register address to write to. + * @param buffer byte buffer of data where data read from the I2C device + * register will be copied (from current position to limit) + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ default int readRegister(int register, ByteBuffer buffer) throws IOException{ - return readRegister(register, buffer, 0, buffer.capacity()); + // if the buffer position is already at the buffer limit, then rewind the buffer for + // writing new data into the buffer read from the I/O device + if(buffer.position() == buffer.limit()) buffer.rewind(); + + // read the buffer starting at the current position and fill up to the remaining size + return readRegister(register, buffer, buffer.position(), buffer.remaining()); } - // ------------------------------------------------------------------------------------------------------------ - default String readRegisterString(int register, int length) throws IOException, IOReadException { - return readRegisterString(register, length, StandardCharsets.US_ASCII); + // ------------------------------------------------------------------------------------ + // CHAR ARRAY + // ------------------------------------------------------------------------------------ + + /** + * Read character data from the I2C device register into the provided character array at the given + * offset and up to the specified data length (number of characters). Specify the character + * set to be used to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @param offset the offset index in the character array to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, Charset charset, char[] buffer, int offset, int length) throws IOException{ + // determine the maximum number of bytes that may be needed for this character set + // and create a byte array to temporarily read the raw data from the I/O device + int maxBytes = (int)charset.newDecoder().maxCharsPerByte() * length; + byte[] rx = new byte[maxBytes]; + + // read data from I/O device into temporary byte buffer + int actualLength = readRegister(register, rx, maxBytes); + + // return any error codes ( < 0) + if(actualLength < 0) return actualLength; + + // decode byte array into char buffer + CharBuffer cb = charset.decode(ByteBuffer.wrap(rx)); + + // perform bounds checking on number of bytes read versus the length requested + if(actualLength < length) length = actualLength; + + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.length-offset)){ + length = buffer.length-offset; + } + + // stuff the decoded characters into the provided char array + cb.get(buffer, offset, length); + + // return number of characters put into the array + return length; } - default String readRegisterString(int register, int length, Charset charset) throws IOException, IOReadException { - byte[] temp = new byte[length]; - int actual = readRegister(register, temp, 0, length); - if(actual < 0) throw new IOReadException(actual); - return new String(temp, 0, actual, charset); + /** + * Read data from the I2C device register into the provided character array starting + * with the first byte in the array up to the provided length. Specify the + * character set to be used to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, Charset charset, char[] buffer, int length) throws IOException{ + return readRegister(register, buffer, 0, length); + } + + /** + * Read data from the I2C device register into the provided character array starting at the zero + * index (first byte) and up to the available space in the buffer/array. Specify the + * character set to be used to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, Charset charset, char[] buffer) throws IOException{ + return readRegister(register, buffer, buffer.length); + } + + /** + * Read ASCII character data from the I2C device register into the provided character array at + * the given offset and up to the specified data length (number of characters). + * ASCII is the internal character set used to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param buffer the character array the read data will be copied/inserted into + * @param offset the offset index in the character array to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, char[] buffer, int offset, int length) throws IOException{ + return readRegister(register, StandardCharsets.US_ASCII, buffer, offset, length); + } + + /** + * Read ASCII data from the I2C device register into the provided character array starting + * with the first byte in the array up to the provided length. + * ASCII is the internal character set used to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param buffer the character array the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, char[] buffer, int length) throws IOException{ + return readRegister(register, StandardCharsets.US_ASCII, buffer, length); + } + + /** + * Read ASCII data from the I2C device register into the provided character array starting at + * the zero index (first byte) and up to the available space in the buffer/array. + * ASCII is the internal character set used to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, char[] buffer) throws IOException{ + return readRegister(register, StandardCharsets.US_ASCII, buffer, buffer.length); } + + // ------------------------------------------------------------------------------------ + // CHAR BUFFER + // ------------------------------------------------------------------------------------ + + /** + * Read character data from the I2C device register into the provided character buffer starting + * at the zero index (first position) up to the specified data length (number of characters). + * Specify the character set to be used to decode the bytes into chars. + * + * NOTE: The data characters read and decoded from the I2C device register are + * copied/inserted into the character buffer starting at the current + * position index up to the length requested or up to the buffer's + * remaining limit; whichever is is lower . If the buffer's current + * position is already at the buffer's limit, then we will automatically + * rewind the buffer to begin writing data from the zero position up to + * the buffer's limit. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, Charset charset, CharBuffer buffer, int offset, int length) throws IOException{ + // validate length argument + if(length <=0) throw new IOException("Invalid read request; length must be greater than zero."); + + // determine the maximum number of bytes that may be needed for this character set + // and create a byte array to temporarily read the raw data from the I/O device + int maxBytes = (int)charset.newDecoder().maxCharsPerByte() * length; + byte[] rx = new byte[maxBytes]; + + // read data from I/O device into temporary byte buffer + int actualLength = readRegister(register, rx, maxBytes); + + // return any error codes ( < 0) + if(actualLength < 0) return actualLength; + + // decode byte array into char buffer + CharBuffer cb = charset.decode(ByteBuffer.wrap(rx)); + + // perform bounds checking on number of bytes read versus the length requested + if(actualLength < length) length = actualLength; + + // perform bounds checking on requested length versus total remaining size available + if(length > (buffer.capacity()-offset)){ + length = buffer.capacity()-offset; + } + + // set the buffer position to the provided offset index + buffer.position(offset); + + // stuff the decoded characters into the provided CharBuffer + buffer.put(cb.array(), 0, length); + + // return number of characters put into the array + return length; + } + + /** + * Read character data from the I2C device register into the provided character buffer starting + * at the zero index (first position) up to available space remaining in the buffer. + * Specify the character set to be used to decode the bytes into chars. + * + * NOTE: The data characters read from the I2C device register are copied/ + * inserted into the character buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes (not characters) read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, Charset charset, CharBuffer buffer, int length) throws IOException{ + // if the buffer position is already at the buffer limit, then rewind the buffer for reading + if(buffer.position() == buffer.limit()) buffer.rewind(); + + return readRegister(register, buffer, buffer.position(), length); + } + + /** + * Read character data from the I2C device register into the provided character buffer starting + * at the zero index (first position) up to available space remaining in the buffer. + * Specify the character set to be used to decode the bytes into chars. + * + * NOTE: The data characters read from the I2C device register are copied/ + * inserted into the character buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes (not characters) read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, Charset charset, CharBuffer buffer) throws IOException{ + // if the buffer position is already at the buffer limit, then rewind the buffer for reading + if(buffer.position() == buffer.limit()) buffer.rewind(); + + // read the buffer starting at the current position and fill up to the remaining size + return readRegister(register, buffer, buffer.position(), buffer.remaining()); + } + + /** + * Read ASCII character data from the I/O device into the provided character buffer at the given + * offset and up to the specified data length (number of characters). ASCII is the internal + * character set used to decode the bytes into chars. + * + * NOTE: The buffer's internal position tracking is not + * used but rather only the explicit offset and + * length provided. If the requested length is + * greater than the buffers capacity (minus offset) + * then the specified length will be ignored and + * this function will only write the number of + * characters up to the buffers' available space. + * + * @param buffer the character array the read data will be copied/inserted into + * @param offset the offset index in the character buffer to start copying read data + * @param length the number of bytes to read + * @return If successful, return the number of bytes (not characters) read from the I/O device; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I/O device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, CharBuffer buffer, int offset, int length) throws IOException{ + return readRegister(register, StandardCharsets.US_ASCII, buffer, offset, length); + } + + /** + * Read ASCII character data from the I2C device register into the provided character buffer + * starting at the zero index (first position) up to available space remaining in the buffer. + * ASCII is the internal character set used to decode the bytes into chars. + * + * NOTE: The data characters read from the I2C device register are copied/ + * inserted into the character buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param register The I2C device register address to write to. + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes (not characters) read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, CharBuffer buffer, int length) throws IOException{ + return readRegister(register, StandardCharsets.US_ASCII, buffer, length); + } + + /** + * Read ASCII character data from the I2C device register into the provided character buffer + * starting at the zero index (first position) up to available space remaining in the buffer. + * ASCII is the internal character set used to decode the bytes into chars. + * + * NOTE: The data characters read from the I2C device register are copied/ + * inserted into the character buffer starting at the current + * position index up to the buffer's remaining limit. If + * the buffer's current position is already at the buffer's + * limit, then we will automatically rewind the buffer to + * begin writing data from the zero position up to the + * buffer's limit. + * + * @param register The I2C device register address to write to. + * @param buffer the character array the read data will be copied/inserted into + * @return If successful, return the number of bytes (not characters) read from the I2C device register; + * else on a read error, return a negative error code. + * @throws IOException In some cases, a IOException may be thrown if there is something wrong + * with the I2C device or communication path. Typical read access errors + * are returned as negative return values and not exception. + */ + default int readRegister(int register, CharBuffer buffer) throws IOException{ + return readRegister(register, StandardCharsets.US_ASCII, buffer); + } + + + // ------------------------------------------------------------------------------------ + // AUXILIARY CONVENIENCE METHODS + // ------------------------------------------------------------------------------------ + + /** + * Read a single raw byte (8-bit) value from an I2C device register. + * + * @param register The I2C device register address to write to. + * @return The 8-bit byte value + * @throws IOException In all error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + */ default byte readRegisterByte(int register) throws IOException, IOReadException { int actual = readRegister(register); if(actual < 0) throw new IOReadException(actual); return (byte)actual; } + /** + * Read a single raw word (2-byte; 16-bit) value from an I2C device register. + * + * @param register The I2C device register address to write to. + * @return The 16-bit (2-byte) word value + * @throws IOException In all error conditions, an IOException will be thrown if there is + * something wrong with the I/O device or communication path or for any + * read access errors encountered. + */ default int readRegisterWord(int register) throws IOException, IOReadException { - byte[] buffer= new byte[2]; + byte[] buffer = new byte[2]; int actual = readRegister(register, buffer); if(actual < 2) throw new IOReadException(actual); return ((buffer[0] & 0xff) << 8) | (buffer[1] & 0xff); } - default ByteBuffer readRegisterBuffer(int register, int length) throws IOException, IOReadException { + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new byte array. The 'offset' parameter allows you to skip + * a certain number of bytes in the read data and exclude them from the returned + * data byte array. + * + * Note: the resulting byte array size will be at most the 'length' - 'offset'. + * + * @param register The I2C device register address to write to. + * @param offset the offset index in the data read to start copying read data + * @param length the number of bytes to read + * @return a new byte array containing the data bytes read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default byte[] readRegisterNBytes(int register, int offset, int length) throws IOException, IOReadException { + if (length <= 0) { + throw new IllegalArgumentException("length <= 0"); + } + if (offset < 0) { + throw new IllegalArgumentException("offset < 0"); + } + if (length < offset) { + throw new IllegalArgumentException("length < offset"); + } + int maxLength = offset+length; + byte[] temp = new byte[maxLength]; + int actual = readRegister(register, temp, offset, maxLength); + if(actual < 0) throw new IOReadException(actual); + return Arrays.copyOf(temp, actual); + } + + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new byte array. + * + * @param register The I2C device register address to write to. + * @param length the number of bytes to read + * @return a new byte array containing the data bytes read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default byte[] readRegisterNBytes(int register, int length) throws IOException, IOReadException { + return readRegisterNBytes(register, 0, length); + } + + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new ByteBuffer. The 'offset' parameter allows you to skip + * a certain number of bytes in the read data and excludes them from the returned + * data ByteBuffer. + * + * Note: the resulting byte buffer size will be at most the 'length' - 'offset'. + * + * @param register The I2C device register address to write to. + * @param offset the offset index in the data read to start copying read data + * @param length the number of bytes to read + * @return a new ByteBuffer containing the data bytes read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default ByteBuffer readRegisterByteBuffer(int register, int offset, int length) throws IOException, IOReadException { + if (length <= 0) { + throw new IllegalArgumentException("length <= 0"); + } + if (offset < 0) { + throw new IllegalArgumentException("offset < 0"); + } + if (length < offset) { + throw new IllegalArgumentException("length < offset"); + } byte[] temp = new byte[length]; - int actual = readRegister(register, temp, 0, length); + int actual = readRegister(register, temp, offset, length); if(actual < 0) throw new IOReadException(actual); return ByteBuffer.wrap(temp, 0, actual); } - default byte[] readRegisterArray(int register, int length) throws IOException, IOReadException { + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new ByteBuffer. The 'offset' parameter allows you to skip + * a certain number of bytes in the read data and excludes them from the returned + * data ByteBuffer. + * + * @param register The I2C device register address to write to. + * @param length the number of bytes to read + * @return a new ByteBuffer containing the data bytes read from the I2C device register. + * @throws IOException In most error conditions, I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default ByteBuffer readRegisterByteBuffer(int register, int length) throws IOException, IOReadException { byte[] temp = new byte[length]; int actual = readRegister(register, temp, 0, length); if(actual < 0) throw new IOReadException(actual); - return Arrays.copyOf(temp, actual); + return ByteBuffer.wrap(temp, 0, actual); + } + + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new character array. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character array. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readRegisterCharArray(int register, Charset charset, int offset, int numberOfBytes) throws IOException, IOReadException { + byte[] temp = new byte[numberOfBytes]; + int actual = readRegister(register, temp, offset, numberOfBytes); + if(actual < 0) throw new IOReadException(actual); + CharBuffer cb = charset.decode(ByteBuffer.wrap(temp, 0, actual)); + return cb.array(); + } + + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new character array. + * + * @param register The I2C device register address to write to. + * @param charset character set to use for byte decoding + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readRegisterCharArray(int register, Charset charset, int numberOfBytes) throws IOException, IOReadException { + return readRegisterCharArray(register, charset, 0, numberOfBytes); + } + + /** + * Read ASCII data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new character array. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character array. ASCII is the internal character set used to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readRegisterCharArray(int register, int offset, int numberOfBytes) throws IOException, IOReadException { + return readRegisterCharArray(register, StandardCharsets.US_ASCII, offset, numberOfBytes); + } + + /** + * Read ASCII data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new character array. ASCII is the internal character set used + * to decode the bytes into chars. + * + * @param register The I2C device register address to write to. + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character array containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default char[] readRegisterCharArray(int register, int numberOfBytes) throws IOException, IOReadException { + return readRegisterCharArray(register, 0, numberOfBytes); + } + + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character array. + * + * @param charset character set to use for byte decoding + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readRegisterCharBuffer(int register, Charset charset, int offset, int numberOfBytes) throws IOException, IOReadException { + byte[] temp = new byte[numberOfBytes]; + int actual = readRegister(register, temp, offset, numberOfBytes); + if(actual < 0) throw new IOReadException(actual); + CharBuffer cb = charset.decode(ByteBuffer.wrap(temp, 0, actual)); + return cb.flip(); + } + + /** + * Read data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. + * + * @param charset character set to use for byte decoding + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readRegisterCharBuffer(int register, Charset charset, int numberOfBytes) throws IOException, IOReadException { + return readRegisterCharBuffer(register, charset, 0, numberOfBytes); + } + + /** + * Read ASCII data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * character array. ASCII is the internal character set used to decode the bytes into chars. + * + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readRegisterCharBuffer(int register, int offset, int numberOfBytes) throws IOException, IOReadException { + return readRegisterCharBuffer(register, StandardCharsets.US_ASCII, offset, numberOfBytes); + } + + /** + * Read ASCII data from the I2C device register up to a specified length (number of bytes) and + * return the data read in a new CharBuffer instance. ASCII is the internal character set used + * to decode the bytes into chars. + * + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default CharBuffer readRegisterCharBuffer(int register, int numberOfBytes) throws IOException, IOReadException { + return readRegisterCharBuffer(register, 0, numberOfBytes); + } + + /** + * Read data from the I2C device registere up to a specified length (number of bytes) and + * return the data read in a new String instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * string. + * + * @param charset character set to use for byte decoding + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readRegisterString(int register, Charset charset, int offset, int numberOfBytes) throws IOException, IOReadException { + byte[] temp = new byte[numberOfBytes]; + int actual = readRegister(register, temp, 0, numberOfBytes); + if(actual < 0) throw new IOReadException(actual); + return new String(temp, 0, actual, charset); + } + + /** + * Read data from the I2C device registere up to a specified length (number of bytes) and + * return the data read in a new String instance. + * + * @param charset character set to use for byte decoding + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readRegisterString(int register, Charset charset, int numberOfBytes) throws IOException, IOReadException { + return readRegisterString(register, charset, 0, numberOfBytes); + } + + /** + * Read ASCII data from the I2C device registere up to a specified length (number of bytes) and + * return the data read in a new String instance. The 'offset' parameter allows you to + * skip a certain number of bytes in the read data and excludes them from the returned + * string. ASCII is the internal character set used to decode the bytes into chars. + * + * @param offset the offset index in the raw bytes read to start from + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readRegisterString(int register, int offset, int numberOfBytes) throws IOException, IOReadException { + return readRegisterString(register, StandardCharsets.US_ASCII, offset, numberOfBytes); + } + + /** + * Read ASCII data from the I2C device registere up to a specified length (number of bytes) and + * return the data read in a new String instance. ASCII is the internal character set used to + * decode the bytes into chars. + * + * @param numberOfBytes the number of bytes to read (not number of characters) + * @return a new character buffer (CharBuffer) containing the decoded character data read from the I2C device register. + * @throws IOException In most error conditions, an IOException will be thrown if there is + * something wrong with the I2C device or communication path or for any + * read access errors encountered. + * @throws IOReadException An IOReadException is thrown if a read access error code + * is returned from the underlying read() functions. + * @throws IllegalArgumentException An IllegalArgumentException is thrown if one of the + * method parameters are invalid. + */ + default String readRegisterString(int register, int numberOfBytes) throws IOException, IOReadException { + return readRegisterString(register, 0, numberOfBytes); } } diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java index 0b6b61e75..7e9982652 100644 --- a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java +++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java @@ -95,7 +95,7 @@ public int read(byte[] buffer, int offset, int length) throws IOException { } @Override - public String readString(int length, Charset charset) throws IOException, IOReadException { - return this.i2c.readRegisterString(this.address, length, charset); + public String readString(Charset charset, int length) throws IOException, IOReadException { + return this.i2c.readRegisterString(this.address, charset, length); } } diff --git a/pi4j-example/src/main/java/com/pi4j/example/Main.java b/pi4j-example/src/main/java/com/pi4j/example/Main.java index 7ef0735e1..aee12d91c 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/Main.java +++ b/pi4j-example/src/main/java/com/pi4j/example/Main.java @@ -27,56 +27,109 @@ */ import com.pi4j.Pi4J; -import com.pi4j.io.gpio.analog.AnalogChangeListener; -import com.pi4j.io.gpio.analog.binding.AnalogBindingSync; +import com.pi4j.io.serial.Baud; +import com.pi4j.io.serial.Serial; +import com.pi4j.plugin.pigpio.provider.serial.PiGpioSerialProvider; + +import java.nio.CharBuffer; +import java.util.Arrays; public class Main { + private static String SERIAL_DEVICE = "/dev/ttyS0"; + private static int BAUD_RATE = Baud._38400.value(); + public Main() { } public static void main(String[] args) throws Exception { + // TODO :: REMOVE TEMPORARY PROPERTIES WHEN NATIVE PIGPIO LIB IS READY + // this temporary property is used to tell + // PIGPIO which remote Raspberry Pi to connect to + System.setProperty("pi4j.host", "rpi3bp.savage.lan"); + // Initialize Pi4J with an auto context // An auto context includes AUTO-DETECT BINDINGS enabled // which will load all detected Pi4J extension libraries // (Platforms and Providers) in the class path var pi4j = Pi4J.newAutoContext(); + // create SERIAL config + var config = Serial.newConfigBuilder() + .id("my-serial-port") + .name("My Serial Port") + .device(SERIAL_DEVICE) + .baud8N1(BAUD_RATE) + .build(); -// Serial serial = Serial.instance("/dev/ttyUSB1"); -// serial.open(); -// serial.send("TEST DATA"); -// serial.close(); + var prov = pi4j.provider(PiGpioSerialProvider.class); + var serial = prov.create(config); + + System.out.println("--------------------------------------------------------"); + + serial.write("HELLO"); + CharBuffer b = CharBuffer.allocate(10); + b.put("1234567890"); + serial.read(b.array(), 4, 65); + System.out.println("CHAR ARRAY : " + Arrays.toString(b.array())); + System.out.println(b.rewind().toString()); - var din1 = pi4j.din().create(11); - var ain1 = pi4j.ain().create(21); + System.out.println("--------------------------------------------------------"); - var input = pi4j.ain().create(98); - var output1 = pi4j.aout().create(99); - var output2 = pi4j.aout().create(100); + serial.write("HELLO"); + char[] ca = new char[]{ '0','1','2','3','4', '5', '6', '7', '8', '9' }; - input.addListener((AnalogChangeListener) event -> { - System.out.print(event); - }); + CharBuffer c = CharBuffer.wrap(ca); + //c.put("123456789"); + //c.append("Z"); + c.put("-R-"); + //c.rewind(); + System.out.println(c.remaining()); + serial.read(c); + System.out.println("CHAR BUFFER : " + Arrays.toString(c.array())); + System.out.println(c.rewind().toString()); - output1.addListener((AnalogChangeListener) event -> { - System.out.println(event); - }); - output2.addListener((AnalogChangeListener) event -> { - System.out.println(event); - }); + System.out.println("--------------------------------------------------------"); - input.bind(new AnalogBindingSync(output1, output2)); + + + serial.close(); + + +// Serial serial = Serial.instance("/dev/ttyUSB1"); +// serial.open(); +// serial.send("TEST DATA"); +// serial.close(); +// +// var din1 = pi4j.din().create(11); +// var ain1 = pi4j.ain().create(21); +// +// var input = pi4j.ain().create(98); +// var output1 = pi4j.aout().create(99); +// var output2 = pi4j.aout().create(100); +// +// input.addListener((AnalogChangeListener) event -> { +// System.out.print(event); +// }); +// +// output1.addListener((AnalogChangeListener) event -> { +// System.out.println(event); +// }); +// output2.addListener((AnalogChangeListener) event -> { +// System.out.println(event); +// }); +// +// input.bind(new AnalogBindingSync(output1, output2)); //((TestAnalogInput)input).test(21).test(22).test(23); - output1.value(12); - output1.setValue(78); - output1.value(0x01); +// output1.value(12); +// output1.setValue(78); +// output1.value(0x01); //AnalogOutput aout1 = AnalogOutput.in diff --git a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cDeviceExample.java b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cDeviceExample.java index dce6607d4..86d576068 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cDeviceExample.java +++ b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cDeviceExample.java @@ -91,14 +91,14 @@ public static void main(String[] args) throws Exception { register.write(new byte[] { 0,1,2,3,4,5,6,7,8,9 }); // <-- read a byte array of specified length from the I2C device register - byte[] readArray = register.readArray(10); + byte[] readArray = register.readNBytes(10); // --> write a buffer of data bytes to the I2C device register ByteBuffer buffer = ByteBuffer.allocate(10); register.write(buffer); // <-- read ByteBuffer of specified length from the I2C device register - ByteBuffer readBuffer = register.readBuffer(10); + ByteBuffer readBuffer = register.readByteBuffer(10); // --> write a string of data to the I2C device register register.write("This is a test"); diff --git a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java index 40454474b..91aaea168 100644 --- a/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java +++ b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java @@ -80,14 +80,14 @@ public static void main(String[] args) throws Exception { i2c.write(new byte[] { 0,1,2,3,4,5,6,7,8,9 }); // <-- read a byte array of specified length from the raw I2C device (not to a register) - byte[] readArray = i2c.readArray(10); + byte[] readArray = i2c.readNBytes(10); // --> write a buffer of data bytes to the raw I2C device (not to a register) ByteBuffer buffer = ByteBuffer.allocate(10); i2c.write(buffer); // <-- read ByteBuffer of specified length from the raw I2C device (not to a register) - ByteBuffer readBuffer = i2c.readBuffer(10); + ByteBuffer readBuffer = i2c.readByteBuffer(10); // --> write a string of data to the raw I2C device (not to a register) i2c.write("This is a test"); diff --git a/pi4j-test/src/test/java/com/pi4j/test/io/serial/SerialDataTest.java b/pi4j-test/src/test/java/com/pi4j/test/io/serial/SerialDataTest.java new file mode 100644 index 000000000..3d82278b6 --- /dev/null +++ b/pi4j-test/src/test/java/com/pi4j/test/io/serial/SerialDataTest.java @@ -0,0 +1,377 @@ +package com.pi4j.test.io.serial; + +/*- + * #%L + * ********************************************************************** + * ORGANIZATION : Pi4J + * PROJECT : Pi4J :: TESTING :: Unit/Integration Tests + * FILENAME : SerialDataTest.java + * + * This file is part of the Pi4J project. More information about + * this project can be found here: https://pi4j.com/ + * ********************************************************************** + * %% + * Copyright (C) 2012 - 2019 Pi4J + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.pi4j.Pi4J; +import com.pi4j.context.Context; +import com.pi4j.exception.LifecycleException; +import com.pi4j.io.serial.Serial; +import com.pi4j.plugin.mock.provider.serial.MockSerialProvider; +import org.junit.Assert; +import org.junit.jupiter.api.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; + +import static org.junit.Assert.assertNotNull; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class SerialDataTest { + + private static Context pi4j; + private static Serial serial; + private static String SERIAL_DEVICE = "mock-serial-port"; + + private static byte SAMPLE_BYTE = 0x0d; + private static byte[] SAMPLE_BYTE_ARRAY = new byte[] { 0,1,2,3,4,5,6,7,8,9 }; + private static char[] SAMPLE_CHAR_ARRAY = new char[] { '0','1','2','3','4','5','6','7','8','9' }; + private static byte[] SAMPLE_BUFFER_ARRAY = new byte[] { 10,11,12,13,14,15,16,17,18,19 }; + private static ByteBuffer SAMPLE_BUFFER = ByteBuffer.wrap(SAMPLE_BUFFER_ARRAY); + private static String SAMPLE_STRING = "Hello World!"; + + @BeforeAll + public static void beforeAllTests() throws Exception { + // Initialize Pi4J with Mock Serial Provider only + pi4j = Pi4J.newContextBuilder() + .add(MockSerialProvider.newInstance()) + .build(); + + // create serial instance + serial = pi4j.create(Serial.newConfigBuilder() + .id("my-i2c-bus") + .device(SERIAL_DEVICE) + .build()); + } + + @AfterAll + public static void afterAllTests() throws IOException, LifecycleException { + // close serial port + if(serial.isOpen()) serial.close(); + + // shutdown Pi4J context + pi4j.shutdown(); + } + + // -------------------------------------------------------------------- + // WRITE TESTS + // -------------------------------------------------------------------- + + @DisplayName("SERIAL :: Verify Serial Instance") + @Order(1) + @Test + public void testSerialInstance() throws Exception { + + // ensure that the serial instance is not null; + assertNotNull(serial); + } + + @DisplayName("SERIAL :: Write Single Byte") + @Order(2) + @Test + public void writeByte() throws Exception { + // write a single byte to the serial device + serial.write(SAMPLE_BYTE); + } + + + @DisplayName("SERIAL :: Write Byte Array") + @Order(3) + @Test + public void writeByteArray() throws Exception { + // write an array of bytes to the serial device + serial.write(SAMPLE_BYTE_ARRAY); + } + + @DisplayName("SERIAL :: Write Byte Buffer") + @Order(4) + @Test + public void writeByteBuffer() throws Exception { + // write a buffer of data bytes to the serial device. + serial.write(SAMPLE_BUFFER); + } + + @DisplayName("SERIAL :: Write ASCII String") + @Order(5) + @Test + public void writeString() throws Exception { + // write a string of data to the serial device. + serial.write(SAMPLE_STRING); + } + + @DisplayName("SERIAL :: Write Byte Stream") + @Order(6) + @Test + public void writeStream() throws Exception { + // write a stream to the serial device + ByteArrayInputStream bis = new ByteArrayInputStream(SAMPLE_BYTE_ARRAY); + serial.write(bis); + } + + @DisplayName("SERIAL :: Write Output Stream") + @Order(7) + @Test + public void writeOutStream() throws Exception { + // write directly to the output stream of the serial device + serial.out().write(SAMPLE_BYTE_ARRAY); + } + + @DisplayName("SERIAL :: Write Char Array") + @Order(9) + @Test + public void writeCharArray() throws Exception { + // write char array to the serial device + serial.write(SAMPLE_CHAR_ARRAY); + } + + // -------------------------------------------------------------------- + // READ TESTS + // -------------------------------------------------------------------- + + @DisplayName("SERIAL :: Read Single Byte") + @Order(11) + @Test + public void readByte() throws Exception { + // read single byte from serial device and check for expected value + byte b = (byte)serial.read(); + Assert.assertEquals(SAMPLE_BYTE, b); + } + + @DisplayName("SERIAL :: Read Byte Array") + @Order(12) + @Test + public void readByteArray() throws Exception { + // read an array of data bytes from the serial device and check for expected value + byte byteArray[] = new byte[SAMPLE_BYTE_ARRAY.length]; + serial.read(byteArray, 0, byteArray.length); + Assert.assertArrayEquals(SAMPLE_BYTE_ARRAY, byteArray); + } + + @DisplayName("SERIAL :: Read Byte Buffer") + @Order(13) + @Test + public void readByteBuffer() throws Exception { + // read a buffer of data bytes from the serial device and check for expected value + ByteBuffer buffer = ByteBuffer.allocate(SAMPLE_BUFFER.capacity()); + serial.read(buffer, 0, buffer.capacity()); + Assert.assertArrayEquals(SAMPLE_BUFFER_ARRAY, buffer.array()); + } + + @DisplayName("SERIAL :: Read ASCII String") + @Order(14) + @Test + public void readString() throws Exception { + // read a string of data from the serial device and check for expected value + String testString = serial.readString(SAMPLE_STRING.length()); + Assert.assertEquals(SAMPLE_STRING, testString); + } + + @DisplayName("SERIAL :: Read Byte Stream") + @Order(15) + @Test + public void readStream() throws Exception { + // read a stream of data from the serial device and check for expected value + byte[] byteArray = new byte[SAMPLE_BYTE_ARRAY.length]; + serial.read(byteArray); + Assert.assertArrayEquals(SAMPLE_BYTE_ARRAY, byteArray); + } + + @DisplayName("SERIAL :: Read Input Stream") + @Order(16) + @Test + public void readInputStream() throws Exception { + // read the input stream directly from serial device and check for expected value + InputStream is = serial.in(); + byte[] byteArray = new byte[SAMPLE_BYTE_ARRAY.length]; + is.read(byteArray, 0, byteArray.length); + Assert.assertArrayEquals(SAMPLE_BYTE_ARRAY, byteArray); + } + + @DisplayName("SERIAL :: Read Char Array") + @Order(17) + @Test + public void readCharArray() throws Exception { + // read an array of data chars from the serial device and check for expected value + char charArray[] = new char[SAMPLE_CHAR_ARRAY.length]; + serial.read(charArray, 0, charArray.length); + Assert.assertArrayEquals(SAMPLE_CHAR_ARRAY, charArray); + } + + // -------------------------------------------------------------------- + // BUFFER WRITE/READ TESTS + // -------------------------------------------------------------------- + + @DisplayName("SERIAL :: Write/Read Char Buffer (1)") + @Order(21) + @Test + public void readCharBuffer1() throws Exception { + + // drain any existing data in the serial RX buffer + serial.drain(); + + // write sample data + serial.write("HELLO"); + + // create char buffer to hold read data + CharBuffer buffer = CharBuffer.allocate(10); + buffer.put("1234567890"); + buffer.rewind(); + + // read data into char buffer using explicit offset in data + serial.read(buffer, 2, 5); + Assert.assertEquals("12HELLO890", buffer.rewind().toString()); + + } + + @DisplayName("SERIAL :: Write/Read Char Buffer (2)") + @Order(22) + @Test + public void readCharBuffer2() throws Exception { + + // drain any existing data in the serial RX buffer + serial.drain(); + + // create a character buffer from the sample data array + char[] charArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; + CharBuffer charBuffer = CharBuffer.wrap(charArray); + + // change char at explicit index; this should not change buffer position + charBuffer.put(5, '#'); + + // write 3 chars into the buffer from position 0 + // this will offset the buffer position by 3 + charBuffer.put("---"); + + // write sample data; should be "34#67890ABCDEFGHIJ" + serial.write(charBuffer); + + // create char buffer to hold read data + CharBuffer readBuffer = CharBuffer.allocate(14); + + // add some initial chars to the buffer which will create an offset of 2 + readBuffer.put("**"); + + // read data into char buffer using explicit offset in data + serial.read(readBuffer); + Assert.assertEquals("**34#6789ABCDE", readBuffer.rewind().toString()); + } + + @DisplayName("SERIAL :: Write/Read Byte Buffer (1)") + @Order(23) + @Test + public void readByteBuffer1() throws Exception { + + // drain any existing data in the serial RX buffer + serial.drain(); + + // write sample data + serial.write("HELLO"); + + // create char buffer to hold read data + ByteBuffer buffer = ByteBuffer.allocate(10); + buffer.put("1234567890".getBytes()); + buffer.rewind(); + + // read data into char buffer using explicit offset in data + serial.read(buffer, 2, 5); +// System.out.println("[SAMPLE DATA] - 0x" + StringUtil.toHexString("12HELLO890".getBytes())); +// System.out.println("[READ DATA ] - 0x" + StringUtil.toHexString(buffer)); + Assert.assertArrayEquals("12HELLO890".getBytes(), buffer.array()); + } + + @DisplayName("SERIAL :: Write/Read Byte Buffer (2)") + @Order(24) + @Test + public void readByteBuffer2() throws Exception { + + // drain any existing data in the serial RX buffer + serial.drain(); + + // create a byte buffer for the sample data array + byte[] byteArray = new byte[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + ByteBuffer writeBuffer = ByteBuffer.wrap(byteArray); + + // change byte at explicit index; this should not change buffer position + writeBuffer.put(5, (byte)99); + + // write 3 bytes nto the buffer from position 0 + // this will offset the buffer position by 3 + writeBuffer.put(new byte[] { (byte)0, (byte)0, (byte)0}); + + // write sample data; should be "4,5,99,7,8,9,10,11,12,13,14,15" + serial.write(writeBuffer); + + // create byte buffer to hold read data + ByteBuffer readBuffer = ByteBuffer.allocate(12); + + // add some initial bytes to the buffer which will create an offset of 2 + readBuffer.put((byte)0xFF); + readBuffer.put((byte)0xFF); + + // read data into char buffer using explicit offset in data + serial.read(readBuffer); + + Assert.assertArrayEquals( + new byte[]{ (byte)0xFF, (byte)0xFF, (byte)4, (byte)5, (byte)99, (byte)7, (byte)8, (byte)9, (byte)10, (byte)11, (byte)12, (byte)13 }, + readBuffer.array()); + } + +// @Test +// public void testRawDataStream() throws Exception { +// // create random set of sample data +// Random rand = new Random(); +// byte sample[] = new byte[1024]; +// rand.nextBytes(sample); +// +// // create I2C config +// var config = I2C.newConfigBuilder() +// .id("my-i2c-bus") +// .name("My I2C Bus") +// .bus(I2C_BUS) +// .device(I2C_DEVICE) +// .build(); +// +// // use try-with-resources to auto-close I2C when complete +// try (var i2c = pi4j.i2c().create(config);) { +// +// // write sample data using output stream +// i2c.out().write(sample); +// +// // read sample data using input stream +// byte[] result = i2c.in().readNBytes(sample.length); +// +// System.out.println("[SAMPLE DATA] - 0x" + StringUtil.toHexString(sample)); +// System.out.println("[READ DATA ] - 0x" + StringUtil.toHexString(result)); +// +// // copare sample data against returned read data +// Assert.assertArrayEquals(sample, result); +// } +// } +} diff --git a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java index e1c94aad3..0aa31c3a7 100644 --- a/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java +++ b/plugins/pi4j-plugin-mock/src/main/java/com/pi4j/plugin/mock/provider/i2c/MockI2C.java @@ -38,7 +38,6 @@ import com.pi4j.util.StringUtil; import java.io.IOException; -import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayDeque; import java.util.Objects; @@ -167,7 +166,7 @@ public int read(byte[] buffer, int offset, int length) throws IOException{ } @Override - public String readString(int length, Charset charset) throws IOException{ + public String readString(Charset charset, int length) throws IOException{ if(raw.isEmpty()) return null; byte[] buffer = new byte[length]; for(int p = 0; p < length; p++) { @@ -279,15 +278,15 @@ public int readRegister(int register) throws IOException { } @Override - public int readRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException { + public int readRegister(int register, byte[] buffer, int offset, int length) throws IOException { if(registers[register] == null) return -1; if(registers[register].isEmpty()) return -1; int counter = 0; for(int p = 0; p < length; p++) { - if(p+offset > buffer.capacity()) break; + if(p+offset > buffer.length) break; if(registers[register].isEmpty()) break;; - buffer.put(offset + p, registers[register].pop()); + buffer[offset + p] = registers[register].pop(); counter++; } System.out.print(" ["); @@ -304,7 +303,7 @@ public int readRegister(int register, ByteBuffer buffer, int offset, int length) } @Override - public String readRegisterString(int register, int length, Charset charset) throws IOException { + public String readRegisterString(int register, Charset charset, int length) throws IOException { if(registers[register] == null) return null; if(registers[register].isEmpty()) return null; diff --git a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java index aaa96f193..7a8db9a8f 100644 --- a/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java +++ b/plugins/pi4j-plugin-pigpio/src/main/java/com/pi4j/plugin/pigpio/provider/i2c/PiGpioI2C.java @@ -41,7 +41,6 @@ import com.pi4j.library.pigpio.PiGpioMode; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.Objects; public class PiGpioI2C extends I2CBase implements I2C { @@ -144,8 +143,8 @@ public int readRegister(int register) throws IOException { } @Override - public int readRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException { - Objects.checkFromIndexSize(offset, length, buffer.capacity()); + public int readRegister(int register, byte[] buffer, int offset, int length) throws IOException { + Objects.checkFromIndexSize(offset, length, buffer.length); return piGpio.i2cReadI2CBlockData(this.handle, register, buffer, offset, length); } diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java index cda15b25b..6fd1cca23 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cRawUsingTestHarness.java @@ -193,7 +193,7 @@ public void testI2CByteArrayWrite() throws Exception { @Order(7) public void testI2CByteArrayRead() throws Exception { // read an array of data bytes from the raw I2C device (not from a register) - byte[] byteArray = i2c.readArray(SAMPLE_BYTE_ARRAY.length); + byte[] byteArray = i2c.readNBytes(SAMPLE_BYTE_ARRAY.length); Assert.assertArrayEquals(SAMPLE_BYTE_ARRAY, byteArray); } @@ -210,7 +210,7 @@ public void testI2CByteBufferWrite() throws Exception { @Order(9) public void testI2CByteBufferRead() throws Exception { // read a buffer of data bytes from the raw I2C device (not from a register) - ByteBuffer buffer = i2c.readBuffer(SAMPLE_BUFFER.capacity()); + ByteBuffer buffer = i2c.readByteBuffer(SAMPLE_BUFFER.capacity()); Assert.assertArrayEquals(SAMPLE_BUFFER.array(), buffer.array()); } diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java index fa605390b..59e466667 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/i2c/TestI2cUsingTestHarness.java @@ -296,7 +296,7 @@ public void testI2CByteArrayWriteRead() throws IOException, InterruptedException System.out.println("[TEST READ BYTE-ARRAY] :: REGISTER=" + register.address()); // READ :: BYTE-ARRAY - byte[] value = register.readArray(10); + byte[] value = register.readNBytes(10); byte[] expected = values.get(r); System.out.println(" (READ) << VALUE = " + StringUtil.toHexString(value) + @@ -305,14 +305,14 @@ public void testI2CByteArrayWriteRead() throws IOException, InterruptedException if(!Arrays.equals(expected, value)){ Thread.sleep(500); // READ :: BYTE-BUFFER - register.readArray(10); + register.readNBytes(10); System.out.println(" (READ) << VALUE = " + StringUtil.toHexString(value) + "; (EXPECTED=" + StringUtil.toHexString(expected) + ") "); if(!Arrays.equals(expected, value)){ Thread.sleep(1000); // READ :: BYTE-BUFFER - register.readArray(10); + register.readNBytes(10); System.out.println(" (READ) << VALUE = " + StringUtil.toHexString(value) + "; (EXPECTED=" + StringUtil.toHexString(expected) + ") "); @@ -362,7 +362,7 @@ public void testI2CByteBufferWriteRead() throws IOException, InterruptedExceptio System.out.println("[TEST READ BYTE-BUFFER] :: REGISTER=" + register.address()); // READ :: BYTE-BUFFER - ByteBuffer value = register.readBuffer(10); + ByteBuffer value = register.readByteBuffer(10); ByteBuffer expected = values.get(r); System.out.println(" (READ) << VALUE = " + StringUtil.toHexString(value) + @@ -371,14 +371,14 @@ public void testI2CByteBufferWriteRead() throws IOException, InterruptedExceptio if(!Arrays.equals(expected.array(), value.array())){ Thread.sleep(500); // READ :: BYTE-BUFFER - value = register.readBuffer(10); + value = register.readByteBuffer(10); System.out.println(" (READ) << VALUE = " + StringUtil.toHexString(value) + "; (EXPECTED=" + StringUtil.toHexString(expected) + ") "); if(!Arrays.equals(expected.array(), value.array())){ Thread.sleep(500); // READ :: BYTE-BUFFER - value = register.readBuffer(10); + value = register.readByteBuffer(10); System.out.println(" (READ) << VALUE = " + StringUtil.toHexString(value) + "; (EXPECTED=" + StringUtil.toHexString(expected) + ") "); diff --git a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java index a684eb60f..5911b9737 100644 --- a/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java +++ b/plugins/pi4j-plugin-pigpio/src/test/java/com/pi4j/plugin/pigpio/serial/TestSerialUsingTestHarness.java @@ -214,7 +214,7 @@ public void testSerialByteArrayWrite() throws Exception { @Order(5) public void testSerialByteArrayRead() throws Exception { // read an array of data bytes from the serial device - byte[] byteArray = serial.readArray(SAMPLE_BYTE_ARRAY.length); + byte[] byteArray = serial.readNBytes(SAMPLE_BYTE_ARRAY.length); Assert.assertArrayEquals(SAMPLE_BYTE_ARRAY, byteArray); } @@ -231,7 +231,7 @@ public void testSerialByteBufferWrite() throws Exception { @Order(7) public void testSerialByteBufferRead() throws Exception { // read a buffer of data bytes from the serial device - ByteBuffer buffer = serial.readBuffer(SAMPLE_BUFFER.capacity()); + ByteBuffer buffer = serial.readByteBuffer(SAMPLE_BUFFER.capacity()); Assert.assertArrayEquals(SAMPLE_BUFFER.array(), buffer.array()); } diff --git a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java index c704755a9..4f4a6c37f 100644 --- a/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java +++ b/plugins/pi4j-plugin-raspberrypi/src/main/java/com/pi4j/plugin/raspberrypi/provider/i2c/RpiI2C.java @@ -36,7 +36,6 @@ import com.pi4j.io.i2c.I2CProvider; import java.io.IOException; -import java.nio.ByteBuffer; public class RpiI2C extends I2CBase implements I2C { @@ -70,7 +69,7 @@ public int readRegister(int register) throws IOException { } @Override - public int readRegister(int register, ByteBuffer buffer, int offset, int length) throws IOException { + public int readRegister(int register, byte[] buffer, int offset, int length) throws IOException { return 0; }