jdk.dio.gpio.GPIOPinConfig Maven / Gradle / Ivy
Show all versions of org.openjdk.dio Show documentation
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.dio.gpio;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Objects;
import com.oracle.dio.impl.Platform;
import com.oracle.dio.utils.ExceptionMessage;
import com.oracle.dio.utils.Utils;
import jdk.dio.DeviceConfig;
import jdk.dio.DeviceManager;
import jdk.dio.InvalidDeviceConfigException;
import romizer.*;
import serializator.*;
/**
* The {@code GPIOPinConfig} class encapsulates the hardware addressing information, and static and
* dynamic configuration parameters of a GPIO pin.
*
* Some hardware addressing, static or dynamic configuration parameters may be
* set to {@link #UNASSIGNED UNASSIGNED} or {@code null} (see
* Unassigned, Default or Unused Parameter Values).
*
* An instance of {@code GPIOPinConfig} can be passed to the
* {@link DeviceManager#open(DeviceConfig) open(DeviceConfig, ...)} and
* {@link DeviceManager#open(Class, DeviceConfig) open(Class, DeviceConfig, ...)}
* methods of the {@link DeviceManager} to open the designated GPIO pin
* with the specified configuration. A {@link InvalidDeviceConfigException} is thrown when
* attempting to open a device with an invalid or unsupported configuration.
*
*
* @see DeviceManager#open(DeviceConfig)
* @see DeviceManager#open(DeviceConfig, int)
* @see DeviceManager#open(Class, DeviceConfig)
* @see DeviceManager#open(Class, DeviceConfig, int)
* @since 1.0
*/
@SerializeMe
@apimarker.API("device-io_1.1_gpio")
public final class GPIOPinConfig implements DeviceConfig, DeviceConfig.HardwareAddressing {
/**
* Bidirectional pin direction with initial input direction.
*/
public static final int DIR_BOTH_INIT_INPUT = 2;
/**
* Bidirectional pin direction with initial output direction.
*/
public static final int DIR_BOTH_INIT_OUTPUT = 3;
/**
* Input pin direction.
*/
public static final int DIR_INPUT_ONLY = 0;
/**
* Output pin direction.
*/
public static final int DIR_OUTPUT_ONLY = 1;
/**
* Input pull-down drive mode.
*
* This bit flag can be bitwise-combined (OR) with other drive mode bit flags.
*
*/
public static final int MODE_INPUT_PULL_DOWN = 2;
/**
* Input pull-up drive mode.
*
* This bit flag can be bitwise-combined (OR) with other drive mode bit flags.
*
*/
public static final int MODE_INPUT_PULL_UP = 1;
/**
* Output open-drain drive mode.
*
* This bit flag can be bitwise-combined (OR) with other drive mode bit flags.
*
*/
public static final int MODE_OUTPUT_OPEN_DRAIN = 8;
/**
* Output push-pull drive mode.
*
* This bit flag can be bitwise-combined (OR) with other drive mode bit flags.
*
*/
public static final int MODE_OUTPUT_PUSH_PULL = 4;
/**
* Rising edge trigger.
*/
public static final int TRIGGER_BOTH_EDGES = 3;
/**
* Both levels trigger.
*/
public static final int TRIGGER_BOTH_LEVELS = 6;
/**
* Falling edge trigger.
*/
public static final int TRIGGER_FALLING_EDGE = 1;
/**
* High level trigger.
*/
public static final int TRIGGER_HIGH_LEVEL = 4;
/**
* Low level trigger.
*/
public static final int TRIGGER_LOW_LEVEL = 5;
/**
* No interrupt trigger.
*/
public static final int TRIGGER_NONE = 0;
/**
* Rising edge trigger.
*/
public static final int TRIGGER_RISING_EDGE = 2;
private String controllerName;
private int direction = UNASSIGNED;
private boolean initValue;
private int mode = UNASSIGNED;
private int pinNumber = UNASSIGNED;
private int controllerNumber = UNASSIGNED;
private int trigger;
/**
* The {@code Builder} class allows for creating and initializing
* {@code GPIOPinConfig} objects. Calls can be chained in the following
* manner:
*
*
* GPIOPinConfig config = new GPIOPinConfig.Builder()
* .setControllerNumber(1)
* .setPinNumber(1)
* .setDirection(DIR_OUTPUT_ONLY)
* .setDriveMode(MODE_OUTPUT_PUSH_PULL)
* .setInitValue(true)
* .build();
*
*
*
* @since 1.1
*/
@apimarker.API("device-io_1.1_gpio")
public static final class Builder {
private final GPIOPinConfig instance = new GPIOPinConfig();
/**
* Creates a new {@code Builder} instance.
*/
public Builder() {
}
/**
* Creates a new {@code GPIOPinConfig} instance initialized with the
* values set for each configuration parameters. If a configuration
* parameter was not explictly set its default value will be used.
*
* @return a new initialized {@code GPIOPinConfig} instance.
* @throws IllegalArgumentException if any of the following is true:
*
* - the interrupt trigger event setting is incompatible with the direction setting:
* if the direction is set to output-only then the trigger mode must be
* {@link #TRIGGER_NONE}.
* - the drive mode setting is incompatible with the direction setting: if
* the direction is set to both input and output then the drive mode
* must specify both an input drive mode and an output drive mode.
*
* @throws IllegalStateException if any of the following is true:
*
* - the allowed and initial pin direction is not set.
*
*/
public GPIOPinConfig build() {
if (instance.direction == UNASSIGNED) {
throw new IllegalStateException(ExceptionMessage.format(ExceptionMessage.GPIO_INVALID_DIRECTION));
}
instance.checkConsistency();
return instance;
}
/**
* Sets the controller name (default value is {@code null} if not set).
*
* @param controllerName the controller name (such as its device
* file name on UNIX systems) or {@code null}.
* @return this {@code Builder} instance.
*/
public Builder setControllerName(String controllerName) {
instance.controllerName = controllerName;
return this;
}
/**
* Sets the pin number (default value is {@code UNASSIGNED} if not set).
*
* @param pinNumber the pin number (a positive or zero integer) or
* {@link #UNASSIGNED UNASSIGNED}.
* @return this {@code Builder} instance.
* @throws IllegalArgumentException if {@code pinNumber} is not in the
* defined range.
*/
public Builder setPinNumber(int pinNumber) {
Utils.checkIntValue(pinNumber);
instance.pinNumber = pinNumber;
return this;
}
/**
* Sets the controller number (default value is {@code UNASSIGNED} if
* not set).
*
* @param controllerNumber the controller number (a positive or zero
* integer) or {@link #UNASSIGNED UNASSIGNED}.
* @return this {@code Builder} instance.
* @throws IllegalArgumentException if {@code controllerNumber} is not
* in the defined range.
*/
public Builder setControllerNumber(int controllerNumber) {
Utils.checkIntValue(controllerNumber);
instance.controllerNumber = controllerNumber;
return this;
}
/**
* Sets the allowed and initial pin direction.
*
* @param direction the allowed and initial direction of the pin, one
* of: {@link #DIR_INPUT_ONLY},
* {@link #DIR_OUTPUT_ONLY}, {@link #DIR_BOTH_INIT_INPUT},
* {@link #DIR_BOTH_INIT_OUTPUT}.
* @return this {@code Builder} instance.
* @throws IllegalArgumentException if {@code direction} is not in the
* defined range.
*/
public Builder setDirection(int direction) {
checkDirection(direction);
instance.direction = direction;
return this;
}
/**
* Sets the initial value of the pin when initially set for output
* (default value is {@code false} if not set).
*
* @param initValue the initial value of the pin when initially set for
* output.
* @return this {@code Builder} instance.
*/
public Builder setInitValue(boolean initValue) {
instance.initValue = initValue;
return this;
}
/**
* Sets the pin drive mode (default value is {@code UNASSIGNED} if not
* set).
*
* @param mode the pin drive mode: either {@link #UNASSIGNED UNASSIGNED} or a
* bitwise OR of at least one of: {@link #MODE_INPUT_PULL_UP}, {@link #MODE_INPUT_PULL_DOWN} ,
* {@link #MODE_OUTPUT_PUSH_PULL}, {@link #MODE_OUTPUT_OPEN_DRAIN}.
* @return this {@code Builder} instance.
* @throws IllegalArgumentException if any of the following is true:
*
* - {@code mode} does not designate any mode (i.e. equals
* {@code 0});
* - {@code mode} designates more than one input or output drive
* mode.
*
*/
public Builder setDriveMode(int mode) {
checkMode(mode);
instance.mode = mode;
return this;
}
/**
* Sets the initial interrupt trigger events (default value is
* {@code TRIGGER_NONE} if not set).
*
* @param trigger the initial interrupt trigger events, one of: {@link #TRIGGER_NONE},
* {@link #TRIGGER_FALLING_EDGE}, {@link #TRIGGER_RISING_EDGE},
* {@link #TRIGGER_BOTH_EDGES}, {@link #TRIGGER_HIGH_LEVEL},
* {@link #TRIGGER_LOW_LEVEL}, {@link #TRIGGER_BOTH_LEVELS}.
* @return this {@code Builder} instance.
* @throws IllegalArgumentException if {@code trigger} is not in the
* defined range.
*/
public Builder setTrigger(int trigger) {
checkTrigger(trigger);
instance.trigger = trigger;
return this;
}
}
// hidden constructor for serializer
@DontRenameMethod
GPIOPinConfig() {}
/**
* Creates a new {@code GPIOPinConfig} with the specified hardware addressing information and
* configuration parameters.
*
* The controller name is set to {@code null}.
*
*
* @param controllerNumber
* the hardware port's number (a positive or zero integer) or {@link #UNASSIGNED UNASSIGNED}.
* @param pinNumber
* the hardware pin's number (a positive or zero integer) or {@link #UNASSIGNED UNASSIGNED}.
* @param direction
* the allowed and initial direction of the pin, one of: {@link #DIR_INPUT_ONLY},
* {@link #DIR_OUTPUT_ONLY}, {@link #DIR_BOTH_INIT_INPUT},
* {@link #DIR_BOTH_INIT_OUTPUT}.
* @param mode
* the drive mode of the pin: either {@link #UNASSIGNED UNASSIGNED} or a bitwise OR of at least one
* of: {@link #MODE_INPUT_PULL_UP}, {@link #MODE_INPUT_PULL_DOWN} ,
* {@link #MODE_OUTPUT_PUSH_PULL}, {@link #MODE_OUTPUT_OPEN_DRAIN}; if the pin can be
* set in both input and output direction then the mode must specify both an input
* drive mode and an output drive mode (bit mask).
* @param trigger
* the initial interrupt trigger events, one of: {@link #TRIGGER_NONE},
* {@link #TRIGGER_FALLING_EDGE}, {@link #TRIGGER_RISING_EDGE},
* {@link #TRIGGER_BOTH_EDGES}, {@link #TRIGGER_HIGH_LEVEL},
* {@link #TRIGGER_LOW_LEVEL}, {@link #TRIGGER_BOTH_LEVELS}; if the pin is
* set for output-only then {@code trigger} must be {@link #TRIGGER_NONE}.
* @param initValue
* the initial value of the pin when initially set for output; ignored otherwise.
* @throws IllegalArgumentException
* if any of the following is true:
*
* - {@code controllerNumber} is not in the defined range;
* - {@code pinNumber} is not in the defined range;
* - {@code direction} is not one of the defined values;
* - {@code trigger} is not one of the defined values;
* - {@code trigger} is incompatible with the direction(s) designated by {@code direction};
* - {@code mode} does not designate any mode (i.e. equals {@code 0});
* - {@code mode} designates more than one input or output drive mode;
* - {@code mode} does not designates a drive mode for or designates a drive mode
* incompatible with the direction(s) designated by {@code direction}.
*
*
* @deprecated As of 1.1, use {@link Builder} instead.
*/
@Deprecated
public GPIOPinConfig(int controllerNumber, int pinNumber, int direction, int mode, int trigger, boolean initValue) {
this.controllerNumber = controllerNumber;
this.pinNumber = pinNumber;
if (controllerNumber < DeviceConfig.UNASSIGNED || pinNumber < DeviceConfig.UNASSIGNED ) {
throw new IllegalArgumentException();
}
this.direction = direction;
this.trigger = trigger;
this.mode = mode;
this.initValue = initValue;
checkAll();
}
/**
* Creates a new {@code GPIOPinConfig} with the specified hardware addressing information and
* configuration parameters.
*
* The controller number is set to {@code UNASSIGNED}.
*
*
* @param controllerName
* the controller name (such as its device file name on UNIX systems).
* @param pinNumber
* the hardware pin's number (a positive or zero integer) or {@link #UNASSIGNED UNASSIGNED}.
* @param direction
* the allowed and initial direction of the pin, one of: {@link #DIR_INPUT_ONLY},
* {@link #DIR_OUTPUT_ONLY}, {@link #DIR_BOTH_INIT_INPUT},
* {@link #DIR_BOTH_INIT_OUTPUT}.
* @param mode
* the drive mode of the pin: either {@link #UNASSIGNED UNASSIGNED} or a bitwise OR of at least one
* of: {@link #MODE_INPUT_PULL_UP}, {@link #MODE_INPUT_PULL_DOWN} ,
* {@link #MODE_OUTPUT_PUSH_PULL}, {@link #MODE_OUTPUT_OPEN_DRAIN}; if the pin can be
* set in both input and output direction then the mode must specify both an input
* drive mode and an output drive mode (bit mask).
* @param trigger
* the initial interrupt trigger events, one of: {@link #TRIGGER_NONE},
* {@link #TRIGGER_FALLING_EDGE}, {@link #TRIGGER_RISING_EDGE},
* {@link #TRIGGER_BOTH_EDGES}, {@link #TRIGGER_HIGH_LEVEL},
* {@link #TRIGGER_LOW_LEVEL}, {@link #TRIGGER_BOTH_LEVELS}; if the pin is
* set for output-only then {@code trigger} must be {@link #TRIGGER_NONE}.
* @param initValue
* the initial value of the pin when initially set for output; ignored otherwise.
* @throws IllegalArgumentException
* if any of the following is true:
*
* - {@code pinNumber} is not in the defined range;
* - {@code direction} is not one of the defined values;
* - {@code trigger} is not one of the defined values;
* - {@code trigger} is incompatible with the direction(s) designated by {@code direction};
* - {@code mode} does not designate any mode (i.e. equals {@code 0});
* - {@code mode} designates more than one input or output drive mode;
* - {@code mode} does not designates a drive mode for or designates a drive mode
* incompatible with the direction(s) designated by {@code direction}.
*
* @throws NullPointerException
* if {@code controllerName} is {@code null}.
*
* @deprecated As of 1.1, use {@link Builder} instead.
*/
@Deprecated
public GPIOPinConfig(String controllerName, int pinNumber, int direction, int mode, int trigger, boolean initValue) {
this(UNASSIGNED, pinNumber, direction, mode, trigger, initValue);
controllerName.length();// NPE check
this.controllerName = controllerName;
}
/**
* Creates a new {@code GPIOPinConfig} whose state is deserialized from the specified {@code InputStream}.
* This method may be invoked to restore the state of a {@code GPIOPinConfig}
* object from a persistent store.
*
* @param in the stream to read from.
* @return a new {@code GPIOPinConfig} instance.
* @throws IOException if an I/O error occurs or if the provided stream does not
* contain a representation of a {@code GPIOPinConfig} object.
*
* @since 1.1
*/
public static GPIOPinConfig deserialize(InputStream in) throws IOException {
return (GPIOPinConfig) Platform.deserialize(in);
}
/**
* Serializes the state of this {@code GPIOPinConfig} object to the specified {@code OutputStream}.
* This method may be invoked by the {@link jdk.dio.DeviceManager DeviceManager}
* to save the state of this {@code GPIOPinConfig} object to a persistent store.
*
* @param out the stream to write to.
* @throws IOException if an I/O error occurs.
*
* @since 1.1
*/
@Override
public int serialize(OutputStream out) throws IOException {
return Platform.serialize(this, out);
}
/**
* Gets the configured pin direction.
*
* @return the pin direction, one of: {@link #DIR_INPUT_ONLY}, {@link #DIR_OUTPUT_ONLY},
* {@link #DIR_BOTH_INIT_INPUT}, {@link #DIR_BOTH_INIT_OUTPUT}.
*/
public int getDirection() {
return direction;
}
/**
* Gets the configured pin drive mode.
*
* @return the pin drive mode: either {@link #UNASSIGNED UNASSIGNED} or a bitwise OR of at least one of :
* {@link #MODE_INPUT_PULL_UP}, {@link #MODE_INPUT_PULL_DOWN},
* {@link #MODE_OUTPUT_PUSH_PULL}, {@link #MODE_OUTPUT_OPEN_DRAIN}.
*/
public int getDriveMode() {
return mode;
}
/**
* Gets the configured initial value of the pin, if configured for output.
*
* @return the pin's initial output value; {@code false} if configured for input.
*/
public boolean getInitValue() {
return initValue;
}
/**
* Gets the configured pin number.
*
* @return the hardware pin's number (a positive or zero integer) or {@link #UNASSIGNED UNASSIGNED}.
*/
public int getPinNumber() {
return pinNumber;
}
/**
* Gets the configured controller number for the pin.
*
* @return the hardware port's number (a positive or zero integer) or {@link #UNASSIGNED UNASSIGNED}.
*/
@Override
public int getControllerNumber() {
return controllerNumber;
}
/**
* Gets the configured controller name (such as its device file name on UNIX systems).
*
* @return the controller name or {@code null}.
*/
@Override
public String getControllerName() {
return controllerName;
}
/**
* Gets the configured initial pin interrupt trigger.
*
* @return the pin interrupt trigger, one of: {@link #TRIGGER_NONE},
* {@link #TRIGGER_FALLING_EDGE}, {@link #TRIGGER_RISING_EDGE},
* {@link #TRIGGER_BOTH_EDGES}, {@link #TRIGGER_HIGH_LEVEL}, {@link #TRIGGER_LOW_LEVEL},
* {@link #TRIGGER_BOTH_LEVELS}.
*/
public int getTrigger() {
return trigger;
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
return Platform.hash(this, 7, 59);
}
/**
* Checks two {@code GPIOPinConfig} objects for equality.
*
* @param obj
* the object to test for equality with this object.
* @return {@code true} if {@code obj} is a {@code GPIOPinConfig} and has the same hardware
* addressing information and configuration parameter values as this
* {@code GPIOPinConfig} object; {@code false} otherwise.
*/
@Override
public boolean equals(Object obj) {
return Platform.equals(this, obj);
}
private static void checkDirection(int direction) {
if (direction < DIR_INPUT_ONLY || direction > DIR_BOTH_INIT_OUTPUT) {
throw new IllegalArgumentException(ExceptionMessage.format(ExceptionMessage.GPIO_INVALID_DIRECTION));
}
}
private static void checkMode(int mode) {
if (UNASSIGNED != mode
&& (0 == mode
|| 0 != (mode & ~(GPIOPinConfig.MODE_INPUT_PULL_UP | GPIOPinConfig.MODE_INPUT_PULL_DOWN | GPIOPinConfig.MODE_OUTPUT_PUSH_PULL | GPIOPinConfig.MODE_OUTPUT_OPEN_DRAIN))
|| (GPIOPinConfig.MODE_INPUT_PULL_UP | GPIOPinConfig.MODE_INPUT_PULL_DOWN) == (mode & (GPIOPinConfig.MODE_INPUT_PULL_UP | GPIOPinConfig.MODE_INPUT_PULL_DOWN))
|| (GPIOPinConfig.MODE_OUTPUT_PUSH_PULL | GPIOPinConfig.MODE_OUTPUT_OPEN_DRAIN) == (mode & (GPIOPinConfig.MODE_OUTPUT_PUSH_PULL | GPIOPinConfig.MODE_OUTPUT_OPEN_DRAIN)))) {
throw new IllegalArgumentException(ExceptionMessage.format(ExceptionMessage.GPIO_INVALID_MODE));
}
}
private static void checkTrigger(int trigger) {
if (trigger < TRIGGER_NONE || trigger > TRIGGER_BOTH_LEVELS) {
throw new IllegalArgumentException(ExceptionMessage.format(ExceptionMessage.GPIO_INVALID_TRIGGER));
}
}
/** check if @see GPIOPinConfig.Builder.build() passed successfully.
* It differs from checking for setters such as setPinNumber etc. */
private void checkConsistency() {
if (direction == DIR_OUTPUT_ONLY && trigger != TRIGGER_NONE) {
throw new IllegalArgumentException(
ExceptionMessage.format(ExceptionMessage.GPIO_INCOMPATIBLE_DIR)
);
}
switch (direction) {
case GPIOPinConfig.DIR_INPUT_ONLY:
if (UNASSIGNED != mode &&
0 != (mode & ~(GPIOPinConfig.MODE_INPUT_PULL_DOWN | GPIOPinConfig.MODE_INPUT_PULL_UP))) {
throw new IllegalArgumentException(
ExceptionMessage.format(ExceptionMessage.GPIO_INCOMPATIBLE_MODE)
);
}
break;
case GPIOPinConfig.DIR_OUTPUT_ONLY:
if (UNASSIGNED != mode &&
0 != (mode & ~(GPIOPinConfig.MODE_OUTPUT_OPEN_DRAIN | GPIOPinConfig.MODE_OUTPUT_PUSH_PULL ))) {
throw new IllegalArgumentException(
ExceptionMessage.format(ExceptionMessage.GPIO_INCOMPATIBLE_MODE)
);
}
break;
case GPIOPinConfig.DIR_BOTH_INIT_INPUT:
case GPIOPinConfig.DIR_BOTH_INIT_OUTPUT:
if (UNASSIGNED != mode &&
((mode != (MODE_INPUT_PULL_DOWN | MODE_OUTPUT_OPEN_DRAIN)) &&
(mode != (MODE_INPUT_PULL_DOWN | MODE_OUTPUT_PUSH_PULL)) &&
(mode != (MODE_INPUT_PULL_UP | MODE_OUTPUT_OPEN_DRAIN)) &&
(mode != (MODE_INPUT_PULL_UP | MODE_OUTPUT_PUSH_PULL))) ) {
throw new IllegalArgumentException(
ExceptionMessage.format(ExceptionMessage.GPIO_INCOMPATIBLE_MODE)
);
}
break;
default:
throw new IllegalArgumentException(
ExceptionMessage.format(ExceptionMessage.GPIO_INCOMPATIBLE_MODE)
);
}
}
/** check everything for deprecated @see GPIOPinConfig call */
private void checkAll() {
Utils.checkIntValue(controllerNumber);
Utils.checkIntValue(pinNumber);
checkDirection(direction);
checkMode(mode);
checkTrigger(trigger);
checkConsistency();
}
}