/**
* Take an instantaneous reading of the wind vane position as a 10 bit unsigned
- * value.
+ * value. In this case, the instantaneous reading is 4 very fast 12-bit samples
+ * plus the possibility of an additional four to deal with the dead band.
*
* @author R. Steve McKown <smckown@gmail.com>
*/
interface ReadRef<uint16_t>;
interface GeneralIO as WPower;
interface GeneralIO as WDead;
- interface Average<uint16_t>;
interface State;
}
}
/* The wind vane has a dead zone where it returns an ADC value that also
* represents another angular location. Therefore, we implement special
* dead zone checking over a certain range of return values from the
- * wind vane.
+ * wind vane, with hardware assistance (WDead).
*
* Note: the wind vane's dead zone is probably 5-10 degrees. We would be
* more accurate if we took the ADC range over 350 or 355 degrees, then
* within the dead zone, of course, but would be even if we did implement
* the extra logic.
*/
- DEAD_BEGIN = 1500, /* 10-bit degree value; about 120 degrees */
- DEAD_END = 2500, /* About 220 degrees */
- DEAD_THRESH = 14472, /* > when checking means in dead zone */
+ DEAD_BEGIN = 1500 * count, /* About 132 degrees */
+ DEAD_END = 2500 * count, /* About 220 degrees */
+ DEAD_THRESH = 3618 * count, /* > when checking means in dead zone */
+
+ /* If we assume the greatest angular velocity of the wind vane is 4 full
+ * rotations in a second, then in the 460us it takes to read the vane 4
+ * times, it could move over 6 degrees. This means that the vane could
+ * cross into, out of, or over the dead band, causing readings that can
+ * not be averaged. If we see a delta from min reading to max reading
+ * suggesting a large enough deflection, we can assume the reading is
+ * invalid.
+ */
+ MAX_DEFLECT = 1024, /* 90 degrees */
};
uint16_t m_value;
call WPower.clr();
call State.toIdle();
+ /* Read has returned a value that is count * 12-bit ADC values. Convert
+ * this to a 10-bit value, with rounding.
+ */
+ value = (value + (count / 2)) / count / 4;
signal Read.readDone(error, value);
}
- void averageAngle();
-
- event void ReadRef.readDone(error_t error, uint16_t* result)
- {
- if (error != SUCCESS)
- signalReadDone(error, 0);
- else
- averageAngle();
- }
-
- void averageAngle()
+ bool badReading(uint16_t* result)
{
unsigned i;
+ uint16_t min = result[0];
+ uint16_t max = result[0];
- /* Submit a full set of values to be averaged, which will cause
- * Average.average() to be signalled.
- */
- call Average.reset();
- for (i = 0; i < count; i++)
- call Average.submit(m_samples[i]);
+ for (i = 1; i < count; i++) {
+ if (result[i] < min)
+ min = result[i];
+ if (result[i] > max)
+ max = result[i];
+ }
+ return (max - min) > MAX_DEFLECT;
}
- event void Average.average(uint16_t result)
+ event void ReadRef.readDone(error_t error, uint16_t* result)
{
- switch (call State.getState()) {
- case S_READ:
- if (result < DEAD_BEGIN || result > DEAD_END)
- signalReadDone(SUCCESS, result);
- else {
- m_value = result;
- call WDead.makeOutput();
- if (call ReadRef.read(m_samples) == SUCCESS)
- call State.forceState(S_CHECK);
- else
- signalReadDone(FAIL, 0);
- }
- break;
- case S_CHECK:
- signalReadDone(SUCCESS, (result > DEAD_THRESH) ? 0 : m_value);
- break;
+ if (error != SUCCESS || badReading(result))
+ signalReadDone(error, 0);
+ else {
+ unsigned i;
+ uint16_t value = result[0];
+
+ for (i = 1; i < count; i++)
+ value += result[i];
+
+ switch (call State.getState()) {
+ case S_READ:
+ if (value < DEAD_BEGIN || value > DEAD_END)
+ signalReadDone(SUCCESS, value);
+ else {
+ m_value = value;
+ call WDead.makeOutput();
+ if (call ReadRef.read(m_samples) == SUCCESS)
+ call State.forceState(S_CHECK);
+ else
+ signalReadDone(FAIL, 0);
+ }
+ break;
+ case S_CHECK:
+ signalReadDone(SUCCESS, (value > DEAD_THRESH) ? 0 : m_value);
+ break;
+ }
}
}
}