7 package com.google.appinventor.components.runtime;
20 import android.os.Handler;
29 @DesignerComponent(version = YaVersion.NXT_ULTRASONICSENSOR_COMPONENT_VERSION,
30 description =
"A component that provides a high-level interface to an ultrasonic sensor on a " +
31 "LEGO MINDSTORMS NXT robot.",
32 category = ComponentCategory.LEGOMINDSTORMS,
34 iconName =
"images/legoMindstormsNxt.png")
38 private enum State { UNKNOWN, BELOW_RANGE, WITHIN_RANGE, ABOVE_RANGE }
39 private static final String DEFAULT_SENSOR_PORT =
"4";
40 private static final int DEFAULT_BOTTOM_OF_RANGE = 30;
41 private static final int DEFAULT_TOP_OF_RANGE = 90;
43 private Handler handler;
44 private final Runnable sensorReader;
45 private State previousState;
46 private int bottomOfRange;
47 private int topOfRange;
48 private boolean belowRangeEventEnabled;
49 private boolean withinRangeEventEnabled;
50 private boolean aboveRangeEventEnabled;
56 super(container,
"NxtUltrasonicSensor");
57 handler =
new Handler();
58 previousState = State.UNKNOWN;
59 sensorReader =
new Runnable() {
62 SensorValue<Integer> sensorValue = getDistanceValue(
"");
63 if (sensorValue.valid) {
65 if (sensorValue.value < bottomOfRange) {
66 currentState = State.BELOW_RANGE;
67 }
else if (sensorValue.value > topOfRange) {
68 currentState = State.ABOVE_RANGE;
70 currentState = State.WITHIN_RANGE;
73 if (currentState != previousState) {
74 if (currentState == State.BELOW_RANGE && belowRangeEventEnabled) {
77 if (currentState == State.WITHIN_RANGE && withinRangeEventEnabled) {
80 if (currentState == State.ABOVE_RANGE && aboveRangeEventEnabled) {
85 previousState = currentState;
88 if (isHandlerNeeded()) {
89 handler.post(sensorReader);
104 setInputMode(functionName,
port, SENSOR_TYPE_LOWSPEED_9V, SENSOR_MODE_RAWMODE);
105 configureUltrasonicSensor(functionName);
108 private void configureUltrasonicSensor(String functionName) {
110 byte[] data =
new byte[3];
111 data[0] = (byte) 0x02;
112 data[1] = (byte) 0x41;
113 data[2] = (byte) 0x02;
121 @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_LEGO_NXT_SENSOR_PORT,
122 defaultValue = DEFAULT_SENSOR_PORT)
123 @SimpleProperty(userVisible =
false)
128 @
SimpleFunction(description =
"Returns the current distance in centimeters as a value between " +
129 "0 and 254, or -1 if the distance can not be read.")
131 String functionName =
"GetDistance";
136 SensorValue<Integer> sensorValue = getDistanceValue(functionName);
137 if (sensorValue.valid) {
138 return sensorValue.value;
145 private SensorValue<Integer> getDistanceValue(String functionName) {
147 byte[] data =
new byte[2];
148 data[0] = (byte) 0x02;
149 data[1] = (byte) 0x42;
153 for (
int i = 0; i < 3; i++) {
155 if (countAvailableBytes > 0) {
157 byte[] returnPackage =
lsRead(functionName,
port);
158 if (returnPackage !=
null) {
160 if (value >= 0 && value <= 254) {
161 return new SensorValue<Integer>(
true, value);
169 return new SensorValue<Integer>(
false,
null);
176 @SimpleProperty(description =
"The bottom of the range used for the BelowRange, WithinRange," +
177 " and AboveRange events.",
178 category = PropertyCategory.BEHAVIOR)
180 return bottomOfRange;
188 defaultValue =
"" + DEFAULT_BOTTOM_OF_RANGE)
191 this.bottomOfRange = bottomOfRange;
192 previousState = State.UNKNOWN;
199 @
SimpleProperty(description =
"The top of the range used for the BelowRange, WithinRange, and" +
200 " AboveRange events.",
211 defaultValue =
"" + DEFAULT_TOP_OF_RANGE)
214 this.topOfRange = topOfRange;
215 previousState = State.UNKNOWN;
222 @
SimpleProperty(description =
"Whether the BelowRange event should fire when the distance" +
223 " goes below the BottomOfRange.",
226 return belowRangeEventEnabled;
236 boolean handlerWasNeeded = isHandlerNeeded();
238 belowRangeEventEnabled = enabled;
240 boolean handlerIsNeeded = isHandlerNeeded();
241 if (handlerWasNeeded && !handlerIsNeeded) {
242 handler.removeCallbacks(sensorReader);
244 if (!handlerWasNeeded && handlerIsNeeded) {
245 previousState = State.UNKNOWN;
246 handler.post(sensorReader);
250 @
SimpleEvent(description =
"Distance has gone below the range.")
259 @
SimpleProperty(description =
"Whether the WithinRange event should fire when the distance" +
260 " goes between the BottomOfRange and the TopOfRange.",
263 return withinRangeEventEnabled;
273 boolean handlerWasNeeded = isHandlerNeeded();
275 withinRangeEventEnabled = enabled;
277 boolean handlerIsNeeded = isHandlerNeeded();
278 if (handlerWasNeeded && !handlerIsNeeded) {
279 handler.removeCallbacks(sensorReader);
281 if (!handlerWasNeeded && handlerIsNeeded) {
282 previousState = State.UNKNOWN;
283 handler.post(sensorReader);
287 @
SimpleEvent(description =
"Distance has gone within the range.")
296 @
SimpleProperty(description =
"Whether the AboveRange event should fire when the distance" +
297 " goes above the TopOfRange.",
300 return aboveRangeEventEnabled;
310 boolean handlerWasNeeded = isHandlerNeeded();
312 aboveRangeEventEnabled = enabled;
314 boolean handlerIsNeeded = isHandlerNeeded();
315 if (handlerWasNeeded && !handlerIsNeeded) {
316 handler.removeCallbacks(sensorReader);
318 if (!handlerWasNeeded && handlerIsNeeded) {
319 previousState = State.UNKNOWN;
320 handler.post(sensorReader);
324 @
SimpleEvent(description =
"Distance has gone above the range.")
329 private boolean isHandlerNeeded() {
330 return belowRangeEventEnabled || withinRangeEventEnabled || aboveRangeEventEnabled;
337 handler.removeCallbacks(sensorReader);