
/*
Ovladac vysílac
 */

#include <aes.h>
#include <RF22Datagram.h>
#include <RF22.h>
#include <SPI.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <EEPROM.h>

#include "eepromrw.h"
#include "ovladac.h"

//#include <avr/interrupt.h>
// Singleton instance of the radio
RF22Datagram rf22(0);

remotet         remote;
uint8_t         key[16] ;
uint8_t         button=0;
uint8_t         *premote = (uint8_t*)(&remote); // pointer to remote structure
const baset     *pee = 0;                       // pointer to eeprom structure


//********************************* RF PACKET *****************************************

void rf_init() {
  
  RfOn;
  if (!rf22.init()) {
    dprintln("RF Init fail");  
    ledPulse(3,200);
  } 
}  


// checks eeprom counters
// write  next TX counter value to eeprom
// return next TX counter value 
uint32_t getCounterTx() {
  
  uint32_t  counter[CountersTx];
  uint32_t  getCounter;
  uint32_t  maxCounter;  
  uint32_t  minCounter;    
  uint8_t   smooth=0;    
  uint8_t   smoothMax = 0;  
  uint8_t   min = 0;
  uint8_t   max = 0;  
  uint8_t   i;  
  uint8_t   il;  
  uint8_t   ih;    
  uint16_t  window;
  
  eepromr((uint32_t)(&(pee->counterWindow)), window, sizeof(window)); 
  eepromr((uint32_t)(&(pee->counterTx[0])),  counter[0], sizeof(counter)); 

  maxCounter = counter[0];
  minCounter = counter[0];  
  for (uint8_t i=1; i<CountersTx; i++) {          // find min and max element
    if ( minCounter > counter[i] ) {
      minCounter = counter[i];
      min = i;
    }  
    if ( maxCounter < counter[i] ) {
      maxCounter = counter[i];
      max = i;    
    }  
  }
 /* 
  dprint("min= ");
  dprint(min);
  dprint(" max= ");
  dprint(max);
  dprint(" CounterMin= ");
  dprint(counter[min]);
  dprint(" CounterMax= ");
  dprint(counter[max]);
  dprintln();
*/
  
  // if whole region is not smooth  
  // find largest smooth region where next value is 
  if ( counter[max]-counter[min] > CountersTx-1 ) {
    // loop from min to max 
    for ( i=0, il=min, ih=min+1; i<CountersTx; i++, il++, ih++ ) {     // find min and max element
      if (il >= CountersTx)  il = 0;            // index low in range of round buffer
      if (ih >= CountersTx)  ih = 0;            // index high in range of round buffer      
      if ( counter[ih] - counter[il] > 1 ) {
        smooth++;
        if (smooth > smoothMax) {               // biggest smooth region found
          smoothMax = smooth;
          max = ih;
        }  
 /*      dprint("il= ");
       dprint(il);
       dprint(" SmoothMax= ");
       dprint(smoothMax);
       dprint(" Smooth= ");
       dprint(smooth);
       dprint(" Max= ");
       dprint(max);
       dprintln();  */
      }
      else 
        smooth = 0;
    }    
  }
  
  getCounter = counter[max] + 1;
/*
  dprint(" max= ");
  dprint(max);
  dprint(" CounterMax= ");
  dprint(counter[max]);
  dprint(" GetCounter= ");
  dprint(getCounter);
  dprintln();
*/
  if ( ++max >= CountersTx )
    max = 0;
  eepromw((uint32_t)(&(pee->counterTx[max])),  getCounter, sizeof(getCounter)); // store new counter value to eeprom
  return getCounter;
}


// prepare buffer, encrypt and send packet
void sendPacket()  {
  
  // prepare buffer
  memset((void*)&remote, 0, sizeof(remote)); // clear of structure's data
  eepromr((uint32_t)(&(pee->serialn)),  remote.serialn, sizeof(remote.serialn)) ;
  remote.command = CmdRemoteKey ;
  remote.counter = getCounterTx();
  remote.battery = readVcc();    
  remote.temperature = rf22.temperatureRead();
  remote.button  = button;    
  
  // read key
  eepromr((uint32_t)(&(pee->key[0])), key[0], sizeof(key)); 
  D(for (uint8_t i= 0; i < sizeof(remote); i++) { dprintHex(premote[i],HEX); dprint(" "); }  ; dprintln("");)

  // send data packet
  rf22.setThisAddress(remote.serialn & 0xFF);   // set  my address
  rf22.setHeaderId(IdRemoteS);                  // set ID
  aes((uint8_t*)(&remote),key,Encrypt);         // encrypt packet
  rf22.sendto((uint8_t*)(&remote), sizeof(remote), GateAddr);    // SEND!!!!
}

//********************************* INTERRUPT *******************************************
// port C buttons
ISR(PCINT1_vect) {  
}


// port B buttons
ISR(PCINT0_vect) {
}


void int_init() {
  cli();
  PCICR =  KeyIntRegister;   // enable port C 
  PCMSK0 = KeyIntMaskB;      // enable pins for interrupt  register B
  PCMSK1 = KeyIntMaskC;      // enable pins for interrupt  register C
  sei();
}


void wake_up()        // here the interrupt is handled after wakeup
{  
}

//********************************* PINS *******************************************

void pins_init() {

  // setup port B
  DDRB =  SetupPortB;       // LedPin and SPI output bits
  PORTB = 0xFF;             // GPIO1 & GPIO2 to 0 
  
  // setup port C
  DDRC = SetupPortC;        // all inputs
  PORTC = 0xFF;             // pull ups all
  
  // setup port D
  DDRD  = SetupPortD;       // OFF output
  PORTD = 0xFF;             // OFF "1",  pull ups rest 
}


void pins_sleep() {
  
  DDRB  = 0;
  PORTB = 0xFF;        // LedPin off, input pull up
  DDRC  = 0;  
  PORTC = 0xFF;        // module OFF, rest pull up  
  DDRD  = 0;
  PORTD = 0xFF;        // pull ups all 


  DIDR0  = 0x3F;             // disable digital input buffers on ALL ADC-ADC5 pins
  DIDR1  = (1<<AIN1D) | (1<< AIN0D);  // disable digital input buffer on AIN1/0
  WDTCSR = 0;                // watchdog OFF 
  ADCSRA = 0;                // disable ADC otherwise has 100uA power current
  ACSR  = (1<<ACD);          // disable comparator

}


//********************************* BUTTON *******************************************


uint8_t read_button_filtered() {
  uint8_t button = 0;  
  
  while (button != read_button() ) {
    button = read_button();
    delay(100);
  }  
  return button;
}  

uint8_t read_button() {
  uint8_t button = 0;  
  if (!Button1In) button += 1;
  if (!Button2In) button += 2;
  if (!Button3In) button += 4;
  if (!Button4In) button += 8;
/*  
  dprint("Button=");
  dprint(button);
  dprint(" Portc=");
  dprintln(PINC);
*/  
  return button;
}



unsigned char readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference

  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both

  long result = (high<<8) | low;

  result = 1125300L / result /10 - 200; // Calculate Vcc (in 10 mV); 1125300 = 1.1*1023*1000
  return result; // result in 10 mv - 2 V  ( for 3V = 100, for 3.5 = 150, for 2.5 = 50)
}




//********************************* SETUP *******************************************
// the setup routine runs once when you press reset:

void setup() {
  pins_init();    // initialize the digital pin as input
  int_init();

}

void sleep_now()  {       // here we put the arduino to sleep

//  dprintln("Sleep");  
  noInterrupts();
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  //  sleep mode is set here
  sleep_enable();
  pins_sleep();                         // setup pins input and pull up
  MCUCR |= (1<<BODS) | (1<<BODSE);      // BOD and BODSE stop brown detector
  MCUCR &= ~(1<<BODSE);                 // BOD and BODSE stop brown detector
  power_all_disable();                  // disable power to SPI, TWI,  UART, TIMERS
  interrupts();
  sleep_mode();
  // sleeping.....

  
  // wake up here
  sleep_disable();          // first thing after waking from sleep:
  power_all_enable();       // enable all powers
  ADCSRA |= 1 << ADEN;      // take on ADC
  SMCR = 0;
//  PRR = 0x0;                 // POWER reduction none
  pins_init();
//  dprintln("Wake up");  
//  detachInterrupt(0);      // disables interrupt 0 on pin 2 so the 
}


// the loop routine runs over and over again forever:
//********************************* LOOP *******************************************

void loop() {
  uint8_t i;    
  
  button =  read_button_filtered();
  if (button) {
 
    D(Serial.begin(9600);)

    // prints title with ending line break
    dprintln("Ovladac ready");        
    rf_init();          
    
    sendPacket();
   D(for (i= 0; i < sizeof(remote); i++) { dprintHex(premote[i],HEX); dprint(" "); }  ; dprintln("");)
//    D(for (i= 16; i < 32; i++) { eepromr(i,button, 1); dprintHex(button,HEX); dprint(" "); }  ; dprintln("");)
    
    ledPulse(1, 100);
  }   
  sleep_now();  // sleep and wait for key
}


//-------------------------------------------------------------------------
void ledPulse(uint8_t pulses, uint8_t ledOn) {

  for ( ; pulses > 0 ;  pulses--) {
    LedPinOn;  delay(ledOn);         
    LedPinOff; delay(ledOn); 
  }
}

