/****************************************************************************/
/* Copyright 2007 MBARI.                                                    */
/* Monterey Bay Aquarium Research Institute Proprietary Information.        */
/* All rights reserved.       																						  */
/*																																					*/
/* loadControl_main.c - main loop program															  		*/
/*																																					*/
/* Rev History:																															*/
/* Initial Creation 11/2007		B.Kieft																		    */
/*																																					*/
/*																																					*/
/****************************************************************************/
#include <16f876A.h>
#device ADC=10 ICD=true *=16

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#use delay(clock=4000000, restart_wdt)

#include "loadControl_main.h"
#include "RS485.c"
#include "spi.c"
#include "Command_Handler.c"

#if DEBUG
#fuses XT,WDT,NOPROTECT,PUT,NOBROWNOUT,NOLVP
#else
#fuses XT,WDT,NOPROTECT,PUT,NOLVP
#endif

#define  RS485_USE_EXT_INT    FALSE


// Purpose: ISR that checks for over-current condition when the load is on
#INT_TIMER1                     
void high_priority_isr() {                    
  set_adc_channel(4);	       // Set A/D channel   
  read_adc(ADC_START_ONLY); 	                         
  // set_timer1(0xFD95);  // sets timer to interrupt in 5 ms (100 Hz waveform)
  set_timer1(0xF641);  // sets timer to interrupt in 20 ms (25 Hz waveform)   
  if(rtos_pin == HI)
    rtos_pin = LO;
  else
    rtos_pin = HI;
    output_bit(PIN_C1, rtos_pin); // *** DEBUG

  if(read_adc(ADC_READ_ONLY) > overcurrent_adc_val) {
    over_curr_err = true;
    output_bit(PIN_C2, HI); // *** DEBUG  
  }
  else {
 	  output_bit(PIN_C2, LO); // *** DEBUG  
  }

}

//*** DEBUG
//#INT_AD
//void adc_isr() {
//  adc_ready = true;
//  output_bit(PIN_C2, HI); // *** DEBUG  
//}
//*** DEBUG


// Purpose: Does A/D calculation of current from MAX4081. Stores value in global
void do_adc_current_calcs(int16 vref, int16 vscale, int8 rsense, int8 currDiv) {
  ldiv_t lidiv;
  adc_value_glob = read_adc();  

  adc_value_glob = ((adc_value_glob * 1000) / 1023) * vscale;      // scale to vscale   
  adc_value_glob = adc_value_glob - (((int32)vref * 1000) / 2);    // subtract Vref/2 since ref1B is grounded    
  adc_value_glob = adc_value_glob / currDiv;                       // Divide by 5V/V apmplification 
  adc_value_glob = (adc_value_glob / rsense);                      // Divide by Rsense
}


// Purpose: Does A/D calculation of voltage through divider and scales to vscale.
// Stores value in global
void do_adc_voltage_calcs(int8 vscale) {
  adc_value_glob = read_adc();    
  adc_value_glob = (adc_value_glob * 1000 / 1023) * (int32)vscale; // scale for 0-vscale Volts	
}

// Purpose: Reads a bytes from data EEPROM
int8 read_eeprom8(int8 address) {
  return(read_eeprom(address));
}

// Purpose: Writes a byte to data EEPROM
void write_eeprom8(int8 address, int8 data) {
  write_eeprom(address, data);
}

// Purpose: Reads two bytes from data EEPROM
int16 read_eeprom16(int8 address) {
  union {
    int8 bytes[2];
    int16 val;
  } data;

  data.bytes[0]=read_eeprom8(address++);
  data.bytes[1]=read_eeprom8(address);

  return(data.val);
}


// Purpose: Writes 2 bytes to Data EEPROM at location "address"
void write_eeprom16(int8 address, int16 data) {
  write_eeprom8(address++, make8(data,0));
  write_eeprom8(address, make8(data,1));
}


// Purpose: Clears all errors if true. Otherwise, just clears non-persistent errors
void clear_errors(Boolean clear_persistent) {
  // Clear the persistent errors if necessary
  if(clear_persistent) {
    flash_write_err_slave = false;
    flash_write_err       = false;
    ground_fault_err      = false;
    over_temp_err         = false;
    over_curr_err         = false;
    switch_err            = false;
    wdt_reset_err         = false;
  }
  // And clear all other errors 
  invld_cmd_err           = false;
  invld_param_err         = false;
  invld_cksum_err         = false;
  slv_cmd_err             = false;
}


// Purpose: If the slave isn't on, this routine turns it on and leaves it on
void check_slave_on() {
	if(!slave_is_on) {
    output_bit(PIN_B4, HI); // Turn on slave processor
    slave_is_on = true;
		delay_ms(85);           // Time for slave to boot up and initialize ~ 80 msec    
	}
}


// Purpose: Removes power from the slave if the load is off
void check_slave_off() {
	if(!load_is_on) {
   	output_bit(PIN_B4, LO); 
  	slave_is_on = false;   	
	}
}


// Purpose: This routine gets called once per cycle to add in any errors 
//          that the slave may have detected. 
void calculate_errors() {
  //Calculate error bytes for the master
  error_status =(
                (flash_write_err_slave << 10) |
                (flash_write_err   << 9) |
                (ground_fault_err  << 8) |
                (over_temp_err     << 7) |
                (over_curr_err     << 6) |
                (switch_err        << 5) |
                (invld_cmd_err     << 4) |
                (invld_param_err   << 3) |
                (invld_cksum_err   << 2) |
                (wdt_reset_err     << 1) |
                (slv_cmd_err       )
                );
                	
// Get any slave errors	
	if(slave_is_on) {
    spi_write(80);                
    delay_ms(50);     //Takes approx 32 msec to complete transaction
  
    // Get repsonse from slave
    SPI_strread(received_spi_data_mastr);

    // Verify that we got some sort of number back
    if(strlen(received_spi_data_mastr) > 3) {
      slave_errors = strtoul(received_spi_data_mastr,null,16);
    }
    else {
    	//*** DEBUG set some error here TBD
    }

    // Then OR with the master errors
    error_status |= slave_errors;
  }
}

// Purpose: Calculates overcurrent thresholds as read out by the A/D
//          and stores them in globals
#SEPARATE
void calc_adc_val_nominal() {
  overcurrent_adc_val = ( (((((((int32)steady_oc_threshold * (int32)RSENSE) * (int32)CURRDIVISOR) + (((int32)VREF / 2) * 1000)) / VREF) * 1023) / 1000) );
}

// Purpose: Calculates overcurrent thresholds as read out by the A/D
//          and stores them in globals
#SEPARATE
void calc_adc_val_startup() {
  overcurrent_adc_val_startup = ( (((((((int32)startup_oc_threshold * (int32)RSENSE) * (int32)CURRDIVISOR) + (((int32)VREF / 2) * 1000)) / VREF) * 1023) / 1000) );
}


// Purpose: Holds software in infinite loop to allow watchdog to reset
#SEPARATE
void software_reset() {
  for(;;) {
    null;
  }
}

// Purpose: Removes and re-applies power to the islolated controller
#SEPARATE
void slave_reset() {
  output_bit(PIN_B4, LO); // Turn off PIC  
  delay_ms(1000);
  output_bit(PIN_B4, HI); // Turn on PIC  
}

// Purpose: Initialization for elements common to both PICs
#SEPARATE
void initializeLC() {
  // Set up the system clocks and watchdog
  setup_wdt(WDT_288MS); // See fuses WDT also
  
  // Using timer 1 for "real time" ground fault detection interrupts
  setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); 
}

// External interrupt does nothing (currently) to simply return execution back to where it
// left off after the sleep() command
//#INT_EXT
//void ext_isr() {
//	null;
//}


// Purpose: Initialization for the Master (non-iso) PIC
#SEPARATE
void initializeMaster() {  
  // Initialize Outputs/Inputs
  set_tris_a(0x0F); // Pins A3-A0 inputs. Pins A5-A4 outputs
  set_tris_b(0xC1); // Pins B7, B6, B0 inputs. Pins B5, B4, B3, B2, B1 outputs
  set_tris_c(0x93); // Pins C7, C4, C1, C0 inputs. Pins C6, C5, C3, C2 outputs

  // Set outputs low
  output_bit(PIN_A4, LO);
  output_bit(PIN_A5, LO);
  output_bit(PIN_B1, LO);
  output_bit(PIN_B2, LO);
  output_bit(PIN_B3, LO);
  output_bit(PIN_B4, LO);
  output_bit(PIN_B5, LO);
	output_bit(PIN_C2, LO);
	output_bit(PIN_C3, LO);
  output_bit(PIN_C5, LO);
	output_bit(PIN_C6, LO);  

  // Initialize Serial and enable interrupts
  rs485_init();

//  // Setup interrupt for wakeup from sleep //*** DEBUG
//  ext_int_edge(H_TO_L);       
//  enable_interrupts(INT_EXT); // turn on interrupt
    
  // Initialize SPI bus
  SETUP_SPI(SPI_SS_DISABLED | SPI_MASTER | SPI_L_TO_H); 

  // Set up analog input for AN0 and AN1
  setup_adc(ADC_CLOCK_INTERNAL);
  setup_adc_ports(AN0_AN1_VREF_VREF); // A0 A1 VRef+=A3 VRef-=A2


  // Check for parameters stored in data EEPROM and
  // initialze from there if set
  if( read_eeprom(EE_eeprom_written) == 0x99 ) {
  	startup_oc_threshold = read_eeprom16(EE_startup_oc_threshold);
    steady_oc_threshold = read_eeprom16(EE_steady_oc_threshold);
    startup_oc_time = read_eeprom16(EE_startup_oc_time);
    RS485_ID = read_eeprom(EE_RS485_ID);
    relay_status_closed = read_eeprom(EE_relay_status_closed);     
    
    sprintf(response_message, "use EE\r\n"); //*** DEBUG
    send_response(response_message);    	   //*** DEBUG
  }
  else { // Write the interface parameters to flash for the first time
    write_eeprom16(EE_startup_oc_threshold, startup_oc_threshold);
    write_eeprom16(EE_steady_oc_threshold, steady_oc_threshold);
    write_eeprom16(EE_startup_oc_time, startup_oc_time);
    write_eeprom16(EE_RS485_ID, RS485_ID);
    write_eeprom16(EE_relay_status_closed, relay_status_closed);

    // Now read it back just to be sure...
    if( (startup_oc_threshold != read_eeprom16(EE_startup_oc_threshold)) ||
        (steady_oc_threshold != read_eeprom16(EE_steady_oc_threshold))   ||
        (startup_oc_time != read_eeprom16(EE_startup_oc_time))           ||
        (RS485_ID != read_eeprom(EE_RS485_ID))                           ||
        (relay_status_closed != read_eeprom(EE_relay_status_closed)) ) {
      // There was an error. Set the error bit and 
      // don't initialize from flash on boot
      flash_write_err = true;
    }
    else {
      // Write "secret code" in order to initialize 
      // parameters from flash upon boot next time
      eeprom_written = 0x99; // set to 10011001 (or 0x99) for safety
      write_eeprom8(EE_eeprom_written, eeprom_written);
    }  	
  }

  // Always initialize the comms relays to a known state. 
  if(relay_status_closed) {
    output_bit(PIN_B2, HI); 
    delay_ms(8);           // Hold time for latching relay
    output_bit(PIN_B2, LO);   	
  }
  // circuit is set open
  else {
    output_bit(PIN_B1, HI); 
    delay_ms(8);           // Hold time for latching relay
    output_bit(PIN_B1, LO);   	
  }


  // Check for WDT reboot
  if(wdt_reset) {
    // Set error bit for next transmission
    wdt_reset_err = true;
    
    //*** DEBUG - to be removed. Should interface spec include "alphabet soup" on power up?
    sprintf(response_message, "MBARI Load Controller v1.0\r\n");
    send_response(response_message);  
    sprintf(response_message, "Enter Command\r\n");
    send_response(response_message);
    //*** DEBUG    
  }  
  else {
  //*** DEBUG - to be removed. Should interface spec include "alphabet soup" on power up?
  sprintf(response_message, "MBARI Load Controller v1.0\r\n");
  send_response(response_message);  
  sprintf(response_message, "Enter Command\r\n");
  send_response(response_message);
  //*** DEBUG
  }	
	
}

// Purpose: Initialization for the Slave (iso) PIC
#SEPARATE
void initializeSlave() {

  // Initialize SPI bus. SS_DISABLED since A5 is potentially a high input.
  // See Document: DS39582B-page 71 for more info
  SETUP_SPI(SPI_SS_DISABLED | SPI_SLAVE | SPI_L_TO_H); 

  // Initialize Outputs/Inputs
  set_tris_a(0x2F); // Pins A5, A3, A2, A1, A0 inputs. Pin A4 output
  set_tris_b(0xC0); // Pins B7, B6 inputs. Pins B5, B4, B3, B2, B1, B0 outputs.
  set_tris_c(0x19); // Pins C4, C3, C0 inputs. Pins C7, C6, C5, C2, C1 outputs.

  // Set outputs low
  output_bit(PIN_A4, LO);
  output_bit(PIN_B5, LO);
  output_bit(PIN_B4, LO);
  output_bit(PIN_B3, LO);
  output_bit(PIN_B2, LO);
  output_bit(PIN_B1, LO);
  output_bit(PIN_B0, LO);
	output_bit(PIN_C1, LO);
	output_bit(PIN_C2, LO);
	output_bit(PIN_C5, LO);	
  output_bit(PIN_C6, LO);
  output_bit(PIN_C7, LO);
    
  // Set up analog input for AN0, AN1, AN5
  setup_adc(ADC_CLOCK_INTERNAL);
  setup_adc_ports(AN0_AN1_AN4_VREF_VREF); // A0 A1 A5 VRef+=A3 VRef-=A2  
  
  // Check for parameters stored in data EEPROM and
  // initialze from there if set
  if( read_eeprom(EE_eeprom_written) == 0x99 ) {
  	startup_oc_threshold = read_eeprom16(EE_startup_oc_threshold);
    steady_oc_threshold = read_eeprom16(EE_steady_oc_threshold);
    startup_oc_time = read_eeprom16(EE_startup_oc_time);
  }
  else { // Write the interface parameters to flash for the first time
    write_eeprom16(EE_startup_oc_threshold, startup_oc_threshold);
    write_eeprom16(EE_steady_oc_threshold, steady_oc_threshold);
    write_eeprom16(EE_startup_oc_time, startup_oc_time);

    // Now read it back just to be sure...
    if( (startup_oc_threshold != read_eeprom16(EE_startup_oc_threshold)) ||
        (steady_oc_threshold != read_eeprom16(EE_steady_oc_threshold))   ||
        (startup_oc_time != read_eeprom16(EE_startup_oc_time)) ) {    
      // There was an error. Set the error bit and 
      // don't initialize from flash on boot
      flash_write_err_slave = true;
    }
    else {
      // Write "secret code" in order to initialize 
      // parameters from flash upon boot next time
      eeprom_written = 0x99; // set to 10011001 (or 0x99) for safety
      write_eeprom8(EE_eeprom_written, eeprom_written);
    }  	
  }

  // Set ADC allowable maximum
  calc_adc_val_nominal();
  calc_adc_val_startup();

  // Set interrupt masking
  enable_interrupts(GLOBAL);
  disable_interrupts(INT_AD);    //disables A/D interrupt
  enable_interrupts(INT_TIMER1); // fires up the timer interrupt

  // Check for WDT reboot
  if(wdt_reset) {
    // Set error bit
    wdt_reset_err = true;
  }
      
}


// Purpose: Main control loop for Master (non-iso) PIC
#SEPARATE
void mainMaster() {

  // Initialize the PIC
  initializeMaster();

  /* Begin Loop */        
  for(;;)
	{ 
	  // strobe the dog
	  restart_wdt(); 
	
	  // Check for new RS485 command
 		if(rs485_get_new_message(false)) 
	 	{
	    cmd_received = true;
            
	 	  // Check to see which command was received...
	 	  // And call associated handler
      if(!strcmp(commandStr,load_power)) {
        handle_load_power();
      }
      else if(!strcmp(commandStr,comm_relay)) {
     	  handle_comm_relay();
      }  
      else if(!strcmp(commandStr,sleep_enable)) {
     	  handle_sleep_enable();
      }
      else if(!strcmp(commandStr,read_bus_voltage)) {
     	  handle_read_bus_voltage();
      }  
      else if(!strcmp(commandStr,read_load_voltage)) {
     	  handle_read_load_voltage();
      }
      else if(!strcmp(commandStr,read_bus_current)) {
     	  handle_read_bus_current();
      }      
      else if(!strcmp(commandStr,read_load_current)) {
     	  handle_read_load_current();
      }  
      else if(!strcmp(commandStr,read_gf_current)) {
     	  handle_read_gf_current();
      }
      else if(!strcmp(commandStr,read_startup_oc_threshold)) {
     	  handle_read_startup_oc_threshold();
      }  
      else if(!strcmp(commandStr,read_q_oc_threshold)) {
     	  handle_read_q_oc_threshold();
      }
      else if(!strcmp(commandStr,read_startup_oc_time)) {
     	  handle_read_startup_oc_time();
      }  
      else if(!strcmp(commandStr,read_comm_realy_status)) {
     	  handle_read_comm_realy_status();
      }
      else if(!strcmp(commandStr,read_device_serial_number)) {
     	  handle_read_device_serial_number();
      }  
      else if(!strcmp(commandStr,read_version)) {
     	  handle_sw_version();
      }
      else if(!strcmp(commandStr,oc_threshold_startup)) {
     	  handle_oc_threshold_startup();
      }  
      else if(!strcmp(commandStr,oc_threshold_q)) {
     	  handle_oc_threshold_q();
      }
      else if(!strcmp(commandStr,oc_time_startup)) {
     	  handle_oc_time_startup();
      }  
      else if(!strcmp(commandStr,set_address)) {
     	  handle_set_address();
      }                                         
      //...Or if the command is invalid
      else { 
      	// Send a command error
  	    invld_cmd_err = true;
  	    send_485_response(empty_string[0]);
        // wait for a new command
        cmd_received = false;
      }
		}	// Check for new command
		
	  //*** DEBUG - The rest of the functionality (e.g. BIT) goes here	  
    

  
  } // Close of main control loop
	
}


// Purpose: Main control loop for Slave (iso) PIC
#SEPARATE
void mainSlave() {
  int8 spi_cmd_buff[1] = {28};
  char sent_spi_data_slave[MAX_SPI_CHARS];
  char received_spi_data_slave[MAX_SPI_CHARS]; // *** DEBUG
  
  // Initialize the PIC
  initializeSlave();
 
  output_bit(PIN_C1, HI); // *** DEBUG
 
  // Begin the main loop. 
  // This loop waits for a SPI bus command from the Master
  for(;;) {
  	
    // strobe the dog
	  restart_wdt(); 

    // Check for new SPI command
    if( spi_data_is_in() ) {
    	spi_cmd_buff[0] = spi_read(); 

      // Handle Read GF Currents
      // Chan 0
      if( spi_cmd_buff[0] == 1 ) {
        set_adc_channel(1);	
        output_bit(PIN_B1, HI);  // Switch GF channel on
        delay_ms(1);             // Rise time to AN1 ~ .25 msec
        do_adc_current_calcs(VREF, GF_VSCALE, GF_RSENSE, CURRDIVISOR); // Calculate current
        output_bit(PIN_B1, LO);  // Switch GF channel off
        sprintf(sent_spi_data_slave, "GF0:%Lu",adc_value_glob);     // Send back the results
        SPI_strwrite(sent_spi_data_slave);  	              
    	} 
      // Chan 1    	
      else if( spi_cmd_buff[0] == 2 ) {
        set_adc_channel(1);	
        output_bit(PIN_B2, HI);  // Switch GF channel on
        delay_ms(1);             // Rise time to AN1 ~ .25 msec
        do_adc_current_calcs(VREF, GF_VSCALE, GF_RSENSE, CURRDIVISOR); // Calculate current
        output_bit(PIN_B2, LO);  // Switch GF channel off

        sprintf(sent_spi_data_slave, "GF1:%Lu",adc_value_glob);     // Send back the results
        SPI_strwrite(sent_spi_data_slave);       		
    	}     	
    	// Chan 2
    	else if( spi_cmd_buff[0] == 3 ) {  
        set_adc_channel(1);	
        output_bit(PIN_B3, HI);  // Switch GF channel on
        delay_ms(1);             // Rise time to AN1 ~ .25 msec
        do_adc_current_calcs(VREF, GF_VSCALE, GF_RSENSE, CURRDIVISOR); // Calculate current
        output_bit(PIN_B3, LO);  // Switch GF channel off

        sprintf(sent_spi_data_slave, "GF2:%Lu",adc_value_glob);     // Send back the results
        SPI_strwrite(sent_spi_data_slave);            		
    	}
    	// Chan 3
    	else if( spi_cmd_buff[0] == 4 ) {
        set_adc_channel(1);	
        output_bit(PIN_B4, HI);  // Switch GF channel on
        delay_ms(1);             // Rise time to AN1 ~ .25 msec
        do_adc_current_calcs(VREF, GF_VSCALE, GF_RSENSE, CURRDIVISOR); // Calculate current
        output_bit(PIN_B4, LO);  // Switch GF channel off

        sprintf(sent_spi_data_slave, "GF3:%Lu",adc_value_glob);     // Send back the results
        SPI_strwrite(sent_spi_data_slave); 		
    	}
    	// End of Ground Faults
    	
      // Handle Load voltage
      else if( spi_cmd_buff[0] == 50 ) {
        set_adc_channel(0);	
        do_adc_voltage_calcs(12);
 	      sprintf(sent_spi_data_slave, "%5.3w",adc_value_glob); 
        SPI_strwrite(sent_spi_data_slave);    	
    	}    	

    	// Handle Load current
    	else if( spi_cmd_buff[0] == 51 ) {
        set_adc_channel(4);	                                     // Set A/D channel
        do_adc_current_calcs(VREF, VREF, RSENSE, CURRDIVISOR);   // Calculate current. In this case, VREF == VSCALE
      //***DEBUG  sprintf(sent_spi_data_slave, "%Lu",adc_value_glob);      // Send back the results
      sprintf(sent_spi_data_slave, "%5.3w",adc_value_glob);      // Send back the results
        SPI_strwrite(sent_spi_data_slave);  		
    	}
    	
    	// Set Thresholds
    	// Startup Overcurrent Threshold
    	else if( spi_cmd_buff[0] == 60 ) {
        SPI_slave_strread(received_spi_data_slave); // Get the parameter
        startup_oc_threshold = atoi32(received_spi_data_slave);        

        sprintf(sent_spi_data_slave, "%Lu",startup_oc_threshold); // Send back the results
        SPI_strwrite(sent_spi_data_slave);  		
        calc_adc_val_startup(); // Calculate the maximum allowed ADC output for current checking
    
        // Save the parameter to flash
        write_eeprom16(EE_startup_oc_threshold, startup_oc_threshold);
        // Now read it back just to be sure...
        if( (startup_oc_threshold != read_eeprom16(EE_startup_oc_threshold)) ) {    
          // There was an error.
          flash_write_err_slave = true;
        }        
    	}    	
    	// Overcurrent Threshold Nominal
    	else if( spi_cmd_buff[0] == 61 ) {
        SPI_slave_strread(received_spi_data_slave); // Get the parameter
        steady_oc_threshold = atoi32(received_spi_data_slave);
        
        sprintf(sent_spi_data_slave, "%Lu",steady_oc_threshold); // Send back the results
        SPI_strwrite(sent_spi_data_slave);  	
        calc_adc_val_nominal(); // Calculate the maximum allowed ADC output for current checking

        // Save the parameter to flash
        write_eeprom16(EE_steady_oc_threshold, steady_oc_threshold);
        // Now read it back just to be sure...
        if( (steady_oc_threshold != read_eeprom16(EE_steady_oc_threshold)) ) {    
          // There was an error.
          flash_write_err_slave = true;
        }        
    	} 
    	// Startup Overcurrent Time
    	else if( spi_cmd_buff[0] == 62 ) {
        SPI_slave_strread(received_spi_data_slave); // Get the parameter
        startup_oc_time = atoi32(received_spi_data_slave);
        
        sprintf(sent_spi_data_slave, "%Lu",startup_oc_time); // Send back the results
        SPI_strwrite(sent_spi_data_slave);  		

        // Save the parameter to flash
        write_eeprom16(EE_startup_oc_time, startup_oc_time);
        // Now read it back just to be sure...
        if( (startup_oc_time != read_eeprom16(EE_startup_oc_time)) ) {    
          // There was an error.
          flash_write_err_slave = true;
        }               
    	} 
    	// Load Control 
    	// Load power off
    	else if( spi_cmd_buff[0] == 70 ) {
        output_bit(PIN_B5, LO); // Turn off load
    //    disable_interrupts(INT_TIMER1); // fires up the timer interrupt
        sprintf(sent_spi_data_slave, "%u",spi_cmd_buff[0]); // Send back the results
        SPI_strwrite(sent_spi_data_slave);  		
    	}    	
     	// Load power on
    	else if( spi_cmd_buff[0] == 71 ) {
        output_bit(PIN_B5, HI); // Turn on load
    //    enable_interrupts(INT_TIMER1); // fires up the overcurrent interrupt. A/D gives very high reading when load power is off since there's no ref voltage
        sprintf(sent_spi_data_slave, "%u",spi_cmd_buff[0]); // Send back the results
        SPI_strwrite(sent_spi_data_slave);  		
    	}
    	// Error notification
    	// Get Errors
    	else if( spi_cmd_buff[0] == 80 ) {
        //Calculate error bytes
        error_status =(
                      (flash_write_err   << 9) |
                      (ground_fault_err  << 8) |
                      (over_temp_err     << 7) |
                      (over_curr_err     << 6) |
                      (switch_err        << 5) |
                      (invld_cmd_err     << 4) |
                      (invld_param_err   << 3) |
                      (invld_cksum_err   << 2) |
                      (wdt_reset_err     << 1) |
                      (slv_cmd_err       )
                      );
        sprintf(sent_spi_data_slave, "%LX",error_status); // Send back the results
        SPI_strwrite(sent_spi_data_slave);          	
    	}    	
    	// Clear Errors
    	else if( spi_cmd_buff[0] == 81 ) {
        clear_errors(true); //Clear all errors including persistent
        
        sprintf(sent_spi_data_slave, "%u",spi_cmd_buff[0]); // Send back the results
        SPI_strwrite(sent_spi_data_slave);  		      	
    	}    	
    	    	
    }	// End spi_data_is_in

  } // End main "slave" loop
}



//
// Main execution loop.
//
#SEPARATE
main()
{
  // Check for WDT reset and output error if necessary
  switch ( restart_cause() )
  {
  	case WDT_FROM_SLEEP:
    case WDT_TIMEOUT:
    {
      wdt_reset = true;
      break;
    }
    case NORMAL_POWER_UP:
    {
    	wdt_reset = false;
      break;
    }
  }     

  // Run initialization common to both PICs
  initializeLC();

  // Determine if controller is master or slave
  if(input(PIN_C0) ) { 
  	master = false;
    mainSlave();
  }
  else {
  	mainMaster();
  }

  //
  // If we execute here, there has been a critical failure. Log error and reset the board
  //
  
  // log error here
  
  software_reset();  

}





