DCDW = Dirt Cheap Dumb Wireless

Tonight status is :

Working on SSID (Single Sensor plus IDent, but thats easily confused with the WiFi term). We currently have 2 problems.
(1) the CD 4093 Quad NAND with Schmitt Trigger Inputs produced by Texas Instruments is not acting like it has Schmitt trigger inputs. This makes the "gated oscillator" frequency chirp downward badly. Currently using slow packets of 10 sec every 3 minutes and the software can latch the data before the chirp becomes too bad.

Likely solution is avoiding this particular manufacturer for this chip

(2) when a collision of packets occurs, the software is sometimes does not recognize the error but rather mistakes the ID part of the second packet as the data part of the first one. Over night this happened about 10 times in 500 sensor readings, or in other terms about half the packet collisions were erroneously accepted as valid data. These are easily recognized as invalid readings but are still nuisances.

Solution is a more robust state machine, which is being tested overnight tonight.

Here is the master station


When DCDW development is finished, only the l33t beta testers will have the genuine DCDW master station official mounting string. Compatible with all genuine Arduino boards. Cost is just one carton of Samuel Adams for the development team! Supplies are limited, Sign up today!
Here is the indoor temperature sensor node

Here is the outdoor temperature sensor node

PCB layout v0.01 requires the ugly hack to scab on a diode, resistor and capacitor to put the DCDW in SSID mode. This will be cleanly accommodated on all PCB versions going forward.

Here is a Open Office import of what the DCDW master received from its nodes

Long straight lines are missing data when WinDoze7 ( >:(DONT get me STARTED >:( ) despite all power profile settings fell asleep and stopped listening to Arduino Uno.

Time is Arduino millis(), we have no Real Time Clock as you would use in a proper data logging project. We also have made no effort yet to convert frequency (Y axis) backto temperature. This is only a proof-of-concept for DCDW with one master node monitoring a swarm of sensors on a single channel.

The collisions are evident. Most falsely accepted collisions the outdoor node was sending its ID and was interrupted by (much stronger) indoor node ID which was erroneously accepted as the data for the outdoor temperature. Better spaghetti code software will fix this. You software mugs will get a laugh out of this:

// Dirt Cheap Dumb Wireless  (DCDW)
// Demo code for DCDW Single Channel Sensor with Ident 
// 2011 Jan 09   by AltairLabs <http://www.altair.org> 
// This example code is in the public domain.
//
// visit Dirt Cheap Dumb Wireless   www.DCDWireless.com 
// for more open source DCDW hardware and software
// Set up DCDW PCB for Single Channel Sensor with Ident
// Oscillator frequencies in this demo use 
// Osc A = 1000 pF 100k ohms thermistor (large resistor reduces battery drain)
// Osc B = 0.01 uF and 1 meg ohms
// Osc C = 22 uF Tantalum, R5 = 10 Meg, R6 = 330k
//
// visit Arduino   www.arduino.cc 
// for great open source microcontroller hardware and software
//
// declare stuff
#include "WProgram.h"
void setup();
void loop();
long countFrequency (int pin, int precision);

int normLED = 13;             // the on-off LED is digital pin 13
int RXpin = 8;                // DCDW data link on digital pin 2
long frequency;               // frequency of pulse train 
long freq1;                   // frequency recognized as tone 1
long freq2;                   // frequency recognized as tone 2 
unsigned long interval;       // millisecs interval between samples logged
unsigned long logTime;        // time to start log entry

boolean debug = false;         // true = more verbose

const int idle=0;
const int tone1=1;
const int tone2=2;
const int tGap=3;
const int silentGap= 2;
const int toneDurat = 1;
int rxtone;
int silent;
int state;
int lastState;

const int numSensors = 6;
int sensorNode;
long sensorTone;
const int IDtones[numSensors]={80,165,368,740};   // IDent tones (B)of each sensor
int freqT2[numSensors]={0,0,0,0,0,0};             // last Sensor Tone (A) from each sensor
unsigned long lastTime[numSensors]={0,0,0,0,0,0}; // last time each sensor was heard


void setup() 
{ 
  pinMode(normLED, OUTPUT);        // optional, used for demo only
  pinMode(RXpin, INPUT);           // set RX pin to input 
  digitalWrite(RXpin, LOW);        // no pullup
  Serial.begin(9600);              // start up the serial communications USART
  Serial.println(" ");             // test the comm port
  Serial.println("Good morning, Dr. Chandra.  This is HALduino.");    
  Serial.println("Ready to log Dirt Cheep Dumb Wireless sensor data");    
  interval = 1000;                 // log data every 1 second
  logTime = millis() + interval;   // starting next sample time
} 

void loop() 
{ 
  // DCDW code starts here
  digitalWrite(normLED, HIGH);  // debug: set normLED on before counting freq
  frequency = countFrequency(RXpin, 3); // count freq at RXpin with 3 digit precision
  digitalWrite(normLED, LOW);   // debug: set normLED off when done counting
  // end of DCDW receive, now display result
  if (debug) {
    if (frequency > 0 ) {
      Serial.print("   Freq = ");               
    } 
    else {
      Serial.print("  Error = ");
    }
    Serial.println(frequency); 
  }
  // Log the data sample
  if (frequency < 0) frequency =0;
  if (debug) {
    print_time(logTime);
    Serial.print(", "); 
    Serial.print(frequency); 
    Serial.print(", "); 
    Serial.println(" ");
  }

  //
  //  state machine for recognizing remote sensors
  //
  lastState = state;
  if (frequency > 0 ) {
    rxtone++;
    silent=0;  
  } 
  else {
    rxtone=0;
    silent++;    
  }
  if (silent > silentGap) {
    state = idle;
    freq1 = 0; 
    freq2 = 0;
  }
  if (rxtone >= toneDurat && state == idle) {
    state = tone1;
    freq1 = frequency;
  }
  if (rxtone >= toneDurat && state == tone1 && (abs(frequency-freq1) > 100)) {
    state = tone2;
    freq2 = frequency;
  }
  if (state == tone2 && state != lastState) { // we have a new SSID sensor reading
    float ratio = 999.0;
    float bestRatio = 999.0;
    for (int i = 1; i <= numSensors; i++) {   // find closest match to known ID tone
      if (freq1 > IDtones[i]) {               // make the ratio >1
        ratio = float(freq1) / float(IDtones[i]);
      } else {
        ratio = float(IDtones[i]) / float(freq1);
      }
      if (ratio < bestRatio) {                // if better match thsn before
        bestRatio = ratio;
        sensorNode = i;                       // sensorNode is index of best match
        sensorTone = freq2;
      }
    } 
      freqT2[6]=int(100.0*bestRatio);                // fake sensor to log match ratio
      freqT2[5]=sensorNode;                   // fake sensor to log snesorNode
      freqT2[sensorNode]=sensorTone;
      print_time(logTime);
      for (int i = 1; i <= numSensors; i++) {
        Serial.print(", ");  
        Serial.print(freqT2[i]);  
      }
      Serial.println(" ");  
  }

  // Set time for next sample
  logTime = logTime + interval;                    // usual time
  if (logTime > 4294967295)logTime -= 4294967295;  // need in case of rollover?
  while (logTime < millis()) logTime = logTime + interval;  // in case we miss a sked
  while (millis() < logTime) {
  };                   // now wait
}