/*****************************************************
HV_Converter.c

Project : High Voltage Converter 12-bit
Version : 2.1
Date    : 19 May 2008
Company : Yerevan Physics Institute 
Comments: 

Author  : Varuzhan Danielyan              

Chip type        : ADuc7021

*****************************************************/
#include "defs.h"
#include "EEPROM.h"

int ProgramOk;
u16 HV_Setting, Flags;

int MaxADC;

#define MaxDAC_Value    8090

#define int_shift       4/*10*/

volatile int HV_Measured;
volatile int integral;

#ifdef Watchdog
#else
void FeedWatchdog(void) {};
#endif


#define FIRST_ADC_INPUT 0
#define LAST_ADC_INPUT 3
volatile u32 adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
volatile int Temperature;

void Timer0_IRQ_Handler(void);

void Timer0_IRQ_Handler(void)
{
  static u32 input_index = 1;
  u32 DAC_Value;
  int delta;

  ADCCP = input_index;

  if (input_index == 0x10) {
    ADCCON = 0x6A3;				// ADC config: fADC/2, acq. time = 16 clocks => ADC Speed = 1MSPS
	while (!ADCSTA);			// wait for end of conversion
    Temperature = 0x525 - (ADCDAT >> 16);
    input_index = FIRST_ADC_INPUT;
  }
  else {
    if (input_index == FIRST_ADC_INPUT) {		// HV Feedback
	  ADCCON = 0x6A3;				// ADC config: fADC/2, acq. time = 16 clocks => ADC Speed = 1MSPS
	  while (!ADCSTA);			// wait for end of conversion
      adc_data[input_index] = HV_Measured = ADCDAT >> 16;    	
      if (GP1DAT & PowerEN) {
        delta = (HV_Measured - (int)HV_Setting);
        integral += delta;
        if (integral < 0)
          DAC_Value = 0;
        else if (integral > (MaxDAC_Value << int_shift)) {
          integral = MaxDAC_Value << int_shift;
          DAC_Value = MaxDAC_Value;
		}
        else
          DAC_Value = (u32)integral >> int_shift;

        DAC0DAT = (DAC_Value << 15);
	    DAC1DAT = ((DAC_Value + 1) << 15);

        if (abs(delta) > 2)
          T0LD = 25;
        else
          T0LD = 800;
      }
    }
    else {
	  ADCCON = 0x6A3;				// ADC config: fADC/2, acq. time = 16 clocks => ADC Speed = 1MSPS
	  while (!ADCSTA);			// wait for end of conversion
      adc_data[input_index] = (ADCDAT >> 16);    

    } 

    //Select next ADC input
    if (++input_index > LAST_ADC_INPUT)
      input_index = 0x10;	// Choose temperature sensor
  }
  
  if (ProgramOk) {
    ProgramOk = 0;
    FeedWatchdog();
  }

  T0CLRI = 0;
}



char NextChar;

static u16 GetWORD(void)
{ 
  u16 i;
  
  i = 0;
  do {
//    while (!received())
//      ProgramOk = 1;   
    NextChar = getchar();
    if (isdigit(NextChar)) {
      i *= 10;
      i += NextChar - '0';
    }
    else  
      break;
  }  while(1);

  return i;
}


u16 MyAddress, ADC2HV;

float Code2Voltage;


char String[16];

//#define _RS485_TEST_

static u8 GoodAddress(void)
{
  u8 b;
  
  b = (u8)GetWORD();
  return (b == MyAddress);      
}


static void InitADC(void)
{
  int time;

  time = 20000;
  ADCCON = 0x20;	 					// power-on the ADC
  while (time >=0)	  				// wait for ADC to be fully powered on
    time--;

  REFCON = 0x01;				// connect internal 2.5V reference to Vref pin
  ADCCON = 0x623;				// ADC config: fADC/2, acq. time = 16 clocks => ADC Speed = 1MSPS
}

//#define _RS485_TEST_
//#define _INIT_EEPROM_
//#define _EEPROM_TEST_

int main(void)
{

  int ch, i, b;
#ifdef _EEPROM_TEST_
  u16 j;
#endif

  InitController();
  InitADC();
  InitSerial();

#ifndef _EEPROM_TEST
  IRQ = Timer0_IRQ_Handler;			// Specify Interrupt Service Rountine
  T0LD = 50;						// Counter Value
  T0CON = 0xC4;						// Enabled,Periodic,Binary and CLK/16
  IRQEN = TIMER0_BIT;				// Enable Timer0 IRQ
#endif

#ifdef _RS485_TEST_  
  ch =0x55;
  putchar(ch);
  while (1) {
    if (received()) {
      ch = toupper(getchar());
      putchar(ch);
	}
    FeedWatchdog();
	if (ch == 'N')
	  break;
	if (ch == 'T') {
      IRQEN = 0;
 	}
  }
#endif



#ifdef _EEPROM_TEST_
  if (EE_Erased()) {
    EE_Format();
	delay(50000);
    EE_Write(0, 0x1234);
    EE_Write(2, 0x5678);
    EE_Write(4, 0xA5A5);
  }
  else
    EE_Write(4, 0x4321);
while (1) {
  EE_Read(0, &j);
  rprintf("%X\n", j);
  EE_Read(2, &j);
  rprintf("%X\n", j);
  EE_Read(4, &j);
  rprintf("%X\n", j);
  getchar();
} 
#endif

  if (EE_Erased()) {
    EE_Format();
    EE_Write(MyAddressAdr, MyAddress0);
    EE_Write(HV_SettingAdr, HV_Setting0);
	EE_Write(ADC2HV_Adr, ADC2HV0);
	EE_Write(FlagsAdr, Flags0);
  }

  EE_Read(MyAddressAdr, &MyAddress);
  EE_Read(HV_SettingAdr, &HV_Setting);
  EE_Read(ADC2HV_Adr, &ADC2HV);
  EE_Read(FlagsAdr, &Flags);

  Code2Voltage = (float)ADC2HV/0x8000;
  MaxADC = MaxHV/Code2Voltage;

  integral = (MaxDAC_Value - (int)HV_Setting) << int_shift;

  if (Flags & HV_OnFlag)
    GP1DAT |= PowerEN;

  while (1) {
    ProgramOk = 1;
    if(received()) {
      ch = toupper(getchar());
      if (ch == 'A') {                 // Set and read Address
        b = (u8)GetWORD();
        if ((b == 253) | (b == MyAddress)) {
          if (NextChar == ' ') {
            b = (u8)GetWORD();
            if (b)
			{
              MyAddress = b;
			  EE_Write(MyAddressAdr, MyAddress);
			  }
            else
              b = MyAddress;
          }
          else
            b = MyAddress;
		  rprintf("%u", b);
        }
      }
      else {
        switch(ch) {
        case 'C':    // Calibrate
          if (GoodAddress()) { 
            i = GetWORD();
            Code2Voltage = ((float) i)/HV_Setting;
			ADC2HV = (u16)(Code2Voltage*0x8000 + 0.5);
			EE_Write(ADC2HV_Adr, ADC2HV);
            MaxADC = MaxHV/Code2Voltage; 
          }
        break;         
        case 'V':                 // Set HV in Volts
        case 'E':                 // Set HV in ADC units
          if (GoodAddress()) {
            i = GetWORD();
            if (ch == 'V')
              i =  (u16)(i/Code2Voltage);
            if (i > MaxADC)
              i = MaxADC;
			if (i != HV_Setting) {
              HV_Setting = i;
              integral = (MaxDAC_Value - (int)HV_Setting) << int_shift;
              EE_Write(HV_SettingAdr, HV_Setting);
			}
          }
        break;
        case 'H':                 // Read HV in Volts
        case 'R':                 // ReadHV in ADC units
          if (GoodAddress()) {
            i = HV_Measured;
            if (ch == 'H')
              i *= Code2Voltage;
            rprintf("e=%u", i);
          }
        break;     
        case 'S':                 // Switch HV off
          if (GoodAddress()) {
		    Flags &= ~HV_OnFlag;
	        EE_Write(FlagsAdr, Flags);
		    GP1DAT &= ~PowerEN;
          }
        break;
        case 'G':                 // Switch HV on
          if (GoodAddress()) {
		    Flags |= HV_OnFlag;
	        EE_Write(FlagsAdr, Flags);
            GP1DAT |= PowerEN;
            integral = (MaxDAC_Value - (int)HV_Setting) << int_shift;			
          }
        break;
        case 'D':
          if (GoodAddress()) {
		    rprintf("\n");
            for (i = FIRST_ADC_INPUT; i <= LAST_ADC_INPUT; i++)
              rprintf("ADC[%i]=%u\n", i, adc_data[i]);
            rprintf("Temperature=%i\n", (Temperature*10)/13);
		    rprintf("\n");
          }
        break;
        }
      }
    }
  }
}
