]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/m16c62p/adc/AdcStreamP.nc
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / tos / chips / m16c62p / adc / AdcStreamP.nc
diff --git a/tos/chips/m16c62p/adc/AdcStreamP.nc b/tos/chips/m16c62p/adc/AdcStreamP.nc
new file mode 100755 (executable)
index 0000000..bb65d24
--- /dev/null
@@ -0,0 +1,270 @@
+/* $Id$
+ * Copyright (c) 2005 Intel Corporation
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached INTEL-LICENSE     
+ * file. If you do not find these files, copies can be found by writing to
+ * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
+ * 94704.  Attention:  Intel License Inquiry.
+ *
+ * Copyright (c) 2004, Technische Universitaet Berlin
+ * 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 the Technische Universitaet Berlin 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.
+ *
+ */
+
+/**
+ * Convert M16c62p HAL A/D interface to the HIL interfaces.
+ * @author Fan Zhang <hauer@tkn.tu-berlin.de>
+ */
+#include "Timer.h"
+
+module AdcStreamP
+{
+  provides {
+    interface Init @atleastonce();
+    interface ReadStream<uint16_t>[uint8_t client];
+  }
+  uses {
+    interface M16c62pAdcSingle;
+    interface M16c62pAdcConfig[uint8_t client];
+    //interface M16c62pCalibrate;
+    interface Alarm<TMicro, uint32_t>;
+  }
+}
+implementation {
+  enum {
+    NSTREAM = uniqueCount(UQ_ADC_READSTREAM)
+  };
+
+  /* Resource reservation is required, and it's incorrect to call getData
+     again before dataReady is signaled, so there are no races in correct
+     programs */
+  norace uint8_t client = NSTREAM;
+
+  /* Stream data */
+  struct list_entry_t {
+    uint16_t count;
+    struct list_entry_t * ONE_NOK next;
+  };
+  struct list_entry_t *bufferQueue[NSTREAM];
+  struct list_entry_t * ONE_NOK * bufferQueueEnd[NSTREAM];
+  uint16_t * COUNT_NOK(lastCount) lastBuffer, lastCount;
+
+  norace uint16_t count;
+  norace uint16_t * COUNT_NOK(count) buffer; 
+  norace uint16_t * BND_NOK(buffer, buffer+count) pos;
+  norace uint32_t now, period;
+
+
+  command error_t Init.init() {
+    uint8_t i;
+
+    for (i = 0; i != NSTREAM; i++)
+      bufferQueueEnd[i] = &bufferQueue[i];
+    
+    return SUCCESS;
+  }
+
+  uint8_t channel() {
+    return call M16c62pAdcConfig.getChannel[client]();
+  }
+
+  uint8_t precision() {
+    return call M16c62pAdcConfig.getPrecision[client]();
+  }
+
+  uint8_t prescaler() {
+    return call M16c62pAdcConfig.getPrescaler[client]();
+  }
+
+  void sample() {
+    call M16c62pAdcSingle.getData(channel(), precision(), prescaler());
+  }
+
+  command error_t ReadStream.postBuffer[uint8_t c](uint16_t *buf, uint16_t n) {
+    if (n < sizeof(struct list_entry_t))
+      return ESIZE;
+    atomic
+      {
+       struct list_entry_t * ONE newEntry = TCAST(struct list_entry_t * ONE, buf);
+
+       if (!bufferQueueEnd[c]) // Can't post right now.
+         return FAIL;
+
+       newEntry->count = n;
+       newEntry->next = NULL;
+       *bufferQueueEnd[c] = newEntry;
+       bufferQueueEnd[c] = &newEntry->next;
+      }
+    return SUCCESS;
+  }
+
+  task void readStreamDone() {
+    uint8_t c = client;
+    //uint32_t actualPeriod = call M16c62pCalibrate.actualMicro(period);
+    uint32_t actualPeriod = period; // fanzha not debug
+    atomic
+      {
+       bufferQueue[c] = NULL;
+       bufferQueueEnd[c] = &bufferQueue[c];
+      }
+
+    client = NSTREAM;
+    signal ReadStream.readDone[c](SUCCESS, actualPeriod);
+  }
+
+  task void readStreamFail() {
+    /* By now, the pending bufferDone has been signaled (see readStream). */
+    struct list_entry_t *entry;
+    uint8_t c = client;
+
+    atomic entry = bufferQueue[c];
+    for (; entry; entry = entry->next){
+      uint16_t tmp_count __DEPUTY_UNUSED__ = entry->count;
+      signal ReadStream.bufferDone[c](FAIL, TCAST(uint16_t * COUNT_NOK(tmp_count),entry), entry->count);
+    }
+
+    atomic
+      {
+       bufferQueue[c] = NULL;
+       bufferQueueEnd[c] = &bufferQueue[c];
+      }
+
+    client = NSTREAM;
+    signal ReadStream.readDone[c](FAIL, 0);
+  }
+
+  task void bufferDone() {
+    uint16_t *b, c;
+    atomic
+      {
+       b = lastBuffer;
+       c = lastCount;
+       lastBuffer = NULL;
+      }
+
+    signal ReadStream.bufferDone[client](SUCCESS, b, c);
+  }
+
+  void nextAlarm() {
+    call Alarm.startAt(now, period);
+    now += period;
+  }
+
+  async event void Alarm.fired() {
+    sample();
+  }
+
+  command error_t ReadStream.read[uint8_t c](uint32_t usPeriod)
+  {
+    /* The first reading may be imprecise. So we just do a dummy read
+       to get things rolling - this is indicated by setting count to 0 */
+    buffer = pos = NULL;
+    count = 0;
+    //period = call M16c62pCalibrate.calibrateMicro(usPeriod);
+    client = c;
+    sample();
+
+    return SUCCESS;
+  }
+
+  void nextBuffer() {
+    atomic
+      {
+       struct list_entry_t *entry = bufferQueue[client];
+
+       if (!entry)
+         {
+           // all done
+           bufferQueueEnd[client] = NULL; // prevent post
+           post readStreamDone();
+         }
+       else
+         {
+            uint16_t tmp_count;
+           bufferQueue[client] = entry->next;
+           if (!bufferQueue[client])
+             bufferQueueEnd[client] = &bufferQueue[client];
+           pos = buffer = NULL;
+           count = entry->count;
+            tmp_count = count;
+           pos = buffer = TCAST(uint16_t * COUNT_NOK(tmp_count), entry);
+           nextAlarm();
+         }
+      }
+  }
+
+  async event void M16c62pAdcSingle.dataReady(uint16_t data, bool precise) {
+    if (client == NSTREAM)
+      return;
+
+    if (count == 0)
+      {
+       now = call Alarm.getNow();
+       nextBuffer();
+      }
+    else
+      {
+       *pos++ = data;
+       if (pos == buffer + count)
+         {
+           atomic
+             {
+               if (lastBuffer)
+                 {
+                   /* We failed to signal bufferDone in time. Fail. */
+                   bufferQueueEnd[client] = NULL; // prevent post
+                   post readStreamFail();
+                   return;
+                 }
+               else
+                 {
+                   lastCount = count;
+                   lastBuffer = buffer;
+                 }
+             }
+           post bufferDone();
+           nextBuffer();
+         }
+       else
+         nextAlarm();
+      }       
+  }
+
+  /* Configuration defaults. Read ground fast! ;-) */
+  default async command uint8_t M16c62pAdcConfig.getChannel[uint8_t c]() {
+    return M16c62p_ADC_CHL_AN0;
+  }
+
+  default async command uint8_t M16c62pAdcConfig.getPrecision[uint8_t c]() {
+    return M16c62p_ADC_PRECISION_10BIT;
+  }
+
+  default async command uint8_t M16c62pAdcConfig.getPrescaler[uint8_t c]() {
+    return M16c62p_ADC_PRESCALE_2;
+  }
+}