' attribute");
+
+ // make sure the field instance is null; we can only register our own dynamically created I/O instances
+ if(field.get(instance) != null)
+ throw new AnnotationException("This @Register annotated instance is not null; it must be NULL " +
+ "to register a new I/O instance. If you just want to access an existing I/O instance, " +
+ "use the '@Inject(id)' annotation instead.");
+
+ // create I/O config builder
+ var builder = Pwm.newConfigBuilder();
+ if (annotation.value() != null) builder.id((annotation).value());
+
+ // test for required additional annotations
+ if (!field.isAnnotationPresent(Address.class))
+ throw new AnnotationException("Missing required '@Address' annotation for this I/O type.");
+
+ // all supported additional annotations for configuring the digital output
+ Address address = field.getAnnotation(Address.class);
+ builder.address(address.value());
+
+ Name name = null;
+ if (field.isAnnotationPresent(Name.class)) {
+ name = field.getAnnotation(Name.class);
+ if (name != null) builder.name(name.value());
+ }
+
+ Description description = null;
+ if (field.isAnnotationPresent(Description.class)) {
+ description = field.getAnnotation(Description.class);
+ if (description != null) builder.description(description.value());
+ }
+
+ ShutdownValue shutdownValue = null;
+ if (field.isAnnotationPresent(ShutdownValue.class)) {
+ shutdownValue = field.getAnnotation(ShutdownValue.class);
+ if (shutdownValue != null) builder.shutdown(shutdownValue.value());
+ }
+
+ InitialValue initialValue = null;
+ if (field.isAnnotationPresent(InitialValue.class)) {
+ initialValue = field.getAnnotation(InitialValue.class);
+ if (initialValue != null) builder.initial(initialValue.value());
+ }
+
+ Frequency frequency = null;
+ if (field.isAnnotationPresent(Frequency.class)) {
+ frequency = field.getAnnotation(Frequency.class);
+ if (frequency != null) builder.frequency(frequency.value());
+ }
+
+ DutyCycle dutyCycle = null;
+ 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());
+ }
+ }
+ }
+
+ AddPwmPresets pwmPresets = null;
+ if (field.isAnnotationPresent(AddPwmPresets.class)) {
+ pwmPresets = field.getAnnotation(AddPwmPresets.class);
+ AddPwmPreset[] presets = pwmPresets.value();
+ for(AddPwmPreset preset : presets){
+ PwmPresetBuilder presetBuilder = PwmPreset.newBuilder(preset.name());
+ if(preset.dutyCycle() >= 0)
+ presetBuilder.dutyCycle(preset.dutyCycle());
+ if(preset.frequency() >= 0)
+ presetBuilder.frequency(preset.frequency());
+
+ // add applyPreset to PWM config builder
+ builder.preset(presetBuilder.build());
+ }
+ }
+
+ // get designated platform to use to register this IO (if provided)
+ Platform platform = null;
+ if (field.isAnnotationPresent(WithPlatform.class)) {
+ platform = WithAnnotationProcessor.getPlatform(context, field);
+ }
+
+ // get designated provider to use to register this IO (if provided)
+ PwmProvider provider = null;
+ if (field.isAnnotationPresent(WithProvider.class)) {
+ provider = WithAnnotationProcessor.getProvider(context, platform, field, PwmProvider.class);
+ }
+
+ // if a provider was found, then create PWM IO instance using that provider
+ if(provider != null){
+ return provider.create(builder.build());
+ }
+
+ // if no provider was found, then create PWM IO instance using defaults
+ else {
+ if(platform != null)
+ return platform.provider(PwmProvider.class).create(builder.build());
+ else
+ return context.provider(PwmProvider.class).create(builder.build());
+ }
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/config/impl/AddressConfigBase.java b/pi4j-api/src/main/java/com/pi4j/config/impl/AddressConfigBase.java
index 82248f48b..05cbbb0c1 100644
--- a/pi4j-api/src/main/java/com/pi4j/config/impl/AddressConfigBase.java
+++ b/pi4j-api/src/main/java/com/pi4j/config/impl/AddressConfigBase.java
@@ -48,6 +48,11 @@ protected AddressConfigBase(){
super();
}
+ protected AddressConfigBase(Number address){
+ super();
+ this.address = address.intValue();
+ }
+
/**
* PRIVATE CONSTRUCTOR
* @param properties
diff --git a/pi4j-api/src/main/java/com/pi4j/context/Context.java b/pi4j-api/src/main/java/com/pi4j/context/Context.java
index 80710e9fe..314652b87 100644
--- a/pi4j-api/src/main/java/com/pi4j/context/Context.java
+++ b/pi4j-api/src/main/java/com/pi4j/context/Context.java
@@ -32,13 +32,19 @@
import com.pi4j.common.Descriptor;
import com.pi4j.exception.LifecycleException;
import com.pi4j.io.IOType;
-import com.pi4j.io.gpio.analog.AnalogInputProvider;
-import com.pi4j.io.gpio.analog.AnalogOutputProvider;
-import com.pi4j.io.gpio.digital.DigitalInputProvider;
-import com.pi4j.io.gpio.digital.DigitalOutputProvider;
+import com.pi4j.io.gpio.analog.*;
+import com.pi4j.io.gpio.digital.*;
+import com.pi4j.io.i2c.I2C;
+import com.pi4j.io.i2c.I2CConfig;
import com.pi4j.io.i2c.I2CProvider;
+import com.pi4j.io.pwm.Pwm;
+import com.pi4j.io.pwm.PwmConfig;
import com.pi4j.io.pwm.PwmProvider;
+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.io.spi.SpiConfig;
import com.pi4j.io.spi.SpiProvider;
import com.pi4j.platform.Platform;
import com.pi4j.platform.Platforms;
@@ -52,6 +58,7 @@
public interface Context extends Describable {
ContextConfig config();
+ ContextProperties properties();
Providers providers();
Registry registry();
Platforms platforms();
@@ -159,6 +166,31 @@ default P platform(){
return platforms().getDefault();
}
+ default AnalogOutput create(AnalogOutputConfig config) throws Exception{
+ return this.aout().create(config);
+ }
+ default AnalogInput create(AnalogInputConfig config) throws Exception{
+ return this.ain().create(config);
+ }
+ default DigitalOutput create(DigitalOutputConfig config) throws Exception{
+ return this.dout().create(config);
+ }
+ default DigitalInput create(DigitalInputConfig config) throws Exception{
+ return this.din().create(config);
+ }
+ default Pwm create(PwmConfig config) throws Exception{
+ return this.pwm().create(config);
+ }
+ default I2C create(I2CConfig config) throws Exception{
+ return this.i2c().create(config);
+ }
+ default Spi create(SpiConfig config) throws Exception{
+ return this.spi().create(config);
+ }
+ default Serial create(SerialConfig config) throws Exception{
+ return this.serial().create(config);
+ }
+
default Descriptor describe() {
Descriptor descriptor = Descriptor.create()
.category("CONTEXT")
@@ -168,6 +200,7 @@ default Descriptor describe() {
descriptor.add(registry().describe());
descriptor.add(platforms().describe());
descriptor.add(providers().describe());
+ descriptor.add(properties().describe());
return descriptor;
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/context/ContextBuilder.java b/pi4j-api/src/main/java/com/pi4j/context/ContextBuilder.java
index db314a422..2417d7e8f 100644
--- a/pi4j-api/src/main/java/com/pi4j/context/ContextBuilder.java
+++ b/pi4j-api/src/main/java/com/pi4j/context/ContextBuilder.java
@@ -32,6 +32,13 @@
import com.pi4j.platform.Platform;
import com.pi4j.provider.Provider;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.Map;
+import java.util.Properties;
+
public interface ContextBuilder extends Builder {
static ContextBuilder newInstance(){
@@ -91,4 +98,75 @@ default ContextBuilder setDefaultPlatform(String platformId){
default ContextBuilder setDefaultPlatform(Platform platform){
return defaultPlatform(platform);
}
+
+
+ ContextBuilder property(String key, String value);
+ ContextBuilder property(Map.Entry ... value);
+
+ ContextBuilder properties(Map values);
+ ContextBuilder properties(Map properties, String prefixFilter);
+ ContextBuilder properties(Properties properties, String prefixFilter);
+ ContextBuilder properties(InputStream stream, String prefixFilter) throws IOException;
+ ContextBuilder properties(Reader reader, String prefixFilter) throws IOException;
+ ContextBuilder properties(File file, String prefixFilter) throws IOException;
+
+ default ContextBuilder properties(Properties properties){
+ return properties(properties, null);
+ }
+ default ContextBuilder properties(InputStream stream) throws IOException{
+ return properties(stream, null);
+ }
+ default ContextBuilder properties(Reader reader) throws IOException{
+ return properties(reader, null);
+ }
+ default ContextBuilder properties(File file) throws IOException{
+ return properties(file, null);
+ }
+
+ default ContextBuilder addProperty(String key, String value){
+ return property(key, value);
+ }
+ default ContextBuilder addProperty(Map.Entry ... value){
+ return property(value);
+ }
+ default ContextBuilder addProperties(Properties properties, String prefixFilter){
+ return properties(properties, prefixFilter);
+ }
+ default ContextBuilder addProperties(Properties properties){
+ return properties(properties, null);
+ }
+ default ContextBuilder addProperties(Map properties){
+ return properties(properties, null);
+ }
+ default ContextBuilder addProperties(Map properties, String prefixFilter){
+ return properties(properties, prefixFilter);
+ }
+
+ default ContextBuilder addProperties(InputStream stream) throws IOException{
+ return properties(stream, null);
+ }
+ default ContextBuilder addProperties(InputStream stream, String prefixFilter) throws IOException{
+ return properties(stream, prefixFilter);
+ }
+
+ default ContextBuilder addProperties(Reader reader) throws IOException{
+ return properties(reader, null);
+ }
+ default ContextBuilder addProperties(Reader reader, String prefixFilter) throws IOException{
+ return properties(reader, prefixFilter);
+ }
+
+ default ContextBuilder addProperties(File file) throws IOException{
+ return properties(file, null);
+ }
+ default ContextBuilder addProperties(File file, String prefixFilter) throws IOException{
+ return properties(file, prefixFilter);
+ }
+
+ default ContextBuilder add(Properties properties, String prefixFilter){
+ return properties(properties, prefixFilter);
+ }
+ default ContextBuilder add(Properties properties){
+ return properties(properties, null);
+ }
}
diff --git a/pi4j-api/src/main/java/com/pi4j/context/ContextConfig.java b/pi4j-api/src/main/java/com/pi4j/context/ContextConfig.java
index aed107449..d264f2550 100644
--- a/pi4j-api/src/main/java/com/pi4j/context/ContextConfig.java
+++ b/pi4j-api/src/main/java/com/pi4j/context/ContextConfig.java
@@ -31,6 +31,7 @@
import com.pi4j.provider.Provider;
import java.util.Collection;
+import java.util.Map;
public interface ContextConfig {
@@ -60,4 +61,9 @@ default Collection getProviders(){
boolean autoDetectProviders();
default boolean getAutoDetectProviders() { return autoDetectProviders(); };
default boolean isAutoDetectProviders() { return autoDetectProviders(); };
+
+ // **************************************************
+ // PROPERTIES
+ // **************************************************
+ Map properties();
}
diff --git a/pi4j-api/src/main/java/com/pi4j/context/ContextProperties.java b/pi4j-api/src/main/java/com/pi4j/context/ContextProperties.java
new file mode 100644
index 000000000..875415f4c
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/context/ContextProperties.java
@@ -0,0 +1,82 @@
+package com.pi4j.context;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : ContextProperties.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.common.Describable;
+import com.pi4j.common.Descriptor;
+import com.pi4j.util.StringUtil;
+
+import java.util.Map;
+
+public interface ContextProperties extends Describable {
+
+ boolean has(String key);
+ String get(String key);
+
+ Map all();
+ int count();
+
+ default String get(String key, String defaultValue){
+ String value = get(key);
+ if(StringUtil.isNotNullOrEmpty(value)) {
+ return value;
+ }
+ return defaultValue;
+ }
+
+ default boolean exists(String key){
+ return has(key);
+ }
+
+ default Integer getInteger(String key){
+ return getInteger(key, null);
+ }
+
+ default Integer getInteger(String key, Integer defaultValue){
+ if(has(key)) return StringUtil.parseInteger(get(key), defaultValue);
+ return defaultValue;
+ }
+
+ default Descriptor describe() {
+ Descriptor descriptor = Descriptor.create()
+ .category("PROPERTIES")
+ .name("Properties")
+ .quantity(this.count())
+ .type(this.getClass());
+
+ for(Map.Entry e : this.all().entrySet()){
+ descriptor.add(
+ Descriptor.create()
+ .name(e.getKey().toString())
+ .category("PROPERTY")
+ .description(e.getValue().toString())
+ );
+ }
+ return descriptor;
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContext.java b/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContext.java
index ad943dce2..b5dd13d0d 100644
--- a/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContext.java
+++ b/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContext.java
@@ -30,6 +30,7 @@
import com.pi4j.annotation.exception.AnnotationException;
import com.pi4j.context.Context;
import com.pi4j.context.ContextConfig;
+import com.pi4j.context.ContextProperties;
import com.pi4j.exception.LifecycleException;
import com.pi4j.exception.Pi4JException;
import com.pi4j.exception.ShutdownException;
@@ -49,6 +50,7 @@ public class DefaultContext implements Context {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private Runtime runtime = null;
private ContextConfig config = null;
+ private ContextProperties properties = null;
private Providers providers = null;
private Platforms platforms = null;
private Registry registry = null;
@@ -72,6 +74,9 @@ private DefaultContext(ContextConfig config) throws Pi4JException {
// create internal runtime state instance (READ-ONLY ACCESS OBJECT)
this.runtime = DefaultRuntime.newInstance(this);
+ // create API accessible properties instance (READ-ONLY ACCESS OBJECT)
+ this.properties = DefaultContextProperties.newInstance(this.runtime.properties());
+
// create API accessible registry instance (READ-ONLY ACCESS OBJECT)
this.registry = DefaultRegistry.newInstance(this.runtime.registry());
@@ -90,6 +95,11 @@ private DefaultContext(ContextConfig config) throws Pi4JException {
@Override
public ContextConfig config() { return this.config; }
+ @Override
+ public ContextProperties properties() {
+ return this.properties;
+ }
+
@Override
public Providers providers() { return providers; }
diff --git a/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContextBuilder.java b/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContextBuilder.java
index 0885d8ffc..97111239e 100644
--- a/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContextBuilder.java
+++ b/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContextBuilder.java
@@ -33,13 +33,13 @@
import com.pi4j.exception.Pi4JException;
import com.pi4j.platform.Platform;
import com.pi4j.provider.Provider;
+import com.pi4j.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
+import java.io.*;
+import java.util.*;
+import java.util.stream.Collectors;
public class DefaultContextBuilder implements ContextBuilder {
@@ -56,6 +56,9 @@ public class DefaultContextBuilder implements ContextBuilder {
protected Collection platforms = Collections.synchronizedList(new ArrayList<>());
protected Collection providers = Collections.synchronizedList(new ArrayList<>());
+ // properties
+ protected Map properties = Collections.synchronizedMap(new HashMap<>());
+
/**
* Private Constructor
*/
@@ -116,6 +119,72 @@ public ContextBuilder noAutoDetectProviders() {
return this;
}
+ @Override
+ public ContextBuilder property(String key, String value){
+ this.properties.put(key, value);
+ return this;
+ }
+
+ @Override
+ public ContextBuilder property(Map.Entry ... value){
+ for(Map.Entry e : value){
+ this.properties.put(e.getKey().toString(), e.getValue().toString());
+ }
+ return this;
+ }
+
+ @Override
+ public ContextBuilder properties(Properties properties, String prefixFilter){
+ // convert java.util.Properties to a Map object
+ Map entries = properties.keySet().stream()
+ .collect(Collectors.toMap(k->k.toString(), key->properties.get(key).toString()));
+ return properties(entries, prefixFilter);
+ }
+
+ @Override
+ public ContextBuilder properties(Map properties) {
+ this.properties.putAll(properties);
+ return this;
+ }
+
+ @Override
+ public ContextBuilder properties(Map properties, String prefixFilter){
+
+ // if a filter was not provided, then load properties without a filter
+ if(StringUtil.isNullOrEmpty(prefixFilter)) return properties(properties);
+
+ // sanitize the prefix filter and make sure it includes a "." character at the end
+ var prefix = (prefixFilter.endsWith(".")) ? prefixFilter : prefixFilter+".";
+
+ // iterate the properties object and assign any key with the prefix filter to this config
+ properties.keySet().stream().filter(key -> key.startsWith(prefix)).forEach((key)->{
+ this.properties.put(key.substring(prefix.length()), properties.get(key));
+ });
+ return this;
+ }
+
+ @Override
+ public ContextBuilder properties(InputStream stream, String prefixFilter) throws IOException{
+ Properties prop = new Properties();
+ prop.load(stream);
+ return properties(prop, prefixFilter);
+ }
+
+ @Override
+ public ContextBuilder properties(Reader reader, String prefixFilter) throws IOException{
+ Properties prop = new Properties();
+ prop.load(reader);
+ return properties(prop, prefixFilter);
+ }
+
+ @Override
+ public ContextBuilder properties(File file, String prefixFilter) throws IOException{
+ Properties prop = new Properties();
+ prop.load(new FileInputStream(file));
+ return properties(prop, prefixFilter);
+ }
+
+
@Override
public ContextConfig toConfig() {
// set instance reference
@@ -147,6 +216,11 @@ public boolean autoDetectPlatforms() {
public boolean autoDetectProviders() {
return builder.autoDetectProviders;
}
+
+ @Override
+ public Map properties() {
+ return Collections.unmodifiableMap(builder.properties);
+ }
};
}
diff --git a/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContextProperties.java b/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContextProperties.java
new file mode 100644
index 000000000..b6e6b29cd
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/context/impl/DefaultContextProperties.java
@@ -0,0 +1,66 @@
+package com.pi4j.context.impl;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : DefaultContextProperties.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.ContextProperties;
+import com.pi4j.runtime.RuntimeProperties;
+
+import java.util.Map;
+
+public class DefaultContextProperties implements ContextProperties {
+
+ private final RuntimeProperties properties;
+
+ public static ContextProperties newInstance(RuntimeProperties properties){
+ return new DefaultContextProperties(properties);
+ }
+
+ private DefaultContextProperties(RuntimeProperties properties){
+ this.properties = properties;
+ }
+
+ @Override
+ public boolean has(String key) {
+ return this.properties.has(key);
+ }
+
+ @Override
+ public String get(String key) {
+ return this.properties.get(key);
+ }
+
+ @Override
+ public Map all() {
+ return this.properties.all();
+ }
+
+ @Override
+ public int count() {
+ return this.properties.count();
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/extension/Extension.java b/pi4j-api/src/main/java/com/pi4j/extension/Extension.java
index 78e3e7de6..2b91f9b6a 100644
--- a/pi4j-api/src/main/java/com/pi4j/extension/Extension.java
+++ b/pi4j-api/src/main/java/com/pi4j/extension/Extension.java
@@ -37,7 +37,7 @@ default Descriptor describe() {
return Descriptor.create()
.id(this.id())
.name(this.name())
- .category("BINDING")
+ .category("EXTENSION")
.description(this.description()).type(this.getClass());
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/extension/Plugin.java b/pi4j-api/src/main/java/com/pi4j/extension/Plugin.java
index 3f61b5ad6..6e8c8b94f 100644
--- a/pi4j-api/src/main/java/com/pi4j/extension/Plugin.java
+++ b/pi4j-api/src/main/java/com/pi4j/extension/Plugin.java
@@ -27,6 +27,14 @@
* #L%
*/
+import com.pi4j.context.Context;
+
+import java.io.IOException;
+
public interface Plugin {
- void initialize(PluginService service);
+ void initialize(PluginService service) throws IOException;
+
+ default void shutdown(Context context) throws IOException{
+ // do nothing
+ }
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java b/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java
new file mode 100644
index 000000000..2898640fb
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/IODataReader.java
@@ -0,0 +1,147 @@
+package com.pi4j.io;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : IODataReader.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.exception.IOReadException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Data Writer Interface for Pi4J Data Communications
+ *
+ * @author Robert Savage
+ *
+ * Based on previous contributions from:
+ * Daniel Sendula,
+ * RasPelikan
+ */
+public interface IODataReader {
+
+ 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);
+ }
+ 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);
+ }
+ 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());
+ }
+
+ // ------------------------------------------------------------------------------------------------------------
+
+ 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);
+ }
+
+ default String readString(int length) throws IOException, IOReadException {
+ return readString(length, StandardCharsets.US_ASCII);
+ }
+
+ /**
+ * Read a single byte value (16-bit) from the raw I2C device (not a register).
+ *
+ * @return The 16-bit word value
+ * @throws IOException thrown on write error
+ */
+ default byte readByte() throws IOException{
+ int actual = read();
+ if(actual < 0) {
+ System.out.println(actual);
+ 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).
+ *
+ * @return The 16-bit word value
+ * @throws IOException thrown on write error
+ */
+ 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 ByteBuffer readBuffer(int length) throws IOException, IOReadException {
+ byte[] temp = new byte[length];
+ int actual = read(temp, 0, 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);
+ if(actual < 0) throw new IOReadException(actual);
+ return Arrays.copyOf(temp, actual);
+ }
+
+ default InputStream getInputStream(){
+ var t = this;
+ return new InputStream() {
+ @Override
+ public int read() throws IOException {
+ return t.read();
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ Objects.checkFromIndexSize(off, len, b.length);
+ return t.read(b, off, len);
+ }
+ };
+ }
+
+ 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
new file mode 100644
index 000000000..9e4a2e843
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/IODataWriter.java
@@ -0,0 +1,214 @@
+package com.pi4j.io;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : IODataWriter.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 java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+/**
+ * Data Writer Interface for Pi4J Data Communications
+ *
+ * @author Robert Savage
+ *
+ * Based on previous contributions from:
+ * Daniel Sendula,
+ * RasPelikan
+ */
+public interface IODataWriter {
+
+ /**
+ * Write a single raw byte value.
+ *
+ * @param b byte to be written
+ * @throws IOException thrown on write error
+ */
+ void write(byte b) throws IOException;
+
+ /**
+ * Write a buffer of byte values with given offset (starting position) and length in the provided data buffer.
+ *
+ * @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
+ */
+ int write(ByteBuffer buffer, int offset, int length) throws IOException;
+
+ /**
+ * Write a single raw byte value.
+ *
+ * @param b byte to be written
+ * @throws IOException thrown on write error
+ */
+ default void write(int b) throws IOException{
+ write((byte)b);
+ }
+
+ /**
+ * Write a single word value (16-bit) to the raw I2C device.
+ *
+ * @param word 16-bit word value to be written
+ * @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);
+ }
+
+ /**
+ * 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
+ */
+ default int write(byte[] data, int offset, int length) throws IOException{
+ Objects.checkFromIndexSize(offset, length, data.length);
+ return write(ByteBuffer.wrap(data), offset, length);
+ }
+
+ /**
+ * Write an array of byte values starting with the first byte in the array up to the provided length.
+ *
+ * @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 int write(byte[] data, int length) throws IOException{
+ return write(data, 0, length);
+ }
+
+ /**
+ * Write an array of byte values (all bytes in array).
+ *
+ * @param data data array 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);
+ }
+
+ /**
+ * Write a buffer of byte values starting with the first byte in the array up to the provided length.
+ *
+ * @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{
+ return write(buffer, 0, length);
+ }
+
+ /**
+ * Write a buffer of byte values (all bytes in buffer).
+ *
+ * @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{
+ return write(buffer, 0, buffer.capacity());
+ }
+
+ /**
+ * 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{
+ return write(stream.readAllBytes());
+ }
+
+ /**
+ * Writes an ASCII data string.
+ *
+ * @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(String data) throws IOException{
+ return write(data, StandardCharsets.US_ASCII);
+ }
+
+ /**
+ * 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, Charset charset) throws IOException{
+ return write(data.getBytes(charset));
+ }
+
+ /**
+ * Get an output stream to write data to
+ * @return new output stream instance to write to
+ */
+ default OutputStream getOutputStream(){
+ var t = this;
+ return new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ t.write((byte)b);;
+ }
+
+ @Override
+ public void write(byte b[]) throws IOException {
+ t.write(b);
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) throws IOException {
+ this.write(b, off, len);
+ }
+ };
+ }
+
+ /**
+ * Get an output stream to write data to
+ * @return new output stream instance to write to
+ */
+ default OutputStream out() {
+ return getOutputStream();
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/exception/IOReadException.java b/pi4j-api/src/main/java/com/pi4j/io/exception/IOReadException.java
new file mode 100644
index 000000000..d4da1e7aa
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/exception/IOReadException.java
@@ -0,0 +1,56 @@
+package com.pi4j.io.exception;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : IOReadException.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%
+ */
+
+
+/**
+ *
+ * This exception is thrown if a platform assignment is attempted when a
+ * platform instance has already been assigned.
+ *
+ *
+ * @see http://www.pi4j.com/
+ * @author Robert Savage (http://www.savagehomeautomation.com)
+ */
+public class IOReadException extends IOException {
+
+ /**
+ * Default Constructor
+ */
+ public IOReadException(String message){
+ super(message);
+ }
+
+ /**
+ * Alternate Constructor
+ */
+ public IOReadException(int error){
+ super("I/O READ ERROR: " + error);
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogInput.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogInput.java
index 252335a77..4e5944eec 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogInput.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogInput.java
@@ -30,5 +30,8 @@
import com.pi4j.io.Input;
public interface AnalogInput extends Analog, Input {
+ static AnalogInputConfigBuilder newConfigBuilder(){
+ return AnalogInputConfigBuilder.newInstance();
+ }
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogOutput.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogOutput.java
index 6edccbba5..ec46e2e9e 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogOutput.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/analog/AnalogOutput.java
@@ -32,11 +32,14 @@
import com.pi4j.io.exception.IOIllegalValueException;
public interface AnalogOutput extends Analog, Output {
- AnalogOutput value(Integer value) throws IOIllegalValueException, IOBoundsException;
+ static AnalogOutputConfigBuilder newConfigBuilder(){
+ return AnalogOutputConfigBuilder.newInstance();
+ }
+
+ AnalogOutput value(Integer value) throws IOIllegalValueException, IOBoundsException;
AnalogOutput stepUp();
AnalogOutput stepDown();
AnalogOutput step(Integer value) throws IOIllegalValueException, IOBoundsException;
-
default AnalogOutput setValue(Integer value) throws IOIllegalValueException, IOBoundsException { return value(value); };
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalBase.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalBase.java
index 46e9a3ca5..f715fa3f0 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalBase.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalBase.java
@@ -28,6 +28,7 @@
*/
import com.pi4j.context.Context;
+import com.pi4j.exception.ShutdownException;
import com.pi4j.io.gpio.GpioBase;
import com.pi4j.io.gpio.digital.binding.DigitalBinding;
@@ -91,7 +92,7 @@ protected void dispatch(DigitalChangeEvent event){
}
@Override
- public DIGITAL_TYPE shutdown(Context context){
+ public DIGITAL_TYPE shutdown(Context context) throws ShutdownException {
// remove all listeners
listeners.clear();
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInput.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInput.java
index 91281113a..4a646a67f 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInput.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInput.java
@@ -31,5 +31,10 @@
import com.pi4j.io.Input;
public interface DigitalInput extends Digital, Input {
+
+ static DigitalInputConfigBuilder newConfigBuilder(){
+ return DigitalInputConfigBuilder.newInstance();
+ }
+
default PullResistance pull() { return config().pull(); }
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputBase.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputBase.java
index ae4f645f1..7ad003796 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputBase.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputBase.java
@@ -30,6 +30,5 @@
public abstract class DigitalInputBase extends DigitalBase implements DigitalInput {
public DigitalInputBase(DigitalInputProvider provider, DigitalInputConfig config){
super(provider, config);
- this.name = (config.name() != null) ? config.name() : "DIN-" + config.address();
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputProvider.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputProvider.java
index 1d0640a99..0c85d7271 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputProvider.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalInputProvider.java
@@ -29,27 +29,41 @@
public interface DigitalInputProvider extends DigitalProvider {
- default T create(Integer address) throws Exception {
- var builder = DigitalInputConfigBuilder.newInstance();
- builder.address(address);
+ default T create(DigitalInputConfigBuilder builder) throws Exception {
return (T)create(builder.build());
}
+ default T create(Integer address) throws Exception {
+ var config = DigitalInput.newConfigBuilder()
+ .address(address)
+ .build();
+ return (T)create(config);
+ }
+
default T create(Integer address, String id) throws Exception {
- var builder = DigitalInputConfigBuilder.newInstance();
- builder.id(id).address(address).id(id);
- return (T)create(builder.build());
+ var config = DigitalInput.newConfigBuilder()
+ .address(address)
+ .id(id)
+ .build();
+ return (T)create(config);
}
default T create(Integer address, String id, String name) throws Exception {
- var builder = DigitalInputConfigBuilder.newInstance();
- builder.id(id).address(address).id(id).name(name);
- return (T)create(builder.build());
+ var config = DigitalInput.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 builder = DigitalInputConfigBuilder.newInstance();
- builder.id(id).address(address).id(id).name(name).description(description);
- return (T)create(builder.build());
+ var config = DigitalInput.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/gpio/digital/DigitalOutput.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutput.java
index ae986910c..ab18903eb 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
@@ -28,6 +28,7 @@
*/
import com.pi4j.io.Output;
+import com.pi4j.io.exception.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
@@ -35,48 +36,52 @@
public interface DigitalOutput extends Digital, Output {
- DigitalOutput state(DigitalState state);
- DigitalOutput pulse(int interval, TimeUnit unit, DigitalState state, Callable callback);
+ static DigitalOutputConfigBuilder newConfigBuilder(){
+ return DigitalOutputConfigBuilder.newInstance();
+ }
+
+ DigitalOutput state(DigitalState state) throws IOException;
+ DigitalOutput pulse(int interval, TimeUnit unit, DigitalState state, Callable callback) throws IOException;
Future> pulseAsync(int interval, TimeUnit unit, DigitalState state, Callable callback);
DigitalOutput blink(int delay, int duration, TimeUnit unit, DigitalState state, Callable callback);
Future> blinkAsync(int delay, int duration, TimeUnit unit, DigitalState state, Callable callback);
- default DigitalOutput setState(boolean state){
+ default DigitalOutput setState(boolean state) throws IOException {
return this.state(DigitalState.getState(state));
}
- default DigitalOutput setState(byte state){
+ default DigitalOutput setState(byte state) throws IOException {
return this.state(DigitalState.getState(state));
}
- default DigitalOutput setState(short state){
+ default DigitalOutput setState(short state) throws IOException {
return this.state(DigitalState.getState(state));
}
- default DigitalOutput setState(int state){
+ default DigitalOutput setState(int state) throws IOException {
return this.state(DigitalState.getState(state));
}
- default DigitalOutput setState(long state){
+ default DigitalOutput setState(long state) throws IOException {
return this.state(DigitalState.getState(state));
}
- default DigitalOutput setState(float state){
+ default DigitalOutput setState(float state) throws IOException {
return this.state(DigitalState.getState(state));
}
- default DigitalOutput setState(double state){
+ default DigitalOutput setState(double state) throws IOException {
return this.state(DigitalState.getState(state));
}
- default DigitalOutput high(){
+ default DigitalOutput high() throws IOException {
return this.state(DigitalState.HIGH);
}
- default DigitalOutput low(){
+ default DigitalOutput low() throws IOException {
return this.state(DigitalState.LOW);
}
- default DigitalOutput toggle(){
+ default DigitalOutput toggle() throws IOException {
return this.state(DigitalState.getInverseState(this.state()));
}
- default DigitalOutput pulseHigh(int interval, TimeUnit unit){
+ default DigitalOutput pulseHigh(int interval, TimeUnit unit) throws IOException {
return pulse(interval, unit, DigitalState.HIGH);
}
- default DigitalOutput pulseLow(int interval, TimeUnit unit){
+ default DigitalOutput pulseLow(int interval, TimeUnit unit) throws IOException {
return pulse(interval, unit, DigitalState.LOW);
}
@@ -88,10 +93,10 @@ default Future> pulseLowAsync(int interval, TimeUnit unit, Callable call
return pulseAsync(interval, unit, DigitalState.LOW, callback);
}
- default DigitalOutput pulse(int interval, TimeUnit unit){
+ default DigitalOutput pulse(int interval, TimeUnit unit) throws IOException {
return pulse(interval, unit, DigitalState.HIGH);
}
- default DigitalOutput pulse(int interval, TimeUnit unit, DigitalState state){
+ default DigitalOutput pulse(int interval, TimeUnit unit, DigitalState state) throws IOException {
return pulse(interval, unit, state, null);
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBase.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBase.java
index 696cf78ac..05d5e4a62 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBase.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputBase.java
@@ -28,6 +28,9 @@
*/
import com.pi4j.context.Context;
+import com.pi4j.exception.InitializeException;
+import com.pi4j.exception.ShutdownException;
+import com.pi4j.io.exception.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
@@ -39,16 +42,25 @@ public abstract class DigitalOutputBase extends DigitalBase callback){
+ public DigitalOutput pulse(int interval, TimeUnit unit, DigitalState state, Callable callback) throws IOException {
int millis = 0;
// validate arguments
@@ -97,17 +109,20 @@ public DigitalOutput pulse(int interval, TimeUnit unit, DigitalState state, Call
@Override
public Future> pulseAsync(int interval, TimeUnit unit, DigitalState state, Callable callback) {
- return null;
+ // TODO :: IMPLEMENT DIGITAL OUTPUT PULSE ASYNC
+ throw new UnsupportedOperationException("PULSE ASYNC has not yet been implemented!");
}
@Override
public DigitalOutput blink(int delay, int duration, TimeUnit unit, DigitalState state, Callable callback) {
- return null;
+ // TODO :: IMPLEMENT DIGITAL OUTPUT BLINK
+ throw new UnsupportedOperationException("BLINK has not yet been implemented!");
}
@Override
public Future> blinkAsync(int delay, int duration, TimeUnit unit, DigitalState state, Callable callback) {
- return null;
+ // TODO :: IMPLEMENT DIGITAL OUTPUT BLINK ASYNC
+ throw new UnsupportedOperationException("BLINK ASYNC has not yet been implemented!");
}
@Override
@@ -116,11 +131,15 @@ public DigitalState state() {
}
@Override
- public DigitalOutput shutdown(Context context){
+ public DigitalOutput shutdown(Context context) throws ShutdownException {
// set pin state to shutdown state if a shutdown state is configured
if(config().shutdownState() != null && config().shutdownState() != DigitalState.UNKNOWN){
- state(config().shutdownState());
+ try {
+ state(config().shutdownState());
+ } catch (IOException e) {
+ throw new ShutdownException(e);
+ }
}
- return this;
+ return super.shutdown(context);
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputProvider.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputProvider.java
index bae42d0c9..605a94c34 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputProvider.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalOutputProvider.java
@@ -28,28 +28,41 @@
*/
public interface DigitalOutputProvider extends DigitalProvider {
- default T create(Integer address) throws Exception {
- var builder = DigitalOutputConfigBuilder.newInstance();
- builder.address(address);
+ default T create(DigitalOutputConfigBuilder builder) throws Exception {
return (T)create(builder.build());
}
+ default T create(Integer address) throws Exception {
+ var config = DigitalOutput.newConfigBuilder()
+ .address(address)
+ .build();
+ return (T)create(config);
+ }
+
default T create(Integer address, String id) throws Exception {
- var builder = DigitalOutputConfigBuilder.newInstance();
- builder.id(id).address(address).id(id);
- return (T)create(builder.build());
+ var config = DigitalOutput.newConfigBuilder()
+ .id(id)
+ .address(address)
+ .build();
+ return (T)create(config);
}
default T create(Integer address, String id, String name) throws Exception {
- var builder = DigitalOutputConfigBuilder.newInstance();
- builder.id(id).address(address).id(id).name(name);
- return (T)create(builder.build());
+ var config = DigitalOutput.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 builder = DigitalOutputConfigBuilder.newInstance();
- builder.id(id).address(address).id(id).name(name).description(description);
- return (T)create(builder.build());
+ var config = DigitalOutput.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/gpio/digital/DigitalState.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalState.java
index 80864c6fa..288cb6be3 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalState.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/DigitalState.java
@@ -57,6 +57,10 @@ public boolean isLow() {
return (this == LOW);
}
+ public Number value() {
+ return getValue();
+ }
+
public Number getValue() {
return value;
}
@@ -99,6 +103,10 @@ public String toString() {
return name;
}
+ public static DigitalState state(Number state) {
+ return getState(state);
+ }
+
public static DigitalState getState(Number state) {
for (var item : DigitalState.values()) {
if (item.getValue().intValue() == state.intValue()) {
@@ -108,6 +116,10 @@ public static DigitalState getState(Number state) {
return null;
}
+ public static DigitalState inverseState(DigitalState state) {
+ return getInverseState(state);
+ }
+
public static DigitalState getInverseState(DigitalState state) {
return (state == HIGH ? LOW : HIGH);
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingInverseSync.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingInverseSync.java
index c40225f72..46263760b 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingInverseSync.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingInverseSync.java
@@ -27,10 +27,13 @@
* #L%
*/
+import com.pi4j.io.exception.IOException;
import com.pi4j.io.gpio.digital.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class DigitalBindingInverseSync extends DigitalBindingBase implements DigitalBinding {
-
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* Default Constructor
* @param target Variable argument list of analog outputs
@@ -42,7 +45,11 @@ public DigitalBindingInverseSync(DigitalOutput ... target){
@Override
public void process(DigitalChangeEvent event) {
targets.forEach((target)->{
- ((DigitalOutput)target).state(DigitalState.getInverseState(event.state()));
+ try {
+ ((DigitalOutput)target).state(DigitalState.getInverseState(event.state()));
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
});
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingSync.java b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingSync.java
index 3a49df6bf..9b708b67b 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingSync.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/gpio/digital/binding/DigitalBindingSync.java
@@ -27,13 +27,18 @@
* #L%
*/
+import com.pi4j.io.exception.IOException;
import com.pi4j.io.gpio.digital.DigitalChangeEvent;
import com.pi4j.io.gpio.digital.DigitalOutput;
import com.pi4j.io.gpio.digital.DigitalOutputConfig;
import com.pi4j.io.gpio.digital.DigitalOutputProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class DigitalBindingSync extends DigitalBindingBase implements DigitalBinding {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
/**
* Default Constructor
* @param target Variable argument list of analog outputs
@@ -45,7 +50,11 @@ public DigitalBindingSync(DigitalOutput ... target){
@Override
public void process(DigitalChangeEvent event) {
targets.forEach((target)->{
- ((DigitalOutput)target).state(event.state());
+ try {
+ ((DigitalOutput)target).state(event.state());
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
});
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2C.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2C.java
index 1e499cc82..d783b6def 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2C.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2C.java
@@ -27,176 +27,82 @@
* #L%
*/
-import com.pi4j.context.Context;
import com.pi4j.io.IO;
-import com.pi4j.io.i2c.impl.I2CFactory;
-import com.pi4j.provider.exception.ProviderException;
-
-import java.io.IOException;
+import com.pi4j.io.IODataReader;
+import com.pi4j.io.IODataWriter;
/**
- * This is abstraction of an i2c device. It allows data to be read or written to the device.
+ * I2C I/O Interface for Pi4J I2C Bus/Device Communications
*
- * @author Daniel Sendula, refactored by RasPelikan
+ * @author Robert Savage
*
+ * Based on previous contributions from:
+ * Daniel Sendula,
+ * RasPelikan
*/
-public interface I2C extends IO {
-
- static final String ID = "I2C";
-
- static I2C instance(Context context, String device, int address) throws ProviderException {
- return I2CFactory.instance(context, device, address);
- }
-
- static I2C instance(Context context, I2CConfig config) throws ProviderException {
- return I2CFactory.instance(context, config);
- }
-
- static I2C instance(Context context, String providerId, String device, int address) throws ProviderException {
- return I2CFactory.instance(context, providerId, device, address);
- }
-
- static I2C instance(Context context, String providerId, I2CConfig config) throws ProviderException {
- return I2CFactory.instance(context, providerId, config);
+public interface I2C extends IO,
+ IODataWriter,
+ IODataReader,
+ I2CRegisterDataReaderWriter,
+ AutoCloseable {
+
+ static I2CConfigBuilder newConfigBuilder(){
+ return I2CConfigBuilder.newInstance();
}
- static I2C instance(I2CProvider provider, String device, int address) throws ProviderException {
- return I2CFactory.instance(provider, device ,address);
- }
-
- static I2C instance(I2CProvider provider, I2CConfig config) throws ProviderException {
- return I2CFactory.instance(provider, config);
- }
-
- /**
- * @return The address for which this instance is constructed for.
- */
- int getAddress();
-
- /**
- * This method writes one byte directly to i2c device.
- *
- * @param b byte to be written
- *
- * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
- */
- void write(byte b) throws IOException;
-
- /**
- * This method writes several bytes directly to the i2c device from given buffer at given offset.
- *
- * @param buffer buffer of data to be written to the i2c device in one go
- * @param offset offset in buffer
- * @param size number of bytes to be written
- *
- * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
- */
- void write(byte[] buffer, int offset, int size) throws IOException;
-
/**
- * This method writes all bytes included in the given buffer directly to the i2c device.
- *
- * @param buffer buffer of data to be written to the i2c device in one go
- *
- * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
+ * I2C Device Address
+ * @return The I2C device address for which this instance is constructed for.
*/
- void write(byte[] buffer) throws IOException;
-
- /**
- * This method writes one byte to i2c device.
- *
- * @param address local address in the i2c device
- * @param b byte to be written
- *
- * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
- */
- void write(int address, byte b) throws IOException;
-
- /**
- * This method writes several bytes to the i2c device from given buffer at given offset.
- *
- * @param address local address in the i2c device
- * @param buffer buffer of data to be written to the i2c device in one go
- * @param offset offset in buffer
- * @param size number of bytes to be written
- *
- * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
- */
- void write(int address, byte[] buffer, int offset, int size) throws IOException;
+ default int device(){
+ return config().device();
+ }
/**
- * This method writes all bytes included in the given buffer directoy to the register address on the i2c device
- *
- * @param address local address in the i2c device
- * @param buffer buffer of data to be written to the i2c device in one go
- *
- * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
+ * I2C Bus Address
+ * @return The I2C bus address for which this instance is constructed for.
*/
- void write(int address, byte[] buffer) throws IOException;
+ default int bus(){
+ return config().bus();
+ }
/**
- * This method reads one byte from the i2c device.
- * Result is between 0 and 255 if read operation was successful, else a negative number for an error.
- *
- * @return byte value read: positive number (or zero) to 255 if read was successful. Negative number if reading failed.
- *
- * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
+ * I2C Device Communication State is OPEN
+ * @return The I2C device communication state
*/
- int read() throws IOException;
+ boolean isOpen();
/**
- * This method reads bytes directly from the i2c device to given buffer at asked offset.
- *
- * @param buffer buffer of data to be read from the i2c device in one go
- * @param offset offset in buffer
- * @param size number of bytes to be read
- *
- * @return number of bytes read
- *
- * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
+ * I2C Bus Address
+ * @return The I2C bus address for which this instance is constructed for.
*/
- int read(byte[] buffer, int offset, int size) throws IOException;
+ default int getBus(){
+ return bus();
+ }
/**
- * This method reads one byte from the i2c device.
- * Result is between 0 and 255 if read operation was successful, else a negative number for an error.
- *
- * @param address local address in the i2c device
- * @return byte value read: positive number (or zero) to 255 if read was successful. Negative number if reading failed.
- *
- * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
+ * I2C Device Address
+ * @return The I2C device address for which this instance is constructed for.
*/
- int read(int address) throws IOException;
+ default int getDevice(){
+ return device();
+ }
/**
- * This method reads bytes from the i2c device to given buffer at asked offset.
- *
- * @param address local address in the i2c device
- * @param buffer buffer of data to be read from the i2c device in one go
- * @param offset offset in buffer
- * @param size number of bytes to be read
- *
- * @return number of bytes read
- *
- * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
+ * Get an encapsulated interface for reading and writing to a specific I2C device register
+ * @param address
+ * @return
*/
- int read(int address, byte[] buffer, int offset, int size) throws IOException;
+ I2CRegister getRegister(int address);
/**
- * This method writes and reads bytes to/from the i2c device in a single method call
- *
- * @param writeBuffer buffer of data to be written to the i2c device in one go
- * @param writeOffset offset in write buffer
- * @param writeSize number of bytes to be written from buffer
- * @param readBuffer buffer of data to be read from the i2c device in one go
- * @param readOffset offset in read buffer
- * @param readSize number of bytes to be read
- *
- * @return number of bytes read
- *
- * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
+ * I2C Device Register
+ * Get an encapsulated interface for reading and writing to a specific I2C device register
+ * @param address the (16-bit) device register address
+ * @return an instance of I2CRegister for the provided register address
*/
- int read(byte[] writeBuffer, int writeOffset, int writeSize, byte[] readBuffer, int readOffset, int readSize) throws IOException;
-
+ default I2CRegister register(int address){
+ return getRegister(address);
+ }
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CBase.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CBase.java
index 0d6cafd0c..e2241aad9 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CBase.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CBase.java
@@ -27,11 +27,54 @@
* #L%
*/
+import com.pi4j.context.Context;
+import com.pi4j.exception.ShutdownException;
import com.pi4j.io.IOBase;
+import com.pi4j.io.i2c.impl.DefaultI2CRegister;
+
+import java.io.IOException;
public abstract class I2CBase extends IOBase implements I2C {
+ protected boolean isOpen = false;
+
public I2CBase(I2CProvider provider, I2CConfig config) {
super(provider, config);
+ this.name = config.name();
+ this.id = config.id();
+ this.description = config.description();
+ this.isOpen = true;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return this.isOpen;
+ }
+
+ @Override
+ public void close() throws IOException {
+ this.isOpen = false;
+ }
+
+ /**
+ * Get an encapsulated interface for reading and writing to a specific I2C device register
+ * @param address
+ * @return
+ */
+ public I2CRegister getRegister(int address){
+ return new DefaultI2CRegister(this, address);
+ }
+
+ @Override
+ public I2C shutdown(Context context) throws ShutdownException {
+ // if this I2C device is still open, then we need to close it since we are shutting down
+ if(this.isOpen()) {
+ try {
+ this.close();
+ } catch (Exception e) {
+ throw new ShutdownException(e);
+ }
+ }
+ return (I2C)this;
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CConfig.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CConfig.java
index 03f399e0c..9127abffe 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CConfig.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CConfig.java
@@ -27,16 +27,24 @@
* #L%
*/
-import com.pi4j.config.impl.DeviceConfigBase;
import com.pi4j.io.IOConfig;
-public class I2CConfig extends DeviceConfigBase implements IOConfig {
+public interface I2CConfig extends IOConfig {
- private I2CConfig(){
- super();
+ String BUS_KEY = "bus";
+ String DEVICE_KEY = "device";
+
+ Integer bus();
+ default Integer getBus() {
+ return bus();
+ }
+
+ Integer device();
+ default Integer getDevice() {
+ return device();
}
- public I2CConfig(String device, int address){
- //super(device, address);
+ static I2CConfigBuilder newBuilder() {
+ return I2CConfigBuilder.newInstance();
}
}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CConfigBuilder.java
new file mode 100644
index 000000000..e4403826e
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CConfigBuilder.java
@@ -0,0 +1,40 @@
+package com.pi4j.io.i2c;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : I2CConfigBuilder.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.ConfigBuilder;
+import com.pi4j.io.i2c.impl.DefaultI2CConfigBuilder;
+
+public interface I2CConfigBuilder extends ConfigBuilder {
+ static I2CConfigBuilder newInstance() {
+ return DefaultI2CConfigBuilder.newInstance();
+ }
+
+ I2CConfigBuilder bus(Integer bus);
+ I2CConfigBuilder device(Integer device);
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CProvider.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CProvider.java
index 1cfa97dd6..b06edb3ca 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CProvider.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CProvider.java
@@ -30,5 +30,47 @@
import com.pi4j.provider.Provider;
public interface I2CProvider extends Provider {
- //I2C instance(I2CConfig config) throws Exception;
+
+ default T create(I2CConfigBuilder builder) throws Exception {
+ return (T)create(builder.build());
+ }
+
+ default T create(Integer bus, Integer device) throws Exception {
+ var config = I2C.newConfigBuilder()
+ .bus(bus)
+ .device(device)
+ .build();
+ return (T)create(config);
+ }
+
+ default T create(Integer bus, Integer device, String id) throws Exception {
+ var config = I2C.newConfigBuilder()
+ .bus(bus)
+ .device(device)
+ .id(id)
+ .build();
+ return (T)create(config);
+ }
+
+ default T create(Integer bus, Integer device, String id, String name) throws Exception {
+ var config = I2C.newConfigBuilder()
+ .bus(bus)
+ .device(device)
+ .id(id)
+ .name(name)
+ .build();
+ return (T)create(config);
+ }
+
+ default T create(Integer bus, Integer device, String id, String name, String description) throws Exception {
+ var config = I2C.newConfigBuilder()
+ .bus(bus)
+ .device(device)
+ .id(id)
+ .name(name)
+ .description(description)
+ .build();
+ return (T)create(config);
+ }
+
}
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
new file mode 100644
index 000000000..66c306c77
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegister.java
@@ -0,0 +1,60 @@
+package com.pi4j.io.i2c;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : I2CRegister.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.IODataReader;
+import com.pi4j.io.IODataWriter;
+import com.pi4j.io.exception.IOReadException;
+
+import java.io.IOException;
+
+/**
+ * I2C Device Register.
+ * This abstraction allows data to be read or written to a specific device register on the I2C bus.
+ *
+ * @author Robert Savage
+ */
+public interface I2CRegister extends IODataWriter, IODataReader {
+ /**
+ * @return This I2C device register address
+ */
+ int getAddress();
+ default int address(){
+ return getAddress();
+ }
+
+ /**
+ * Write a single word value (16-bit) to the I2C device register
+ * and immediately reads back a 16-bit word value.
+ *
+ * @param word 16-bit word value to be written
+ * @return The 16-bit word value read/returned; or a negative value if error
+ * @throws IOException thrown on write error
+ */
+ int writeReadWord(int word) throws IOException, IOReadException;
+}
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
new file mode 100644
index 000000000..d4ff983eb
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReader.java
@@ -0,0 +1,112 @@
+package com.pi4j.io.i2c;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : I2CRegisterDataReader.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.exception.IOReadException;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * I2C Register Data Writer Interface for Pi4J Data Communications
+ *
+ * @author Robert Savage
+ *
+ * Based on previous contributions from:
+ * Daniel Sendula,
+ * RasPelikan
+ */
+public interface I2CRegisterDataReader {
+
+ // ------------------------------------------------------------------------------------------------------------
+
+ 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);
+ }
+ default int readRegister(int register, byte[] buffer, int length) throws IOException{
+ return readRegister(register, buffer, 0, length);
+ }
+ default int readRegister(int register, byte[] buffer) throws IOException{
+ return readRegister(register, buffer, 0, buffer.length);
+ }
+ default int readRegister(int register, ByteBuffer buffer, int length) throws IOException{
+ return readRegister(register, buffer, 0, length);
+ }
+ default int readRegister(int register, ByteBuffer buffer) throws IOException{
+ return readRegister(register, buffer, 0, buffer.capacity());
+ }
+
+ // ------------------------------------------------------------------------------------------------------------
+
+ default String readRegisterString(int register, int length) throws IOException, IOReadException {
+ return readRegisterString(register, length, StandardCharsets.US_ASCII);
+ }
+
+ 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);
+ }
+
+ default byte readRegisterByte(int register) throws IOException, IOReadException {
+ int actual = readRegister(register);
+ if(actual < 0) throw new IOReadException(actual);
+ return (byte)actual;
+ }
+
+ default int readRegisterWord(int register) throws IOException, IOReadException {
+ 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 {
+ byte[] temp = new byte[length];
+ int actual = readRegister(register, temp, 0, length);
+ if(actual < 0) throw new IOReadException(actual);
+ return ByteBuffer.wrap(temp, 0, actual);
+ }
+
+ default byte[] readRegisterArray(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);
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReaderWriter.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReaderWriter.java
new file mode 100644
index 000000000..83cb9282a
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataReaderWriter.java
@@ -0,0 +1,57 @@
+package com.pi4j.io.i2c;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : I2CRegisterDataReaderWriter.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.exception.IOReadException;
+
+import java.io.IOException;
+
+/**
+ * I2C Register Data Writer Interface for Pi4J Data Communications
+ *
+ * @author Robert Savage
+ *
+ * Based on previous contributions from:
+ * Daniel Sendula,
+ * RasPelikan
+ */
+public interface I2CRegisterDataReaderWriter extends I2CRegisterDataReader, I2CRegisterDataWriter {
+ /**
+ * Write a single word value (16-bit) to the I2C device register
+ * and immediately reads back a 16-bit word value.
+ *
+ * @param register the register address to write to
+ * @param word 16-bit word value to be written
+ * @return The 16-bit word value read/returned; or a negative value if error
+ * @throws IOException thrown on write error
+ */
+ default int writeReadRegisterWord(int register, int word) throws IOException, IOReadException {
+ writeRegisterWord(register, word);
+ return readRegisterWord(register);
+ }
+}
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
new file mode 100644
index 000000000..65e92ebc4
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/I2CRegisterDataWriter.java
@@ -0,0 +1,193 @@
+package com.pi4j.io.i2c;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : I2CRegisterDataWriter.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 java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+/**
+ * I2C Register Data Writer Interface for Pi4J Data Communications
+ *
+ * @author Robert Savage
+ *
+ * Based on previous contributions from:
+ * Daniel Sendula,
+ * RasPelikan
+ */
+public interface I2CRegisterDataWriter {
+
+ /**
+ * Write a single raw byte (8-bit) value to the I2C device register.
+ *
+ * @param register the register address to write to
+ * @param b byte to be written
+ * @throws IOException thrown on write error
+ */
+ void writeRegister(int register, byte b) throws IOException;
+
+ /**
+ * Write a single raw byte (8-bit) value to the I2C device register.
+ *
+ * @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);
+ }
+
+ /**
+ * Write a single word value (16-bit) to the I2C device register.
+ *
+ * @param register the register address to write to
+ * @param word 16-bit word value to be written
+ * @throws IOException thrown on write error
+ */
+ default void writeRegisterWord(int register, int word) throws IOException{
+ byte[] buffer = new byte[] { (byte)(word >> 8), (byte)word };
+ 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;
+
+ /**
+ * Write a array of byte values with given offset (starting position)
+ * and length in the provided data array to a specific I2C device register.
+ *
+ * @param register the register address to write to
+ * @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 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);
+ }
+
+ /**
+ * Write a array of byte values starting with the first byte in the array up to the provided length.
+ *
+ * @param register the register address to write to
+ * @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 int writeRegister(int register, byte[] data, int length) throws IOException{
+ return writeRegister(register, data, 0, length);
+ }
+
+ /**
+ * This method writes all bytes included in the given buffer directly to the i2c device.
+ *
+ * @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{
+ return writeRegister(register, data, 0, data.length);
+ }
+
+ /**
+ * 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
+ * @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);
+ }
+
+
+ /**
+ * 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
+ * @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, 0, buffer.capacity());
+ }
+
+ /**
+ * This method writes all bytes included in the given buffer directly to the i2c device.
+ *
+ * @param register the register address to write to
+ * @param stream stream 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, InputStream stream) throws IOException{
+ return writeRegister(register, stream.readAllBytes());
+ }
+
+ /**
+ * This method writes all bytes included in the given buffer directly to the i2c device.
+ *
+ * @param register the register address to write to
+ * @param data string 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, String data) throws IOException{
+ return writeRegister(register, data.getBytes(StandardCharsets.US_ASCII));
+ }
+
+ /**
+ * This method writes all bytes included in the given buffer directly to the i2c device.
+ *
+ * @param register the register address to write to
+ * @param data string 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, String data, Charset charset) throws IOException{
+ return writeRegister(register, data.getBytes(charset));
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CConfig.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CConfig.java
new file mode 100644
index 000000000..dc36bc42b
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CConfig.java
@@ -0,0 +1,92 @@
+package com.pi4j.io.i2c.impl;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : DefaultI2CConfig.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.ConfigBase;
+import com.pi4j.config.exception.ConfigMissingRequiredKeyException;
+import com.pi4j.io.gpio.digital.PullResistance;
+import com.pi4j.io.i2c.I2CConfig;
+import com.pi4j.util.StringUtil;
+
+import java.util.Map;
+
+public class DefaultI2CConfig
+ extends ConfigBase
+ implements I2CConfig {
+
+ // private configuration properties
+ protected Integer bus = null;
+ protected Integer device = null;
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ */
+ private DefaultI2CConfig(){
+ super();
+ }
+
+ // private configuration properties
+ protected PullResistance pullResistance = PullResistance.OFF;
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ * @param properties
+ */
+ protected DefaultI2CConfig(Map properties){
+ super(properties);
+
+ // define default property values if any are missing (based on the required address value)
+ this.id = StringUtil.setIfNullOrEmpty(this.id, "I2C-" + this.bus() + "." + this.device(), true);
+ this.name = StringUtil.setIfNullOrEmpty(this.name, "I2C-" + this.bus() + "." + this.device(), true);
+ this.description = StringUtil.setIfNullOrEmpty(this.description, "I2C-" + this.bus() + "." + this.device(), true);
+
+ // load (required) BUS property
+ if(properties.containsKey(BUS_KEY)){
+ this.bus = Integer.parseInt(properties.get(BUS_KEY));
+ } else {
+ throw new ConfigMissingRequiredKeyException(BUS_KEY);
+ }
+
+ // load (required) DEVICE property
+ if(properties.containsKey(DEVICE_KEY)){
+ this.device = Integer.parseInt(properties.get(DEVICE_KEY));
+ } else {
+ throw new ConfigMissingRequiredKeyException(DEVICE_KEY);
+ }
+ }
+
+ @Override
+ public Integer bus() {
+ return this.bus;
+ }
+
+ @Override
+ public Integer device() {
+ return this.device;
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CConfigBuilder.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CConfigBuilder.java
new file mode 100644
index 000000000..4c762d874
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CConfigBuilder.java
@@ -0,0 +1,66 @@
+package com.pi4j.io.i2c.impl;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : DefaultI2CConfigBuilder.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.ConfigBuilderBase;
+import com.pi4j.io.i2c.I2CConfig;
+import com.pi4j.io.i2c.I2CConfigBuilder;
+
+public class DefaultI2CConfigBuilder
+ extends ConfigBuilderBase
+ implements I2CConfigBuilder {
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ */
+ protected DefaultI2CConfigBuilder(){
+ super();
+ }
+
+ public static I2CConfigBuilder newInstance() {
+ return new DefaultI2CConfigBuilder();
+ }
+
+ @Override
+ public I2CConfig build() {
+ I2CConfig config = new DefaultI2CConfig(properties);
+ return config;
+ }
+
+ @Override
+ public I2CConfigBuilder bus(Integer bus){
+ this.properties.put(I2CConfig.BUS_KEY, bus.toString());
+ return this;
+ }
+
+ @Override
+ public I2CConfigBuilder device(Integer device){
+ this.properties.put(I2CConfig.DEVICE_KEY, device.toString());
+ return this;
+ }
+}
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
new file mode 100644
index 000000000..3a557ad88
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/DefaultI2CRegister.java
@@ -0,0 +1,107 @@
+package com.pi4j.io.i2c.impl;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : DefaultI2CRegister.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.exception.IOReadException;
+import com.pi4j.io.i2c.I2C;
+import com.pi4j.io.i2c.I2CRegister;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Objects;
+
+public class DefaultI2CRegister implements I2CRegister {
+
+ protected final int address;
+ protected final I2C i2c;
+
+ public DefaultI2CRegister(I2C i2c, int address){
+ this.i2c = i2c;
+ this.address = address;
+ }
+
+ @Override
+ public int getAddress() {
+ return this.address;
+ }
+
+ @Override
+ public void write(byte b) throws IOException {
+ this.i2c.writeRegister(this.address, b);
+ }
+
+ /**
+ * 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
+ */
+ @Override
+ public void writeWord(int word) throws IOException{
+ this.i2c.writeRegisterWord(this.address, word);
+ }
+
+ @Override
+ public int readWord() throws IOException, IOReadException {
+ return this.i2c.readRegisterWord(this.address);
+ }
+
+ @Override
+ 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());
+ return this.i2c.readRegister(this.address, buffer, offset, length);
+ }
+
+ @Override
+ public String readString(int length, Charset charset) throws IOException, IOReadException {
+ return this.i2c.readRegisterString(this.address, length, charset);
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/I2CFactory.java b/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/I2CFactory.java
deleted file mode 100644
index 2fb728148..000000000
--- a/pi4j-api/src/main/java/com/pi4j/io/i2c/impl/I2CFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.pi4j.io.i2c.impl;
-
-/*
- * #%L
- * **********************************************************************
- * ORGANIZATION : Pi4J
- * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
- * FILENAME : I2CFactory.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.i2c.I2C;
-import com.pi4j.io.i2c.I2CConfig;
-import com.pi4j.io.i2c.I2CProvider;
-import com.pi4j.provider.exception.ProviderException;
-
-/**
- * @author Robert Savage (http://www .savagehomeautomation.com)
- */
-public class I2CFactory {
-
- // private constructor
- private I2CFactory() {
- // forbid object construction
- }
-
- public static I2C instance(Context context, I2CConfig config) throws ProviderException {
- // get I2C instance using default io
- var provider = context.platform().i2c();
- return instance(provider, config);
- }
-
- public static I2C instance(Context context, String device, int address) throws ProviderException {
- return instance(context, new I2CConfig(device, address));
- }
-
- public static I2C instance(Context context, String providerId, String device, int address) throws ProviderException {
- return instance(context, providerId, new I2CConfig(device, address));
- }
-
- public static I2C instance(Context context, String providerId, I2CConfig 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().i2c().get(providerId);
- return instance(provider, config);
- }
- }
-
- public static I2C instance(I2CProvider provider, String device, int address) throws ProviderException {
- return instance(provider, new I2CConfig(device, address));
- }
-
- public static I2C instance(I2CProvider provider, I2CConfig config) throws ProviderException {
- try {
- // create a I2C instance using the io
- return provider.create(config);
- } catch(ProviderException pe){
- throw pe;
- } catch (Exception e) {
- throw new ProviderException(provider, e);
- }
- }
-}
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 c55ce82dc..f9a7b1881 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
@@ -27,36 +27,100 @@
* #L%
*/
-import com.pi4j.context.Context;
import com.pi4j.io.IO;
-import com.pi4j.io.pwm.impl.PwmFactory;
-import com.pi4j.provider.exception.ProviderException;
+
+import java.io.IOException;
+import java.util.Map;
public interface Pwm extends IO {
- static final String ID = "PWM";
+ static PwmConfigBuilder newConfigBuilder(){
+ return PwmConfigBuilder.newInstance();
+ }
+
+ default int getAddress(){
+ return config().address();
+ }
+ default int address(){
+ return getAddress();
+ }
+
+ boolean isOn();
+ Pwm on() throws IOException;
+ Pwm off() throws IOException;
+
+ default PwmType pwmType(){
+ return config().getPwmType();
+ }
+ default PwmType getPwmType(){
+ return pwmType();
+ }
+
+ default Pwm on(int dutyCycle) throws IOException{
+ if(dutyCycle > 0) {
+ setDutyCycle(dutyCycle);
+ return on();
+ }
+ else{
+ return off();
+ }
+ }
- static Pwm instance(Context context, PwmConfig config) throws ProviderException {
- return PwmFactory.instance(context, config);
+ default Pwm on(int dutyCycle, int frequency) throws IOException{
+ if(dutyCycle > 0 && frequency > 0) {
+ setDutyCycle(dutyCycle);
+ setFrequency(frequency);
+ return on();
+ }
+ else{
+ return off();
+ }
}
- static Pwm instance(Context context, int address) throws ProviderException {
- return PwmFactory.instance(context, address);
+ default boolean isOff(){
+ return !isOn();
}
- static Pwm instance(Context context, String providerId, int address) throws ProviderException {
- return PwmFactory.instance(context, providerId, address);
+ default float getDutyCyclePercent() throws IOException{
+ return getDutyCycle() * 100 / getRange();
}
+ default float dutyCyclePercent() throws IOException { return getDutyCyclePercent();}
+
+ int getDutyCycle() throws IOException;
+ default int dutyCycle() throws IOException { return getDutyCycle();}
+
+ int getFrequency() 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; }
- static Pwm instance(Context context, String providerId, PwmConfig config) throws ProviderException {
- return PwmFactory.instance(context, providerId, config);
+ 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; }
- static Pwm instance(PwmProvider provider, int address) throws ProviderException {
- return PwmFactory.instance(provider, address);
+ 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; }
+
+ Map getPresets();
+ default Map presets(){
+ return getPresets();
}
- static Pwm instance(PwmProvider provider, PwmConfig config) throws ProviderException {
- return PwmFactory.instance(provider, config);
+ PwmPreset getPreset(String name);
+ default PwmPreset preset(String name){
+ return getPreset(name);
}
+
+ PwmPreset deletePreset(String name);
+ Pwm addPreset(PwmPreset preset);
+ 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 4c9a42312..a3ba689e6 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
@@ -27,12 +27,142 @@
* #L%
*/
+import com.pi4j.context.Context;
+import com.pi4j.exception.InitializeException;
+import com.pi4j.exception.ShutdownException;
import com.pi4j.io.IOBase;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
public abstract class PwmBase extends IOBase implements Pwm {
+ protected int range = -1;
+ protected int frequency = -1;
+ protected int dutyCycle = -1;
+ protected boolean onState = false;
+ protected Map presets = Collections.synchronizedMap(new HashMap<>());
+
public PwmBase(PwmProvider provider, PwmConfig config) {
super(provider, config);
- this.name = "PWM-" + config.address();
+ this.name = config.name();
+ this.id = config.id();
+ this.description = config.description();
+ for(PwmPreset preset : config.presets()){
+ this.presets.put(preset.name().toLowerCase().trim(), preset);
+ }
+ }
+
+ @Override
+ public int getDutyCycle() throws IOException {
+ return this.dutyCycle;
+ }
+
+ @Override
+ public int getFrequency() throws IOException {
+ return this.frequency;
+ }
+
+ @Override
+ public void setDutyCycle(int dutyCycle) throws IOException {
+ this.dutyCycle = dutyCycle;
+ }
+
+ @Override
+ public void setFrequency(int frequency) throws IOException {
+ this.frequency = frequency;
+ }
+
+ @Override
+ public int getRange() throws IOException {
+ return this.range;
+ }
+
+ @Override
+ public void setRange(int range) throws IOException {
+ this.range = range;
+ }
+
+ @Override
+ public boolean isOn() {
+ return this.onState;
+ }
+
+ @Override
+ public Pwm initialize(Context context) throws InitializeException {
+ // apply an initial value if configured
+ if(this.config.initialValue() != null){
+ try {
+ this.on(this.config.initialValue());
+ } catch (IOException e) {
+ throw new InitializeException(e);
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public Pwm shutdown(Context context) throws ShutdownException {
+ // apply a shutdown value if configured
+ if(this.config.shutdownValue() != null){
+ try {
+ if(this.config.shutdownValue() <= 0){
+ this.off();
+ } else {
+ this.on(this.config.shutdownValue());
+ }
+ } catch (IOException e) {
+ throw new ShutdownException(e);
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public Map getPresets(){
+ return Collections.unmodifiableMap(this.presets);
+ }
+
+ @Override
+ public PwmPreset getPreset(String name){
+ String key = name.toLowerCase().trim();
+ if(presets.containsKey(key)) {
+ return presets.get(key);
+ }
+ return null;
+ }
+
+ @Override
+ public PwmPreset deletePreset(String name){
+ String key = name.toLowerCase().trim();
+ if(presets.containsKey(key)) {
+ return presets.remove(key);
+ }
+ return null;
+ }
+
+ @Override
+ public Pwm addPreset(PwmPreset preset){
+ String key = preset.name().toLowerCase().trim();
+ presets.put(key, preset);
+ return this;
+ }
+
+ @Override
+ public Pwm applyPreset(String name) throws IOException {
+ String key = name.toLowerCase().trim();
+ if(presets.containsKey(key)) {
+ PwmPreset preset = presets.get(key);
+ if(preset.dutyCycle() != null)
+ setDutyCycle(preset.dutyCycle().intValue());
+ if(preset.frequency() != null)
+ setFrequency(preset.frequency().intValue());
+ on(); // update PWM signal now
+ } else{
+ throw new IOException("PWM PRESET NOT FOUND: "+ name);
+ }
+ return this;
}
}
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 674bfaa17..852124289 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
@@ -27,12 +27,64 @@
* #L%
*/
-import com.pi4j.config.impl.AddressConfigBase;
-import com.pi4j.io.IOConfig;
+import com.pi4j.config.AddressConfig;
+import com.pi4j.io.gpio.GpioConfig;
-public class PwmConfig extends AddressConfigBase implements IOConfig {
+import java.util.Collection;
- public PwmConfig(Number address) {
- super();
+public interface PwmConfig extends GpioConfig, AddressConfig {
+
+ String PWM_TYPE_KEY = "pwm-type";
+ String FREQUENCY_KEY = "frequency";
+ String RANGE_KEY = "range";
+ String DUTY_CYCLE_KEY = "duty-cycle";
+ String DUTY_CYCLE_PERCENT_KEY = "duty-cycle-percent";
+ String SHUTDOWN_VALUE_KEY = "shutdown";
+ String INITIAL_VALUE_KEY = "initial";
+ String PRESET_KEY = "applyPreset";
+
+ Integer dutyCycle();
+ default Integer getDutyCycle() {
+ return dutyCycle();
+ }
+
+ Integer dutyCyclePercent();
+ default Integer getDutyCyclePercent() {
+ return dutyCyclePercent();
+ }
+
+ Integer range();
+ default Integer getRange() {
+ return range();
+ }
+
+ Integer frequency();
+ default Integer getFrequency() {
+ return frequency();
+ }
+
+ PwmType pwmType();
+ default PwmType getPwmType(){
+ return pwmType();
+ }
+
+ Integer shutdownValue();
+ PwmConfig shutdownValue(Integer value);
+ default Integer getShutdownValue(){
+ return shutdownValue();
}
+ default void setShutdownValue(Integer value){
+ this.shutdownValue(value);
+ }
+
+ Integer initialValue();
+ default Integer getInitialValue(){
+ return initialValue();
+ }
+
+ Collection presets();
+ 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
new file mode 100644
index 000000000..b2dd3ad69
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmConfigBuilder.java
@@ -0,0 +1,46 @@
+package com.pi4j.io.pwm;
+
+/*-
+ * #%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.io.gpio.GpioConfigBuilder;
+import com.pi4j.io.pwm.impl.DefaultPwmConfigBuilder;
+
+public interface PwmConfigBuilder extends GpioConfigBuilder {
+ static PwmConfigBuilder newInstance() {
+ return DefaultPwmConfigBuilder.newInstance();
+ }
+
+ PwmConfigBuilder range(Integer range);
+ PwmConfigBuilder frequency(Integer frequency);
+ PwmConfigBuilder dutyCycle(Integer dutyCycle);
+ PwmConfigBuilder dutyCyclePercent(Integer percent);
+ PwmConfigBuilder pwmType(PwmType pwmType);
+ PwmConfigBuilder shutdown(Integer value);
+ PwmConfigBuilder initial(Integer value);
+ 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
new file mode 100644
index 000000000..9131d3fca
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPreset.java
@@ -0,0 +1,52 @@
+package com.pi4j.io.pwm;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : PwmPreset.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.impl.DefaultPwmPresetBuilder;
+
+public interface PwmPreset {
+
+ static PwmPresetBuilder newBuilder(String name){
+ return DefaultPwmPresetBuilder.newInstance(name);
+ }
+
+ String name();
+ default String getName() {
+ return name();
+ }
+
+ Integer dutyCycle();
+ default Integer getDutyCycle() {
+ return dutyCycle();
+ }
+
+ Integer frequency();
+ 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
new file mode 100644
index 000000000..145c6844b
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmPresetBuilder.java
@@ -0,0 +1,39 @@
+package com.pi4j.io.pwm;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : PwmPresetBuilder.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.Builder;
+import com.pi4j.io.pwm.impl.DefaultPwmPresetBuilder;
+
+public interface PwmPresetBuilder extends Builder {
+ static PwmPresetBuilder newInstance(String name) {
+ return DefaultPwmPresetBuilder.newInstance(name);
+ }
+ PwmPresetBuilder frequency(Integer frequency);
+ PwmPresetBuilder dutyCycle(Integer dutyCycle);
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmProvider.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmProvider.java
index e3da04e4e..a259d9bb1 100644
--- a/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmProvider.java
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmProvider.java
@@ -30,5 +30,42 @@
import com.pi4j.provider.Provider;
public interface PwmProvider extends Provider {
- //Pwm instance(PwmConfig config) throws Exception;
+
+ default T create(PwmConfigBuilder builder) throws Exception {
+ return (T)create(builder.build());
+ }
+
+ default T create(Integer address) throws Exception {
+ var config = Pwm.newConfigBuilder()
+ .address(address)
+ .build();
+ return (T)create(config);
+ }
+
+ default T create(Integer address, String id) throws Exception {
+ var config = Pwm.newConfigBuilder()
+ .address(address)
+ .id(id)
+ .build();
+ return (T)create(config);
+ }
+
+ default T create(Integer address, String id, String name) throws Exception {
+ var config = Pwm.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 = Pwm.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/pwm/PwmType.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmType.java
new file mode 100644
index 000000000..b318efeb8
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/PwmType.java
@@ -0,0 +1,74 @@
+package com.pi4j.io.pwm;
+
+import java.util.EnumSet;
+
+/*
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : PwmType.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%
+ */
+
+/**
+ * Digital Pin Pull Resistance Enumerations
+ *
+ * @author Robert Savage (http://www.savagehomeautomation.com)
+ */
+public enum PwmType {
+ SOFTWARE(0, "software"),
+ HARDWARE(1, "hardware");
+
+ private final int value;
+ private final String name;
+
+ private PwmType(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return name.toUpperCase();
+ }
+
+ public static EnumSet all() {
+ return EnumSet.allOf(PwmType.class);
+ }
+
+ public static PwmType parse(String pull) {
+ if(pull.equalsIgnoreCase("0")) return PwmType.SOFTWARE;
+ if(pull.equalsIgnoreCase("1")) return PwmType.HARDWARE;
+ if(pull.toLowerCase().startsWith("h")) return PwmType.HARDWARE;
+ if(pull.toLowerCase().startsWith("s")) return PwmType.SOFTWARE;
+ return PwmType.SOFTWARE; // default
+ }
+}
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
new file mode 100644
index 000000000..945c1f10b
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfig.java
@@ -0,0 +1,184 @@
+package com.pi4j.io.pwm.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.AddressConfigBase;
+import com.pi4j.io.gpio.digital.PullResistance;
+import com.pi4j.io.pwm.PwmConfig;
+import com.pi4j.io.pwm.PwmPreset;
+import com.pi4j.io.pwm.PwmType;
+import com.pi4j.util.StringUtil;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public class DefaultPwmConfig
+ extends AddressConfigBase
+ implements PwmConfig {
+
+ // private configuration properties
+ protected Integer dutyCycle = null;
+ protected Integer dutyCyclePercent = null;
+ protected Integer range = null;
+ protected Integer frequency = null;
+ protected PwmType pwmType = PwmType.SOFTWARE;
+ protected Integer shutdownValue = null;
+ protected Integer initialValue = null;
+ protected List presets = new ArrayList<>();
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ */
+ private DefaultPwmConfig(){
+ super();
+ }
+
+ // private configuration properties
+ protected PullResistance pullResistance = PullResistance.OFF;
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ * @param properties
+ */
+ protected DefaultPwmConfig(Map properties, Collection presets){
+ this(properties);
+ this.presets.addAll(presets);
+ }
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ * @param properties
+ */
+ protected DefaultPwmConfig(Map properties){
+ super(properties);
+
+ // define default property values if any are missing (based on the required address value)
+ this.id = StringUtil.setIfNullOrEmpty(this.id, "PWM-" + this.address, true);
+ this.name = StringUtil.setIfNullOrEmpty(this.name, "PWM-" + this.address, true);
+ this.description = StringUtil.setIfNullOrEmpty(this.description, "PWM-" + this.address, true);
+
+ // 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));
+ }
+
+ // load optional pwm frequency from properties
+ if(properties.containsKey(FREQUENCY_KEY)){
+ 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));
+ }
+
+ // load initial value property
+ if(properties.containsKey(INITIAL_VALUE_KEY)){
+ this.initialValue = Integer.parseInt(properties.get(INITIAL_VALUE_KEY));
+ }
+
+ // load shutdown value property
+ if(properties.containsKey(SHUTDOWN_VALUE_KEY)){
+ this.shutdownValue = Integer.parseInt(properties.get(SHUTDOWN_VALUE_KEY));
+ }
+
+ // bounds checking
+ if(this.dutyCyclePercent != null && this.dutyCyclePercent > 100)
+ this.dutyCyclePercent = 100;
+
+ // bounds checking
+ if(this.dutyCyclePercent != null && this.dutyCyclePercent < 0)
+ this.dutyCyclePercent = 0;
+ }
+
+ @Override
+ public Integer dutyCycle() {
+ return this.dutyCycle;
+ }
+
+ @Override
+ public Integer range() {
+ return this.range;
+ }
+
+ @Override
+ public Integer frequency() {
+ return this.frequency;
+ }
+
+ @Override
+ public PwmType pwmType() {
+ return this.pwmType;
+ }
+
+ @Override
+ public Integer 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;
+
+ return this.dutyCyclePercent;
+ }
+
+ @Override
+ public PwmConfig shutdownValue(Integer value){
+ this.shutdownValue = value;
+ return this;
+ }
+
+ @Override
+ public Integer initialValue() {
+ return this.initialValue;
+ }
+
+ @Override
+ public Collection presets(){
+ return this.presets;
+ }
+}
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
new file mode 100644
index 000000000..e2dd120ad
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmConfigBuilder.java
@@ -0,0 +1,120 @@
+package com.pi4j.io.pwm.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.AddressConfigBuilderBase;
+import com.pi4j.io.pwm.PwmConfig;
+import com.pi4j.io.pwm.PwmConfigBuilder;
+import com.pi4j.io.pwm.PwmPreset;
+import com.pi4j.io.pwm.PwmType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DefaultPwmConfigBuilder
+ extends AddressConfigBuilderBase
+ implements PwmConfigBuilder {
+
+ protected List presets = new ArrayList<>();
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ */
+ protected DefaultPwmConfigBuilder(){
+ super();
+ }
+
+ 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());
+ return this;
+ }
+
+ @Override
+ public PwmConfigBuilder dutyCycle(Integer dutyCycle) {
+ this.properties.put(PwmConfig.DUTY_CYCLE_KEY, dutyCycle.toString());
+ return this;
+ }
+
+ @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());
+ return this;
+ }
+
+ @Override
+ public PwmConfigBuilder pwmType(PwmType pwmType) {
+ this.properties.put(PwmConfig.PWM_TYPE_KEY, pwmType.toString());
+ return this;
+ }
+
+ @Override
+ public PwmConfigBuilder shutdown(Integer value) {
+ this.properties.put(PwmConfig.SHUTDOWN_VALUE_KEY, value.toString());
+ return this;
+ }
+
+ @Override
+ public PwmConfigBuilder initial(Integer value) {
+ this.properties.put(PwmConfig.INITIAL_VALUE_KEY, value.toString());
+ return this;
+ }
+
+ @Override
+ public PwmConfigBuilder preset(PwmPreset ... preset){
+ for(PwmPreset p : preset) {
+ this.presets.add(p);
+ }
+ return this;
+ }
+
+ @Override
+ public PwmConfig build() {
+ PwmConfig config = new DefaultPwmConfig(this.properties, this.presets);
+ return config;
+ }
+}
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
new file mode 100644
index 000000000..0bc312ea3
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPreset.java
@@ -0,0 +1,64 @@
+package com.pi4j.io.pwm.impl;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : DefaultPwmPreset.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.PwmPreset;
+
+public class DefaultPwmPreset implements PwmPreset {
+
+ protected final String name;
+ protected final Integer dutyCycle;
+ protected final Integer frequency;
+
+ public DefaultPwmPreset(String name, Integer dutyCycle){
+ this.name = name.toLowerCase().trim();
+ this.dutyCycle = dutyCycle;
+ this.frequency = null;
+ }
+
+ public DefaultPwmPreset(String name, Integer dutyCycle, Integer frequency){
+ this.name = name.toLowerCase().trim();
+ this.dutyCycle = dutyCycle;
+ this.frequency = frequency;
+ }
+
+ @Override
+ public String name() {
+ return this.name;
+ }
+
+ @Override
+ public Integer dutyCycle() {
+ return this.dutyCycle;
+ }
+
+ @Override
+ public Integer frequency() {
+ return this.frequency;
+ }
+}
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
new file mode 100644
index 000000000..09414fc3f
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/DefaultPwmPresetBuilder.java
@@ -0,0 +1,64 @@
+package com.pi4j.io.pwm.impl;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : DefaultPwmPresetBuilder.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.PwmPreset;
+import com.pi4j.io.pwm.PwmPresetBuilder;
+
+public class DefaultPwmPresetBuilder implements PwmPresetBuilder{
+ protected Integer dutyCycle = null;
+ protected Integer frequency = null;
+ protected final String name;
+
+ /**
+ * PRIVATE CONSTRUCTOR
+ */
+ protected DefaultPwmPresetBuilder(String name){
+ super(); this.name = name;
+ }
+
+ public static PwmPresetBuilder newInstance(String name) {
+ return new DefaultPwmPresetBuilder(name);
+ }
+
+ @Override
+ public PwmPresetBuilder frequency(Integer frequency) {
+ this.frequency = frequency;
+ return this;
+ }
+
+ @Override
+ public PwmPresetBuilder dutyCycle(Integer dutyCycle) {
+ this.dutyCycle = dutyCycle;
+ return this;
+ }
+ @Override
+ public PwmPreset build() {
+ return new DefaultPwmPreset(this.name, this.dutyCycle, this.frequency);
+ }
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/PwmFactory.java b/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/PwmFactory.java
deleted file mode 100644
index 052bdee07..000000000
--- a/pi4j-api/src/main/java/com/pi4j/io/pwm/impl/PwmFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.pi4j.io.pwm.impl;
-
-/*
- * #%L
- * **********************************************************************
- * ORGANIZATION : Pi4J
- * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
- * FILENAME : PwmFactory.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.pwm.Pwm;
-import com.pi4j.io.pwm.PwmConfig;
-import com.pi4j.io.pwm.PwmProvider;
-import com.pi4j.provider.exception.ProviderException;
-
-/**
- * @author Robert Savage (http://www .savagehomeautomation.com)
- */
-public class PwmFactory {
-
- // private constructor
- private PwmFactory() {
- // forbid object construction
- }
-
- public static Pwm instance(Context context, PwmConfig config) throws ProviderException {
- // get I2C instance using default io
- var provider = context.platform().pwm();
- return instance(provider, config);
- }
-
- public static Pwm instance(Context context, int address) throws ProviderException {
- return instance(context, new PwmConfig(address));
- }
-
- public static Pwm instance(Context context, String providerId, int address) throws ProviderException {
- return instance(context, providerId, new PwmConfig(address));
- }
-
- public static Pwm instance(Context context, String providerId, PwmConfig config) throws ProviderException {
- // if provided, lookup the specified io; else use the default io
- if(providerId == null) {
- return instance(context, config);
- }
- else{
- PwmProvider provider = context.providers().pwm().get(providerId);
- return instance(provider, config);
- }
- }
-
- public static Pwm instance(PwmProvider provider, int address) throws ProviderException {
- return instance(provider, new PwmConfig(address));
- }
-
- public static Pwm instance(PwmProvider provider, PwmConfig config) throws ProviderException {
- try {
- // create a PWM instance using the io
- return provider.create(config);
- } catch(ProviderException pe){
- throw pe;
- } catch (Exception e) {
- throw new ProviderException(provider, e);
- }
- }
-}
diff --git a/pi4j-api/src/main/java/com/pi4j/runtime/Runtime.java b/pi4j-api/src/main/java/com/pi4j/runtime/Runtime.java
index 70efae21e..083939130 100644
--- a/pi4j-api/src/main/java/com/pi4j/runtime/Runtime.java
+++ b/pi4j-api/src/main/java/com/pi4j/runtime/Runtime.java
@@ -39,6 +39,7 @@ public interface Runtime {
RuntimeRegistry registry();
RuntimeProviders providers();
RuntimePlatforms platforms();
+ RuntimeProperties properties();
Context context();
Runtime inject(Object... objects) throws AnnotationException;
diff --git a/pi4j-api/src/main/java/com/pi4j/runtime/RuntimeProperties.java b/pi4j-api/src/main/java/com/pi4j/runtime/RuntimeProperties.java
new file mode 100644
index 000000000..8bb95ec22
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/runtime/RuntimeProperties.java
@@ -0,0 +1,40 @@
+package com.pi4j.runtime;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : RuntimeProperties.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.ContextProperties;
+
+import java.util.Map;
+import java.util.Properties;
+
+public interface RuntimeProperties extends ContextProperties {
+ void put(String key, String value);
+ void put(Properties properties);
+ void put(Map values);
+ void put(Map.Entry ... value);
+}
diff --git a/pi4j-api/src/main/java/com/pi4j/runtime/impl/DefaultRuntime.java b/pi4j-api/src/main/java/com/pi4j/runtime/impl/DefaultRuntime.java
index df0716878..9ef62c36d 100644
--- a/pi4j-api/src/main/java/com/pi4j/runtime/impl/DefaultRuntime.java
+++ b/pi4j-api/src/main/java/com/pi4j/runtime/impl/DefaultRuntime.java
@@ -46,13 +46,11 @@
import com.pi4j.registry.impl.DefaultRuntimeRegistry;
import com.pi4j.registry.impl.RuntimeRegistry;
import com.pi4j.runtime.Runtime;
+import com.pi4j.runtime.RuntimeProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.ServiceLoader;
-import java.util.Set;
+import java.util.*;
public class DefaultRuntime implements Runtime {
@@ -62,6 +60,9 @@ public class DefaultRuntime implements Runtime {
private RuntimeRegistry registry = null;
private RuntimeProviders providers = null;
private RuntimePlatforms platforms = null;
+ private RuntimeProperties properties = null;
+ private List plugins = new ArrayList<>();
+ private boolean isShutdown = false;
public static Runtime newInstance(Context context) throws Pi4JException {
return new DefaultRuntime(context);
@@ -72,12 +73,26 @@ private DefaultRuntime(Context context) throws Pi4JException {
// set local references
this.context = context;
+ this.properties = DefaultRuntimeProperties.newInstance(context);
this.annotationEngine = DefaultAnnotationEngine.newInstance(context);
this.registry = DefaultRuntimeRegistry.newInstance(this);
this.providers = DefaultRuntimeProviders.newInstance(this);
this.platforms = DefaultRuntimePlatforms.newInstance(this);
logger.debug("Pi4J runtime context successfully created & initialized.'");
+
+ // listen for shutdown to properly clean up
+ // TODO :: ADD PI4J INTERNAL SHUTDOWN CALLBACKS/EVENTS
+ java.lang.Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ try {
+ // shutdown Pi4J
+ shutdown();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }));
+
}
@Override
@@ -96,6 +111,11 @@ public RuntimePlatforms platforms() {
return this.platforms;
}
+ @Override
+ public RuntimeProperties properties() {
+ return this.properties;
+ }
+
@Override
public Runtime inject(Object... objects) throws AnnotationException {
annotationEngine.inject(objects);
@@ -104,24 +124,36 @@ public Runtime inject(Object... objects) throws AnnotationException {
@Override
public Runtime shutdown() throws ShutdownException {
- logger.trace("invoked 'shutdown();'");
- try {
- // shutdown all providers
- this.providers.shutdown();
-
- // shutdown platforms
- this.platforms.shutdown();
-
- // remove all I/O instances
- this.registry.shutdown();
+ if(!isShutdown) { // re-entrant calls should not perform shutdown again
+ isShutdown = true;
+ logger.trace("invoked 'shutdown();'");
+ try {
+ // remove all I/O instances
+ this.registry.shutdown();
+
+ // shutdown platforms
+ this.platforms.shutdown();
+
+ // shutdown all providers
+ this.providers.shutdown();
+
+ // shutdown all plugins
+ for (Plugin plugin : this.plugins) {
+ try {
+ plugin.shutdown(this.context);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ } catch (Exception e) {
+ logger.error("failed to 'shutdown(); '", e);
+ throw new ShutdownException(e);
+ }
- } catch (Exception e) {
- logger.error("failed to 'shutdown(); '", e);
- throw new ShutdownException(e);
+ logger.debug("Pi4J context/runtime successfully shutdown.'");
+ } else{
+ logger.debug("Pi4J context/runtime is already shutdown.'");
}
-
- logger.debug("Pi4J context/runtime successfully shutdown.'");
-
return this;
}
@@ -129,6 +161,9 @@ public Runtime shutdown() throws ShutdownException {
public Runtime initialize() throws InitializeException {
logger.trace("invoked 'initialize();'");
try {
+ // clear plugins container
+ plugins.clear();
+
// container sets for providers and platforms to load
Set providers = Collections.synchronizedSet(new HashSet<>());
Set platforms = Collections.synchronizedSet(new HashSet<>());
@@ -147,6 +182,9 @@ public Runtime initialize() throws InitializeException {
logger.trace("detected plugin: [{}] in classpath; calling 'initialize()'",
plugin.getClass().getName());
try {
+ // add plugin to internal cache
+ this.plugins.add(plugin);
+
PluginStore store = new PluginStore();
plugin.initialize(DefaultPluginService.newInstance(this.context(), store));
diff --git a/pi4j-api/src/main/java/com/pi4j/runtime/impl/DefaultRuntimeProperties.java b/pi4j-api/src/main/java/com/pi4j/runtime/impl/DefaultRuntimeProperties.java
new file mode 100644
index 000000000..c636ef19d
--- /dev/null
+++ b/pi4j-api/src/main/java/com/pi4j/runtime/impl/DefaultRuntimeProperties.java
@@ -0,0 +1,225 @@
+package com.pi4j.runtime.impl;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: LIBRARY :: Java Library (API)
+ * FILENAME : DefaultRuntimeProperties.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.runtime.RuntimeProperties;
+import com.pi4j.util.StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+public class DefaultRuntimeProperties implements RuntimeProperties {
+
+ public static String PI4J_PROPERTIES_FILE_NAME = "pi4j.properties";
+
+ protected Map properties = Collections.synchronizedMap(new HashMap<>());
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ // static singleton instance
+ public static RuntimeProperties newInstance(Context context){
+ return new DefaultRuntimeProperties(context);
+ }
+
+ private DefaultRuntimeProperties(Context context){
+ // now lets load optional Pi4J.properties files from the file system
+
+ // first; load any default Pi4J properties defined in the Environment Variables
+ try{
+ // use "pi4j." prefix filter to limit the environment variables that we care about
+ put(System.getenv(), "pi4j.");
+ }
+ catch (Exception e){
+ logger.error(e.getMessage(), e);
+ }
+
+ // first; load system-scoped Pi4J properties file
+ // /etc/pi4j/pi4j.properties
+ try {
+ Path appFile = Paths.get("/etc/pi4j", PI4J_PROPERTIES_FILE_NAME);
+ if (Files.exists(appFile)) {
+ Properties p = new Properties();
+ p.load(new FileInputStream(appFile.toFile()));
+ put(p);
+ }
+ }
+ catch (Exception e){
+ logger.error(e.getMessage(), e);
+ }
+
+ // second; load user-scoped Pi4J properties file
+ // ~/.pi4j.properties
+ try {
+ Path appFile = Paths.get(System.getProperty("user.home"), "." + PI4J_PROPERTIES_FILE_NAME);
+ if (Files.exists(appFile)) {
+ Properties p = new Properties();
+ p.load(new FileInputStream(appFile.toFile()));
+ put(p);
+ }
+ }
+ catch (Exception e){
+ logger.error(e.getMessage(), e);
+ }
+
+ // third; load an application-scoped Pi4J properties file
+ // {pwd}/pi4j.properties
+ try {
+ Path appFile = Paths.get(System.getProperty("user.dir"), PI4J_PROPERTIES_FILE_NAME);
+ if (Files.exists(appFile)) {
+ Properties p = new Properties();
+ p.load(new FileInputStream(appFile.toFile()));
+ put(p);
+ }
+ }
+ catch (Exception e){
+ logger.error(e.getMessage(), e);
+ }
+
+ // fourth; load an application-embedded resource Pi4J properties file
+ // {app}/{resources}/pi4j.properties
+ try {
+ URL resource = getClass().getClassLoader().getResource(PI4J_PROPERTIES_FILE_NAME);
+ if(resource != null) {
+ File resourceFile = new File(resource.getFile());
+ if (resourceFile != null && resourceFile.exists()) {
+ Properties p = new Properties();
+ p.load(new FileInputStream(resourceFile));
+ put(p);
+ }
+ }
+ }
+ catch (Exception e){
+ logger.error(e.getMessage(), e);
+ }
+
+ // finally; load any default properties defined in the System.properties
+ try{
+ // use "pi4j." prefix filter to limit the system properties that we care about
+ put(System.getProperties(), "pi4j.");
+ }
+ catch (Exception e){
+ logger.error(e.getMessage(), e);
+ }
+
+
+ // add all context pre-configured properties to the runtime properties cache
+ this.put(context.config().properties());
+ }
+
+ protected String sanitizeKey(String key){
+ return key.trim().toLowerCase();
+ }
+
+ @Override
+ public boolean has(String key) {
+ return properties.containsKey(sanitizeKey(key));
+ }
+
+ @Override
+ public String get(String key) {
+ String k = sanitizeKey(key);
+
+ // first, attempt to get property for internal cache
+ if(properties.containsKey(k)){
+ return properties.get(k);
+ }
+ return null;
+ }
+
+ @Override
+ public void put(String key, String value) {
+ properties.put(sanitizeKey(key), value);
+ }
+
+ @Override
+ public void put(Properties properties) {
+ properties.forEach((key,value)->{
+ this.properties.put(sanitizeKey(key.toString()), value.toString());
+ });
+ }
+
+ @Override
+ public void put(Map values) {
+ values.forEach((key,value)->{
+ this.properties.put(sanitizeKey(key), value);
+ });
+ }
+
+ @Override
+ public void put(Map.Entry... value) {
+ for(Map.Entry e : value){
+ this.properties.put(sanitizeKey(e.getKey().toString()), e.getValue().toString());
+ }
+ }
+
+ @Override
+ public Map all() {
+ return Collections.unmodifiableMap(this.properties);
+ }
+
+ @Override
+ public int count() {
+ return this.properties.size();
+ }
+
+
+ protected void put(Properties properties, String prefixFilter){
+ // convert java.util.Properties to a Map object
+ Map entries = properties.keySet().stream()
+ .collect(Collectors.toMap(k->k.toString(), key->properties.get(key).toString()));
+ put(entries, prefixFilter);
+ }
+
+ protected void put(Map properties, String prefixFilter){
+
+ // if a filter was not provided, then load properties without a filter
+ if(StringUtil.isNullOrEmpty(prefixFilter)) {
+ put(properties);
+ return;
+ }
+
+ // sanitize the prefix filter and make sure it includes a "." character at the end
+ var prefix = (prefixFilter.endsWith(".")) ? prefixFilter : prefixFilter+".";
+
+ // iterate the properties object and assign any key with the prefix filter to this config
+ properties.keySet().stream().filter(key -> key.startsWith(prefix)).forEach((key)->{
+ put(key.substring(prefix.length()), properties.get(key));
+ });
+ }
+}
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 b946be59a..325ac3336 100644
--- a/pi4j-api/src/main/java/com/pi4j/util/StringUtil.java
+++ b/pi4j-api/src/main/java/com/pi4j/util/StringUtil.java
@@ -28,6 +28,9 @@
*/
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
public class StringUtil {
public static final String EMPTY = "";
@@ -249,4 +252,75 @@ public static String concat(String ... data) {
}
return sb.toString();
}
+
+ public static void appendHexString(StringBuilder builder, byte byt){
+ builder.append(String.format("%02X", byt));
+ }
+ public static String toHexString(byte byt){
+ return String.format("%02X", byt);
+ }
+
+ public static void appendHexString(StringBuilder builder, int byt){
+ builder.append(String.format("%02X", (byte)byt));
+ }
+ public static String toHexString(int byt){
+ return String.format("%02X", (byte)byt);
+ }
+
+ public static void appendHexString(StringBuilder builder, byte[] bytes){
+ for (byte b : bytes) {
+ builder.append(String.format("%02X ", b));
+ }
+ }
+ public static String toHexString(byte[] bytes){
+ StringBuilder sb = new StringBuilder();
+ appendHexString(sb, bytes);
+ return sb.toString().trim();
+ }
+
+ public static void appendHexString(StringBuilder builder, ByteBuffer buffer){
+ appendHexString(builder, buffer.array());
+ }
+ public static String toHexString(ByteBuffer buffer){
+ StringBuilder sb = new StringBuilder();
+ appendHexString(sb, buffer);
+ return sb.toString().trim();
+ }
+
+ public static void appendHexString(StringBuilder builder, byte[] bytes, int offset, int length){
+ appendHexString(builder, Arrays.copyOfRange(bytes, offset, length));
+ }
+ public static String toHexString(byte[] bytes, int offset, int length){
+ StringBuilder sb = new StringBuilder();
+ appendHexString(sb, bytes, offset, length);
+ return sb.toString().trim();
+ }
+
+ public static void appendHexString(StringBuilder builder, ByteBuffer buffer, int offset, int length){
+ appendHexString(builder, buffer.array(), offset, length);
+ }
+ public static String toHexString(ByteBuffer buffer, int offset, int length){
+ StringBuilder sb = new StringBuilder();
+ appendHexString(sb, buffer, offset, length);
+ return sb.toString().trim();
+ }
+
+ public static boolean isNumeric(String str) {
+ try {
+ Double.parseDouble(str);
+ return true;
+ } catch(NumberFormatException e){
+ return false;
+ }
+ }
+
+ public static int parseInteger(String str, Integer defaultValue) {
+ try {
+ Integer v = Integer.parseInt(str);
+ return v.intValue();
+ } catch(NumberFormatException e){
+ return defaultValue;
+ }
+ }
}
+
diff --git a/pi4j-api/src/main/java/module-info.java b/pi4j-api/src/main/java/module-info.java
index 224ad84e2..5eeef51c4 100644
--- a/pi4j-api/src/main/java/module-info.java
+++ b/pi4j-api/src/main/java/module-info.java
@@ -80,8 +80,10 @@
DigitalChangeListenerRegistrationProcessor,
DigitalInputRegistrationProcessor,
DigitalOutputRegistrationProcessor,
+ I2CRegistrationProcessor,
PlatformRegistrationProcessor,
ProviderRegistrationProcessor,
+ PwmRegistrationProcessor,
com.pi4j.annotation.processor.event.AnalogChangeEventProcessor,
com.pi4j.annotation.processor.event.DigitalChangeEventProcessor;
diff --git a/pi4j-api/src/main/resources/META-INF/services/com.pi4j.annotation.Processor b/pi4j-api/src/main/resources/META-INF/services/com.pi4j.annotation.Processor
index 179a0abb3..01db0387f 100644
--- a/pi4j-api/src/main/resources/META-INF/services/com.pi4j.annotation.Processor
+++ b/pi4j-api/src/main/resources/META-INF/services/com.pi4j.annotation.Processor
@@ -20,7 +20,9 @@ com.pi4j.annotation.processor.register.AnalogOutputRegistrationProcessor
com.pi4j.annotation.processor.register.DigitalChangeListenerRegistrationProcessor
com.pi4j.annotation.processor.register.DigitalInputRegistrationProcessor
com.pi4j.annotation.processor.register.DigitalOutputRegistrationProcessor
+com.pi4j.annotation.processor.register.I2CRegistrationProcessor
com.pi4j.annotation.processor.register.PlatformRegistrationProcessor
com.pi4j.annotation.processor.register.ProviderRegistrationProcessor
+com.pi4j.annotation.processor.register.PwmRegistrationProcessor
com.pi4j.annotation.processor.event.AnalogChangeEventProcessor
com.pi4j.annotation.processor.event.DigitalChangeEventProcessor
diff --git a/pi4j-example/pom.xml b/pi4j-example/pom.xml
index 6727372cc..ea85366b4 100644
--- a/pi4j-example/pom.xml
+++ b/pi4j-example/pom.xml
@@ -19,15 +19,9 @@
pi4j-api
${project.version}
-
- junit
- junit
- test
-
org.slf4j
slf4j-simple
-
@@ -36,6 +30,11 @@
pi4j-plugin-raspberrypi
${project.version}
+
+ com.pi4j
+ pi4j-plugin-pigpio
+ ${project.version}
+
com.pi4j
pi4j-plugin-mock
@@ -88,6 +87,4 @@
-
-
diff --git a/pi4j-example/src/main/java/com/pi4j/example/GettingStartedExample2.java b/pi4j-example/src/main/java/com/pi4j/example/GettingStartedExample2.java
index 52e66c808..1348b2f37 100644
--- a/pi4j-example/src/main/java/com/pi4j/example/GettingStartedExample2.java
+++ b/pi4j-example/src/main/java/com/pi4j/example/GettingStartedExample2.java
@@ -29,7 +29,10 @@
import com.pi4j.Pi4J;
import com.pi4j.context.Context;
-import com.pi4j.io.gpio.analog.*;
+import com.pi4j.io.gpio.analog.AnalogInput;
+import com.pi4j.io.gpio.analog.AnalogInputConfig;
+import com.pi4j.io.gpio.analog.AnalogInputProvider;
+import com.pi4j.io.gpio.analog.AnalogInputProviderBase;
import com.pi4j.io.spi.Spi;
import com.pi4j.io.spi.SpiConfig;
import com.pi4j.io.spi.SpiProviderBase;
@@ -84,7 +87,7 @@ public Spi create(SpiConfig config) throws Exception {
AnalogInput ain1 = pi4j.ain().create(1, "my-custom-name-1");
// create I/O config
- AnalogInputConfig config = AnalogInputConfigBuilder.newInstance()
+ var config = AnalogInput.newConfigBuilder()
.address(2)
.name("my-custom-name-2")
.build();
diff --git a/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExample.java b/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExample.java
index 2e860ab6b..ccc6c255c 100644
--- a/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExample.java
+++ b/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExample.java
@@ -29,7 +29,7 @@
import com.pi4j.Pi4J;
import com.pi4j.io.gpio.analog.AnalogChangeListener;
-import com.pi4j.io.gpio.analog.AnalogOutputConfigBuilder;
+import com.pi4j.io.gpio.analog.AnalogOutput;
import com.pi4j.util.Console;
public class AnalogOutputExample {
@@ -61,11 +61,13 @@ public static void main(String[] args) throws Exception {
// (Platforms and Providers) in the class path
var pi4j = Pi4J.newAutoContext();
- AnalogOutputConfigBuilder builder = AnalogOutputConfigBuilder.newInstance();
- builder.id(ANALOG_OUTPUT_PIN_ID)
+ // create Analog Output configuration
+ var config = AnalogOutput.newConfigBuilder()
+ .id(ANALOG_OUTPUT_PIN_ID)
.name(ANALOG_OUTPUT_PIN_NAME)
- .address(ANALOG_OUTPUT_PIN);
- var output = pi4j.aout().create(builder.build());
+ .address(ANALOG_OUTPUT_PIN)
+ .build();
+ var output = pi4j.aout().create(config);
// create an analog output instance using the default analog output provider
//var output = AnalogOutput.create(ANALOG_OUTPUT_PIN_ID, ANALOG_OUTPUT_PIN);
diff --git a/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExampleFromPropertiesFile.java b/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExampleFromPropertiesFile.java
index 71a582528..983e08099 100644
--- a/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExampleFromPropertiesFile.java
+++ b/pi4j-example/src/main/java/com/pi4j/example/gpio/analog/AnalogOutputExampleFromPropertiesFile.java
@@ -29,7 +29,7 @@
import com.pi4j.Pi4J;
import com.pi4j.io.gpio.analog.AnalogChangeListener;
-import com.pi4j.io.gpio.analog.AnalogOutputConfigBuilder;
+import com.pi4j.io.gpio.analog.AnalogOutput;
import com.pi4j.util.Console;
import java.io.IOException;
@@ -75,8 +75,10 @@ public static void main(String[] args) throws Exception {
var pi4j = Pi4J.newAutoContext();
// build the analog output config using the loaded properties, but include a prefix filter
- var builder = AnalogOutputConfigBuilder.newInstance().load(prop, "my-analog-example");
- var output = pi4j.analogOutput().create(builder.build());
+ var config = AnalogOutput.newConfigBuilder()
+ .load(prop, "my-analog-example")
+ .build();
+ var output = pi4j.analogOutput().create(config);
// setup a analog output listener to listen for any state changes on the analog output
output.addListener((AnalogChangeListener) event -> {
diff --git a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExample.java b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExample.java
index 6c5463b69..1be04fe1a 100644
--- a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExample.java
+++ b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExample.java
@@ -29,7 +29,7 @@
import com.pi4j.Pi4J;
import com.pi4j.io.gpio.digital.DigitalChangeListener;
-import com.pi4j.io.gpio.digital.DigitalInputConfigBuilder;
+import com.pi4j.io.gpio.digital.DigitalInput;
import com.pi4j.io.gpio.digital.PullResistance;
import com.pi4j.util.Console;
@@ -60,11 +60,12 @@ public static void main(String[] args) throws Exception {
// create a digital input instance using the default digital input provider
// we will use the PULL_DOWN argument to set the pin pull-down resistance on this GPIO pin
- DigitalInputConfigBuilder builder = DigitalInputConfigBuilder.newInstance();
- builder.id("my-digital-input")
+ var config = DigitalInput.newConfigBuilder()
+ //.id("my-digital-input")
.address(DIGITAL_INPUT_PIN)
- .pull(PullResistance.PULL_DOWN);
- var input = pi4j.din().create(builder.build());
+ .pull(PullResistance.PULL_DOWN)
+ .build();
+ var input = pi4j.din().create(config);
// setup a digital output listener to listen for any state changes on the digital input
input.addListener((DigitalChangeListener) event -> {
diff --git a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExampleFromProperties.java b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExampleFromProperties.java
index a8b4610f5..68f17f9ee 100644
--- a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExampleFromProperties.java
+++ b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalInputExampleFromProperties.java
@@ -29,7 +29,7 @@
import com.pi4j.Pi4J;
import com.pi4j.io.gpio.digital.DigitalChangeListener;
-import com.pi4j.io.gpio.digital.DigitalInputConfigBuilder;
+import com.pi4j.io.gpio.digital.DigitalInput;
import com.pi4j.util.Console;
import java.util.Properties;
@@ -68,8 +68,11 @@ public static void main(String[] args) throws Exception {
// create a digital input instance using the default digital input provider
// we will use the PULL_DOWN argument to set the pin pull-down resistance on this GPIO pin
- var builder = DigitalInputConfigBuilder.newInstance().load(properties);
- var input = pi4j.din().create(builder.build());
+ var config = DigitalInput.newConfigBuilder()
+ .load(properties)
+ .build();
+
+ var input = pi4j.din().create(config);
// setup a digital output listener to listen for any state changes on the digital input
input.addListener((DigitalChangeListener) event -> {
diff --git a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputFromProperties.java b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputFromProperties.java
index eb1e2491f..21d308080 100644
--- a/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputFromProperties.java
+++ b/pi4j-example/src/main/java/com/pi4j/example/gpio/digital/DigitalOutputFromProperties.java
@@ -29,7 +29,7 @@
import com.pi4j.Pi4J;
import com.pi4j.io.gpio.digital.DigitalChangeListener;
-import com.pi4j.io.gpio.digital.DigitalOutputConfigBuilder;
+import com.pi4j.io.gpio.digital.DigitalOutput;
import com.pi4j.io.gpio.digital.DigitalState;
import com.pi4j.util.Console;
@@ -69,8 +69,10 @@ public static void main(String[] args) throws Exception {
properties.put("name", "DIGI4");
// create a digital output instance using the default digital output provider
- var builder = DigitalOutputConfigBuilder.newInstance().load(properties);
- var output = pi4j.dout().create(builder.build());
+ var config = DigitalOutput.newConfigBuilder()
+ .load(properties)
+ .build();
+ var output = pi4j.dout().create(config);
// setup a digital output listener to listen for any state changes on the digital output
output.addListener((DigitalChangeListener) event -> {
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
new file mode 100644
index 000000000..dce6607d4
--- /dev/null
+++ b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cDeviceExample.java
@@ -0,0 +1,119 @@
+package com.pi4j.example.i2c;
+
+/*-
+ * #%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.util.Console;
+
+import java.nio.ByteBuffer;
+
+public class I2cDeviceExample {
+
+ 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 I2C Device 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 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);) {
+
+ // we will be reading and writing to register address 0x01
+ var register = i2c.register(0x01);
+
+ // --> write a single (8-bit) byte value to the I2C device register
+ register.write(0x0D);
+
+ // <-- read a single (8-bit) byte value from the I2C device register
+ byte readByte = register.readByte();
+
+ // --> write a single (16-bit) word value to the I2C device register
+ register.writeWord(0xFFFF);
+
+ // <-- read a single (16-bit) word value from the I2C device register
+ int readWord = register.readWord();
+
+ // --> write an array of data bytes to the I2C device register
+ 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);
+
+ // --> 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);
+
+ // --> write a string of data to the I2C device register
+ register.write("This is a test");
+
+ // <-- read string of data of specified length from the I2C device register
+ String readString = register.readString(14);
+ }
+
+
+ // 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/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cExampleUsingDependencyInjection.java b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cExampleUsingDependencyInjection.java
new file mode 100644
index 000000000..e7345cb24
--- /dev/null
+++ b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cExampleUsingDependencyInjection.java
@@ -0,0 +1,107 @@
+package com.pi4j.example.i2c;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: EXAMPLE :: Sample Code
+ * FILENAME : I2cExampleUsingDependencyInjection.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.annotation.I2CAddress;
+import com.pi4j.annotation.Name;
+import com.pi4j.annotation.Register;
+import com.pi4j.annotation.WithProvider;
+import com.pi4j.context.Context;
+import com.pi4j.io.i2c.I2C;
+import com.pi4j.plugin.mock.provider.i2c.MockI2CProvider;
+import com.pi4j.util.Console;
+
+import java.util.concurrent.Callable;
+
+public class I2cExampleUsingDependencyInjection {
+
+ private static final int I2C_BUS = 1;
+ private static final int I2C_DEVICE = 0x04;
+ private static final int I2C_DEVICE_REGISTER = 0x01;
+
+ 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");
+
+ // Pi4J cannot perform dependency injection on static classes
+ // we will create a container instance to run our example
+ new RuntimeContainer().call();
+ }
+
+ public static class RuntimeContainer implements Callable {
+
+ // create a digital output instance using the default digital output provider
+ @Register("I2C-TEST-DI")
+ @Name("My I2C Device")
+ @I2CAddress(bus=I2C_BUS, device=I2C_DEVICE)
+ @WithProvider(type= MockI2CProvider.class)
+ private I2C i2c;
+
+ @Override
+ public Void call() 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 -->", "PWM Example using Dependency Injection");
+
+ // 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
+ // ...
+ // Also, inject this class instance into the Pi4J context
+ // for annotation processing and dependency injection
+ Context pi4j = Pi4J.newAutoContext().inject(this);
+
+ // we will be reading and writing to register address 0x01
+ var register = i2c.register(I2C_DEVICE_REGISTER);
+
+ // --> write a single (8-bit) byte value to the I2C device register
+ register.write(0x0D);
+
+ // <-- read a single (8-bit) byte value from the I2C device register
+ byte readByte = register.readByte();
+
+ // close I2C device :: I2C closure will happen automatically when Pi4J shuts down
+ //i2c.close();
+
+ // shutdown Pi4J
+ pi4j.shutdown();
+
+ // we are done
+ return null;
+ }
+ }
+}
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
new file mode 100644
index 000000000..79038740c
--- /dev/null
+++ b/pi4j-example/src/main/java/com/pi4j/example/i2c/I2cRawDeviceExample.java
@@ -0,0 +1,108 @@
+package com.pi4j.example.i2c;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: EXAMPLE :: Sample Code
+ * FILENAME : I2cRawDeviceExample.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.util.Console;
+
+import java.nio.ByteBuffer;
+
+public class I2cRawDeviceExample {
+
+ 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 I2C Raw Device Example");
+
+ // 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 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 a single (8-bit) byte value to the raw I2C device (not to a register)
+ i2c.write(0x0D);
+
+ // <-- 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 });
+
+ // <-- read a byte array of specified length from the raw I2C device (not to a register)
+ byte[] readArray = i2c.readArray(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);
+
+ // --> write a string of data to the raw I2C device (not to a register)
+ i2c.write("This is a test");
+
+ // <-- read string of data of specified length from the raw I2C device (not to a register)
+ String readString = i2c.readString(14);
+ }
+
+ // shutdown Pi4J
+ console.println("ATTEMPTING TO SHUTDOWN/TERMINATE THIS PROGRAM");
+ pi4j.shutdown();
+ }
+}
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
new file mode 100644
index 000000000..503fa90b1
--- /dev/null
+++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingDependencyInjection.java
@@ -0,0 +1,151 @@
+package com.pi4j.example.pwm;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: EXAMPLE :: Sample Code
+ * FILENAME : PwmExampleUsingDependencyInjection.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.annotation.*;
+import com.pi4j.context.Context;
+import com.pi4j.io.pwm.Pwm;
+import com.pi4j.plugin.pigpio.provider.pwm.PiGpioPwmProvider;
+import com.pi4j.util.Console;
+
+import java.util.concurrent.Callable;
+
+public class PwmExampleUsingDependencyInjection {
+
+ public static void main(String[] args) throws Exception {
+
+ // Pi4J cannot perform dependency injection on static classes
+ // we will create a container instance to run our example
+ new RuntimeContainer().call();
+ }
+
+ 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)
+ @WithProvider(type=PiGpioPwmProvider.class)
+ @Frequency(5000)
+ @DutyCycle(range=1000, percent=50)
+ @AddPwmPreset(name = "one-quarter", dutyCycle = 250 )
+ @AddPwmPreset(name = "three-quarter", dutyCycle = 750 )
+ @AddPwmPreset(name = "1KHZ", frequency = 1000)
+ @AddPwmPreset(name = "10KHZ", frequency = 10000)
+ private Pwm pwm;
+
+ @Override
+ public Void call() 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 -->", "PWM Example using Dependency Injection");
+
+ // 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
+ // ...
+ // Also, inject this class instance into the Pi4J context
+ // for annotation processing and dependency injection
+ var contextBuidler = Pi4J.newContextBuilder().autoDetect();
+
+ // 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
+ contextBuidler.property("host", "rpi3bp.savage.lan");
+
+ // create Pi4J context
+ Context pi4j = contextBuidler.build().inject(this);
+
+ pi4j.describe().print(System.out);
+
+ // 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();
+ 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(" - IS-ON : " + pwm.isOn());
+ console.println();
+ console.println(" ... WAITING 5 SECONDS TO APPLY PRESET: 10KHZ");
+
+ // wait 5 seconds then exit
+ Thread.sleep(5000);
+
+ // turn off PWM pin
+ pwm.applyPreset("10KHZ");
+
+ console.println();
+ console.println(" ... PWM SIGNAL SHOULD BE <--10KHZ-->");
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+
+ console.println(" ... WAITING 5 SECONDS TO TURN PWM SIGNAL OFF");
+
+ // wait 5 seconds then exit
+ Thread.sleep(5000);
+
+ // turn off PWM pin
+ pwm.off();
+
+ console.println();
+ console.println(" ... PWM SIGNAL SHOULD BE <--OFF-->");
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+ // shutdown Pi4J
+ pi4j.shutdown();
+
+ // we are done
+ return null;
+ }
+ }
+}
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
new file mode 100644
index 000000000..874c617e0
--- /dev/null
+++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingHardwarePwm.java
@@ -0,0 +1,113 @@
+package com.pi4j.example.pwm;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: EXAMPLE :: Sample Code
+ * FILENAME : PwmExampleUsingHardwarePwm.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.pwm.Pwm;
+import com.pi4j.io.pwm.PwmType;
+import com.pi4j.plugin.pigpio.provider.pwm.PiGpioPwmProvider;
+import com.pi4j.util.Console;
+
+public class PwmExampleUsingHardwarePwm {
+
+ public static int PWM_PIN = 13; // MUST BE A HARDWARE PWM SUPPORTED PIN
+
+ 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 -->", "PWM Example using Software-Emulated PWM");
+
+ // 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 PWM instance config
+ var config = Pwm.newConfigBuilder()
+ .id("my-pwm-pin")
+ .name("My Test PWM Pin")
+ .address(PWM_PIN)
+ .pwmType(PwmType.HARDWARE) // USE HARDWARE PWM
+ .frequency(1000) // optionally pre-configure the desired frequency to 1KHz
+ .shutdown(0) // optionally pre-configure a shutdown duty-cycle value (on terminate)
+ //.initial(125) // optionally pre-configure an initial duty-cycle value (on startup)
+ .build();
+
+ // use try-with-resources to auto-close I2C when complete
+ var pwm = pi4j.providers().get(PiGpioPwmProvider.class).create(config);
+
+ //
+ // optionally override pre-configured PWM frequency; set PWM frequency to 1KHz
+ //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%
+
+ // enable the PWM signal
+ pwm.on();
+
+ console.println("[PWM I/O INSTANCE] : ");
+ pwm.describe().print(System.out);
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+ // 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");
+
+ // shutdown Pi4J
+ pi4j.shutdown();
+ }
+}
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
new file mode 100644
index 000000000..19322a1ae
--- /dev/null
+++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmExampleUsingSoftwarePwm.java
@@ -0,0 +1,118 @@
+package com.pi4j.example.pwm;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: EXAMPLE :: Sample Code
+ * FILENAME : PwmExampleUsingSoftwarePwm.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.pwm.Pwm;
+import com.pi4j.plugin.pigpio.provider.pwm.PiGpioPwmProvider;
+import com.pi4j.util.Console;
+
+public class PwmExampleUsingSoftwarePwm {
+
+ public static int PWM_PIN = 4;
+
+ 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 -->", "PWM Example using Software-Emulated PWM");
+
+ // 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 PWM instance config
+ var config = Pwm.newConfigBuilder()
+ .id("my-pwm-pin")
+ .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%)
+ .shutdown(0) // optionally pre-configure a shutdown duty-cycle value (on terminate)
+ //.initial(125) // optionally pre-configure an initial duty-cycle value (on startup)
+ .build();
+
+ // use try-with-resources to auto-close I2C when complete
+ var pwm = pi4j.providers().get(PiGpioPwmProvider.class).create(config);
+
+ //
+ // optionally override pre-configured PWM frequency; set PWM frequency to 1KHz
+ //pwm.frequency(1000);
+
+ //
+ // optionally override pre-configured duty-cycle range (Default is 0-255);
+ // this function sets the upper limit of the range
+ //pwm.setRange(255);
+
+ //
+ // optionally override pre-configured duty-cycle value;
+ // this is in relation to the previously defined rage value
+ //pwm.setDutyCycle(128);
+
+ //
+ // alternatively, you can also just simply set the duty-cycle as a percent value
+ //pwm.setDutyCyclePercent(50); // 50%
+
+ // enable the PWM signal
+ pwm.on();
+
+ console.println("[PWM I/O INSTANCE] : ");
+ pwm.describe().print(System.out);
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+ // 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");
+
+ // shutdown Pi4J
+ pi4j.shutdown();
+ }
+}
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
new file mode 100644
index 000000000..91d105ad1
--- /dev/null
+++ b/pi4j-example/src/main/java/com/pi4j/example/pwm/PwmPresetsExample.java
@@ -0,0 +1,191 @@
+package com.pi4j.example.pwm;
+
+/*-
+ * #%L
+ * **********************************************************************
+ * ORGANIZATION : Pi4J
+ * PROJECT : Pi4J :: EXAMPLE :: Sample Code
+ * FILENAME : PwmPresetsExample.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.pwm.Pwm;
+import com.pi4j.io.pwm.PwmPreset;
+import com.pi4j.plugin.pigpio.provider.pwm.PiGpioPwmProvider;
+import com.pi4j.util.Console;
+
+public class PwmPresetsExample {
+
+ public static int PWM_PIN = 4;
+
+ 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 -->", "PWM Presets Example using Software-Emulated PWM");
+
+ // 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 PWM instance config
+ var config = Pwm.newConfigBuilder()
+ .id("my-pwm-pin")
+ .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%)
+ .shutdown(0) // optionally pre-configure a shutdown duty-cycle value (on terminate)
+ //.initial(125) // optionally pre-configure an initial duty-cycle value (on startup)
+ .build();
+
+ // use try-with-resources to auto-close I2C when complete
+ var pwm = pi4j.providers().get(PiGpioPwmProvider.class).create(config);
+
+ // add PWM presets
+ pwm.addPreset(PwmPreset.newBuilder("one")
+ .frequency(5000)
+ .dutyCycle(128)
+ .build());
+
+ pwm.addPreset(PwmPreset.newBuilder("two")
+ .frequency(80)
+ .build());
+
+ pwm.addPreset(PwmPreset.newBuilder("three")
+ .dutyCycle(180)
+ .build());
+
+
+ console.println("[PWM I/O INSTANCE] : ");
+ pwm.describe().print(System.out);
+
+ //
+ // optionally override pre-configured PWM frequency; set PWM frequency to 1KHz
+ //pwm.frequency(1000);
+
+ //
+ // optionally override pre-configured duty-cycle range (Default is 0-255);
+ // this function sets the upper limit of the range
+ //pwm.setRange(255);
+
+ //
+ // optionally override pre-configured duty-cycle value;
+ // this is in relation to the previously defined rage value
+ //pwm.setDutyCycle(128);
+
+ //
+ // alternatively, you can also just simply set the duty-cycle as a percent value
+ //pwm.setDutyCyclePercent(50); // 50%
+
+ // enable the PWM signal (using the configured settings)
+ pwm.on();
+
+ console.println();
+ console.println(" ... PWM SIGNAL SHOULD BE <--ON-->");
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+ // wait 5 seconds then exit
+ console.println();
+ console.println(" ... WAITING 5 SECONDS ... ");
+ Thread.sleep(5000);
+
+ // recall applyPreset one
+ pwm.applyPreset("one");
+
+ console.println();
+ console.println(" ... RECALLING PWM PRESET <--PRESET('one')-->");
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+
+ // wait 5 seconds then exit
+ console.println();
+ console.println(" ... WAITING 5 SECONDS ... ");
+ Thread.sleep(5000);
+
+ // recall applyPreset two
+ pwm.applyPreset("two");
+
+ console.println();
+ console.println(" ... RECALLING PWM PRESET <--PRESET('two')-->");
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+
+ // wait 5 seconds then exit
+ console.println();
+ console.println(" ... WAITING 5 SECONDS ... ");
+ Thread.sleep(5000);
+
+ // recall applyPreset two
+ pwm.applyPreset("three");
+
+ console.println();
+ console.println(" ... RECALLING PWM PRESET <--PRESET('two')-->");
+ console.println();
+ 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(" - IS-ON : " + pwm.isOn());
+
+ // wait 5 seconds then exit
+ console.println();
+ console.println(" ... WAITING 5 SECONDS ... ");
+ Thread.sleep(5000);
+
+ // shutdown Pi4J
+ console.println("ATTEMPTING TO SHUTDOWN/TERMINATE THIS PROGRAM");
+
+ // shutdown Pi4J
+ pi4j.shutdown();
+ }
+}
diff --git a/pi4j-example/src/main/java/module-info.java b/pi4j-example/src/main/java/module-info.java
index 879bd56a2..55f968e62 100644
--- a/pi4j-example/src/main/java/module-info.java
+++ b/pi4j-example/src/main/java/module-info.java
@@ -53,8 +53,14 @@
uses com.pi4j.plugin.mock.provider.serial.MockSerial;
uses com.pi4j.plugin.mock.provider.serial.MockSerialProvider;
+ requires pi4j.plugin.pigpio;
+ requires pi4j.plugin.raspberrypi;
+ requires pi4j.plugin.linuxfs;
+
// allow access to classes in the following namespaces for Pi4J annotation processing
opens com.pi4j.example.gpio.analog;
opens com.pi4j.example.gpio.digital;
+ opens com.pi4j.example.pwm;
+ opens com.pi4j.example.i2c;
opens com.pi4j.example;
}
diff --git a/pi4j-example/src/main/resources/pi4j-example.properties b/pi4j-example/src/main/resources/pi4j-example.properties
index d9ad442ff..e6c2fd73f 100644
--- a/pi4j-example/src/main/resources/pi4j-example.properties
+++ b/pi4j-example/src/main/resources/pi4j-example.properties
@@ -4,3 +4,5 @@ my-analog-example.name=My Test Analog Output
my-analog-example.description=My Test Analog Output Description
my-analog-example.initial=56
my-analog-example.shutdown=2
+
+host=rpi3bp.savage.lan
diff --git a/pi4j-test-harness/pom.xml b/pi4j-test-harness/pom.xml
new file mode 100644
index 000000000..a822c7b09
--- /dev/null
+++ b/pi4j-test-harness/pom.xml
@@ -0,0 +1,78 @@
+
+
+
+ pi4j-parent
+ com.pi4j
+ 2.0-SNAPSHOT
+
+
+ 4.0.0
+ pi4j-test-harness
+ Pi4J :: TESTING :: Arduino Test Harness
+ Arduino-based Testing Harness for Pi4J Hardware Integration Testing
+
+
+
+
+ com.fazecast
+ jSerialComm
+ 2.5.1
+
+
+ com.google.code.gson
+ gson
+ 2.8.5
+
+
+ org.json
+ json
+ 20190722
+
+
+
+
+
+
+ default-profile
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ **/*.java
+
+
+
+
+
+
+
+
+
+ test-hardware
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ **
+
+ ${pi4j.test.pigpio.host}
+ ${pi4j.test.pigpio.port}
+ ${pi4j.test.harness.port}
+
+
+
+
+
+
+
+
diff --git a/pi4j-test-harness/src/main/arduino/.gitignore b/pi4j-test-harness/src/main/arduino/.gitignore
new file mode 100644
index 000000000..45c5c9824
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/.gitignore
@@ -0,0 +1,70 @@
+# **********************************************************************
+# 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
+# .
+# **********************************************************************
+
+# Build files/directories
+out
+target
+gen
+build
+dist
+temp
+trash
+scratch
+
+# Log directory
+log
+
+# 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
+
+# IntelliJ IDE files
+.idea
+*.iml
+
+# Eclipse IDE files
+.settings
+.classpath
+.project
+.externalToolBuilders
+.metadata
+maven-eclipse.xml
+
+# Vim files
+*.swp
+
+# Mac files
+.DS_Store
+
+# Windows files
+Thumbs.db
+
diff --git a/pi4j-test-harness/src/main/arduino/.travis.yml b/pi4j-test-harness/src/main/arduino/.travis.yml
new file mode 100644
index 000000000..4170000cb
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/.travis.yml
@@ -0,0 +1,93 @@
+# **********************************************************************
+# 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
+# .
+# **********************************************************************
+
+
+# Continuous Integration (CI) is the practice, in software
+# engineering, of merging all developer working copies with a shared mainline
+# several times a day < https://docs.platformio.org/page/ci/index.html >
+#
+# Documentation:
+#
+# * Travis CI Embedded Builds with PlatformIO
+# < https://docs.travis-ci.com/user/integration/platformio/ >
+#
+# * PlatformIO integration with Travis CI
+# < https://docs.platformio.org/page/ci/travis.html >
+#
+# * User Guide for `platformio ci` command
+# < https://docs.platformio.org/page/userguide/cmd_ci.html >
+#
+#
+# Please choose one of the following templates (proposed below) and uncomment
+# it (remove "# " before each line) or use own configuration according to the
+# Travis CI documentation (see above).
+#
+
+
+#
+# Template #1: General project. Test it using existing `platformio.ini`.
+#
+
+# language: python
+# python:
+# - "2.7"
+#
+# sudo: false
+# cache:
+# directories:
+# - "~/.platformio"
+#
+# install:
+# - pip install -U platformio
+# - platformio update
+#
+# script:
+# - platformio run
+
+
+#
+# Template #2: The project is intended to be used as a library with examples.
+#
+
+# language: python
+# python:
+# - "2.7"
+#
+# sudo: false
+# cache:
+# directories:
+# - "~/.platformio"
+#
+# env:
+# - PLATFORMIO_CI_SRC=path/to/test/file.c
+# - PLATFORMIO_CI_SRC=examples/file.ino
+# - PLATFORMIO_CI_SRC=path/to/test/directory
+#
+# install:
+# - pip install -U platformio
+# - platformio update
+#
+# script:
+# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
diff --git a/pi4j-test-harness/src/main/arduino/VERSION b/pi4j-test-harness/src/main/arduino/VERSION
new file mode 100644
index 000000000..74ced3132
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/VERSION
@@ -0,0 +1 @@
+1.0.0-ALPHA
\ No newline at end of file
diff --git a/pi4j-test-harness/src/main/arduino/lib/readme.txt b/pi4j-test-harness/src/main/arduino/lib/readme.txt
new file mode 100644
index 000000000..cfa16dfa2
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/lib/readme.txt
@@ -0,0 +1,41 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link them to executable files.
+
+The source code of each library should be placed in separate directories, like
+"lib/private_lib/[here are source files]".
+
+For example, see the structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+| |
+| |--Bar
+| | |--docs
+| | |--examples
+| | |--src
+| | |- Bar.c
+| | |- Bar.h
+| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+| |
+| |--Foo
+| | |- Foo.c
+| | |- Foo.h
+| |
+| |- readme.txt --> THIS FILE
+|
+|- platformio.ini
+|--src
+ |- main.c
+
+Then in `src/main.c` you should use:
+
+#include
+#include
+
+// rest H/C/CPP code
+
+PlatformIO will find your libraries automatically, configure preprocessor's
+include paths and build them.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/pi4j-test-harness/src/main/arduino/platformio.ini b/pi4j-test-harness/src/main/arduino/platformio.ini
new file mode 100644
index 000000000..6535f6e7d
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/platformio.ini
@@ -0,0 +1,77 @@
+# * **********************************************************************
+# * 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
+# * .
+# * **********************************************************************
+
+[platformio]
+env_default = arduino_due
+build_dir=build
+
+; ---------------------------------------------------------------
+; COMMON BUILD ENVIRONMENT
+; ---------------------------------------------------------------
+
+; You MUST inject these options into [env:] section
+; using ${common_env_data.***} (see below)
+[common_env_data]
+
+platform = atmelsam@3.5.0
+framework = arduino
+extra_scripts =
+
+; Build options
+build_flags =
+ !echo "-DFIRMWARE_VERSION="$(cat VERSION) "-DFIRMWARE_DATE="$(date +\"%Y-%m-%d\")
+
+lib_deps_builtin =
+ SPI
+ Wire
+lib_deps_external =
+ ArduinoSTL
+ ArduinoJson
+ https://github.com/ppedro74/Arduino-SerialCommands
+ https://github.com/paulo-raca/ArduinoBufferedStreams
+
+; ---------------------------------------------------------------
+; ARDUNIO DUE BOARD CONFIG
+; ---------------------------------------------------------------
+[env:arduino_due]
+platform = ${common_env_data.platform}
+framework = ${common_env_data.framework}
+board = due
+extra_scripts = ${common_env_data.extra_scripts}
+
+; Build options
+build_flags =
+ ${common_env_data.build_flags}
+ -D DEBUG=0
+
+; Library options
+lib_deps =
+ ${common_env_data.lib_deps_builtin}
+ ${common_env_data.lib_deps_external}
+
+; Board communication
+upload_port = /dev/cu.usbmodem142401
+monitor_port = /dev/cu.usbmodem142401
+monitor_speed = 115200
diff --git a/pi4j-test-harness/src/main/arduino/src/command/Commands.h b/pi4j-test-harness/src/main/arduino/src/command/Commands.h
new file mode 100644
index 000000000..4340d56c3
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/Commands.h
@@ -0,0 +1,67 @@
+/*
+ * **********************************************************************
+ * 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_COMMANDS_H
+#define PI4J_COMMANDS_H
+
+#include "main.h"
+#include
+#include "CommandsArgumentParser.h"
+#include "EchoCommand.h"
+#include "FrequencyCommand.h"
+#include "I2cCommand.h"
+#include "InfoCommand.h"
+#include "InvalidCommand.h"
+#include "PinCommand.h"
+#include "PinsCommand.h"
+#include "RebootCommand.h"
+#include "ResetCommand.h"
+
+
+/**
+ * ADD INTERACTIVE COMMAND TO THE SERIAL COMMAND PROCESSOR
+ */
+void AddInteractiveCommands(SerialCommands& processor){
+
+ // add default command handler for unrecognized commands
+ processor.SetDefaultHandler(invalid_command_handler);
+
+ // add Pi4J interactive commands
+ processor.AddCommand(&EchoCommand);
+ processor.AddCommand(&FrequencyCommand);
+ processor.AddCommand(&FrequencyShortCommand);
+ processor.AddCommand(&RebootCommand);
+ processor.AddCommand(&ResetCommand);
+ processor.AddCommand(&I2cCommand);
+ processor.AddCommand(&InfoCommand);
+ processor.AddCommand(&InfoCommandKey);
+ processor.AddCommand(&PinCommand);
+ processor.AddCommand(&PinsCommand);
+ processor.AddCommand(&PinShortCommand);
+}
+
+#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
new file mode 100644
index 000000000..41fe13085
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/CommandsArgumentParser.h
@@ -0,0 +1,282 @@
+/*
+ * **********************************************************************
+ * 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
+ * .
+ * **********************************************************************
+ */
+
+#include
+#include
+#include
+#include "util/StringUtil.h"
+
+#ifndef PI4J_COMMAND_ARGUMENT_PARSER_H
+#define PI4J_COMMAND_ARGUMENT_PARSER_H
+
+/**
+ * GET I/O PIN VALUE FROM COMMANDS ARGUMENTS
+ */
+int GetCommandPinArgument(SerialCommands* sender){
+ char* pin_str = sender->Next();
+ if (pin_str == NULL){
+ return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument
+ }
+
+ // validate numeric string
+ if(!StringUtil::isNumeric(pin_str)){
+ return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument
+ }
+ int pin = atoi(pin_str);
+
+ // validate pin range
+ if(pin >= GPIO_MAX_PINS){
+ return ERROR_INVALID_PIN_OUT_OF_RANGE;
+ }
+
+ // validate restricted pins
+ if(pin >= 0){
+ if(pins[pin].restricted){
+ return ERROR_INVALID_PIN_RESTRICTED;
+ }
+
+ // special pin overrides for Raspberry Pi
+ if(pin == 2){
+ return 20;
+ }
+ if(pin == 3){
+ return 21;
+ }
+ }
+
+
+ return pin;
+}
+
+/**
+ * GET I/O DIGITAL PIN STATE FROM COMMANDS ARGUMENTS
+ */
+int GetCommandDigitalStateArgument(SerialCommands* sender){
+
+ // get state argument
+ char* state_str = sender->Next();
+ if (state_str == NULL){
+ return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument
+ }
+ String state = String(state_str);
+ if(state.equalsIgnoreCase("HIGH")){
+ return 1;
+ } else if(state.equalsIgnoreCase("HI")){
+ return 1;
+ } else if(state.equalsIgnoreCase("H")){
+ return 1;
+ } else if(state.equalsIgnoreCase("1")){
+ return 1;
+ } else if(state.equalsIgnoreCase("ON")){
+ return 1;
+ } else if(state.equalsIgnoreCase("LOW")){
+ return 0;
+ } else if(state.equalsIgnoreCase("LO")){
+ return 0;
+ } else if(state.equalsIgnoreCase("L")){
+ return 0;
+ } else if(state.equalsIgnoreCase("0")){
+ return 0;
+ } else if(state.equalsIgnoreCase("OFF")){
+ return 0;
+ } else {
+ return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument
+ }
+}
+
+
+/**
+ * GET "ON/OFF" or "ENABLE/DISABLE" FROM COMMANDS ARGUMENTS
+ */
+int GetCommandBooleanArgument(SerialCommands* sender){
+
+ // get state argument
+ char* state_str = sender->Next();
+ if (state_str == NULL){
+ return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument
+ }
+ String state = String(state_str);
+ if(state.equalsIgnoreCase("TRUE")){
+ return 1;
+ } else if(state.equalsIgnoreCase("T")){
+ return 1;
+ } else if(state.equalsIgnoreCase("ENABLE")){
+ return 1;
+ } else if(state.equalsIgnoreCase("ON")){
+ return 1;
+ } else if(state.equalsIgnoreCase("YES")){
+ return 0;
+ } else if(state.equalsIgnoreCase("Y")){
+ return 0;
+ } else if(state.equalsIgnoreCase("1")){
+ return 1;
+ } else if(state.equalsIgnoreCase("FALSE")){
+ return 0;
+ } else if(state.equalsIgnoreCase("F")){
+ return 0;
+ } else if(state.equalsIgnoreCase("DISABLE")){
+ return 0;
+ } else if(state.equalsIgnoreCase("OFF")){
+ return 0;
+ } else if(state.equalsIgnoreCase("NO")){
+ return 0;
+ } else if(state.equalsIgnoreCase("N")){
+ return 0;
+ } else if(state.equalsIgnoreCase("0")){
+ return 0;
+ } else {
+ return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument
+ }
+}
+
+
+/**
+ * GET PIN MODE ARGUMENT
+ */
+int GetCommandPinModeArgument(SerialCommands* sender){
+
+ // get mode argument
+ char* mode_str = sender->Next();
+ if (mode_str == NULL){
+ return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument
+ }
+ String mode = String(mode_str);
+ if(mode.equalsIgnoreCase("INPUT")){
+ return INPUT;
+ } else if(mode.equalsIgnoreCase("IN")){
+ return INPUT;
+ } else if(mode.equalsIgnoreCase("I")){
+ return INPUT;
+ } else if(mode.equalsIgnoreCase("INPUT_PULLUP")){
+ return INPUT_PULLUP;
+ } else if(mode.equalsIgnoreCase("IN_PULLUP")){
+ return INPUT_PULLUP;
+ } else if(mode.equalsIgnoreCase("IN_UP")){
+ return INPUT_PULLUP;
+ } else if(mode.equalsIgnoreCase("IUP")){
+ return INPUT_PULLUP;
+ } else if(mode.equalsIgnoreCase("IU")){
+ return INPUT_PULLUP;
+ } else if(mode.equalsIgnoreCase("OUTPUT")){
+ return OUTPUT;
+ } else if(mode.equalsIgnoreCase("OUT")){
+ return OUTPUT;
+ } else if(mode.equalsIgnoreCase("O")){
+ return OUTPUT;
+ } else if(mode.equalsIgnoreCase("HIGH")){
+ return PIN_MODE_OUTPUT_HIGH;
+ } else if(mode.equalsIgnoreCase("HI")){
+ return PIN_MODE_OUTPUT_HIGH;
+ } else if(mode.equalsIgnoreCase("H")){
+ return PIN_MODE_OUTPUT_HIGH;
+ } else if(mode.equalsIgnoreCase("ON")){
+ return PIN_MODE_OUTPUT_HIGH;
+ } else if(mode.equalsIgnoreCase("1")){
+ return PIN_MODE_OUTPUT_HIGH;
+ } else if(mode.equalsIgnoreCase("LOW")){
+ return PIN_MODE_OUTPUT_LOW;
+ } else if(mode.equalsIgnoreCase("LO")){
+ return PIN_MODE_OUTPUT_LOW;
+ } else if(mode.equalsIgnoreCase("L")){
+ return PIN_MODE_OUTPUT_LOW;
+ } else if(mode.equalsIgnoreCase("OFF")){
+ return PIN_MODE_OUTPUT_LOW;
+ } else if(mode.equalsIgnoreCase("0")){
+ return PIN_MODE_OUTPUT_LOW;
+ } else if(mode.equalsIgnoreCase("DISABLE")){
+ return PIN_MODE_DISABLE;
+ } else if(mode.equalsIgnoreCase("STOP")){
+ return PIN_MODE_DISABLE;
+ } else if(mode.equalsIgnoreCase("CANCEL")){
+ return PIN_MODE_DISABLE;
+ } else if(mode.equalsIgnoreCase("RESET")){
+ return PIN_MODE_DISABLE;
+ } else {
+ return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument
+ }
+}
+
+/**
+ * GET I2C BUS VALUE FROM COMMANDS ARGUMENTS
+ */
+int GetCommandI2cBusArgument(SerialCommands* sender){
+ char* bus_str = sender->Next();
+ if (bus_str == NULL){
+ return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument
+ }
+
+ // validate numeric string
+ if(!StringUtil::isNumeric(bus_str)){
+ return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument
+ }
+ int bus = atoi(bus_str);
+
+ // validate bus
+ if(bus < 0 || bus > 1){
+ return ERROR_INVALID_I2C_BUS_OUT_OF_RANGE;
+ }
+
+ return bus;
+}
+
+/**
+ * GET I2C DEVICE VALUE FROM COMMANDS ARGUMENTS
+ */
+int GetCommandI2cDeviceArgument(SerialCommands* sender){
+ char* dev_str = sender->Next();
+ if (dev_str == NULL){
+ return ERROR_COMMAND_ARGUMENT_MISSING; // -1 :: missing argument
+ }
+
+ // validate numeric string
+ if(!StringUtil::isNumeric(dev_str)){
+ return ERROR_COMMAND_ARGUMENT_INVALID; // -2 :: invalid argument
+ }
+ int device = atoi(dev_str);
+
+ // validate device
+ if(device < 0 || device > 127){
+ return ERROR_INVALID_I2C_DEVICE_OUT_OF_RANGE;
+ }
+
+ return device;
+}
+
+
+String GetCommandArgumentError(int error){
+ switch(error){
+ case ERROR_COMMAND_ARGUMENT_MISSING : {return "MISSING ARGUMENT"; break;}
+ case ERROR_COMMAND_ARGUMENT_INVALID : {return "INVALID ARGUMENT"; break;}
+ case ERROR_INVALID_PIN_OUT_OF_RANGE : {return "INVALID PIN NUMBER; OUT OF ACCEPTED RANGE"; break;}
+ 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;}
+ default: return "UNKNOWN ARGUMENT ERROR";
+ }
+}
+
+#endif //PI4J_COMMAND_ARGUMENT_PARSER_H
diff --git a/pi4j-test-harness/src/main/arduino/src/command/EchoCommand.h b/pi4j-test-harness/src/main/arduino/src/command/EchoCommand.h
new file mode 100644
index 000000000..254a3afb4
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/EchoCommand.h
@@ -0,0 +1,69 @@
+/*
+ * **********************************************************************
+ * 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_ECHO_H
+#define PI4J_COMMAND_ECHO_H
+
+#include
+#include
+#include
+
+// create ECHO command invocation handler
+void echo_command_execute(SerialCommands* sender){
+ DynamicJsonDocument doc(256);
+ JsonObject response = doc.to();
+
+ // get enabled argument
+ int enable = GetCommandBooleanArgument(sender);
+
+ // if a state was not provided, then return the current pin state
+ if (enable == ERROR_COMMAND_ARGUMENT_MISSING){
+ enable = console_pipe.isEcho();
+ response["id"] = "get";
+ response["echo"] = (enable) ? "on" : "off";
+ }
+ else if(enable < 0) {
+ response["id"] = "error";
+ response["errno"] = enable;
+ response["arg"] = "state";
+ response["msg"] = GetCommandArgumentError(enable);
+ }
+ else {
+ console_pipe.echo(enable); // update echo state on console pipe
+ response["id"] = "set";
+ response["echo"] = (enable) ? "on" : "off";
+ }
+
+ // output response
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+}
+
+// create ECHO command variable
+SerialCommand EchoCommand = SerialCommand("echo", echo_command_execute);
+
+#endif //PI4J_COMMAND_ECHO_H
diff --git a/pi4j-test-harness/src/main/arduino/src/command/FrequencyCommand.h b/pi4j-test-harness/src/main/arduino/src/command/FrequencyCommand.h
new file mode 100644
index 000000000..9a3e73345
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/FrequencyCommand.h
@@ -0,0 +1,78 @@
+/*
+ * **********************************************************************
+ * 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_FREQUENCY_H
+#define PI4J_COMMAND_FREQUENCY_H
+
+#include
+#include
+#include
+#include
+#include "CommandsArgumentParser.h"
+#include "main.h"
+
+// create FREQUENCY command invocation handler
+void frequency_command_execute(SerialCommands* sender){
+ DynamicJsonDocument doc(256);
+ JsonObject response = doc.to();
+
+ // get PIN argument
+ int pin = GetCommandPinArgument(sender);
+
+ // handle pin argument errors
+ if(pin < 0 && pin != ERROR_INVALID_PIN_DISABLED) {
+ response["id"] = "error";
+ response["errno"] = pin;
+ response["arg"] = "pin";
+ response["msg"] = GetCommandArgumentError(pin);
+ }
+ else {
+ // make sure the reading pin is an input pin
+ pinMode(pin, INPUT);
+ pins[pin].enabled = true;
+ pins[pin].mode = INPUT;
+
+ // count the number of pulses and calculate the frequency in Hz
+ long frequency = 500000/pulseIn(pin, HIGH);
+
+ // prepare response
+ response["id"] = "frequency";
+ response["pin"] = pin;
+ response["frequency"] = frequency;
+ response["units"] = "Hz";
+ }
+
+ // output response
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+}
+
+// create FREQUENCY command variable
+SerialCommand FrequencyCommand = SerialCommand("frequency", frequency_command_execute);
+SerialCommand FrequencyShortCommand = SerialCommand("f", frequency_command_execute);
+
+#endif //PI4J_COMMAND_FREQUENCY_H
diff --git a/pi4j-test-harness/src/main/arduino/src/command/I2cCommand.h b/pi4j-test-harness/src/main/arduino/src/command/I2cCommand.h
new file mode 100644
index 000000000..dc91cb845
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/I2cCommand.h
@@ -0,0 +1,117 @@
+/*
+ * **********************************************************************
+ * 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_I2C_H
+#define PI4J_COMMAND_I2C_H
+
+#include
+#include
+#include
+#include
+#include
+#include "CommandsArgumentParser.h"
+#include "main.h"
+
+// create ECHO command invocation handler
+void i2c_command_execute(SerialCommands* sender){
+ DynamicJsonDocument doc(256);
+ JsonObject response = doc.to();
+
+ // get I2C bus
+ int bus = GetCommandI2cBusArgument(sender);
+
+ // get I2C device
+ int device = GetCommandI2cDeviceArgument(sender);
+
+ // get I2C "raw" mode data processing
+ int rawMode = GetCommandBooleanArgument(sender);
+
+ // handle bus argument errors
+ if(bus < 0) {
+ response["id"] = "error";
+ response["errno"] = bus;
+ response["arg"] = "bus";
+ response["msg"] = GetCommandArgumentError(bus);
+ }
+
+ // handle device argument errors
+ else if(device < 0) {
+ response["id"] = "error";
+ response["errno"] = bus;
+ response["arg"] = "device";
+ response["msg"] = GetCommandArgumentError(device);
+ }
+
+ else{
+ response["id"] = "i2c";
+ response["bus"] = bus;
+ response["device"] = device;
+ response["raw"] = (bool)rawMode;
+
+ // default callback handlers for Register operations
+ void (*i2cReceive_ptr)(int) = &receiveI2CData;
+ void (*i2cSend_ptr)(void) = &sendI2CData;
+
+ // if raw mode is enabled, then swap function pointers
+ // for the raw data processing callbacks
+ if(rawMode > 0){
+ i2cReceive_ptr = &receiveI2CDataRaw;
+ i2cSend_ptr = &sendI2CDataRaw;
+ }
+
+ // end I2C on existing bus if previously assigned
+ if(i2cCache.wire != nullptr){
+ i2cCache.wire->end();
+ }
+
+ // reset I2C cache
+ i2cCache.reset();
+
+ // setup which I2C bus to enable
+ if(bus == 0){
+ i2cCache.wire = &Wire; // setup I2C BUS 0
+ } else if(bus == 1){
+ i2cCache.wire = &Wire1; // setup I2C BUS 1
+ }
+
+ // initialize i2c as slave
+ i2cCache.wire->begin(device);
+
+ // define callbacks for i2c communication
+ i2cCache.wire->onReceive(i2cReceive_ptr);
+ i2cCache.wire->onRequest(i2cSend_ptr);
+ }
+
+ // output response
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+}
+
+// create I2C command variable
+SerialCommand I2cCommand = SerialCommand("i2c", i2c_command_execute);
+
+#endif //PI4J_COMMAND_I2C_H
diff --git a/pi4j-test-harness/src/main/arduino/src/command/InfoCommand.h b/pi4j-test-harness/src/main/arduino/src/command/InfoCommand.h
new file mode 100644
index 000000000..f1f7c684e
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/InfoCommand.h
@@ -0,0 +1,44 @@
+/*
+ * **********************************************************************
+ * 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_INFO_H
+#define PI4J_COMMAND_INFO_H
+
+#include
+#include
+#include
+
+// create INFO command invocation handler
+void info_command_execute(SerialCommands* sender){
+ info(sender->GetSerial());
+}
+
+// create INFO command variable
+SerialCommand InfoCommand = SerialCommand("info", info_command_execute);
+SerialCommand InfoCommandKey("?", info_command_execute, true);
+
+#endif //PI4J_COMMAND_INFO_H
diff --git a/pi4j-test-harness/src/main/arduino/src/command/InvalidCommand.h b/pi4j-test-harness/src/main/arduino/src/command/InvalidCommand.h
new file mode 100644
index 000000000..d7f8f0f7f
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/InvalidCommand.h
@@ -0,0 +1,52 @@
+/*
+ * **********************************************************************
+ * 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_INVALID_H
+#define PI4J_COMMAND_INVALID_H
+
+#include
+#include
+#include
+
+// create INVALID command invocation handler
+
+//This is the default handler, and gets called when no other command matches.
+// Note: It does not get called for one_key commands that do not match
+void invalid_command_handler(SerialCommands* sender, const char* cmd){
+ DynamicJsonDocument doc(1024);
+ JsonObject response = doc.to();
+ response["id"] = "error";
+ response["errno"] = ERROR_UNSUPPORTED_COMMAND;
+ response["msg"] = "Invalid or unsupported command";
+ response["cmd"] = cmd;
+
+ // output response
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+}
+
+#endif //PI4J_COMMAND_INVALID_H
diff --git a/pi4j-test-harness/src/main/arduino/src/command/PinCommand.h b/pi4j-test-harness/src/main/arduino/src/command/PinCommand.h
new file mode 100644
index 000000000..f984da730
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/PinCommand.h
@@ -0,0 +1,229 @@
+/*
+ * **********************************************************************
+ * 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_PIN_H
+#define PI4J_COMMAND_PIN_H
+
+#include
+#include
+#include
+#include "CommandsArgumentParser.h"
+#include
+
+// create PIN command invocation handler
+void pin_command_execute(SerialCommands* sender){
+ DynamicJsonDocument doc(1024);
+ JsonObject response = doc.to();
+
+ // get argument
+ int pin = GetCommandPinArgument(sender);
+
+ // check for missing or invalid argument
+ if (pin < 0){
+ response["id"] = "error";
+ response["errno"] = pin;
+ response["arg"] = "pin";
+ response["msg"] = GetCommandArgumentError(pin);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+ return;
+ }
+
+ // get pin argument
+ int mode = GetCommandPinModeArgument(sender);
+
+ // ---------------------------------------------------------------------
+ // GET PIN INFO
+ // ---------------------------------------------------------------------
+ // if a mode was not provided, then return the current pin state
+ if (mode == ERROR_COMMAND_ARGUMENT_MISSING){
+
+ // check to see if this pin is enabled
+ if(!pins[pin].enabled){
+ response["id"] = "error";
+ SerializePin(response, pin);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+ return;
+ }
+
+ // get current pin state
+ pins[pin].value = digitalRead(pin);
+
+ // return current pin state
+ response["id"] = "get";
+ SerializePin(response, pin);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+ return;
+ }
+
+ // ---------------------------------------------------------------------
+ // SET PIN ERROR
+ // ---------------------------------------------------------------------
+ // any other argument errors need to be notified
+ if (mode < 0){
+ response["id"] = "error";
+ response["errno"] = mode;
+ response["pin"] = pin;
+ response["arg"] = "mode";
+ response["msg"] = GetCommandArgumentError(mode);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+ return;
+
+ }
+
+ // ---------------------------------------------------------------------
+ // DISABLE PIN
+ // ---------------------------------------------------------------------
+ // disable/reset pin tracking
+ if (mode == PIN_MODE_DISABLE){
+
+ // disable and reset pin state
+ pins[pin].enabled = false;
+ pins[pin].counter = 0;
+ pins[pin].value = -1;
+ pins[pin].mode = -1;
+
+ // reset actual hardware pins to default mode
+ pinMode(pin, INPUT);
+
+ // return current pin state
+ response["id"] = "set";
+ SerializePin(response, pin, false);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+ return;
+ }
+
+ // ---------------------------------------------------------------------
+ // ENABLE OUTPUT PIN (and set state to HIGH)
+ // ---------------------------------------------------------------------
+ // handle pin output HIGH
+ else if (mode == PIN_MODE_OUTPUT_HIGH){
+
+ // setup actual GPIO pin and initial state
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, HIGH);
+
+ // update pin cache
+ pins[pin].mode = OUTPUT;
+ pins[pin].value = HIGH;
+ }
+
+ // ---------------------------------------------------------------------
+ // ENABLE OUTPUT PIN (and set state to LOW)
+ // ---------------------------------------------------------------------
+ // handle pin output LOW
+ else if (mode == PIN_MODE_OUTPUT_LOW){
+
+ // setup actual GPIO pin and initial state
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, LOW);
+
+ // update pin cache
+ pins[pin].mode = OUTPUT;
+ pins[pin].value = LOW;
+ }
+
+ // ---------------------------------------------------------------------
+ // ENABLE OUTPUT PIN (and set state to use provided value)
+ // ---------------------------------------------------------------------
+ // handle pin output
+ else if (mode == OUTPUT){
+
+ // get pin argument
+ int value = GetCommandDigitalStateArgument(sender);
+
+ // if a state was not provided, then return the current pin state
+ if (value < 0){
+ response["id"] = "error";
+ response["errno"] = value;
+ response["pin"] = pin;
+ response["mode"] = "output";
+ response["arg"] = "value";
+ response["msg"] = GetCommandArgumentError(value);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+ return;
+ }
+
+ // setup actual GPIO pin
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, value);
+
+ // update pin cache mode
+ pins[pin].mode = OUTPUT;
+ }
+
+ // ---------------------------------------------------------------------
+ // ENABLE INPUT PIN (pull-down)
+ // ---------------------------------------------------------------------
+ // handle pin input
+ else if (mode == INPUT){
+
+ // setup actual GPIO pin
+ pinMode(pin, INPUT);
+
+ // update pin cache mode
+ pins[pin].mode = INPUT;
+
+ }
+
+ // ---------------------------------------------------------------------
+ // ENABLE INPUT PIN (pull-up)
+ // ---------------------------------------------------------------------
+ // handle pin input
+ else if (mode == INPUT_PULLUP){
+
+ // setup actual GPIO pin
+ pinMode(pin, INPUT_PULLUP);
+
+ // update pin cache mode
+ pins[pin].mode = INPUT_PULLUP;
+
+ }
+
+ // enable and sync pin state
+ pins[pin].enabled = true;
+ pins[pin].value = digitalRead(pin);
+ pins[pin].counter = 0;
+
+ // output status
+ response["id"] = "set";
+ SerializePin(response, pin);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+}
+
+// create DOUT command variable
+SerialCommand PinCommand = SerialCommand("pin", pin_command_execute);
+SerialCommand PinShortCommand = SerialCommand("p", pin_command_execute);
+
+#endif //PI4J_COMMAND_PIN_H
+
diff --git a/pi4j-test-harness/src/main/arduino/src/command/PinsCommand.h b/pi4j-test-harness/src/main/arduino/src/command/PinsCommand.h
new file mode 100644
index 000000000..df9b49661
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/PinsCommand.h
@@ -0,0 +1,100 @@
+/*
+ * **********************************************************************
+ * 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_PINS_H
+#define PI4J_COMMAND_PINS_H
+
+#include
+#include
+#include
+#include "CommandsArgumentParser.h"
+
+// create PINS command invocation handler
+void pins_command_execute(SerialCommands* sender){
+
+ DynamicJsonDocument doc(1024*GPIO_MAX_PINS);
+ JsonObject response = doc.to();
+
+ // get argument
+ int all = GetCommandBooleanArgument(sender);
+
+ // check for missing or invalid argument
+ if (all != ERROR_COMMAND_ARGUMENT_MISSING && all < 0){
+ response["id"] = "error";
+ response["errno"] = all;
+ response["arg"] = "all";
+ response["msg"] = GetCommandArgumentError(all);
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+ return;
+ }
+
+ response["id"] = "pins";
+ JsonArray pinscontainer = response.createNestedArray("pins");
+
+ // iterate pin states in cache
+ int total, enabled, restricted, disabled, inputs, outputs;
+ total = enabled = restricted = disabled = inputs = outputs = 0;
+ for(int p = 0; p < GPIO_MAX_PINS; p++){
+
+ if(all > 0 || (pins[p].enabled && !pins[p].restricted)){
+ int v = digitalRead(p);
+ pins[p].value = v;
+
+ // increment summary counters
+ total++;
+ if(pins[p].restricted) restricted++;
+ if(pins[p].enabled) enabled++;
+ if(!pins[p].enabled) disabled++;
+ if(pins[p].mode == OUTPUT) outputs++;
+ if(pins[p].mode == INPUT) inputs++;
+ if(pins[p].mode == INPUT_PULLUP) inputs++;
+
+ // create nested pin object and insert into the container array
+ JsonObject pincontainer = pinscontainer.createNestedObject();
+ SerializePin(pincontainer, p, false);
+ }
+ }
+
+ // include summary totals
+ response["total"] = total;
+ response["restricted"] = restricted;
+ response["disabled"] = disabled;
+ response["enabled"] = enabled;
+ response["inputs"] = inputs;
+ response["outputs"] = outputs;
+
+ // serialize and print
+ serializeJson(doc, *sender->GetSerial());
+ sender->GetSerial()->println();
+}
+
+// create DOUT command variable
+SerialCommand PinsCommand = SerialCommand("pins", pins_command_execute);
+
+#endif //PI4J_COMMAND_PINS_H
+
diff --git a/pi4j-test-harness/src/main/arduino/src/command/RebootCommand.h b/pi4j-test-harness/src/main/arduino/src/command/RebootCommand.h
new file mode 100644
index 000000000..0be3ade76
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/RebootCommand.h
@@ -0,0 +1,49 @@
+/*
+ * **********************************************************************
+ * 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_REBOOT_H
+#define PI4J_COMMAND_REBOOT_H
+
+#include
+#include
+#include
+
+// create REBOOT command invocation handler
+void reboot_command_execute(SerialCommands* sender){
+ DynamicJsonDocument doc(1024);
+ JsonObject response = doc.to();
+ response["id"] = "reboot";
+ response["msg"] = "Rebooting system now";
+ serializeJson(doc, console);
+ console.println();
+ reboot();
+}
+
+// create REBOOT command variable
+SerialCommand RebootCommand = SerialCommand("reboot", reboot_command_execute);
+
+#endif //PI4J_COMMAND_REBOOT_H
diff --git a/pi4j-test-harness/src/main/arduino/src/command/ResetCommand.h b/pi4j-test-harness/src/main/arduino/src/command/ResetCommand.h
new file mode 100644
index 000000000..c9938c5b5
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/command/ResetCommand.h
@@ -0,0 +1,49 @@
+/*
+ * **********************************************************************
+ * 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_RESET_H
+#define PI4J_COMMAND_RESET_H
+
+#include
+#include
+#include
+
+// create RESET command invocation handler
+void reset_command_execute(SerialCommands* sender){
+ // DynamicJsonDocument doc(1024);
+ // JsonObject response = doc.to();
+ // response["id"] = "reset";
+ // response["msg"] = "Resetting all I/O pins and testing states.";
+ // serializeJson(doc, console);
+ // console.println();
+ reset();
+}
+
+// create RESET command variable
+SerialCommand ResetCommand = SerialCommand("reset", reset_command_execute);
+
+#endif //PI4J_COMMAND_RESET_H
diff --git a/pi4j-test-harness/src/main/arduino/src/main.cpp b/pi4j-test-harness/src/main/arduino/src/main.cpp
new file mode 100644
index 000000000..bf2ef390c
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/main.cpp
@@ -0,0 +1,519 @@
+/*
+ * **********************************************************************
+ * 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
+ * .
+ * **********************************************************************
+ */
+
+// include main header
+#include "main.h"
+#include "pins.h"
+#include
+
+// ------------------------------------------------------------------------------------------------------------------------------
+// INTERACTIVE COMMAND PROCESSOR AND COMMANDS
+// ------------------------------------------------------------------------------------------------------------------------------
+
+// create data buffer and command processor
+char serial_command_buffer_[32];
+SerialCommands processor(&console_pipe, serial_command_buffer_, sizeof(serial_command_buffer_), "\r\n", " ");
+
+// include Pi4J interactive commands
+#include "command/Commands.h"
+
+/**
+ * FIRMWARE STARTUP
+ */
+void setup() {
+
+ // define default UART baud rate for serial interfaces
+ // @see: https://www.arduino.cc/en/serial/begin
+ CONSOLE_INTERFACE.begin(CONSOLE_BAUD_RATE);
+ DEBUG_INTERFACE.begin(DEBUG_BAUD_RATE);
+
+ // initialize the interactive diagnostics console using the piped console serial ports
+ console.init(&console_pipe);
+
+ // this is an artificial delay to see this data in the debug console when using Arduino/PlatformIO IDE
+ for(int d = FIRMWARE_BOOT_DELAY; d > 0; d--){
+ console.print("... Pi4J test harness firmware will start in ");
+ console.print(d);
+ console.println(" second(s).");
+ delay(1000);
+ }
+
+ // print firmware startup banner and program information
+ info(&console);
+
+ // pins zero and one are reserved for USB programming port
+ pins[0].restricted = true;
+ pins[1].restricted = true;
+
+ // initialize firmware
+ inititalize();
+}
+
+/**
+ * INITIALIZE FIRMWARE
+ */
+void inititalize(){
+ // configure interactive serial commands
+ AddInteractiveCommands(processor);
+
+ // display ready/running message
+ DynamicJsonDocument doc(1024);
+ JsonObject response = doc.to();
+ response["id"] = "ready";
+ serializeJson(doc, console);
+ console.println();
+
+ // reset I2C cache
+ i2cCache.reset();
+
+ // // initialize i2c as slave
+ // Wire.begin(I2C_SLAVE_ADDRESS);
+
+ // // define callbacks for i2c communication
+ // Wire.onReceive(receiveI2CData);
+ // Wire.onRequest(sendI2CData);
+ // i2cCache.wire = &Wire;
+
+}
+
+void reset(){
+
+ DynamicJsonDocument doc(1024*GPIO_MAX_PINS);
+ JsonObject response = doc.to();
+ response["id"] = "reset";
+ JsonArray pinscontainer = response.createNestedArray("pins");
+
+ // reset pins states
+ int total, inputs, outputs;
+ total = inputs = outputs = 0;
+
+ for(int p = 0; p < GPIO_MAX_PINS; p++){
+ bool isEnabled = pins[p].enabled;
+ if(isEnabled){
+ total++;
+ if(pins[p].mode == OUTPUT) outputs++;
+ if(pins[p].mode == INPUT) inputs++;
+ if(pins[p].mode == INPUT_PULLUP) inputs++;
+ JsonObject pincontainer = pinscontainer.createNestedObject();
+ SerializePin(pincontainer, p, false);
+ }
+ pins[p].enabled = false;
+ pins[p].value = -1;
+ pins[p].mode = -1;
+ pins[p].counter = 0;
+
+ // reset actual hardware pins to default mode
+ if(!pins[p].restricted) pinMode(p, INPUT);
+ }
+
+ // reset I2C cache
+ i2cCache.reset();
+
+ // terminate all I2C buses
+ Wire.end();
+ Wire1.end();
+
+ // include summary totals
+ response["total"] = total;
+ response["inputs"] = inputs;
+ response["outputs"] = outputs;
+
+ serializeJson(doc, console);
+ console.println();
+}
+
+/**
+ * SERVICE LOOP
+ */
+void loop() {
+ processor.ReadSerial();
+ console_pipe.loop();
+
+ // for(int p = 0; p < GPIO_MAX_PINS; p++){
+ // if(pins[p].enabled &&
+ // !pins[p].restricted &&
+ // (pins[p].mode == INPUT || pins[p].mode == INPUT_PULLUP)){
+ // byte v = digitalRead(p);
+ // if(v != pins[p].value){
+
+ // // update pin cache
+ // pins[p].value = v;
+ // pins[p].counter++;
+
+ // // print pin status
+ // DynamicJsonDocument doc(1024);
+ // JsonObject response = doc.to();
+ // response["id"] = "change";
+ // SerializePin(response, p);
+ // serializeJson(doc, console);
+ // console.println();
+ // }
+ // }
+ // }
+}
+
+/**
+ * SYSTEM INFO
+ */
+void info(Stream* out){
+ DynamicJsonDocument doc(1024);
+ JsonObject response = doc.to();
+ response["id"] = "info";
+ response["name"] = FIRMWARE_NAME;
+ response["version"] = FIRMWARE_VERSION_STRING;
+ response["date"] = FIRMWARE_DATE_STRING;
+ response["copyright"] = COPYRIGHT;
+ serializeJson(doc, *out);
+ out->println();
+}
+
+/**
+ * HARD REBOOT SYSTEM (in one second)
+ */
+void reboot() {
+ console.println();
+ console.println(F("****************************************************"));
+ console.println(F("REBOOT!"));
+ console.println(F("****************************************************"));
+ console.println(F("The system has started a REBOOT and will be"));
+ console.println(F("restarted in one second."));
+ console.println(F("****************************************************"));
+ console.println();
+ NVIC_SystemReset();
+}
+
+
+// // 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;
+ uint8_t length = i2cCache.reg[address].length;
+ // console.print("--> I2C SEND [");
+ // console.print(length);
+ // console.println("] BYTES");
+
+ // for(int n = 0; n < length; n++){
+ // console.print(" --> ");
+ // console.println(i2cCache.reg[address].data[n]);
+ // }
+
+ i2cCache.wire->write(i2cCache.reg[address].data, length);
+}
+
+// callback for sending data
+void sendI2CDataRaw(){
+ // console.print("--> I2C SEND [");
+ // console.print(i2cCache.length);
+ // console.println("] BYTES");
+ // for(int n = 0; n < i2cCache.length; n++){
+ // console.print(" --> ");
+ // console.println(i2cCache.buffer[n]);
+ // }
+
+ i2cCache.wire->write(i2cCache.buffer, sizeof(i2cCache.buffer));
+}
+
+// -------------------------------------------
+// WRITING RAW BYTE VALUES
+// -------------------------------------------
+// callback for received data
+void receiveI2CDataRaw(int byteCount){
+ // console.print("<-- I2C RECEIVE [");
+ // console.print(byteCount);
+ // console.println("] BYTES");
+ // if(byteCount == 0) return;
+
+ // clear buffer store
+ memset(i2cCache.buffer, 0, sizeof i2cCache.buffer);
+
+ // read all available bytes from the I2C bus
+ byteCount = i2cCache.wire->readBytes(i2cCache.buffer, byteCount);
+ i2cCache.length = byteCount;
+}
+
+// -------------------------------------------
+// WRITING REGISTERS
+// -------------------------------------------
+// callback for received data
+void receiveI2CData(int byteCount){
+ if(byteCount == 0) return; // ignore any zero byte callbacks
+ uint8_t address = i2cCache.wire->read();
+ uint8_t length = byteCount - 1; // substract for address byte
+ // console.print("--> I2C RECEIVE [");
+ // console.print(length);
+ // console.print("] BYTES");
+ // if(length == 0){
+ // console.print("; GET");
+ // } else {
+ // console.print("; SET");
+ // }
+ // console.println();
+
+ // update active register address
+ i2cCache.address = address;
+
+ // if a data payload is included, then we need to cache
+ // the value in the register's data store
+ if(length > 0){
+
+ // clear register data store
+ memset(i2cCache.reg[address].data, 0, sizeof i2cCache.reg[address].data);
+
+ // update register data length
+ i2cCache.reg[address].length = length;
+
+ // read all available bytes from the I2C bus into the register data store
+ i2cCache.wire->readBytes(i2cCache.reg[address].data, length);
+
+ // for(int n = 0; n < length; n++){
+ // console.print(" <-- ");
+ // console.println(i2cCache.reg[address].data[n]);
+ // }
+
+ }
+
+ // // display ready/running message
+ // DynamicJsonDocument doc(512);
+ // JsonObject response = doc.to();
+ // response["id"] = "i2c";
+ // response["value"] = i2cValue;
+ // serializeJson(doc, console);
+ // console.println();
+}
diff --git a/pi4j-test-harness/src/main/arduino/src/main.h b/pi4j-test-harness/src/main/arduino/src/main.h
new file mode 100644
index 000000000..b787af0b2
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/main.h
@@ -0,0 +1,109 @@
+/*
+ * **********************************************************************
+ * 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_MAIN_H
+#define PI4J_MAIN_H
+
+// include platform libraries
+#include
+
+// include platform specific libraries
+#include // for I2C comms. (SDA, SCL)
+//#include "wiring_private.h"
+
+// include support for Interactive Serial Commands
+// https://raw.githubusercontent.com/ppedro74/Arduino-SerialCommands
+#include
+
+// include Pi4J common
+#include "pi4j.h"
+
+// include Pi4J utility classes
+#include "util/Utils.h"
+
+// ------------------------------------------------------------------------------------------------------------------------------
+// DEFINE FUNTION PROTOTYPES
+// ------------------------------------------------------------------------------------------------------------------------------
+void loop();
+void setup();
+void info(Stream* out);
+void reboot();
+void inititalize();
+void reset();
+void receiveI2CData(int byteCount);
+void sendI2CData();
+void receiveI2CDataRaw(int byteCount);
+void sendI2CDataRaw();
+
+
+// create priped interface for interactive console (muxed serial ports)
+StreamPipe console_pipe(&CONSOLE_INTERFACE, &DEBUG_INTERFACE);
+
+
+// ------------------------------------------------------------------------------------------------------------------------------
+// DEFINE RUNTIME COMPONENTS
+// ------------------------------------------------------------------------------------------------------------------------------
+
+// create NULL stream; used for debugging only
+struct NullStream : public Stream{
+ NullStream( void ) { return; }
+ int available( void ) { return 0; }
+ void flush( void ) { return; }
+ int peek( void ) { return -1; }
+ int read( void ){ return -1; }
+ size_t write( uint8_t u_Data ){ return u_Data; }
+} nullStream;
+
+
+struct I2cRegister {
+ uint8_t data[32] = { 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 };
+ uint16_t length = 0;
+};
+
+struct I2cCache {
+ I2cRegister reg[255];
+ uint8_t address = 0;
+ uint8_t buffer[1024];
+ uint16_t length = 0;
+ bool rawMode = false;
+ TwoWire* wire;
+ void reset(){
+ address = 0;
+ length = 0;
+ rawMode = false;
+ memset(buffer, 0, sizeof buffer);
+ wire = nullptr;
+ for(int i = 0; i < 256; i++){
+ reg[i].length = 0;
+ memset(reg[i].data, 0, sizeof reg[i].data);
+ }
+ }
+};
+
+I2cCache i2cCache;
+
+#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
new file mode 100644
index 000000000..d300c2707
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/pi4j.h
@@ -0,0 +1,153 @@
+/*
+ * **********************************************************************
+ * 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_H
+#define PI4J_H
+
+
+//
+// SEE ARDUINO PIN DEFINITIONS FOR SAMD MICROCONTROLLER HERE:
+// https://github.com/arduino/ArduinoCore-samd/blob/1.6.19/variants/arduino_zero/variant.cpp
+//
+
+// -----------------------------------------------------------------------------------------------------------
+// GENERIC HELPER MACROS
+// -----------------------------------------------------------------------------------------------------------
+
+#define STRINGIZE2(s) #s
+#define STRINGIZE(s) STRINGIZE2(s)
+
+// -----------------------------------------------------------------------------------------------------------
+// FIRMWARE METADATA DEFINITIONS
+// -----------------------------------------------------------------------------------------------------------
+
+// console boot header/banner
+#ifndef PI4J_BANNER
+#define PI4J_CRLF "\r\n"
+#define PI4J_BANNER_LINE "======================================================="
+#define PI4J_BANNER_L1 " "
+#define PI4J_BANNER_L2 " The Pi4J Project "
+#define PI4J_BANNER_L3 " Arduino Test Harness "
+#define PI4J_BANNER_L4 " "
+#define PI4J_BANNER PI4J_BANNER_LINE PI4J_CRLF PI4J_BANNER_L1 PI4J_CRLF PI4J_BANNER_L2 PI4J_CRLF PI4J_BANNER_L3 PI4J_CRLF PI4J_BANNER_L4 PI4J_CRLF PI4J_BANNER_LINE
+#endif
+
+// copyright string
+#ifndef PI4J_COPYRIGHT
+#define PI4J_COPYRIGHT "COPYRIGHT: PI4J, LLC @ 2019, ALL RIGHTS RESERVED"
+#endif
+
+#ifndef BANNER
+#define BANNER PI4J_BANNER
+#endif
+
+#ifndef COPYRIGHT
+#define COPYRIGHT PI4J_COPYRIGHT
+#endif
+
+// -----------------------------------------------------------------------------------------------------------
+// FIRMWARE METADATA DEFINITIONS
+// -----------------------------------------------------------------------------------------------------------
+
+// firmware name, version and last updated date
+#ifndef FIRMWARE_NAME
+#define FIRMWARE_NAME "Pi4J ARDUINO TEST HARNESS"
+#endif
+
+#ifndef FIRMWARE_VERSION
+#define FIRMWARE_VERSION 0.0.0 (ALPHA) // <- this is passed in from build environment
+#endif
+#define FIRMWARE_VERSION_STRING STRINGIZE(FIRMWARE_VERSION)
+
+#ifndef FIRMWARE_DATE
+#define FIRMWARE_DATE 1900-01-01 // <- this is passed in from build environment
+#endif
+#define FIRMWARE_DATE_STRING STRINGIZE(FIRMWARE_DATE)
+
+#ifndef HARDWARE_VERSION
+#define HARDWARE_VERSION "0.1"
+#endif
+
+#ifndef FIRMWARE_BOOT_DELAY
+#define FIRMWARE_BOOT_DELAY 0
+#endif
+
+
+// -----------------------------------------------------------------------------------------------------------
+// FIRMWARE DEVELOPMENT FLAGS
+// -----------------------------------------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------------------------------------
+// GENERIC TIME INTERVAL DEFINITIONS (all interval times are in milliseconds)
+// -----------------------------------------------------------------------------------------------------------
+#define ONE_SECOND 1000
+#define TEN_SECOND 10*ONE_SECOND
+#define ONE_MINUTE 60*ONE_SECOND
+
+// -----------------------------------------------------------------------------------------------------------
+// DEBUGGING INTERFACE SETTINGS AND HARDWARE DEFINITIONS
+// -----------------------------------------------------------------------------------------------------------
+
+#define DEBUG_INTERFACE SerialUSB
+#define DEBUG_BAUD_RATE 115200 // Debug baud rate
+
+// -----------------------------------------------------------------------------------------------------------
+// INTERACTIVE DIAGNOSTICS CONSOLE DEFINITIONS
+// -----------------------------------------------------------------------------------------------------------
+
+#define CONSOLE_INTERFACE Serial
+#define CONSOLE_BAUD_RATE 115200
+
+
+// -----------------------------------------------------------------------------------------------------------
+// I2C DEFINITIONS
+// -----------------------------------------------------------------------------------------------------------
+
+#define I2C_SLAVE_ADDRESS 0x04
+
+// -----------------------------------------------------------------------------------------------------------
+// MISC GLOBAL INCLUDES
+// -----------------------------------------------------------------------------------------------------------
+
+// include global utility classes
+//#include "util/Console.h"
+
+// include runtime classes
+//#include "runtime/Runtime.h"
+
+
+#define ERROR_COMMAND_ARGUMENT_MISSING -1
+#define ERROR_COMMAND_ARGUMENT_INVALID -2
+#define ERROR_INVALID_PIN_OUT_OF_RANGE -3
+#define ERROR_INVALID_PIN_RESTRICTED -4
+#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_COMMAND -99
+
+
+#endif //PI4J_H
diff --git a/pi4j-test-harness/src/main/arduino/src/pins.h b/pi4j-test-harness/src/main/arduino/src/pins.h
new file mode 100644
index 000000000..c458fcd47
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/pins.h
@@ -0,0 +1,184 @@
+/*
+ * **********************************************************************
+ * 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_PINS_H
+#define PI4J_PINS_H
+
+// include platform libraries
+#include
+#include
+#include
+
+// ------------------------------------------------------------------------------------------------------------------------------
+// DEFINE CONSTANTS
+// ------------------------------------------------------------------------------------------------------------------------------
+
+#define GPIO_MAX_PINS 54
+
+#define PIN_MODE_INPUT INPUT // 0x0
+#define PIN_MODE_OUTPUT OUTPUT // 0x1
+#define PIN_MODE_INPUT_PULLUP INPUT_PULLUP // 0x2
+#define PIN_MODE_OUTPUT_LOW 0x3
+#define PIN_MODE_OUTPUT_HIGH 0x4
+#define PIN_MODE_DISABLE 0xF
+
+
+// ------------------------------------------------------------------------------------------------------------------------------
+// DEFINE FUNTION PROTOTYPES
+// ------------------------------------------------------------------------------------------------------------------------------
+void loop();
+void setup();
+void info(Stream* out);
+void reboot();
+void inititalize();
+void reset();
+
+// ------------------------------------------------------------------------------------------------------------------------------
+// DEFINE RUNTIME COMPONENTS
+// ------------------------------------------------------------------------------------------------------------------------------
+
+struct PinCache {
+ bool restricted = false;
+ bool enabled = false;
+ int8_t mode = -1;
+ int16_t value = -1;
+ uint16_t counter = 0;
+
+ String modeString(){
+ switch (mode)
+ {
+ case PIN_MODE_INPUT: return "input"; break;
+ case PIN_MODE_INPUT_PULLUP: return "input_pullup"; break;
+ case PIN_MODE_OUTPUT: return "output"; break;
+ case PIN_MODE_DISABLE: return "disabled"; break;
+ default: return "unknown"; break;
+ }
+ }
+};
+
+PinCache pins[GPIO_MAX_PINS];
+
+// void PrintPinStatus2(Stream* out, int pin, String header, bool includeErroNo = true){
+// PinCache p = pins[pin];
+
+// // return current pin state
+// out->print("<");
+// out->print(header);
+// out->print("> PIN=");
+// out->print(pin);
+
+// if(p.restricted){
+// if(includeErroNo){
+// out->print("; ERRNO=");
+// out->print(ERROR_INVALID_PIN_RESTRICTED);
+// }
+// out->print("; ACCESS=RESTRICTED; MSG=Access to this pin is restricted.");
+// }
+// else if(p.enabled == false){
+// if(includeErroNo){
+// out->print("; ERRNO=");
+// out->print(ERROR_INVALID_PIN_DISABLED);
+// }
+// out->print("; ACCESS=DISABLED; MSG=This pin is not currently in use.");
+// }
+// else {
+// out->print("; MODE=");
+// out->print(p.mode);
+// out->print("; VALUE=");
+// out->print(p.value);
+// out->print("; CHANGES=");
+// out->print(p.counter);
+// }
+// out->println();
+// }
+
+
+// void PrintPinStatus(Stream* out, int pin, String header, bool includeErroNo = true){
+// PinCache p = pins[pin];
+
+// // Allocate a temporary JsonDocument
+// // Use arduinojson.org/v6/assistant to compute the capacity.
+// DynamicJsonDocument doc(1024);
+
+
+// doc["type"] = header.c_str();
+// doc["pin"] = pin;
+
+// if(p.restricted){
+// if(includeErroNo){
+// doc["errno"] = ERROR_INVALID_PIN_RESTRICTED;
+// }
+// doc["access"] = "restricted";
+// doc["msg"] = "Access to this pin is restricted.";
+// }
+// else if(p.enabled == false){
+// if(includeErroNo){
+// doc["errno"] = ERROR_INVALID_PIN_DISABLED;
+// }
+// doc["access"] = "disabled";
+// doc["msg"] = "This pin is not currently in use.";
+// }
+// else {
+// doc["mode"] = p.modeString();
+// doc["value"] = p.value;
+// doc["changes"] = p.counter;
+// }
+
+// serializeJsonPretty(doc, *out);
+// out->println();
+// }
+
+
+
+void SerializePin(JsonObject& json, int pin, bool includeErroNo = true){
+ PinCache p = pins[pin];
+
+ json["pin"] = pin;
+
+ if(p.restricted){
+ if(includeErroNo){
+ json["errno"] = ERROR_INVALID_PIN_RESTRICTED;
+ }
+ json["access"] = "restricted";
+ json["msg"] = "Access to this pin is restricted.";
+ }
+ else if(p.enabled == false){
+ if(includeErroNo){
+ json["errno"] = ERROR_INVALID_PIN_DISABLED;
+ }
+ json["access"] = "disabled";
+ json["msg"] = "This pin is not currently in use.";
+ }
+ else {
+ json["mode"] = p.modeString();
+ json["value"] = p.value;
+ json["changes"] = p.counter;
+ }
+}
+
+
+#endif //PI4J_PINS_H
\ No newline at end of file
diff --git a/pi4j-test-harness/src/main/arduino/src/src.ino b/pi4j-test-harness/src/main/arduino/src/src.ino
new file mode 100644
index 000000000..2bce0ef8c
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/src.ino
@@ -0,0 +1,29 @@
+/*
+ * **********************************************************************
+ * 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
+ * .
+ * **********************************************************************
+ */
+
+ // PLEASE SEE "main.h" and "main.cpp" FOR THE PRIMARY PROGRAM
+
diff --git a/pi4j-test-harness/src/main/arduino/src/util/Console.cpp b/pi4j-test-harness/src/main/arduino/src/util/Console.cpp
new file mode 100644
index 000000000..0ff3e1f79
--- /dev/null
+++ b/pi4j-test-harness/src/main/arduino/src/util/Console.cpp
@@ -0,0 +1,190 @@
+/*
+ * **********************************************************************
+ * 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
+ *