uint8_t duty = 50; // start @ 50 % duty
float freq = 0.44; // start @ 440 hz

void set_duty(uint8_t d) {
  duty = 100- d;
  update_freq();
}

void set_freq(float f) {
  freq = f;
  update_freq();
}

void update_freq() {
  uint16_t top = freq/0.440*142/2;
  
  OCR2A = (top>0xFF)?0xFF:top;
  OCR2B = top * duty / 100;
}

void setup_timer() {
  // setup timer
  update_freq();
   
  TCCR2A= (1<<COM2B1) | (1<<WGM20);
  TCCR2B= (1<<WGM22) | (1<<CS02); // 64 prescaler ( 5khz == TOP of 50, 1khz = 250 )

  DDRD |= (1<<PD3);
}

void setup() {

  setup_timer();
  
  Serial.begin(9600);
  Serial.println("setup complete");
  interrupts();
}

#include <EEPROM.h>

class Panel {
  int maxVals[2];
  
  struct limits {
    int touchThreas;
    int minVals[2];
    float range[2];
    bool caldone;
  } limits;
public:
  Panel():maxVals{1,1} {
    // declare pins as input
    DDRC &= ~((1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3));

    EEPROM.get(0, limits);
  }

  enum Axis {
    X = 0,
    Y
  };
  
  int operator()(Axis axis) {
    int result = -1;
    switch(axis) {
    case X:
      DDRC  |= (1<<PC0)            | (1<<PC2);
      PORTC |= (1<<PC0) | (1<<PC1)           ;
      delay(1);
      result = analogRead(A1);
      break;
    case Y:
      DDRC  |=            (1<<PC1) | (1<<PC3);
      PORTC |= (1<<PC0) | (1<<PC1)           ;
      delay(1);
      result = analogRead(A2);
      break;
    }

    PORTC = 0;
    DDRC  = 0;
      
    return result;
  }

  float normalized(Axis axis) {
    if (!limits.caldone)
      return 0;
      
    return ((*this)(axis)- limits.minVals[axis] )/ limits.range[axis];
  }

  void calibrate() {
    static int state = 0;

    switch(state++) {
    case 0:
      limits.touchThreas = (*this)(X) - 10;
      break;
    case 1:
      limits.minVals[X] = (*this)(X);
      limits.minVals[Y] = (*this)(Y);
      break;
    case 2:
      maxVals[X] = (*this)(X);
      maxVals[Y] = (*this)(Y);
    default:
      limits.range[X] = maxVals[X] - limits.minVals[X];
      limits.range[Y] = maxVals[Y] - limits.minVals[Y];
      limits.caldone = 1;
      Serial.println("calibration complete");
      EEPROM.put(0, limits);
      state = 0;
    }
  }

  operator bool() {
    return ((*this)(X) < limits.touchThreas) || ((*this)(Y) < limits.touchThreas);
  }
  
} panel;

bool newline = true;

int sigmal = 0;
int mu = 0;

void loop() {
  // put your main code here, to run repeatedly:

  if (panel) {
    float x = panel.normalized(Panel::X), 
      y = panel.normalized(Panel::Y);
      
    int n = x*12;
    //float freq = powf(1.0595, n - 9) * 0.440;
    float freq = powf(1.0905, n - 6) * 0.440;
        
   // Serial.print(n);
   // Serial.print("\t");
   // Serial.println(freq);
    
    //analogWrite(11, 255*panel.normalized(Panel::X));
    
    
    set_freq(freq);
    set_duty(y*100);
  } else {
    set_duty(100);
  }

  while(Serial.available()) {
    char c = Serial.read();
    if (newline && c == 'c') {
      panel.calibrate();
      newline = false;
    } else if (!newline && c == '\n') {
      newline = true;
    }
  }

  //delay(100);
}
