diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/accelerometer/AccelerometerLSM303Unit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/accelerometer/AccelerometerLSM303Unit.java
index 9117cb99..35ad0bf3 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/accelerometer/AccelerometerLSM303Unit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/accelerometer/AccelerometerLSM303Unit.java
@@ -16,15 +16,6 @@
*/
package com.robo4j.units.rpi.accelerometer;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
import com.robo4j.AttributeDescriptor;
import com.robo4j.ConfigurationException;
import com.robo4j.DefaultAttributeDescriptor;
@@ -36,157 +27,165 @@
import com.robo4j.hw.rpi.i2c.accelerometer.AccelerometerLSM303Device.DataRate;
import com.robo4j.hw.rpi.i2c.accelerometer.AccelerometerLSM303Device.FullScale;
import com.robo4j.hw.rpi.i2c.accelerometer.AccelerometerLSM303Device.PowerMode;
-import com.robo4j.logging.SimpleLoggingUtil;
import com.robo4j.hw.rpi.i2c.accelerometer.CalibratedAccelerometer;
import com.robo4j.math.geometry.Tuple3f;
import com.robo4j.units.rpi.I2CRoboUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
/**
* Accelerometer unit.
- *
+ *
* Use configuration settings to compensate for inverted axes, and for
* calibration.
- *
+ *
* @author Marcus Hirt (@hirt)
* @author Miroslav Wengner (@miragemiko)
*/
public class AccelerometerLSM303Unit extends I2CRoboUnit {
- /**
- * This key controls the {@link PowerMode}. Use the enum name of the power
- * mode you want to use. The default is NORMAL.
- */
- public static final String PROPERTY_KEY_POWER_MODE = "powerMode";
-
- /**
- * This key controls the {@link DataRate} to use. Use the enum name of the
- * data rate you want to use. The default is HZ_10.
- */
- public static final String PROPERTY_KEY_RATE = "rate";
-
- /**
- * This key controls which axes to enable. See
- * {@link AccelerometerLSM303Device}.
- *
- * Default is 7. See {@link AccelerometerLSM303Device#AXIS_ENABLE_ALL}.
- */
- private static final String PROPERTY_KEY_AXIS_ENABLE = "axisEnable";
-
- /**
- * This key controls the full scale (and thereby the sensitivity) of the
- * accelerometer. See {@link FullScale}. Default is G_2.
- */
- private static final String PROPERTY_KEY_FULL_SCALE = "fullScale";
-
- /**
- * This key controls the enabling the high res mode. Default is false.
- */
- private static final String PROPERTY_KEY_ENABLE_HIGH_RES = "enableHighRes";
-
- /**
- * This key controls how often to read the accelerometer, in ms. Default is
- * 200.
- */
- private static final String PROPERTY_KEY_PERIOD = "period";
-
- /**
- * This attribute will provide the state of the accelerometer as a
- * {@link Tuple3f}.
- */
- public static final String ATTRIBUTE_NAME_STATE = "state";
-
- public static final Collection> KNOWN_ATTRIBUTES = List.of(DefaultAttributeDescriptor.create(Tuple3f.class, ATTRIBUTE_NAME_STATE));
-
- private final Scanner scanner = new Scanner();
-
- private CalibratedFloat3DDevice accelerometer;
- private Integer period;
-
- private volatile ScheduledFuture> scannerTask;
- private final List requests = new ArrayList<>();
-
- private class Scanner implements Runnable {
- @Override
- public void run() {
- try {
- Tuple3f value = accelerometer.read();
- for (AccelerometerRequest request : requests) {
- if (request.getPredicate().test(value)) {
- notify(request.getTarget(), value);
- }
- }
- } catch (IOException e) {
- SimpleLoggingUtil.error(getClass(), "Failed to read accelerometer!", e);
- }
- }
-
- private void notify(RoboReference target, Tuple3f value) {
- target.sendMessage(new AccelerometerEvent(value));
- }
- }
-
- /**
- * Constructor.
- *
- * @param context
- * the robo context.
- * @param id
- * the robo unit id.
- */
- public AccelerometerLSM303Unit(RoboContext context, String id) {
- super(AccelerometerRequest.class, context, id);
- }
-
- @Override
- protected void onInitialization(Configuration configuration) throws ConfigurationException {
- super.onInitialization(configuration);
- PowerMode powerMode = PowerMode.valueOf(configuration.getString(PROPERTY_KEY_POWER_MODE, PowerMode.NORMAL.name()));
- DataRate rate = DataRate.valueOf(configuration.getString(PROPERTY_KEY_RATE, DataRate.HZ_10.name()));
- Integer axisEnable = configuration.getInteger(PROPERTY_KEY_AXIS_ENABLE, AccelerometerLSM303Device.AXIS_ENABLE_ALL);
- FullScale fullScale = FullScale.valueOf(configuration.getString(PROPERTY_KEY_FULL_SCALE, FullScale.G_2.name()));
- Boolean enableHighRes = configuration.getBoolean(PROPERTY_KEY_ENABLE_HIGH_RES, false);
- Tuple3f offsets = readFloat3D(configuration.getChildConfiguration("offsets"));
- Tuple3f multipliers = readFloat3D(configuration.getChildConfiguration("multipliers"));
- period = configuration.getInteger(PROPERTY_KEY_PERIOD, 200);
-
- try {
- AccelerometerLSM303Device device = new AccelerometerLSM303Device(getBus(), getAddress(), powerMode, rate, axisEnable, fullScale,
- enableHighRes);
- accelerometer = new CalibratedAccelerometer(device, offsets, multipliers);
- } catch (IOException e) {
- throw new ConfigurationException(String.format(
- "Failed to initialize lidar device. Make sure it is hooked up to bus: %d address: %xd", getBus(), getAddress()), e);
- }
- }
-
- private Tuple3f readFloat3D(Configuration config) {
- return new Tuple3f(config.getFloat("x", 0f), config.getFloat("y", 0f), config.getFloat("z", 0f));
- }
-
- @Override
- public void onMessage(AccelerometerRequest message) {
- super.onMessage(message);
- registerRequest(message);
- }
-
- private void registerRequest(AccelerometerRequest message) {
- synchronized (this) {
- requests.add(message);
- }
- if (scannerTask == null) {
- scannerTask = getContext().getScheduler().scheduleAtFixedRate(scanner, 0, period, TimeUnit.MILLISECONDS);
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected R onGetAttribute(AttributeDescriptor descriptor) {
- if (descriptor.getAttributeType() == Tuple3f.class && descriptor.getAttributeName().equals(ATTRIBUTE_NAME_STATE)) {
- try {
- return (R) accelerometer.read();
- } catch (IOException e) {
- SimpleLoggingUtil.error(getClass(), "Failed to read the accelerometer!", e);
- }
- }
- return super.onGetAttribute(descriptor);
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(AccelerometerLSM303Unit.class);
+
+ /**
+ * This key controls the {@link PowerMode}. Use the enum name of the power
+ * mode you want to use. The default is NORMAL.
+ */
+ public static final String PROPERTY_KEY_POWER_MODE = "powerMode";
+
+ /**
+ * This key controls the {@link DataRate} to use. Use the enum name of the
+ * data rate you want to use. The default is HZ_10.
+ */
+ public static final String PROPERTY_KEY_RATE = "rate";
+
+ /**
+ * This key controls which axes to enable. See
+ * {@link AccelerometerLSM303Device}.
+ *
+ * Default is 7. See {@link AccelerometerLSM303Device#AXIS_ENABLE_ALL}.
+ */
+ private static final String PROPERTY_KEY_AXIS_ENABLE = "axisEnable";
+
+ /**
+ * This key controls the full scale (and thereby the sensitivity) of the
+ * accelerometer. See {@link FullScale}. Default is G_2.
+ */
+ private static final String PROPERTY_KEY_FULL_SCALE = "fullScale";
+
+ /**
+ * This key controls the enabling the high res mode. Default is false.
+ */
+ private static final String PROPERTY_KEY_ENABLE_HIGH_RES = "enableHighRes";
+
+ /**
+ * This key controls how often to read the accelerometer, in ms. Default is
+ * 200.
+ */
+ private static final String PROPERTY_KEY_PERIOD = "period";
+
+ /**
+ * This attribute will provide the state of the accelerometer as a
+ * {@link Tuple3f}.
+ */
+ public static final String ATTRIBUTE_NAME_STATE = "state";
+
+ public static final Collection> KNOWN_ATTRIBUTES = List.of(DefaultAttributeDescriptor.create(Tuple3f.class, ATTRIBUTE_NAME_STATE));
+
+ private final Scanner scanner = new Scanner();
+
+ private CalibratedFloat3DDevice accelerometer;
+ private Integer period;
+
+ private volatile ScheduledFuture> scannerTask;
+ private final List requests = new ArrayList<>();
+
+ private class Scanner implements Runnable {
+ @Override
+ public void run() {
+ try {
+ Tuple3f value = accelerometer.read();
+ for (AccelerometerRequest request : requests) {
+ if (request.getPredicate().test(value)) {
+ notify(request.getTarget(), value);
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.error("Failed to read accelerometer!:{}", e.getMessage(), e);
+ }
+ }
+
+ private void notify(RoboReference target, Tuple3f value) {
+ target.sendMessage(new AccelerometerEvent(value));
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param context the robo context.
+ * @param id the robo unit id.
+ */
+ public AccelerometerLSM303Unit(RoboContext context, String id) {
+ super(AccelerometerRequest.class, context, id);
+ }
+
+ @Override
+ protected void onInitialization(Configuration configuration) throws ConfigurationException {
+ super.onInitialization(configuration);
+ PowerMode powerMode = PowerMode.valueOf(configuration.getString(PROPERTY_KEY_POWER_MODE, PowerMode.NORMAL.name()));
+ DataRate rate = DataRate.valueOf(configuration.getString(PROPERTY_KEY_RATE, DataRate.HZ_10.name()));
+ Integer axisEnable = configuration.getInteger(PROPERTY_KEY_AXIS_ENABLE, AccelerometerLSM303Device.AXIS_ENABLE_ALL);
+ FullScale fullScale = FullScale.valueOf(configuration.getString(PROPERTY_KEY_FULL_SCALE, FullScale.G_2.name()));
+ Boolean enableHighRes = configuration.getBoolean(PROPERTY_KEY_ENABLE_HIGH_RES, false);
+ Tuple3f offsets = readFloat3D(configuration.getChildConfiguration("offsets"));
+ Tuple3f multipliers = readFloat3D(configuration.getChildConfiguration("multipliers"));
+ period = configuration.getInteger(PROPERTY_KEY_PERIOD, 200);
+
+ try {
+ AccelerometerLSM303Device device = new AccelerometerLSM303Device(getBus(), getAddress(), powerMode, rate, axisEnable, fullScale,
+ enableHighRes);
+ accelerometer = new CalibratedAccelerometer(device, offsets, multipliers);
+ } catch (IOException e) {
+ throw new ConfigurationException(String.format(
+ "Failed to initialize lidar device. Make sure it is hooked up to bus: %d address: %xd", getBus(), getAddress()), e);
+ }
+ }
+
+ private Tuple3f readFloat3D(Configuration config) {
+ return new Tuple3f(config.getFloat("x", 0f), config.getFloat("y", 0f), config.getFloat("z", 0f));
+ }
+
+ @Override
+ public void onMessage(AccelerometerRequest message) {
+ super.onMessage(message);
+ registerRequest(message);
+ }
+
+ private void registerRequest(AccelerometerRequest message) {
+ synchronized (this) {
+ requests.add(message);
+ }
+ if (scannerTask == null) {
+ scannerTask = getContext().getScheduler().scheduleAtFixedRate(scanner, 0, period, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected R onGetAttribute(AttributeDescriptor descriptor) {
+ if (descriptor.getAttributeType() == Tuple3f.class && descriptor.getAttributeName().equals(ATTRIBUTE_NAME_STATE)) {
+ try {
+ return (R) accelerometer.read();
+ } catch (IOException e) {
+ LOGGER.error("Failed to read the accelerometer!:{}", e.getMessage(), e);
+ }
+ }
+ return super.onGetAttribute(descriptor);
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/camera/RaspistillUnit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/camera/RaspistillUnit.java
index 9be60258..3ecefeab 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/camera/RaspistillUnit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/camera/RaspistillUnit.java
@@ -23,7 +23,8 @@
import com.robo4j.RoboUnit;
import com.robo4j.configuration.Configuration;
import com.robo4j.hw.rpi.camera.RaspiDevice;
-import com.robo4j.logging.SimpleLoggingUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.EnumSet;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -31,83 +32,82 @@
/**
* Unit generates image by using Rapsberry Pi raspistill utility
*
- * @see raspistill
- * documentation
- *
* @author Marcus Hirt (@hirt)
* @author Miro Wengner (@miragemiko)
+ * @see raspistill
+ * documentation
*/
public class RaspistillUnit extends RoboUnit {
+ private static final Logger LOGGER = LoggerFactory.getLogger(RaspistillUnit.class);
+ private static final EnumSet acceptedStates = EnumSet.of(LifecycleState.STARTING,
+ LifecycleState.STARTED);
+ private static final String PROPERTY_TARGET = "target";
+ private final AtomicBoolean continualMode = new AtomicBoolean(false);
+ private final AtomicBoolean cameraProgress = new AtomicBoolean(false);
- private static final EnumSet acceptedStates = EnumSet.of(LifecycleState.STARTING,
- LifecycleState.STARTED);
- private static final String PROPERTY_TARGET = "target";
- private final AtomicBoolean continualMode = new AtomicBoolean(false);
- private final AtomicBoolean cameraProgress = new AtomicBoolean(false);
-
- private final RaspiDevice device = new RaspiDevice();
- private String target;
+ private final RaspiDevice device = new RaspiDevice();
+ private String target;
- public RaspistillUnit(RoboContext context, String id) {
- super(RaspistillRequest.class, context, id);
- }
+ public RaspistillUnit(RoboContext context, String id) {
+ super(RaspistillRequest.class, context, id);
+ }
- @Override
- protected void onInitialization(Configuration configuration) throws ConfigurationException {
- target = configuration.getString(PROPERTY_TARGET, null);
- if (target == null) {
- throw ConfigurationException.createMissingConfigNameException(PROPERTY_TARGET);
- }
- }
+ @Override
+ protected void onInitialization(Configuration configuration) throws ConfigurationException {
+ target = configuration.getString(PROPERTY_TARGET, null);
+ if (target == null) {
+ throw ConfigurationException.createMissingConfigNameException(PROPERTY_TARGET);
+ }
+ }
- @Override
- public void onMessage(RaspistillRequest message) {
- processMessage(message);
- }
+ @Override
+ public void onMessage(RaspistillRequest message) {
+ processMessage(message);
+ }
- private void processMessage(RaspistillRequest message) {
- getContext().getScheduler().execute(() -> {
- if (continualMode.get()) {
- stopProgress();
- }
- if (message.isActive()) {
- startContinualMode(message);
- } else if (cameraProgress.compareAndSet(false, true)) {
- createImage(message);
- }
- });
- }
+ private void processMessage(RaspistillRequest message) {
+ getContext().getScheduler().execute(() -> {
+ if (continualMode.get()) {
+ stopProgress();
+ }
+ if (message.isActive()) {
+ startContinualMode(message);
+ } else if (cameraProgress.compareAndSet(false, true)) {
+ createImage(message);
+ }
+ });
+ }
- private void stopProgress() {
- continualMode.set(false);
- while (cameraProgress.get());
- }
+ private void stopProgress() {
+ continualMode.set(false);
+ while (cameraProgress.get()) ;
+ }
- private void startContinualMode(RaspistillRequest message) {
- getContext().getScheduler().execute(() -> {
- continualMode.set(true);
- while (acceptedStates.contains(getState()) && continualMode.get()) {
- if (cameraProgress.compareAndSet(false, true)) {
- createImage(message);
- }
- }
- });
+ private void startContinualMode(RaspistillRequest message) {
+ getContext().getScheduler().execute(() -> {
+ continualMode.set(true);
+ while (acceptedStates.contains(getState()) && continualMode.get()) {
+ if (cameraProgress.compareAndSet(false, true)) {
+ createImage(message);
+ }
+ }
+ });
- }
+ }
- private void createImage(RaspistillRequest message) {
- try {
- final byte[] image = device.executeCommandRaspistill(message.create());
- final RoboReference targetReference = getContext().getReference(target);
- if (targetReference != null && image.length > 0) {
- ImageDTO imageDTO = CameraUtil.createImageDTOBydMessageAndBytes(message, image);
- targetReference.sendMessage(imageDTO);
- }
- cameraProgress.set(false);
- } catch (Exception e) {
- SimpleLoggingUtil.error(getClass(), "create image", e);
- }
- }
+ private void createImage(RaspistillRequest message) {
+ try {
+ final byte[] image = device.executeCommandRaspistill(message.create());
+ final RoboReference targetReference = getContext().getReference(target);
+ if (targetReference != null && image.length > 0) {
+ ImageDTO imageDTO = CameraUtil.createImageDTOBydMessageAndBytes(message, image);
+ targetReference.sendMessage(imageDTO);
+ }
+ cameraProgress.set(false);
+ } catch (Exception e) {
+ LOGGER.error("create image:{}", e.getMessage(), e);
+ }
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/MtkGPSUnit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/MtkGPSUnit.java
index 3eaa7a93..e85aa596 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/MtkGPSUnit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/MtkGPSUnit.java
@@ -16,16 +16,6 @@
*/
package com.robo4j.units.rpi.gps;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
import com.robo4j.AttributeDescriptor;
import com.robo4j.ConfigurationException;
import com.robo4j.DefaultAttributeDescriptor;
@@ -41,160 +31,170 @@
import com.robo4j.logging.SimpleLoggingUtil;
import com.robo4j.math.geometry.Tuple3f;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
/**
* Unit for getting GPS data.
- *
+ *
* @author Marcus Hirt (@hirt)
* @author Miroslav Wengner (@miragemiko)
*/
public class MtkGPSUnit extends RoboUnit {
- /**
- * This key configures the approximate update interval, or how often to
- * schedule reads from the serial port.
- */
- public static final String PROPERTY_KEY_READ_INTERVAL = "readInterval";
-
- /**
- * This key configures the scheduler to use for scheduling reads. Either
- * PLATFORM or INTERNAL. Use INTERNAL if the reads take too long and start
- * disrupting the platform scheduler too much.
- */
- public static final String PROPERTY_KEY_SCHEDULER = "scheduler";
-
- /**
- * Value for the scheduler key for using the platform scheduler.
- */
- public static final String PROPERTY_VALUE_PLATFORM_SCHEDULER = "platform";
-
- /**
- * Value for the scheduler key for using the internal scheduler.
- */
- public static final String PROPERTY_VALUE_INTERNAL_SCHEDULER = "internal";
-
- /**
- * This is the default value for the read interval.
- */
- public static final int DEFAULT_READ_INTERVAL = MTK3339GPS.DEFAULT_READ_INTERVAL;
-
- /**
- * This is the default value for the serial port.
- */
- public static final String DEFAULT_SERIAL_PORT = MTK3339GPS.DEFAULT_GPS_PORT;
-
- /**
- * This attribute will provide the state of the read interval.
- */
- public static final String ATTRIBUTE_NAME_READ_INTERVAL = "readInterval";
-
- public static final Collection> KNOWN_ATTRIBUTES = Collections
- .unmodifiableCollection(Arrays.asList(DefaultAttributeDescriptor.create(Tuple3f.class, ATTRIBUTE_NAME_READ_INTERVAL)));
-
- private MTK3339GPS mtk3339gps;
- private String serialPort;
- private int readInterval = DEFAULT_READ_INTERVAL;
- private List listeners = new ArrayList<>();
-
- // The future, if scheduled with the platform scheduler
- private volatile ScheduledFuture> scheduledFuture;
-
- private static class GPSEventListener implements GPSListener {
- private RoboReference target;
-
- GPSEventListener(RoboReference target) {
- this.target = target;
- }
-
- @Override
- public void onPosition(PositionEvent event) {
- target.sendMessage(event);
- }
-
- @Override
- public void onVelocity(VelocityEvent event) {
- target.sendMessage(event);
- }
- }
-
- public MtkGPSUnit(RoboContext context, String id) {
- super(GPSRequest.class, context, id);
- }
-
- @Override
- protected void onInitialization(Configuration configuration) throws ConfigurationException {
- serialPort = configuration.getString("serialPort", DEFAULT_SERIAL_PORT);
- readInterval = configuration.getInteger("readInterval", DEFAULT_READ_INTERVAL);
- String scheduler = configuration.getString("scheduler", PROPERTY_VALUE_PLATFORM_SCHEDULER);
- boolean usePlatformScheduler = PROPERTY_VALUE_PLATFORM_SCHEDULER.equals(scheduler);
-
- try {
- mtk3339gps = new MTK3339GPS(serialPort, readInterval);
- } catch (IOException e) {
- throw new ConfigurationException("Could not instantiate GPS!", e);
- }
- if (usePlatformScheduler) {
- scheduledFuture = getContext().getScheduler().scheduleAtFixedRate(() -> mtk3339gps.update(), 10, readInterval,
- TimeUnit.MILLISECONDS);
- } else {
- mtk3339gps.start();
- }
- }
-
- @Override
- public Future getAttribute(AttributeDescriptor attribute) {
- return super.getAttribute(attribute);
- }
-
- @Override
- public void onMessage(GPSRequest message) {
- super.onMessage(message);
- RoboReference targetReference = message.getTarget();
- switch (message.getOperation()) {
- case REGISTER:
- register(targetReference);
- break;
- case UNREGISTER:
- unregister(targetReference);
- break;
- default:
- SimpleLoggingUtil.error(getClass(), "Unknown operation: " + message.getOperation());
- break;
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected R onGetAttribute(AttributeDescriptor descriptor) {
- if (descriptor.getAttributeType() == Integer.class && descriptor.getAttributeName().equals(ATTRIBUTE_NAME_READ_INTERVAL)) {
- return (R) Integer.valueOf(readInterval);
- }
- return super.onGetAttribute(descriptor);
- }
-
- @Override
- public void shutdown() {
- if (scheduledFuture != null) {
- scheduledFuture.cancel(false);
- }
- mtk3339gps.shutdown();
- super.shutdown();
- }
-
- // Private Methods
- private synchronized void unregister(RoboReference targetReference) {
- List copy = new ArrayList<>(listeners);
- for (GPSEventListener listener : copy) {
- if (targetReference.equals(listener.target)) {
- listeners.remove(listener);
- mtk3339gps.removeListener(listener);
- // I guess you could theoretically have several registered to
- // the same target, so let's keep checking...
- }
- }
- }
-
- private synchronized void register(RoboReference targetReference) {
- GPSEventListener listener = new GPSEventListener(targetReference);
- listeners.add(listener);
- mtk3339gps.addListener(listener);
- }
+ /**
+ * This key configures the approximate update interval, or how often to
+ * schedule reads from the serial port.
+ */
+ public static final String PROPERTY_KEY_READ_INTERVAL = "readInterval";
+
+ /**
+ * This key configures the scheduler to use for scheduling reads. Either
+ * PLATFORM or INTERNAL. Use INTERNAL if the reads take too long and start
+ * disrupting the platform scheduler too much.
+ */
+ public static final String PROPERTY_KEY_SCHEDULER = "scheduler";
+
+ /**
+ * Value for the scheduler key for using the platform scheduler.
+ */
+ public static final String PROPERTY_VALUE_PLATFORM_SCHEDULER = "platform";
+
+ /**
+ * Value for the scheduler key for using the internal scheduler.
+ */
+ public static final String PROPERTY_VALUE_INTERNAL_SCHEDULER = "internal";
+
+ /**
+ * This is the default value for the read interval.
+ */
+ public static final int DEFAULT_READ_INTERVAL = MTK3339GPS.DEFAULT_READ_INTERVAL;
+
+ /**
+ * This is the default value for the serial port.
+ */
+ public static final String DEFAULT_SERIAL_PORT = MTK3339GPS.DEFAULT_GPS_PORT;
+
+ /**
+ * This attribute will provide the state of the read interval.
+ */
+ public static final String ATTRIBUTE_NAME_READ_INTERVAL = "readInterval";
+
+ public static final Collection> KNOWN_ATTRIBUTES = Collections
+ .unmodifiableCollection(Arrays.asList(DefaultAttributeDescriptor.create(Tuple3f.class, ATTRIBUTE_NAME_READ_INTERVAL)));
+
+ private MTK3339GPS mtk3339gps;
+ private String serialPort;
+ private int readInterval = DEFAULT_READ_INTERVAL;
+ private List listeners = new ArrayList<>();
+
+ // The future, if scheduled with the platform scheduler
+ private volatile ScheduledFuture> scheduledFuture;
+
+ private static class GPSEventListener implements GPSListener {
+ private RoboReference target;
+
+ GPSEventListener(RoboReference target) {
+ this.target = target;
+ }
+
+ @Override
+ public void onPosition(PositionEvent event) {
+ target.sendMessage(event);
+ }
+
+ @Override
+ public void onVelocity(VelocityEvent event) {
+ target.sendMessage(event);
+ }
+ }
+
+ public MtkGPSUnit(RoboContext context, String id) {
+ super(GPSRequest.class, context, id);
+ }
+
+ @Override
+ protected void onInitialization(Configuration configuration) throws ConfigurationException {
+ serialPort = configuration.getString("serialPort", DEFAULT_SERIAL_PORT);
+ readInterval = configuration.getInteger("readInterval", DEFAULT_READ_INTERVAL);
+ String scheduler = configuration.getString("scheduler", PROPERTY_VALUE_PLATFORM_SCHEDULER);
+ boolean usePlatformScheduler = PROPERTY_VALUE_PLATFORM_SCHEDULER.equals(scheduler);
+
+ try {
+ mtk3339gps = new MTK3339GPS(serialPort, readInterval);
+ } catch (IOException e) {
+ throw new ConfigurationException("Could not instantiate GPS!", e);
+ }
+ if (usePlatformScheduler) {
+ scheduledFuture = getContext().getScheduler().scheduleAtFixedRate(() -> mtk3339gps.update(), 10, readInterval,
+ TimeUnit.MILLISECONDS);
+ } else {
+ mtk3339gps.start();
+ }
+ }
+
+ @Override
+ public Future getAttribute(AttributeDescriptor attribute) {
+ return super.getAttribute(attribute);
+ }
+
+ @Override
+ public void onMessage(GPSRequest message) {
+ super.onMessage(message);
+ RoboReference targetReference = message.getTarget();
+ switch (message.getOperation()) {
+ case REGISTER:
+ register(targetReference);
+ break;
+ case UNREGISTER:
+ unregister(targetReference);
+ break;
+ default:
+ SimpleLoggingUtil.error(getClass(), "Unknown operation: " + message.getOperation());
+ break;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected R onGetAttribute(AttributeDescriptor descriptor) {
+ if (descriptor.getAttributeType() == Integer.class && descriptor.getAttributeName().equals(ATTRIBUTE_NAME_READ_INTERVAL)) {
+ return (R) Integer.valueOf(readInterval);
+ }
+ return super.onGetAttribute(descriptor);
+ }
+
+ @Override
+ public void shutdown() {
+ if (scheduledFuture != null) {
+ scheduledFuture.cancel(false);
+ }
+ mtk3339gps.shutdown();
+ super.shutdown();
+ }
+
+ // Private Methods
+ private synchronized void unregister(RoboReference targetReference) {
+ List copy = new ArrayList<>(listeners);
+ for (GPSEventListener listener : copy) {
+ if (targetReference.equals(listener.target)) {
+ listeners.remove(listener);
+ mtk3339gps.removeListener(listener);
+ // I guess you could theoretically have several registered to
+ // the same target, so let's keep checking...
+ }
+ }
+ }
+
+ private synchronized void register(RoboReference targetReference) {
+ GPSEventListener listener = new GPSEventListener(targetReference);
+ listeners.add(listener);
+ mtk3339gps.addListener(listener);
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/TitanGPSUnit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/TitanGPSUnit.java
index e527f129..1ef2140f 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/TitanGPSUnit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gps/TitanGPSUnit.java
@@ -16,12 +16,6 @@
*/
package com.robo4j.units.rpi.gps;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledFuture;
-
import com.robo4j.AttributeDescriptor;
import com.robo4j.ConfigurationException;
import com.robo4j.RoboContext;
@@ -33,106 +27,114 @@
import com.robo4j.hw.rpi.gps.PositionEvent;
import com.robo4j.hw.rpi.gps.VelocityEvent;
import com.robo4j.hw.rpi.i2c.gps.TitanX1GPS;
-import com.robo4j.logging.SimpleLoggingUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledFuture;
/**
* Unit for getting GPS data.
- *
+ *
* @author Marcus Hirt (@hirt)
* @author Miroslav Wengner (@miragemiko)
*/
public class TitanGPSUnit extends RoboUnit {
- private final List listeners = new ArrayList<>();
- private TitanX1GPS titangps;
-
- // The future, if scheduled with the platform scheduler
- private volatile ScheduledFuture> scheduledFuture;
-
- private static class GPSEventListener implements GPSListener {
- private final RoboReference target;
-
- private GPSEventListener(RoboReference target) {
- this.target = target;
- }
-
- @Override
- public void onPosition(PositionEvent event) {
- target.sendMessage(event);
- }
-
- @Override
- public void onVelocity(VelocityEvent event) {
- target.sendMessage(event);
- }
- }
-
- public TitanGPSUnit(RoboContext context, String id) {
- super(GPSRequest.class, context, id);
- }
-
- @Override
- protected void onInitialization(Configuration configuration) throws ConfigurationException {
- // TODO: Configuration for bus, address etc
- try {
- titangps = new TitanX1GPS();
- } catch (IOException e) {
- throw new ConfigurationException("Could not instantiate GPS!", e);
- }
- titangps.start();
- }
-
- @Override
- public Future getAttribute(AttributeDescriptor attribute) {
- return super.getAttribute(attribute);
- }
-
- @Override
- public void onMessage(GPSRequest message) {
- super.onMessage(message);
- RoboReference targetReference = message.getTarget();
- switch (message.getOperation()) {
- case REGISTER:
- register(targetReference);
- break;
- case UNREGISTER:
- unregister(targetReference);
- break;
- default:
- SimpleLoggingUtil.error(getClass(), "Unknown operation: " + message.getOperation());
- break;
- }
- }
-
- @Override
- protected R onGetAttribute(AttributeDescriptor descriptor) {
- return super.onGetAttribute(descriptor);
- }
-
- @Override
- public void shutdown() {
- if (scheduledFuture != null) {
- scheduledFuture.cancel(false);
- }
- titangps.shutdown();
- super.shutdown();
- }
-
- // Private Methods
- private synchronized void unregister(RoboReference targetReference) {
- List copy = new ArrayList<>(listeners);
- for (GPSEventListener listener : copy) {
- if (targetReference.equals(listener.target)) {
- listeners.remove(listener);
- titangps.removeListener(listener);
- // I guess you could theoretically have several registered to
- // the same target, so let's keep checking...
- }
- }
- }
-
- private synchronized void register(RoboReference targetReference) {
- var listener = new GPSEventListener(targetReference);
- listeners.add(listener);
- titangps.addListener(listener);
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(TitanGPSUnit.class);
+ private final List listeners = new ArrayList<>();
+ private TitanX1GPS titangps;
+
+ // The future, if scheduled with the platform scheduler
+ private volatile ScheduledFuture> scheduledFuture;
+
+ private static class GPSEventListener implements GPSListener {
+ private final RoboReference target;
+
+ private GPSEventListener(RoboReference target) {
+ this.target = target;
+ }
+
+ @Override
+ public void onPosition(PositionEvent event) {
+ target.sendMessage(event);
+ }
+
+ @Override
+ public void onVelocity(VelocityEvent event) {
+ target.sendMessage(event);
+ }
+ }
+
+ public TitanGPSUnit(RoboContext context, String id) {
+ super(GPSRequest.class, context, id);
+ }
+
+ @Override
+ protected void onInitialization(Configuration configuration) throws ConfigurationException {
+ // TODO: Configuration for bus, address etc
+ try {
+ titangps = new TitanX1GPS();
+ } catch (IOException e) {
+ throw new ConfigurationException("Could not instantiate GPS!", e);
+ }
+ titangps.start();
+ }
+
+ @Override
+ public Future getAttribute(AttributeDescriptor attribute) {
+ return super.getAttribute(attribute);
+ }
+
+ @Override
+ public void onMessage(GPSRequest message) {
+ super.onMessage(message);
+ RoboReference targetReference = message.getTarget();
+ switch (message.getOperation()) {
+ case REGISTER:
+ register(targetReference);
+ break;
+ case UNREGISTER:
+ unregister(targetReference);
+ break;
+ default:
+ LOGGER.error("Unknown operation:{}", message.getOperation());
+ break;
+ }
+ }
+
+ @Override
+ protected R onGetAttribute(AttributeDescriptor descriptor) {
+ return super.onGetAttribute(descriptor);
+ }
+
+ @Override
+ public void shutdown() {
+ if (scheduledFuture != null) {
+ scheduledFuture.cancel(false);
+ }
+ titangps.shutdown();
+ super.shutdown();
+ }
+
+ // Private Methods
+ private synchronized void unregister(RoboReference targetReference) {
+ List copy = new ArrayList<>(listeners);
+ for (GPSEventListener listener : copy) {
+ if (targetReference.equals(listener.target)) {
+ listeners.remove(listener);
+ titangps.removeListener(listener);
+ // I guess you could theoretically have several registered to
+ // the same target, so let's keep checking...
+ }
+ }
+ }
+
+ private synchronized void register(RoboReference targetReference) {
+ var listener = new GPSEventListener(targetReference);
+ listeners.add(listener);
+ titangps.addListener(listener);
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gyro/GyroL3GD20Unit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gyro/GyroL3GD20Unit.java
index 35f4923e..bf62b3ab 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gyro/GyroL3GD20Unit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/gyro/GyroL3GD20Unit.java
@@ -16,15 +16,6 @@
*/
package com.robo4j.units.rpi.gyro;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
import com.robo4j.AttributeDescriptor;
import com.robo4j.ConfigurationException;
import com.robo4j.DefaultAttributeDescriptor;
@@ -35,203 +26,212 @@
import com.robo4j.hw.rpi.i2c.gyro.CalibratedGyro;
import com.robo4j.hw.rpi.i2c.gyro.GyroL3GD20Device;
import com.robo4j.hw.rpi.i2c.gyro.GyroL3GD20Device.Sensitivity;
-import com.robo4j.logging.SimpleLoggingUtil;
import com.robo4j.math.geometry.Tuple3f;
import com.robo4j.units.rpi.I2CRoboUnit;
import com.robo4j.units.rpi.gyro.GyroRequest.GyroAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
/**
* Gyro unit based on the {@link GyroL3GD20Device}. Note that there can only be
* ONE active notification threshold per target. If a new one is registered
* before it has triggered, the new one will replace the old one.
- *
+ *
* @author Marcus Hirt (@hirt)
* @author Miroslav Wengner (@miragemiko)
*/
@WorkTrait
public class GyroL3GD20Unit extends I2CRoboUnit {
- /**
- * This key configures the sensitivity of the gyro. Use the name of the
- * Sensitivity enum. Default is DPS_245.
- *
- * @see Sensitivity
- */
- public static final String PROPERTY_KEY_SENSITIVITY = "sensitivity";
-
- /**
- * This key configures the high pass filter. Set to true to enable. Default
- * is true.
- *
- * @see GyroL3GD20Device
- */
- public static final String PROPERTY_KEY_HIGH_PASS_FILTER = "enableHighPass";
-
- /**
- * This key configures how often to read the gyro in ms. Default is 10.
- */
- public static final String PROPERTY_KEY_PERIOD = "period";
-
- /**
- * This attribute will provide the state of the gyro as a {@link Tuple3f}.
- */
- public static final String ATTRIBUTE_NAME_STATE = "state";
-
- public static final Collection> KNOWN_ATTRIBUTES = Collections
- .unmodifiableCollection(Arrays.asList(DefaultAttributeDescriptor.create(Tuple3f.class, ATTRIBUTE_NAME_STATE)));
-
- private final Map, GyroNotificationEntry> activeThresholds = new HashMap<>();
-
- private final GyroScanner scanner = new GyroScanner();
-
- // TODO review field purpose
- private Sensitivity sensitivity;
- private boolean highPassFilter;
- private int period;
- private CalibratedGyro gyro;
- private volatile ScheduledFuture> readings;
-
- private class GyroScanner implements Runnable {
- private long lastReadingTime = System.currentTimeMillis();
- private Tuple3f lastReading = new Tuple3f(0f, 0f, 0f);
-
- @Override
- public void run() {
- Tuple3f data = read();
- long newTime = System.currentTimeMillis();
-
- // Trapezoid
- Tuple3f tmp = new Tuple3f(data);
- long deltaTime = newTime - lastReadingTime;
- data.add(lastReading);
- data.multiplyScalar(deltaTime / 2000.0f);
-
- lastReading.set(tmp);
- addToDeltas(data);
- lastReadingTime = newTime;
- }
-
- private void addToDeltas(Tuple3f data) {
- synchronized (GyroL3GD20Unit.this) {
- for (GyroNotificationEntry notificationEntry : activeThresholds.values()) {
- notificationEntry.addDelta(data);
- }
- }
- }
-
- private void reset() {
- lastReadingTime = System.currentTimeMillis();
- lastReading = read();
- }
-
- private Tuple3f read() {
- try {
- return gyro.read();
- } catch (IOException e) {
- SimpleLoggingUtil.error(getClass(), "Could not read gyro, aborting.", e);
- return null;
- }
- }
- }
-
- /**
- * Constructor.
- *
- * @param context
- * the robo context.
- * @param id
- * the robo unit id.
- */
- public GyroL3GD20Unit(RoboContext context, String id) {
- super(GyroRequest.class, context, id);
- }
-
- @Override
- protected void onInitialization(Configuration configuration) throws ConfigurationException {
- super.onInitialization(configuration);
- sensitivity = Sensitivity.valueOf(configuration.getString(PROPERTY_KEY_SENSITIVITY, "DPS_245"));
- period = configuration.getInteger(PROPERTY_KEY_PERIOD, 10);
- highPassFilter = configuration.getBoolean(PROPERTY_KEY_HIGH_PASS_FILTER, true);
- try {
- gyro = new CalibratedGyro(new GyroL3GD20Device(getBus(), getAddress(), sensitivity, highPassFilter));
- } catch (IOException e) {
- throw new ConfigurationException(String.format(
- "Failed to initialize lidar device. Make sure it is hooked up to bus: %d address: %xd", getBus(), getAddress()), e);
- }
- }
-
- @Override
- public Collection> getKnownAttributes() {
- return KNOWN_ATTRIBUTES;
- }
-
- @Override
- public void onMessage(GyroRequest message) {
- RoboReference notificationTarget = message.getTarget();
- switch (message.getAction()) {
- case CALIBRATE:
- try {
- gyro.calibrate();
- scanner.reset();
- if (notificationTarget != null) {
- notificationTarget.sendMessage(new GyroEvent(new Tuple3f(0, 0, 0)));
- }
- } catch (IOException e) {
- SimpleLoggingUtil.error(getClass(), "Failed to calibrate!", e);
- }
- break;
- case STOP:
- stopForNotificationTarget(notificationTarget);
- break;
- case ONCE:
- case CONTINUOUS:
- if (message.getNotificationThreshold() != null) {
- setUpNotification(message);
- }
- break;
- }
- }
-
- private void stopForNotificationTarget(RoboReference notificationTarget) {
- synchronized (this) {
- if (notificationTarget == null) {
- activeThresholds.clear();
- } else {
- activeThresholds.remove(notificationTarget);
- }
- if (activeThresholds.isEmpty()) {
- if (readings != null) {
- readings.cancel(false);
- readings = null;
- }
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected R onGetAttribute(AttributeDescriptor descriptor) {
- if (descriptor.getAttributeType() == Tuple3f.class && descriptor.getAttributeName().equals(ATTRIBUTE_NAME_STATE)) {
- try {
- return (R) gyro.read();
- } catch (IOException e) {
- SimpleLoggingUtil.error(getClass(), "Failed to read the gyro!", e);
- }
- }
- return super.onGetAttribute(descriptor);
- }
-
- private void setUpNotification(GyroRequest request) {
- synchronized (this) {
- if (request.getAction() == GyroAction.CONTINUOUS) {
- activeThresholds.put(request.getTarget(), new ContinuousGyroNotificationEntry(request.getTarget(), request.getNotificationThreshold()));
- } else {
- activeThresholds.put(request.getTarget(), new FixedGyroNotificationEntry(request.getTarget(), request.getNotificationThreshold()));
- }
- }
- if (readings == null) {
- synchronized (this) {
- readings = getContext().getScheduler().scheduleAtFixedRate(scanner, 0, period, TimeUnit.MILLISECONDS);
- }
- }
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(GyroL3GD20Unit.class);
+ /**
+ * This key configures the sensitivity of the gyro. Use the name of the
+ * Sensitivity enum. Default is DPS_245.
+ *
+ * @see Sensitivity
+ */
+ public static final String PROPERTY_KEY_SENSITIVITY = "sensitivity";
+
+ /**
+ * This key configures the high pass filter. Set to true to enable. Default
+ * is true.
+ *
+ * @see GyroL3GD20Device
+ */
+ public static final String PROPERTY_KEY_HIGH_PASS_FILTER = "enableHighPass";
+
+ /**
+ * This key configures how often to read the gyro in ms. Default is 10.
+ */
+ public static final String PROPERTY_KEY_PERIOD = "period";
+
+ /**
+ * This attribute will provide the state of the gyro as a {@link Tuple3f}.
+ */
+ public static final String ATTRIBUTE_NAME_STATE = "state";
+
+ public static final Collection> KNOWN_ATTRIBUTES = Collections
+ .unmodifiableCollection(Arrays.asList(DefaultAttributeDescriptor.create(Tuple3f.class, ATTRIBUTE_NAME_STATE)));
+
+ private final Map, GyroNotificationEntry> activeThresholds = new HashMap<>();
+
+ private final GyroScanner scanner = new GyroScanner();
+
+ // TODO review field purpose
+ private Sensitivity sensitivity;
+ private boolean highPassFilter;
+ private int period;
+ private CalibratedGyro gyro;
+ private volatile ScheduledFuture> readings;
+
+ private class GyroScanner implements Runnable {
+ private long lastReadingTime = System.currentTimeMillis();
+ private Tuple3f lastReading = new Tuple3f(0f, 0f, 0f);
+
+ @Override
+ public void run() {
+ Tuple3f data = read();
+ long newTime = System.currentTimeMillis();
+
+ // Trapezoid
+ Tuple3f tmp = new Tuple3f(data);
+ long deltaTime = newTime - lastReadingTime;
+ data.add(lastReading);
+ data.multiplyScalar(deltaTime / 2000.0f);
+
+ lastReading.set(tmp);
+ addToDeltas(data);
+ lastReadingTime = newTime;
+ }
+
+ private void addToDeltas(Tuple3f data) {
+ synchronized (GyroL3GD20Unit.this) {
+ for (GyroNotificationEntry notificationEntry : activeThresholds.values()) {
+ notificationEntry.addDelta(data);
+ }
+ }
+ }
+
+ private void reset() {
+ lastReadingTime = System.currentTimeMillis();
+ lastReading = read();
+ }
+
+ private Tuple3f read() {
+ try {
+ return gyro.read();
+ } catch (IOException e) {
+ LOGGER.error("Could not read gyro, aborting:", e.getMessage(), e);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param context the robo context.
+ * @param id the robo unit id.
+ */
+ public GyroL3GD20Unit(RoboContext context, String id) {
+ super(GyroRequest.class, context, id);
+ }
+
+ @Override
+ protected void onInitialization(Configuration configuration) throws ConfigurationException {
+ super.onInitialization(configuration);
+ sensitivity = Sensitivity.valueOf(configuration.getString(PROPERTY_KEY_SENSITIVITY, "DPS_245"));
+ period = configuration.getInteger(PROPERTY_KEY_PERIOD, 10);
+ highPassFilter = configuration.getBoolean(PROPERTY_KEY_HIGH_PASS_FILTER, true);
+ try {
+ gyro = new CalibratedGyro(new GyroL3GD20Device(getBus(), getAddress(), sensitivity, highPassFilter));
+ } catch (IOException e) {
+ throw new ConfigurationException(String.format(
+ "Failed to initialize lidar device. Make sure it is hooked up to bus: %d address: %xd", getBus(), getAddress()), e);
+ }
+ }
+
+ @Override
+ public Collection> getKnownAttributes() {
+ return KNOWN_ATTRIBUTES;
+ }
+
+ @Override
+ public void onMessage(GyroRequest message) {
+ RoboReference notificationTarget = message.getTarget();
+ switch (message.getAction()) {
+ case CALIBRATE:
+ try {
+ gyro.calibrate();
+ scanner.reset();
+ if (notificationTarget != null) {
+ notificationTarget.sendMessage(new GyroEvent(new Tuple3f(0, 0, 0)));
+ }
+ } catch (IOException e) {
+ LOGGER.error("Failed to calibrate!:{}", e.getMessage(), e);
+ }
+ break;
+ case STOP:
+ stopForNotificationTarget(notificationTarget);
+ break;
+ case ONCE:
+ case CONTINUOUS:
+ if (message.getNotificationThreshold() != null) {
+ setUpNotification(message);
+ }
+ break;
+ }
+ }
+
+ private void stopForNotificationTarget(RoboReference notificationTarget) {
+ synchronized (this) {
+ if (notificationTarget == null) {
+ activeThresholds.clear();
+ } else {
+ activeThresholds.remove(notificationTarget);
+ }
+ if (activeThresholds.isEmpty()) {
+ if (readings != null) {
+ readings.cancel(false);
+ readings = null;
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected R onGetAttribute(AttributeDescriptor descriptor) {
+ if (descriptor.getAttributeType() == Tuple3f.class && descriptor.getAttributeName().equals(ATTRIBUTE_NAME_STATE)) {
+ try {
+ return (R) gyro.read();
+ } catch (IOException e) {
+ LOGGER.error("Failed to read the gyro!:{}", e.getMessage(), e);
+ }
+ }
+ return super.onGetAttribute(descriptor);
+ }
+
+ private void setUpNotification(GyroRequest request) {
+ synchronized (this) {
+ if (request.getAction() == GyroAction.CONTINUOUS) {
+ activeThresholds.put(request.getTarget(), new ContinuousGyroNotificationEntry(request.getTarget(), request.getNotificationThreshold()));
+ } else {
+ activeThresholds.put(request.getTarget(), new FixedGyroNotificationEntry(request.getTarget(), request.getNotificationThreshold()));
+ }
+ }
+ if (readings == null) {
+ synchronized (this) {
+ readings = getContext().getScheduler().scheduleAtFixedRate(scanner, 0, period, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/Bno080Unit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/Bno080Unit.java
index 00d449fb..d69bfbf2 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/Bno080Unit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/Bno080Unit.java
@@ -28,7 +28,8 @@
import com.robo4j.hw.rpi.imu.bno.DataListener;
import com.robo4j.hw.rpi.imu.bno.impl.Bno080SPIDevice;
import com.robo4j.hw.rpi.imu.bno.shtp.SensorReportId;
-import com.robo4j.logging.SimpleLoggingUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
@@ -42,92 +43,92 @@
* @author Miroslav Wengner (@miragemiko)
*/
public class Bno080Unit extends RoboUnit {
-
- public static final String PROPERTY_REPORT_TYPE = "reportType";
- public static final String PROPERTY_REPORT_DELAY = "reportDelay";
-
- private static final class BnoListenerEvent implements DataListener {
- private final RoboReference target;
-
- BnoListenerEvent(RoboReference target) {
- this.target = target;
- }
-
- @Override
- public void onResponse(DataEvent3f event) {
- target.sendMessage(event);
- }
- }
-
- private final List listeners = new ArrayList<>();
- private Bno080Device device;
-
- public Bno080Unit(RoboContext context, String id) {
- super(BnoRequest.class, context, id);
- }
-
- // TODO review field purpose
- private int reportDelay;
- private SensorReportId report;
-
- @Override
- protected void onInitialization(Configuration configuration) throws ConfigurationException {
-
- final String reportType = configuration.getString(PROPERTY_REPORT_TYPE, null);
- report = SensorReportId.valueOf(reportType.toUpperCase());
- if (report.equals(SensorReportId.NONE)) {
- throw new ConfigurationException(PROPERTY_REPORT_TYPE);
- }
-
- final Integer delay = configuration.getInteger(PROPERTY_REPORT_DELAY, null);
- if (delay == null || delay <= 0) {
- throw new ConfigurationException(PROPERTY_REPORT_DELAY);
- }
- this.reportDelay = delay;
-
- try {
- // TODO: make device configurable
- device = Bno080Factory.createDefaultSPIDevice();
- } catch (IOException | InterruptedException e) {
- throw new ConfigurationException("Could not initiate device", e);
- }
- device.start(report, reportDelay);
- }
-
- @Override
- public void onMessage(BnoRequest message) {
- RoboReference target = message.getTarget();
- switch (message.getListenerAction()) {
- case REGISTER:
- register(target);
- break;
- case UNREGISTER:
- unregister(target);
- break;
- default:
- SimpleLoggingUtil.error(getClass(), String.format("Unknown operation: %s", message));
- }
-
- }
-
- @Override
- public void shutdown() {
- super.shutdown();
- device.shutdown();
- }
-
- private synchronized void register(RoboReference target) {
- BnoListenerEvent event = new BnoListenerEvent(target);
- listeners.add(event);
- device.addListener(event);
- }
-
- private synchronized void unregister(RoboReference target) {
- for (BnoListenerEvent l : new ArrayList<>(listeners)) {
- if (target.equals(l.target)) {
- listeners.remove(l);
- device.removeListener(l);
- }
- }
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(Bno080Unit.class);
+ public static final String PROPERTY_REPORT_TYPE = "reportType";
+ public static final String PROPERTY_REPORT_DELAY = "reportDelay";
+
+ private static final class BnoListenerEvent implements DataListener {
+ private final RoboReference target;
+
+ BnoListenerEvent(RoboReference target) {
+ this.target = target;
+ }
+
+ @Override
+ public void onResponse(DataEvent3f event) {
+ target.sendMessage(event);
+ }
+ }
+
+ private final List listeners = new ArrayList<>();
+ private Bno080Device device;
+
+ public Bno080Unit(RoboContext context, String id) {
+ super(BnoRequest.class, context, id);
+ }
+
+ // TODO review field purpose
+ private int reportDelay;
+ private SensorReportId report;
+
+ @Override
+ protected void onInitialization(Configuration configuration) throws ConfigurationException {
+
+ final String reportType = configuration.getString(PROPERTY_REPORT_TYPE, null);
+ report = SensorReportId.valueOf(reportType.toUpperCase());
+ if (report.equals(SensorReportId.NONE)) {
+ throw new ConfigurationException(PROPERTY_REPORT_TYPE);
+ }
+
+ final Integer delay = configuration.getInteger(PROPERTY_REPORT_DELAY, null);
+ if (delay == null || delay <= 0) {
+ throw new ConfigurationException(PROPERTY_REPORT_DELAY);
+ }
+ this.reportDelay = delay;
+
+ try {
+ // TODO: make device configurable
+ device = Bno080Factory.createDefaultSPIDevice();
+ } catch (IOException | InterruptedException e) {
+ throw new ConfigurationException("Could not initiate device", e);
+ }
+ device.start(report, reportDelay);
+ }
+
+ @Override
+ public void onMessage(BnoRequest message) {
+ RoboReference target = message.getTarget();
+ switch (message.getListenerAction()) {
+ case REGISTER:
+ register(target);
+ break;
+ case UNREGISTER:
+ unregister(target);
+ break;
+ default:
+ LOGGER.error("Unknown operation: {}", message);
+ }
+
+ }
+
+ @Override
+ public void shutdown() {
+ super.shutdown();
+ device.shutdown();
+ }
+
+ private synchronized void register(RoboReference target) {
+ BnoListenerEvent event = new BnoListenerEvent(target);
+ listeners.add(event);
+ device.addListener(event);
+ }
+
+ private synchronized void unregister(RoboReference target) {
+ for (BnoListenerEvent l : new ArrayList<>(listeners)) {
+ if (target.equals(l.target)) {
+ listeners.remove(l);
+ device.removeListener(l);
+ }
+ }
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/DataEventListenerUnit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/DataEventListenerUnit.java
index 4389cfbf..4c6cd526 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/DataEventListenerUnit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/DataEventListenerUnit.java
@@ -20,7 +20,8 @@
import com.robo4j.RoboContext;
import com.robo4j.RoboUnit;
import com.robo4j.hw.rpi.imu.bno.DataEvent3f;
-import com.robo4j.logging.SimpleLoggingUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* DataEventListener unit listens to {@link DataEvent3f} event types produced by
@@ -30,13 +31,14 @@
* @author Miroslav Wengner (@miragemiko)
*/
public class DataEventListenerUnit extends RoboUnit {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DataEventListenerUnit.class);
- public DataEventListenerUnit(RoboContext context, String id) {
- super(DataEvent3f.class, context, id);
- }
+ public DataEventListenerUnit(RoboContext context, String id) {
+ super(DataEvent3f.class, context, id);
+ }
- @Override
- public void onMessage(DataEvent3f message) {
- SimpleLoggingUtil.info(getClass(), "received:" + message);
- }
+ @Override
+ public void onMessage(DataEvent3f message) {
+ LOGGER.info("received:{}", message);
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/VectorEventListenerUnit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/VectorEventListenerUnit.java
index 1fde88a2..63eb50cf 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/VectorEventListenerUnit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/imu/VectorEventListenerUnit.java
@@ -23,8 +23,9 @@
import com.robo4j.RoboUnit;
import com.robo4j.configuration.Configuration;
import com.robo4j.hw.rpi.imu.bno.VectorEvent;
-import com.robo4j.logging.SimpleLoggingUtil;
import com.robo4j.net.LookupServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* BNOVectorEventListenerUnit listen to VectorEvent events produced by {@link Bno080Unit}
@@ -33,34 +34,35 @@
* @author Miroslav Wengner (@miragemiko)
*/
public class VectorEventListenerUnit extends RoboUnit {
-
- public static final String ATTR_TARGET_CONTEXT = "targetContext";
- public static final String ATTR_REMOTE_UNIT = "remoteUnit";
- public VectorEventListenerUnit(RoboContext context, String id) {
- super(VectorEvent.class, context, id);
- }
+ public static final String ATTR_TARGET_CONTEXT = "targetContext";
+ public static final String ATTR_REMOTE_UNIT = "remoteUnit";
+ private static final Logger LOGGER = LoggerFactory.getLogger(VectorEventListenerUnit.class);
- private String targetContext;
- private String remoteUnit;
+ public VectorEventListenerUnit(RoboContext context, String id) {
+ super(VectorEvent.class, context, id);
+ }
- @Override
- protected void onInitialization(Configuration configuration) throws ConfigurationException {
- targetContext = configuration.getString(ATTR_TARGET_CONTEXT, null);
- remoteUnit = configuration.getString(ATTR_REMOTE_UNIT, null);
- }
+ private String targetContext;
+ private String remoteUnit;
- @Override
- public void onMessage(VectorEvent message) {
- SimpleLoggingUtil.info(getClass(), "received:" + message);
- RoboContext remoteContext = LookupServiceProvider.getDefaultLookupService().getContext(targetContext);
- if(remoteContext != null){
- RoboReference roboReference = remoteContext.getReference(remoteUnit);
- if(roboReference != null){
- roboReference.sendMessage(message);
- }
- } else {
- SimpleLoggingUtil.info(getClass(), String.format("context not found: %s", targetContext));
- }
- }
+ @Override
+ protected void onInitialization(Configuration configuration) throws ConfigurationException {
+ targetContext = configuration.getString(ATTR_TARGET_CONTEXT, null);
+ remoteUnit = configuration.getString(ATTR_REMOTE_UNIT, null);
+ }
+
+ @Override
+ public void onMessage(VectorEvent message) {
+ LOGGER.info("received:{}", message);
+ RoboContext remoteContext = LookupServiceProvider.getDefaultLookupService().getContext(targetContext);
+ if (remoteContext != null) {
+ RoboReference roboReference = remoteContext.getReference(remoteUnit);
+ if (roboReference != null) {
+ roboReference.sendMessage(message);
+ }
+ } else {
+ LOGGER.warn("context not found: {}", targetContext);
+ }
+ }
}
diff --git a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/lcd/AdafruitButtonUnit.java b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/lcd/AdafruitButtonUnit.java
index c3b8f0d1..47d75dcf 100644
--- a/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/lcd/AdafruitButtonUnit.java
+++ b/robo4j-units-rpi/src/main/java/com/robo4j/units/rpi/lcd/AdafruitButtonUnit.java
@@ -16,8 +16,6 @@
*/
package com.robo4j.units.rpi.lcd;
-import java.io.IOException;
-
import com.robo4j.ConfigurationException;
import com.robo4j.LifecycleState;
import com.robo4j.RoboContext;
@@ -28,101 +26,105 @@
import com.robo4j.hw.rpi.i2c.adafruitlcd.Button;
import com.robo4j.hw.rpi.i2c.adafruitlcd.ButtonListener;
import com.robo4j.hw.rpi.i2c.adafruitlcd.ButtonPressedObserver;
-import com.robo4j.logging.SimpleLoggingUtil;
import com.robo4j.units.rpi.I2CRoboUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
/**
* A {@link RoboUnit} for the button part of the Adafruit 16x2 character LCD
* shield. Having a separate unit allows the buttons to be used independently of
* the LCD.
- *
+ *
* @author Marcus Hirt (@hirt)
* @author Miroslav Wengner (@miragemiko)
*/
public class AdafruitButtonUnit extends I2CRoboUnit