// JM modified for Ultrasonic and DHT-22
#include <Ports.h>

#include <DHT22.h> //JM
#include <RF12.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/io.h>

//#include <util/atomic.h>

#define SERIAL  0   // set to 1 to also report readings on the serial port
#define DEBUG   0   // set to 1 to display each loop() run and PIR trigger
#define ECHOPIN 3        // Pin to receive echo pulse
#define TRIGPIN 6        // Pin to send trigger pulse
#define tank_height 111 //in centimetres
#define tank_width 67 //in centimetres
#define tank_length 162 //in centimetres
#define sensor_offset 8 //in centimetres

#define MEASURE_PERIOD  30 // how often to measure, in tenths of seconds
#define RETRY_PERIOD    10  // how soon to retry if ACK didn't come in
#define RETRY_LIMIT     5   // maximum number of times to retry
#define ACK_TIME        10  // number of milliseconds to wait for an ack
#define REPORT_EVERY    5   // report every N measurement cycles
#define SMOOTH          3   // smoothing factor used for running averages

// set the sync mode to 2 if the fuses are still the Arduino default
// mode 3 (full powerdown) can only be used with 258 CK startup fuses
#define RADIO_SYNC_MODE 2

// The scheduler makes it easy to perform various tasks at various times:

enum { 
  MEASURE, REPORT, TASK_END };

static word schedbuf[TASK_END];
Scheduler scheduler (schedbuf, TASK_END);

// Other variables used in various places in the code:

static byte reportCount;    // count up until next report, i.e. packet send
static byte myNodeID;       // node ID used for this unit

// This defines the structure of the packets which get sent out by wireless:

struct {
//byte oil;     // percentage full 0 to 100
int oil:16;     // oil sensor: 0..32767
byte moved :
  1;  // motion detector: 0..1
byte humi  :
  7;  // humidity: 0..100
int temp   :
  10; // temperature: -500..+500 (tenths)
byte lobat :
  1;  // supply voltage dropped under 3.1V: 0..1
} 
payload;

// Conditional code, depending on which sensors are connected and how:


// Setup a DHT22 instance
DHT22 myDHT22(7); // Setup the DHT pin 7// JM


// has to be defined because we're using the watchdog for low-power waiting
ISR(WDT_vect) { 
  Sleepy::watchdogEvent(); 
}


// spend a little time in power down mode while the SHT11 does a measurement
static void shtDelay () {
  Sleepy::loseSomeTime(32); // must wait at least 20 ms
}

// wait a few milliseconds for proper ACK to me, return true if indeed received
static byte waitForAck() {
  MilliTimer ackTimer;
  while (!ackTimer.poll(ACK_TIME)) {
    if (rf12_recvDone() && rf12_crc == 0 &&
      // see http://talk.jeelabs.net/topic/811#post-4712
    rf12_hdr == (RF12_HDR_DST | RF12_HDR_CTL | myNodeID))
      return 1;
    set_sleep_mode(SLEEP_MODE_IDLE);
    sleep_mode();
  }
  return 0;
}

// readout all the sensors and other values
static void doMeasure() {
   // Do ultrasonic measurement
  digitalWrite(TRIGPIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIGPIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);
  // Compute distance
  float distance = pulseIn(ECHOPIN, HIGH);
  distance= (distance/58)-sensor_offset;
 float litres=((tank_height-distance)*tank_length*tank_width)/1000;
 payload.oil=litres; 
  delay(200);
  //byte firstTime = payload.humi == 0; // special case to init running avg

  payload.lobat = rf12_lowbat();


 DHT22_ERROR_t errorCode;
 errorCode = myDHT22.readData();

  payload.humi=(myDHT22.getHumidity());
  payload.temp=(myDHT22.getTemperatureC())*10;

 
}

// periodic report, i.e. send out a packet and optionally report on serial port
static void doReport() { 
  // the RF12 runs on INT0 this interrupt is on PCINT18 the same as port PD as
  // the PIR (PCINT23) so when the RF12 is being used the entire PORT gets a PIN
  // CHANGE event PCIFR.
  // We need to capture this and mask it off so the PIR does not fire again.
  
  PCICR &= ~(1 << PCIE2);  // disable the PD pin-change interrupt.     

  rf12_sleep(RF12_WAKEUP);
  while (!rf12_canSend())
    rf12_recvDone();
  rf12_sendStart(0, &payload, sizeof payload, RADIO_SYNC_MODE);
  rf12_sleep(RF12_SLEEP);

  // When a logic change on any PCINT23:16 pin triggers an interrupt request, 
  // PCIF2 becomes set(one). If the I-bit in SREG and the PCIE2 bit in PCICR 
  // are set (one), the MCU will jump to thecorresponding Interrupt Vector. 
  // The flag is cleared when the interrupt routine is executed. Alternatively,
  // the flag can be cleared by writing a logical one to it.
  PCIFR = (1<<PCIF2);   //clear any pending interupt

  PCICR |= (1<<PCIE2);   // and re-enable the PIR interrupt

#if SERIAL
  Serial.print("ROOM ");
  Serial.print((int) payload.oil);
  Serial.print(' ');
  Serial.print((int) payload.moved);
  Serial.print(' ');
  Serial.print((int) payload.humi);
  Serial.print(' ');
  Serial.print((int) payload.temp);
  Serial.print(' ');
  Serial.print((int) payload.lobat);
  Serial.println();
  delay(2); // make sure tx buf is empty before going back to sleep
#endif
}


void setup () {
   pinMode(ECHOPIN, INPUT);
  pinMode(TRIGPIN, OUTPUT);
#if SERIAL || DEBUG
  Serial.begin(57600);
  Serial.print("\n[roomNode.4]");
  myNodeID = rf12_config();
#else
  myNodeID = rf12_config(0); // don't report info on the serial port
#endif

  rf12_sleep(RF12_SLEEP); // power down

  reportCount = REPORT_EVERY;     // report right away for easy debugging
  scheduler.timer(MEASURE, 0);    // start the measurement loop going
}

void loop () {
#if DEBUG
  Serial.print('.');
  delay(2);
#endif


  switch (scheduler.pollWaiting()) {

  case MEASURE:
    // reschedule these measurements periodically
    scheduler.timer(MEASURE, MEASURE_PERIOD);

    doMeasure();

    // every so often, a report needs to be sent out
    if (++reportCount >= REPORT_EVERY) {
      reportCount = 0;
      scheduler.timer(REPORT, 0);
    }
    break;

  case REPORT:
    doReport();
    break;
  }
}