+/*
+ * Copyright (c) 2008, Titanium Mirror, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of Titanium Mirror, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Reads the physical sensors and notifies every read period an aerovane average
+ * vector.
+ *
+ * @author R. Steve McKown <rsmckown@gmail.com>
+ */
+
+#include "AeroVane.h"
+
+generic module AeroVaneReadP(uint16_t period) {
+ provides interface Notify<aerovector_t>;
+ uses {
+#if 0
+ interface Alarm<T32khz, uint16_t>;
+#else
+ interface Timer<TMilli>;
+#endif
+ interface Read<uint16_t>;
+ interface StdControl as AnemometerControl;
+ interface AsyncGet<uint16_t> as Count;
+ interface State;
+ }
+}
+implementation {
+ enum {
+ S_IDLE,
+ S_RUN,
+
+ PHYS_PER_READ = 4, /* # of physical reads per reading */
+ };
+
+ uint16_t m_count;
+ int m_vane;
+ int m_sum;
+
+ task void readVane();
+
+ void init()
+ {
+ m_count = 0;
+ m_vane = 0;
+ m_sum = 0;
+ }
+
+ command error_t Notify.enable()
+ {
+ if (call State.requestState(S_RUN) != SUCCESS)
+ return EBUSY;
+
+ init();
+ call AnemometerControl.start();
+ /* FIXME: First alarm should be synced to top of the next second. How? */
+#if 0
+ call Alarm.start(call Alarm.getNow() + period);
+#else
+ call Timer.startPeriodic(period);
+#endif
+ return SUCCESS;
+ }
+
+ command error_t Notify.disable()
+ {
+ call State.toIdle();
+#if 0
+ call Alarm.stop();
+#else
+ call Timer.stop();
+#endif
+ call AnemometerControl.stop();
+ return SUCCESS;
+ }
+
+#if 0
+ async event void Alarm.fired()
+#else
+ event void Timer.fired()
+#endif
+ {
+ //call Alarm.start(call Alarm.getAlarm() + period);
+ post readVane();
+ }
+
+ task void readVane()
+ {
+ //call Alarm.start(call Alarm.getAlarm() + period);
+ if (!(call State.isIdle()))
+ call Read.read();
+ }
+
+ int distance(int angle1, int angle2)
+ {
+ int d = angle2 - angle1;
+
+ if (d <= -180)
+ d += 360;
+ else if (d > 180)
+ d -= 360;
+ return d;
+ }
+
+ event void Read.readDone(error_t error, uint16_t result)
+ {
+ int newVane;
+
+ if (error != SUCCESS)
+ return;
+
+ newVane = m_vane + distance(m_vane, result);
+ m_sum += result;
+ m_vane = newVane;
+ if (++m_count == PHYS_PER_READ) {
+ norace aerovector_t vector;
+
+ /* Get speed average */
+ atomic vector.speed = call Count.get();
+
+ /* Complete direction average */
+ vector.dir = m_sum / PHYS_PER_READ;
+ while (vector.dir < 0)
+ vector.dir += 360;
+ vector.dir %= 360;
+ init();
+
+ /* Inform the consumer of the vector */
+ if (!(call State.isIdle()))
+ signal Notify.notify(vector);
+ }
+ }
+}