Skip to content

Instantly share code, notes, and snippets.

@fredoche
Forked from markadr/RotaryEncoder.java
Last active July 27, 2020 14:00
Show Gist options
  • Save fredoche/69c5f59cead4b7828653 to your computer and use it in GitHub Desktop.
Save fredoche/69c5f59cead4b7828653 to your computer and use it in GitHub Desktop.
rotary encoder with lock and somehow different decoding
package rotary;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Mark de Reeper
*/
public class RotaryEncoder {
private Lock lock = new ReentrantLock(true);
private final GpioPinDigitalInput inputA;
private final GpioPinDigitalInput inputB;
private final GpioController gpio;
private long encoderValue = 0;
private int lastEncoded = 0;
private boolean firstPass = true;
private RotaryEncoderListener listener;
private static final Logger LOGGER = Logger.getLogger(RotaryEncoder.class.getName());
public RotaryEncoder(Pin pinA, Pin pinB, long initalValue) {
encoderValue = initalValue;
gpio = GpioFactory.getInstance();
inputA = gpio.provisionDigitalInputPin(pinA, "PinA", PinPullResistance.PULL_UP);
inputB = gpio.provisionDigitalInputPin(pinB, "PinB", PinPullResistance.PULL_UP);
GpioPinListenerDigital inputListener = (GpioPinDigitalStateChangeEvent gpdsce) -> {
if (lock.tryLock()) {
int stateA = inputA.getState().getValue();
int stateB = inputB.getState().getValue();
LOGGER.log(Level.INFO, "{0}{1} encodedValue: {2}", new Object[]{stateA, stateB, encoderValue});
try {
calcEncoderValue(stateA, stateB);
} finally {
lock.unlock();
}
} else {
System.out.println("discarded redundant event");
}
};
inputA.addListener(inputListener);
inputB.addListener(inputListener);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
LOGGER.info("RotarySwitch: Shutting down....");
if (gpio != null) {
gpio.removeAllListeners();
gpio.shutdown();
}
}
});
LOGGER.log(Level.INFO, "RotarySwitch initialised on pinA {0} and pinB {1}",
new String[]{pinA.getName(), pinB.getName()});
}
public long getValue() {
return encoderValue;
}
public void setListener(RotaryEncoderListener listener) {
this.listener = listener;
}
private void calcEncoderValue(int stateA, int stateB) {
// converting the 2 pin value to single number to end up with 00, 01, 10 or 11
int encoded = (stateA << 1) | stateB;
if (firstPass) {
firstPass = false;
} else {
// going up states, 01, 11
// going down states 00, 10
int sum = lastEncoded << 2 + encoded;
if (sum == 13 || sum == 4 || sum == 2 || sum == 11) {
encoderValue++;
listener.up(encoderValue);
}
if (sum == 14 || sum == 7 || sum == 1 || sum == 8) {
encoderValue--;
listener.down(encoderValue);
}
}
lastEncoded = encoded;
}
}
/**
*
* @author Mark de Reeper
*/
public interface RotaryEncoderListener {
void up(long encoderValue);
void down(long encoderValue);
}
@kachurovskiy
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment