/*
 *  Waveform generator for curve tracer.
 *
 *  Outputs:
 *      D0-D7     ramp value
 *      D8-D10    step value
 *
 *  Inputs:
 *      A1        0 = 4 steps,  >0 = 8 steps
 *      A2        ladder step amplitudes
 *      A3        ramp amplitude
 *
 *  Versions log:
 *  v0.1  preliminary
 *  v0.2  preliminary
 *  v0.3  waveforms generator woirking version
 *  v0.4  added LCD controls for LCD 2004A
 *  v0.5  added capability of measuring single step voltages and currents
 *  v0.6  fix ranging issues on the ramp voltage
 *  v0.7  fix issues of step voltage and current
 *  v0.8  step voltage and current reading improvements
 *  v1.0  First production version
 */


#include "port_manipulation.h"
#include "Wire.h"
#include "LiquidCrystal_I2C.h"

// Version number
const String version = "v1.0";

// first ramp level is 0 and increases up to 255,
// corresponding to ~5V
unsigned char ramp_level;

// ladder steps control variables
unsigned int step_number;
unsigned char old_a1;
unsigned int max_steps;
unsigned int delta_step;

// display constants and variables
unsigned int ramp_voltage;
unsigned int step_voltage;
unsigned int step_current;
unsigned int old_ramp_voltage;
unsigned int old_step_voltage;
unsigned int old_step_current;
bool read_ramp_voltage;
bool read_step_voltage;
unsigned int read_ramp;
unsigned int read_step;
const unsigned int max_ramp_count = 500;   // adjusted for best performance
const unsigned int max_step_count = 125;    // adjusted for best performance
                                            // of the curve tracer

// LCD Object using:
//  I2C serial communication protocol at address 0x27
//  20 columns
//  4 rows
//  Note: Arduino nano pins for I2C are: A4 for SDA and A5 for SCL
const uint8_t LCD_ADDR = 0x27;
const uint8_t LCD_COLS = 20;
const uint8_t LCD_ROWS = 4;
LiquidCrystal_I2C CTlcd(LCD_ADDR, LCD_COLS, LCD_ROWS);

void setup()
{
  //Serial.begin(9600);
  // initialize pins for input and output
  SET_ALL_OUTPUTS(D);                 /* digital pins 0 to 7 */
  SET_PORT_MODE(B, B00000111);        /* digital pins 8 to 10 */

  ramp_level = 0;
  step_number = 0;
  max_steps = 7;
  old_a1 = 1;
  delta_step = 1;

  ramp_voltage = 0;
  step_voltage = 0;
  step_current = 0;
  old_ramp_voltage = 0;
  old_step_voltage = 0;
  old_step_current = 0;

  read_ramp = 0;
  read_step = 0;
  read_ramp_voltage = false;
  read_step_voltage = false;

  // initialize LCD screen and welcome message
  CTlcd.init();                             // LCD object initialization
  CTlcd.backlight();                        // activate backlight
  CTlcd.setCursor(0,0);                     // set cursor to upper left corner
  CTlcd.print("Curve Tracer   " + version); // welcome message 1
  CTlcd.setCursor(0,3);                     // cursor reposition
  CTlcd.print("by: eleneasy.com");      // welcome message 2

  delay(2000);

  CTlcd.setCursor(0,1);
  CTlcd.print("Ramp Vpp:  0.0  V   ");
  CTlcd.setCursor(0,2);
  CTlcd.print("Step V:    0.0  V   ");
  CTlcd.setCursor(0,3);
  CTlcd.print("Step I:    0.0  mA  ");
}

void step_measurement()
{
  unsigned int adc_read;

  if (read_ramp_voltage == true)
  {
    adc_read = analogRead(A3); 
    ramp_voltage = (unsigned int)((long)adc_read * 1100 / 1023);  // measures up to 11.00 V
    read_ramp_voltage = false;
    step_print();
  }
  if (read_step_voltage == true)
  {
    adc_read = analogRead(A2);
    //Serial.println(adc_read);
    step_voltage = (unsigned int)((long)adc_read * 1040 / 1023);  // measures up to 10.40 V
    step_current = (unsigned int)((long)adc_read *2212 / 1023);   // measures up to 22.12 mA
    read_step_voltage = false; 
    step_print();
  }
}

void step_print()
{
  unsigned int m_value;

  if (ramp_voltage != old_ramp_voltage)
  {
    CTlcd.setCursor(11, 1);
    CTlcd.print(ramp_voltage/100);
    CTlcd.print(".");
    m_value = ramp_voltage % 100;
    if (m_value < 10)
    {
      CTlcd.print(0);
    }
    CTlcd.print(m_value);
    CTlcd.print(" V  ");
    old_ramp_voltage = ramp_voltage;
  }
  if (step_voltage != old_step_voltage)
  {
    CTlcd.setCursor(11, 2);
    CTlcd.print(step_voltage/100);
    CTlcd.print(".");
    m_value = step_voltage % 100;
    if (m_value < 10)
    {
      CTlcd.print(0);
    }
    CTlcd.print(m_value);
    CTlcd.print(" V  ");
    old_step_voltage = step_voltage;
  }
  if (step_current != old_step_current)
  {
    CTlcd.setCursor(11, 3);
    CTlcd.print(step_current/100);
    CTlcd.print(".");
    m_value = step_current % 100;
    if (m_value < 10)
    {
      CTlcd.print(0);
    }
    CTlcd.print(m_value);
    CTlcd.print(" mA  ");
    old_step_current = step_current;
  }
}

void loop()
{
  unsigned char a1;
  unsigned char step_level;

  a1 = PIN_READ(C, 1);     // 1 is the position of A1 inside register C

  if (a1 == 0)        // 4 steps ladder
  {
    max_steps = 3;
    delta_step = 2;
  }
  else
  {
    max_steps = 7;    // 8 steps ladder
    delta_step = 1;
  }

  if (a1 != old_a1)
  {
    step_number = 0;
    ramp_level = 0;
    old_a1 = a1;
  }
  else
  {
    step_level = step_number * delta_step;

    PORT_WRITE(B, step_level);
    PORT_WRITE(D, ramp_level);

    if ((step_number == 1) && (ramp_level == 0x7F))
    {
      if (read_step <= max_step_count)
      {
        read_step++;
      }
      else
      {
        read_step_voltage = true;
        read_step = 0;
      }
    }

    ramp_level++;

    if (ramp_level == 0xFF)
    {
      if (read_ramp <= max_ramp_count)
      {
        read_ramp++;
      }
      else
      {
        read_ramp_voltage = true;
        read_ramp = 0;
      }
      
    }

    step_measurement();

    if(ramp_level == 0)
    {
      step_number++;

      if (step_number > max_steps)
      {
        step_number = 0;
      }
    }
  }
}
