#pragma OT(3)
#pragma ROM(SMALL) 

#include <reg752.h>
#include <stdio.h>
                            
#define FREERUN_I       0x10   //                                      
 
#define SEG_A           0x40   // P3 position for display segment 'a'  
#define SEG_B           0x01   // P3 position for display segment 'b'  
#define SEG_C           0x04   // P3 position for display segment 'c'  
#define SEG_D           0x08   // P3 position for display segment 'd'  
#define SEG_E           0x20   // P3 position for display segment 'e'  
#define SEG_F           0x80   // P3 position for display segment 'f'  
#define SEG_G           0x02   // P3 position for display segment 'g'  
#define SEG_DP          0x10   // P3 position for display decimal pt.  

typedef unsigned char byte;        
typedef unsigned int word;         
typedef unsigned long l_word;      

#define TRUE  1                 
#define FALSE 0                

//----------------------------------------------------------------------------
// Define look-up table of possible seven segment display
// characters possible to display. 
//----------------------------------------------------------------------------
code byte segments[] = {
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F        ,  // 0 
          SEG_B | SEG_C                                ,  // 1 
  SEG_A | SEG_B |         SEG_D | SEG_E |         SEG_G,  // 2 
  SEG_A | SEG_B | SEG_C | SEG_D |                 SEG_G,  // 3 
          SEG_B | SEG_C |                 SEG_F | SEG_G,  // 4 
  SEG_A |         SEG_C | SEG_D         | SEG_F | SEG_G,  // 5 
  SEG_A |         SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,  // 6 
  SEG_A | SEG_B | SEG_C                                ,  // 7 
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,  // 8 
  SEG_A | SEG_B | SEG_C | SEG_D |         SEG_F | SEG_G,  // 9 
  SEG_A |                 SEG_D | SEG_E | SEG_F | SEG_G,  // E 10
                          SEG_D | SEG_E | SEG_F        ,  // L 11
                  SEG_C | SEG_D | SEG_E         | SEG_G,  // o 12
  SEG_A | SEG_B | SEG_C         | SEG_E | SEG_F | SEG_G,  // A 13
          SEG_B | SEG_C |         SEG_E | SEG_F | SEG_G,  // H 14
                  SEG_C                                ,  // i 15
                  SEG_C | SEG_D | SEG_E                ,  // u 16
  SEG_A |                                 SEG_F | SEG_G,  // c 17
  SEG_A | SEG_B | SEG_C | SEG_D |         SEG_F | SEG_G   // g 18
};

//----------------------------------------------------------------------------
// I/O definitions...
//---------------------------------------------------------------------------- 
#define RELAY    P03   // active hi to turn on relay  
#define STROBE_0 P02   // active hi to enable status led's     (P15)
#define STROBE_1 P01   // active hi to enable display lsb      
#define STROBE_2 P00   // active hi to enable display msb      
#define START    P13   // Start button
#define STOP     P12   // Stop button
#define SELECT   P14   // Select button

//----------------------------------------------------------------------------
// ?
//----------------------------------------------------------------------------                     
#define PowerOnTime    10*92
#define WaitTime        3*92
 
#define MM1  0 
#define MM15 1 
#define MM25 2 
#define MM4  3 
#define MM6  4 

#define LEDMM1     SEG_B
#define LEDMM15    SEG_G 
#define LEDMM25    SEG_C 
#define LEDMM4     SEG_D 
#define LEDMM6     SEG_DP
#define AllCableLED (SEG_B  | SEG_G | SEG_C | SEG_D | SEG_DP)

 
#define LEDOK      SEG_E
#define LEDFAULT   SEG_A
#define LEDTESTING SEG_F
//----------------------------------------------------------------------------
// Variables...
//----------------------------------------------------------------------------
data byte disp_pntr=0; // pointer to next display to enable    
data byte display0;    // variables to hold values for the     
data byte display1;    // displays during refresh              
data byte display2;    //                                      
 
bit  UPDATE=1;         // flag set when time to update display 
data byte CableType=MM1;//Current cabletype selected
word Timer=0;          // Timer for test time (10 Sec)
word Timer1=0;         // Timer for wait between tests (3 Sec)
byte ShowMode=0;       // Show U/I/R on display


//----------------------------------------------------------------------------
// use the free-running I timer to multiplex the led displays
// at approx. 1000 hz.
//----------------------------------------------------------------------------
void multiplex() interrupt 3 {
static data count; 
  count++; 
  if (count>20) {
    count=0;
    switch(disp_pntr) {
      case 0:
        STROBE_2 = FALSE;        // turn off display msb
        P3 = 0x00;               // turn off all segments        
        P3 = display0;           // load segments for led's      
        STROBE_0 = TRUE;         // turn on status led's         
        disp_pntr = 1;           // increment pointer to display  
        break;
      case 1:
        STROBE_0 = FALSE;        // turn off status led's        
        P3 = 0x00;               // turn off all segments        
        P3 = display1;           // load segments for tenths     
        STROBE_1 = TRUE;         // turn on display lsb          
        disp_pntr = 2;           // increment pointer to display 
        break;
      case 2:
        STROBE_1 = FALSE;        // turn off display lsb         
        P3 = 0x00;               // turn off all segments        
        P3 = display2;           // load segments for units      
        STROBE_2 = TRUE;         // turn on display msb          
        disp_pntr = 0;           // increment pointer to display 
        break;
    }
  }
}


//----------------------------------------------------------------------------
// Use the free running pwm prescaler to generate
// interrupts every 92 hz. every 8nd interrupt,
// set the UPDATE flag to update the led display contents.
//----------------------------------------------------------------------------/
void read_switch() interrupt 6 {
static byte refresh=0;
 // Timer function...
  if (Timer>=1) {
    Timer--;
    if (Timer==0) { 
     // When timeout...
      RELAY=0; // Kill relay...
      display0 &= ~LEDTESTING; // and LED
      Timer1=WaitTime;
    }
  }
 // Timer function...
  if (Timer1>=1) Timer1--;
 
  if(refresh++ == 8) {
    UPDATE = TRUE; // Force update of display
    refresh = 0;
  }
}

//----------------------------------------------------------------------------
// ?
//----------------------------------------------------------------------------
void ShowCableTypeSelected(void) {                          
static byte OldCableType=99; 
  if (CableType!=OldCableType) {
    OldCableType=CableType;
    display0 &= ~(AllCableLED);
    switch (CableType) {
      case MM1:  display0 |= LEDMM1;  break;
      case MM15: display0 |= LEDMM15; break;
      case MM25: display0 |= LEDMM25; break;
      case MM4:  display0 |= LEDMM4;  break;
      case MM6:  display0 |= LEDMM6;  break;
    }
  }
}

 
//----------------------------------------------------------------------------
// ?
//---------------------------------------------------------------------------- 
byte ReadADC(byte Ch) {
  byte flag; 
  flag=0x28+Ch;
  ADCON = flag;
  while(ADCON & 0x08); // Wait for completion
  return ADAT; 
} 

 
//----------------------------------------------------------------------------
// ?
//----------------------------------------------------------------------------
void main()
{
  word w,w1; 
  byte i; 
  bit  Released=1, Error=0, Auto;
  byte OldSELECT=99;
 
  RELAY   = 0;         // initialize output pins               
  STROBE_0= 0;
  STROBE_1= 0;
  STROBE_2= 0;
  START   = 1;         // and inputs
  STOP    = 1;
  SELECT  = 1;
  
  I2CFG   = FREERUN_I; // enable I timer to run, no i2c        
 
  PWMP    = 255;       // pwm timer interrupt at 92 hz         
  IE        = 0xA8;    // enable intrrupts, PWM overflow, Timer 1
  
  display0 = LEDMM1;                     

  display2=segments[17]; // Say "c" 
  display1=segments[18]; // Say "g"
 // Make a delay...
  for (w=0; w<1100; w++)
    for (w1=0; w1<1; w1++);
          
  if (SELECT==0) {
    display2=segments[13]; // Say "A" 
    display1=segments[13]; // 16 Say "u" on the display to indicate Auto mode...
    while (SELECT==0);     // Stay until both buttons released...
    Auto=1;  
  } else
    Auto=0;

 
  while(1) {
   //----------------------------------------------------------------------------
   // if time to update display & LEDS, go do it...
   //----------------------------------------------------------------------------
    if (UPDATE) {
      UPDATE = 0;
     //----------------------------------------------------------------------------
     // Both STOP and START buttons pressed, cycle around the various ShowModes
     // where 0 is Voltage, 1 is Current and 2 is Resistance
     //----------------------------------------------------------------------------
      if ((STOP==0) && (START==0) && (Released)) {
        ShowMode++;
        if (ShowMode>2) ShowMode=0;
        Released=0;
      } else Released=1;
     //----------------------------------------------------------------------------
     // SELECT button pressed, select cabletype...
     //----------------------------------------------------------------------------
      if (SELECT != OldSELECT) {
        if (SELECT==0) 
          if (++CableType > MM6) CableType=MM1;
        OldSELECT=SELECT;
      }
     //----------------------------------------------------------------------------
     // Update OK/FAULT LED...
     //----------------------------------------------------------------------------
     // Decide maximum voltage...
      switch (CableType) {
        case MM1:  i=33; break;
        case MM15: i=26; break;
        case MM25: i=19; break;
        case MM4:  i=14; break;
        case MM6:  i=10; break;
      }
      if (Timer) {
       // Check measured voltage...
        if (ReadADC(1) > i) {
          display0 |= LEDFAULT;
          display0 &= ~LEDOK;
        } else {
          display0 |= LEDOK;
          display0 &= ~LEDFAULT;
        }
      }

     //----------------------------------------------------------------------------
     // Show the type of cable selected...
     //----------------------------------------------------------------------------
      ShowCableTypeSelected();
 
     //----------------------------------------------------------------------------
     // What shall we show on the 7-segments ?
     //----------------------------------------------------------------------------
      if (Error==0) {
        switch (ShowMode) {
         //----------------------
         // Show voltage...
         //----------------------
          case 0:
           // But only during testing...
            if (Timer) {
              i=ReadADC(1);
              if (i>99) {
                display2 = SEG_G;
                display1 = SEG_G;
              } else {
                display2 = segments[i/10] | SEG_DP;
                display1 = segments[i%10];
              }
            } else {
              display2 = SEG_G;
              display1 = SEG_G;
            }
            break;
   
         //----------------------
         // Show current...
         //----------------------
          case 1:
            i=ReadADC(0) / 10;
           // Remove leading zero...
            if (i/10) 
              display2 = segments[i/10];
            else
              display2=0;
            display1 = segments[i%10];
            break;
         //----------------------
         // Show resistance...
         //----------------------
          case 2:
           // If we are testing, we calculate resistance,
           // and if NOT running we show "Hi"
            if (Timer) {
             // Get current in 0.1 A
             // Get voltage in 0.1 V
              w =ReadADC(1)*10;  // voltage
              w1=ReadADC(0);     // current
              w=w/w1;
              i=w;
              if (i<=99) {
                display2 = segments[i/10] | SEG_DP;
                display1 = segments[i%10] | SEG_DP;
                break; // Done
              }
            }
            // Not running, or resitance is too high...
            display2 = segments[14] | SEG_DP; // H
            display1 = segments[15] | SEG_DP; // i
            break;
        }
      } // if (Error==0)
    } // if (UPDATE)
                   
   //----------------------------------------------------------------------------
   // Check all the buttons, alarms, etc
   //----------------------------------------------------------------------------
 
   //----------------------------------------------------------------------------
   // Stop testing, emergency, smoke comming out...
   //----------------------------------------------------------------------------
    if ((STOP==0) && (START==1)) {
      display0 &= ~LEDTESTING;
      display0 &= ~LEDOK;
      display0 &= ~LEDFAULT;
      Timer=0;
      RELAY=0;
      Timer1=WaitTime;
    }
                   

   //----------------------------------------------------------------------------
   // if current drops below 10 A, after 1/10 of the on time
   // report error "Lo" on display, and stop test
   //----------------------------------------------------------------------------
    if ((ReadADC(0)<100) && (Timer && (Timer < (PowerOnTime - 2*92)))) {
      RELAY=0;
      Timer=0;
      Timer1=WaitTime;
      display0 &= ~LEDTESTING;
      display0 |= LEDFAULT;
      display0 &= ~LEDOK;
      display2 = segments[11]; // "L"
      display1 = segments[12]; // "o"
      Error=1;
    }
 
   //----------------------------------------------------------------------------
   // When the pause delay is run out, reset Error flag...
   //----------------------------------------------------------------------------
    if (Timer1==0) Error=0;
 
   //----------------------------------------------------------------------------
   // Start testing...
   // Either if START button preesed (and STOP is not) 
   //   OR
   // we are in Auto mode and the voltage goes below 2.0 V, 
   // meaning that the circuit is closed AND we are ready, 
   // ie some time (3 Sec) after the power IS switched off...
   //----------------------------------------------------------------------------
    if ((((START==0)      && (STOP==1)) ||
         ((ReadADC(1)<20) && (Timer==0) && Auto)) && (Timer1==0))  {
      display0 |= LEDTESTING;
      Timer=PowerOnTime; // Start timer
      RELAY=1;           // and turn on Relay...
    }
  } // while (1)
}
