/*
  Connection to calibration selection button: 2
  Connection to power sensor: A0
  V.2.0  pouzit displej apex RC162021 (pozor prevracene napajeni 1+, 2GND )
  zmeneny kontakty podle spoje
  
*/
#include <math.h>

float dBmToMicroVolt(float dBm) {
  return 223.6 * pow(10.0, dBm / 20.0);
}
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 7, 5, 4, 3, 2);//
#define BUTTON 9

struct cal {
  char *id;
  int slope;   // Positive (1) or negative (-1) slope
  int dbmv;    // db per millivolt
  int bottomdb; // lowest db reading at lowest voltage
  double bottomv; // lowest voltage
};

// Calibration table
struct cal calibration[] = {
  { "2G", -1, 25, -57, 2.0 },
  { "1G", -1, 22, -60, 1.62 },
  { "430", -1, 22, -60, 1.62 },
  { "144", -1, 22, -60, 1.62 },
};

char cal_selected = 0;   // selected calibration set
char button = 1;  // button state
 float dB= -10.0; 
void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // initialize the serial communications:
  Serial.begin(9600);
  // Initialize the calibration switch button
  pinMode(BUTTON, INPUT_PULLUP);
}


void loop() {
  int a; // analog value
  int n; // number of bars
  double v; // voltage value
  double dv; // voltage relative to calibration
  double dB; // calculated dBm value
  double dbmv; // db per millivolt
  char str[32]; // formatted string for output
  
  a = analogRead(0);
  v = (5.0 / 1024.0) * a;
  //Serial.print(a);
  //Serial.print(" ");
  //Serial.println(v);  // Print for Arduino chart

  // Print to display: 
//   Row 1: Voltage, dB and calibration selection
  // Row 2: Bar Graph

  lcd.clear();
  // Print voltage
  //dtostrf(v, 6, 4, str);
  //lcd.write(str);
  //lcd.write("v ");

  // Convert voltage based on the sensor's slope and minimum value
  // For example, the AD8318 outputs 2.0v at ~-57dBm and 0.6v at 
  // ~2dBm. This is a negative slope.
  if (calibration[cal_selected].slope > 0) {
    dv = v - calibration[cal_selected].bottomv;
  } else {
    dv = calibration[cal_selected].bottomv - v;
  }
  dbmv = calibration[cal_selected].dbmv / 1000.0;
  dB = calibration[cal_selected].bottomdb + dv / dbmv;

  // Print dB for Arduino chart
  Serial.print(dB);
  Serial.println(" dB");
/*float  mv = 223.6068f * exp(0.11512925f * dB);

  Serial.print(mv,4);
  Serial.println(" mV");
  */
 float dBm = dB;      // zadaná hodnota
  float uV = dBmToMicroVolt(dBm);

  Serial.print(dBm);
  Serial.print(" dBm = ");
  Serial.print(uV);
  Serial.println(" uV");
  
  // Print dB
  dtostrf(dB, 6, 2, str);
  lcd.write(str);
  lcd.write(" dBm ");

  // Print which calibration is selected (the ID string in the struct)
  lcd.write(" ");
  lcd.write(calibration[cal_selected].id);

  lcd.setCursor(0,2);
  n = abs(calibration[cal_selected].bottomdb - dB) / 3.5;
    // 70dBm range, 20 characters 
  //n = a/51;  // 20 character display: 1024 / 20 = 51
  while (n-- > 0) {
    lcd.write(255); // character is a full block
  }

  // Read the calibration change button. If pressed, debounce
  // then advance the selected calibration, wrapping around at
  // the end.
  if (button != digitalRead(BUTTON)) {
    delay(10); // debounce the button
    button = digitalRead(BUTTON);
    if (button == 0) {
      cal_selected++; // next item
      if (cal_selected >= sizeof(calibration)/sizeof(struct cal)) {
        cal_selected = 0; // return to zero at the end
      }
    }
  }
  delay(1000);
}
// vim: tabstop=2 expandtab shiftwidth=2 softtabstop=2 
