// Rover Wakey v1.3.0 - Rover Sleep Controller
// Controls power supplies to shut down and wake up PC-104 stack.
// Runs on a PIC16F886 with a 4 MHz main crystal and a 32,768 Hz
// crystal on the Timer1 oscillator.
//
// Compiled with Microchip XC8 v1.33
// The following routines are unique to XC8 and must be replaced if a different
// compiler is used:
// __CONFIG()
// __delay_ms()
// eeprom_read()
// eeprom_write()
// CLRWDT()
// di()
// ei()
//
// Version History
// v1.3.0   Added accessor functions to read and clear gAwakeSecs
// v1.2.0   Added timeout to sleep after too many minutes awake
// v1.1.0   Added code to wake from sleep when modem pulls RB0 low
// v1.0.0   Intitial release based on SES Wakey code - prm



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <xc.h>		// register definitions for this PIC
#include "intserial.h"	// hardware serial I/O routines
#include "adc.h"        // analog-to-digital converter routines
//#include "spi.h"

//__CONFIG(FOSC_HS & WDTE_ON & PWRTE_OFF & MCLRE_OFF & LVP_OFF & CPD_OFF & BOREN_OFF & DEBUG_ON);
#pragma config "FOSC=HS", "WDTE=ON", "PWRTE=OFF", "MCLRE=OFF"
#pragma config "LVP=OFF", "CP=OFF", "BOREN=OFF", "DEBUG=OFF"

#define _XTAL_FREQ 4000000  // must define for delay function to work
#define SER_BUFSIZE 16      // serial command buffer size
#define CR  0x0D            // carriage return
#define LF  0x0A            // line feed
#define BS  0x08            // back space

#define TMR1DLY 32768   // Timer1 delay value, 1 sec with 32,768 Hz crystal
                        //  and divide-by-1 prescaler
#define BATTV   0       // adc channel assignments
#define LHVMON  1
#define RHVMON  2




//
//
//#define RSTRBTRG    RA3
//#define LSTRBTRG    RA4

//#define INHIBIT5V   RB1 // digital output channel assignments

#define ENABLE7V    RB1 // digital output channel assignments
#define ENABLEDIV   RB2
#define RSTRBCHG    RB3
#define RSTRTRIG    RA3
#define LSTRTRIG    RA4
#define LSTRBCHG    RB4
#define FIRESHTR    RB5
#define NFIRESHTR   RA5 // Fire the Near camera shutter

#define SERNOADD    0   // EEPROM address of board serial number
#define VCALADD     1   // EEPROM address of voltage calibration

#define TRUE    1
#define FALSE   0

#define FFCAM  0x01
#define NFCAM  0x02

enum {RESETOK, RESETWD, WAKEOK, WAKEWD, MODEM, TIMEOUT};    // Cause for last reset or wake
struct cmd_s
{
    const char code;
    void (*func)(void);
};

enum CMD_CODES
{
    MENU = 0,
    SLEEP,
    SETSLEEP,
    READSLEEP,
    READWAKE,
    SETDELAY,
    READDELAY,
    SETTIMEOUT,
    READTIMEOUT,
    CAMERAON,
    CAMERAOFF,
    READ7V,
    SETBATT,
    READBATT,
    READRVOLT,
    READLVOLT,
    CHGRSTROBE,
    CHGLSTROBE,
    RSTROBEON,
    RSTROBEOFF,
    LSTROBEON,
    LSTROBEOFF,
    TRIGRSTROBE,
    TRIGLSTROBE,
    TRIGSHUTTER,
    TRIGNFSHUTTER,
    SNAP,
    SNAPNF,
    SETSERNO,
    READSERNO,
    LAST_CMD
};

// Function prototypes
//
void sleep(void);
void setSleep(void);
void setDelay(void);
void setTimeout(void);
void readSleep(void);
void readDelay(void);
void readTimeout(void);
void set7vOn(void);
void set7vOff(void);
void cameraOn(void) {set7vOn();}
void cameraOff(void) {set7vOff();}
void read7v(void);
void setBatt(void);
void readBatt(void);
void readLVmon(void);
void readRVmon(void);
void rStrobeOff(void);
void chgRStrobe(void);
void rStrobeOn (void);
void lStrobeOn(void);
void chgLStrobe(void);
void lStrobeOff(void);
void trigRStrobe(void);
void trigLStrobe(void);
void trigShutter(char cams);
void trigFF(void) {trigShutter(FFCAM);}
void trigNF(void) {trigShutter(NFCAM);}
void takeTestImage(char cams);
void snapFF(void) {takeTestImage(FFCAM);}
void snapNF(void) {takeTestImage(NFCAM);}
void readWake(void);
void setSerno(void);
void readSerno(void);
void help(void);
void testMenu(void);
void setEpochSecs(char y, char mon, char d, char h, char min, char s, char dst);
time_t getEpochSecs(void);
void setInterval(void);
void readInterval(void);
void setChargeTime(void);
void readChargeTime(void);
unsigned int getAwakeSecs(void);
void clrAwakeSecs(void);

void timerSetup(void);
void interrupt isr(void);

static const char* hints[] =
{
    "Print menu",
    "Sleep after delay",  
    "Set sleep time",     
    "Read sleep time",    
    "Read reason for latest wakeup",
    "Set delay time before sleep",
    "Read delay time",    
    "Set max awake time", 
    "Read max awake time",
    "Turn camera on",        
    "Turn camera off",       
    "Read the camera power", 
    "Set battery calibration",      
    "Read battery voltage",  
    "Read right strobe voltage",    
    "Read left strobe voltage",     
    "Charge right strobe",          
    "Charge left strobe",    
    "Turn right strobe on",  
    "Turn right strobe off", 
    "Turn left strobe on",   
    "Turn left strobe off",  
    "Trigger right strobe",  
    "Trigger left strobe",   
    "Trigger far-field shutter",    
    "Trigger near-field shutter",   
    "Snap far-field cam", 
    "Snap near-field cam",
    "Set serial #",
    "Read serial #"
};

static struct cmd_s cmds[] = 
{
    {MENU,          &testMenu},
    {SLEEP,         &sleep},
    {SETSLEEP,      &setSleep},
    {READSLEEP,     &readSleep},
    {READWAKE,      &readWake},
    {SETDELAY,      &setDelay},
    {READDELAY,     &readDelay},
    {SETTIMEOUT,    &setTimeout},
    {READTIMEOUT,   &readTimeout},
    {CAMERAON,      &cameraOn},
    {CAMERAOFF,     &cameraOff},
    {READ7V,        &read7v},
    {SETBATT,       &setBatt},
    {READBATT,      &readBatt},
    {READRVOLT,     &readRVmon},
    {READLVOLT,     &readLVmon},
    {CHGRSTROBE,    &chgRStrobe},
    {CHGLSTROBE,    &chgLStrobe},
    {RSTROBEON,     &rStrobeOn},
    {RSTROBEOFF,    &rStrobeOff},
    {LSTROBEON,     &lStrobeOn},
    {LSTROBEOFF,    &lStrobeOff},
    {TRIGRSTROBE,   &trigRStrobe},
    {TRIGLSTROBE,   &trigLStrobe},
    {TRIGSHUTTER,   &trigFF},
    {TRIGNFSHUTTER, &trigNF},
    {SNAP,          &snapFF},
    {SNAPNF,        &snapNF},
    {SETSERNO,      &setSerno},
    {READSERNO,     &readSerno}
};

// Deployment parameters
struct DeployParams {
    char   intervalMins;   // Minutes between each images
    char   chargeSecs;     // Seconds to charge the strobes
    char   delaySecs;      // Seconds to delay before starting deployment
    time_t startTime;      // Epoch time
};

// Global vars
volatile time_t gEpochSecs   = 0; // Store epoch seconds from user-supplied time
unsigned int    gSleepMins   = 1; // number of minutes to sleep
unsigned int    gDelaySecs   = 0; // number of seconds to wait before sleeping
unsigned int    gTimeoutMins = 0; // max time awake before going back to sleep

char            g7VOn;            // status of 7 V power supply
char            gWakeCause;       // reason for last reset or wakeup
volatile unsigned int gAwakeSecs; // number of seconds elapsed since wakeup

struct DeployParams gDeployParams = {60, 30, 0, 0};

char isCmd(const char *cmdString)
{
    if (!isdigit(cmdString[0])) return 0;
    
    char cmdCode = atoi(cmdString);
    if (cmdCode < LAST_CMD)
    {
        printf("\r\nMatch to %s\r\n", hints[cmdCode]);
        return LAST_CMD; // cmdCode;
    }
    
    return LAST_CMD;
}

// The main loop waits for serial input commands, parses them, and calls the
// appropriate routine.
void main(void) {
    
    extern bit __timeout;   // timeout bit in status reg saved by c startup code
    unsigned char   i;      // index for command buffer
    unsigned char   inChar; // input char for command buffer
    unsigned char   cmdBuf[SER_BUFSIZE];    // command buffer

    // The first thing we do after reset is save the reason for the reset.
    // In XC8, the __timeout bit is a shadow of the nTO bit in the
    // status register, and is only valid if the compiler option
    // --RUNTIME=resetbits is set. To set this in the MPLABX IDE, go to the menu
    // File -> Project Properties… -> Conf: [default] -> XC8 global options ->
    // XC8 Linker and check the "Backup reset condition flags" option.

    gWakeCause = (__timeout ? RESETOK : RESETWD); // save reason for reset
    CLRWDT();               // clear watchdog timer
    WDTCON = 0x17;          // set watchdog timer to timeout after 2.1 seconds
    OPTION_REG = 0xF8;      // don't use timer0 prescaler

    // All unused I/O port pins must be set as output to prevent floating
    // high-impedance inputs from drawing too much current in sleep mode.
    // Note that the serial setup routine will set SREN = 1 and make the
    // serial receive pin RC7 an input. The timer setup routine will set
    // T1OSCEN = 1 and make the timer1 oscillator bits RC0 and RC1 inputs.
    TRISA = 0x07;           // make all porta pins except RA0 outputs
    ANSEL = 0x07;           // make all porta pins except RA0 digital
    TRISB = 0x01;           // make all portb pins except RB0 outputs
    ANSELH = 0x00;          // make all portb pins digital
    TRISC = 0x00;           // make all portc pins outputs
    PORTA = 0;              // set all pins low
    PORTB = 0;
    PORTC = 0;

   // INHIBIT5V = FALSE;    // turn 5V power supply ON
    __delay_ms(100);        // wait for power supply to stabilize
  
    g7VOn = FALSE;

    di();                   // disable all interrupts
    clrAwakeSecs();         // start counting number of seconds awake
    timerSetup();          // set up timer
    serial_setup();         // set up the USART - settings defined in intserial.h
    adc_setup();            // set up ADC
    ei();                   // enable all interrupts

    printf("\r\nRover Wakey v1.3.0\r\n");
    while(1) { // main loop
        i = 0;
        inChar = NULL;
        printf("\r\n> ");   // print prompt

        do {                // read chars until carriage return
            if(kbhit()) {               // if char has been received
                inChar = getch();       // get the char
                if(inChar == BS) {      // if char is a backspace
                    if(i > 0) {         //  and not at beginning of line
                        i--;
                        putch(inChar);  // erase last char
                        putch(' ');
                        putch(inChar);
                    } // end if
                } else {                // otherwise put in buffer
                    cmdBuf[i++] = inChar;
                    putch(inChar);      // and echo char
                } // end if
            } // end if
            CLRWDT();                   // clear watchdog timer while we wait
            
            
            // Check to see if we've been awake too long. If so, go to sleep
            // and when we wake back up, clear the command buffer and wait for
            // the next command.
            if(gTimeoutMins && (getAwakeSecs() >= gTimeoutMins * 60)) {
                printf("\r\nTimeout!");
                sleep();                // go back to sleep
                // Continue here after we wake from sleep. We return to the
                // prompt by executing a null command.
                gWakeCause = TIMEOUT;   // remember reason for wakeup
                i = 1;                  // clear command buffer
                break;                  // break out of do-while loop
            } // end if
        } while((inChar != CR) && (i < SER_BUFSIZE - 1));

        cmdBuf[i-1] = NULL;         // get rid of CR

        // parse and execute command
        //
        char code = 0;
        if(!cmdBuf[0]);     // empty command, do nothing

        else if (!strcmp(cmdBuf,"?")) testMenu();
        else if ((code = isCmd(cmdBuf)) < LAST_CMD) (*cmds[code].func)();
        
        else printf("\r\n%s is an invalid command.", cmdBuf);
    } // end while
} // end main


// Print test menu
void testMenu(void) {
    unsigned int j;
    printf("\r\nValid commands are:\r\n");
    for (j = 0; j < sizeof(cmds)/sizeof(struct cmd_s); j++)
    {
        printf("(%2d)  %s\r\n",
            cmds[j].code, hints[j]);
    }
} // end testMenu()


// Sleep in a low-power state
void sleep(void) {

    unsigned int secsElapsed;
    unsigned int secsToSleep;

    secsToSleep = (60 * gSleepMins);
    printf("\r\nSleeping %u %s...\r\n", gSleepMins,
            gSleepMins == 1 ? "minute" : "minutes");

    // delay before sleeping
    for(secsElapsed = 0; secsElapsed < gDelaySecs; secsElapsed++) {
        CLRWDT();
        __delay_ms(1000);
    } // end for
    
    while(!TRMT);   // wait for last printf to finish sending
    RCIE = 0;       // disable serial receive interrupts
    SPEN = 0;       // turn off TX output so it won't power MAX3232
    PORTA = 0;      // set all pins low (except for power supply inhibits)
    PORTB = 0x0;   // this turns off both power supplies
    PORTC = 0x04;
    INTEDG = 0;     // look for falling edge on modem wakeup input RB0
    INTF = 0;       // clear RB0 interrupt flag
    g7VOn = FALSE; // update status of 7V power supply
    TMR1ON = 0;     // stop timer1
    TMR1 = TMR1DLY; // load the timeout value
    TMR1ON = 1;     // start timer1
    TMR1IE = 1;     // enable timer1 interrupts
    PEIE = 1;       // enable peripheral interrupts
    di();           // disable global interrupts
    // sleep until time elapsed, or modem wakeup on RB0, or watchdog times out
    while((secsElapsed++ <= secsToSleep) && !INTF && nTO) {
        SLEEP();
        // sleep here until timer1 interrupt after 1 second
        // entering sleep will clear the watchdog timer
        // as soon as awake, reload timer1 and start counting the next second
        TMR1ON = 0;     // stop timer1
        TMR1 = TMR1DLY; // load the timeout value
        TMR1ON = 1;     // start timer1
        TMR1IF = 0;     // clear the timer1 interrupt flag
        gEpochSecs++;
    }; // end while
    clrAwakeSecs(); // start counting number of seconds awake
    ei();           // enable global interrupts

    // save the reason for wakeup here before the next CLRWDT() erases it
    if(INTF) gWakeCause = MODEM;            // if modem triggered wakeup line RB0
    else if(!nPD && nTO) gWakeCause = WAKEOK;   // or power-down sleep flag but not WD time-out
    else if(!nPD && !nTO) gWakeCause = WAKEWD;  // or power-down sleep flag and WD time-out

  //  INHIBIT5V = FALSE;  // turn 5V power supply ON
    __delay_ms(100);    // wait for power supply to stabilize
    serial_setup();     // reinitialize the USART
    printf("Awake!");
} // end sleep()


// Set the number of minutes to sleep
void setSleep(void) {

    unsigned int input;
    char inbuf[10];

    printf("\r\nEnter sleep time in minutes (1 - 1092): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input > 0 && input <= 1092) {
        gSleepMins = input;
        printf("\r\nSleep time set to %d %s\r\n", gSleepMins,
                gSleepMins == 1 ? "minute" : "minutes");
    } else {
        printf("\r\nInvalid time!\r\n");
    } // end if
} // end setSleep()


// Set the number of seconds to delay before sleeping
void setDelay(void) {

    int input;
    char inbuf[10];

    printf("\r\nEnter delay time in seconds (0 - 60): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input >= 0 && input <= 60) {
        gDeployParams.delaySecs = gDelaySecs = input;
        printf("\r\nDelay time set to %d %s\r\n", gDelaySecs,
                gDelaySecs == 1 ? "second" : "seconds");
    } else {
        printf("\r\nInvalid time!\r\n");
    } // end if
} // end setDelay()

// Set the max number of minutes to stay awake before sleeping
void setTimeout(void) {

    int input;
    char inbuf[10];

    printf("\r\nEnter timeout in minutes (1 - 1092, 0 for never): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input >= 0 && input <= 1092) {
        gTimeoutMins = input;
        printf("\r\nTimeout set to %d %s\r\n", gTimeoutMins,
                gTimeoutMins == 1 ? "minute" : "minutes");
        clrAwakeSecs(); // restart the timeout timer
    } else {
        printf("\r\nInvalid time!\r\n");
    } // end if
} // end setTimeout()


// Show how many minutes Wakey will sleep
void readSleep(void) {

    printf("\r\nSleep time is %u %s\r\n",gSleepMins,
            gSleepMins == 1 ? "minute" : "minutes");
} // end readSleep()


// Show how many seconds Wakey will delay before sleeping
void readDelay(void) {

    printf("\r\nDelay time is %u %s\r\n", gDelaySecs,
                gDelaySecs == 1 ? "second" : "seconds");
} // end readDelay()


// Show how many minutes before Wakey will time out and go back to sleep
void readTimeout(void) {
    printf("\r\nTimeout is %u %s\r\n",gTimeoutMins,
            gTimeoutMins == 1 ? "minute" : "minutes");
} // end readTimeout()


// Turn on the 7 V power supply
void set7vOn(void) {
    ENABLE7V = TRUE;        // turn 7V power supply ON
    g7VOn = TRUE;
    printf("\r\n7V is ON\r\n");
} // end set7vOn


// Turn off the 7 V power supply
void set7vOff(void) {

    ENABLE7V = FALSE;      // turn 7V power supply OFF
    g7VOn = FALSE;
    printf("\r\n7V is OFF\r\n");
} // end set12vOn

// Show the current state of the 7 V power supply
void read7v(void) {

    printf("\r\n7V is %s\r\n", (g7VOn ? "ON" : "OFF"));
} // end read7v()


// Set the interval between images for deployment
void setInterval(void)
{
    unsigned int input;
    char inbuf[10];

    printf("\r\nEnter interval time between images in minutes (1 - 1092): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input > 0 && input <= 1092) {
        gDeployParams.intervalMins = input;
        printf("\r\nInterval time set to %d %s\r\n", gDeployParams.intervalMins,
                input == 1 ? "minute" : "minutes");
    } else {
        printf("\r\nInvalid time!\r\n");
    } // end if

} // end setInterval

// Display the interval between images for deployment
void readInterval(void)
{
    printf("\r\nMinutes: %d\r\n", gDeployParams.intervalMins);
} // end setInterval

// Set the amount of time to charge the strobes
void setChargeTime(void)
{

    unsigned int input;
    char inbuf[10];

    printf("\r\nEnter the time to charge the strobes in seconds (1 - 80): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input > 0 && input <= 80) {
        gDeployParams.chargeSecs = input;
        printf("\r\nCharge time set to %d %s\r\n", gDeployParams.chargeSecs,
                input == 1 ? "second" : "seconds");
    } else {
        printf("\r\nInvalid time!\r\n");
    } // end if

} // setChargeTime

// SDisplay the amount of time to charge the strobes
void readChargeTime(void)
{
    printf("\r\nSeconds: %d\r\n", gDeployParams.chargeSecs);
} // setChargeTime

// Set the calibration for reading battery voltage
void setBatt(void) {
    unsigned int adcVal;
    unsigned int volts;
    unsigned int input;
    unsigned int gain;
    char inbuf[10];

    printf("\r\nEnter actual input voltage in decivolts (200 - 320, 0 to abort): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input >= 200 && input <= 320) {
        volts = input;          // save the actual voltage
        TRISA = 0x01;           // set up ADC input pin to read battery voltage
        ANSEL = 0x01;
        ENABLEDIV = TRUE;       // turn on voltage divider
        __delay_ms(100);        // wait for divider capacitor to charge
        adcVal = adc_read(BATTV); // read the ADC value
        ENABLEDIV = FALSE;      // turn off voltage divider
        gain = volts * 1000L / adcVal;   // calculate the gain

        // save gain calibration to EEPROM
        eeprom_write(VCALADD, (unsigned char) (gain >> 8));
        eeprom_write(VCALADD+1, (unsigned char) (gain & 0x00ff));
        printf("\r\nGain value of %u saved to EEPROM\r\n", gain);
    } else {
        printf("\r\nInvalid voltage!\r\n");
    } // end if

} // end setBatt()


// Read the battery voltage on Wakey's power input
void readBatt(void) {
    unsigned int adcVal;
    unsigned int decivolts;
    unsigned long gain;

    // retrieve the voltage calibration from EEPROM
    gain = (eeprom_read(VCALADD) << 8) + eeprom_read(VCALADD+1);

    TRISA = 0x01;           // set up the ADC input pin
    ANSEL = 0x01;
    ENABLEDIV = TRUE;       // turn on voltage divider
    __delay_ms(100);        // wait for divider capacitor to charge
    adcVal = adc_read(BATTV); // read the divider voltage
    ENABLEDIV = FALSE;      // turn off voltage divider
    
    // This calculation will result in decivolts, or volts x 10
    decivolts = (unsigned int) (((adcVal * gain) + 500) / 1000); // convert to voltage
    printf("\r\n%u.%u\r\n", decivolts / 10, decivolts % 10);
} // end readBatt()

void readLVmon(void){
    unsigned int adcVal;
    unsigned int volts;
    unsigned long gain;

    // retrieve the voltage calibration from EEPROM
    gain = 48;              // in 100*(volts/count)

    TRISA = 0x07;           // set up the ADC input pin
    ANSEL = 0x07;
    adcVal = adc_read(LHVMON); // read the divider voltage
    
    // This calculation will result in decivolts, or volts x 10
    volts = (unsigned int) (((adcVal * gain) + 50) / 100); // convert to voltage
    printf("\r\n%u\r\n", volts );
}

void readRVmon(void){
    unsigned int adcVal;
    unsigned int volts;
    unsigned long gain;

    // retrieve the voltage calibration from EEPROM
    gain = 48;              // in 100*(volts/count)

    TRISA = 0x07;           // set up the ADC input pin
    ANSEL = 0x07;
    adcVal = adc_read(RHVMON); // read the divider voltage
    
    // This calculation will result in decivolts, or volts x 10
    volts = (unsigned int) (((adcVal * gain) + 50) / 100); // convert to voltage
    printf("\r\n%u\r\n", volts );
}

void rStrobeOn (void){
    RSTRBCHG = TRUE;      // charge right strobe
    printf("\r\nRight Strobe On\r\n");
}

void chgRStrobe (void){
    //declare charge time 
    unsigned int secsElapsed;
    
    rStrobeOn();

    printf("\r\nRight Strobe Charging for %d seconds...\r\n",
           gDeployParams.chargeSecs);
    for(secsElapsed = 0; secsElapsed < gDeployParams.chargeSecs; secsElapsed++) {
        CLRWDT();
        __delay_ms(1000);
    } // end for
    printf("\r\nRight Strobe Charged\r\n");
   
    rStrobeOff();
};

void rStrobeOff (void){
    RSTRBCHG = FALSE;
    printf("\r\nRight Strobe Off\r\n");
};

void lStrobeOn (void){
    LSTRBCHG = TRUE;      // charge left strobe
    printf("\r\nLeft Strobe On\r\n");
}

void chgLStrobe (void){
    unsigned int secsElapsed;

    lStrobeOn();
    
    printf("\r\nLeft Strobe Charging for %d seconds...\r\n",
           gDeployParams.chargeSecs);
    for(secsElapsed = 0; secsElapsed < gDeployParams.chargeSecs; secsElapsed++) {
        CLRWDT();
       __delay_ms(1000);
    } // end for
    printf("\r\nLeft Strobe Charged\r\n");

    lStrobeOff();
   
};
void lStrobeOff (void){
  
    LSTRBCHG = FALSE;
    printf("\r\nLeft Strobe Off\r\n");
  
};
void trigRStrobe (void){
    RSTRTRIG = TRUE;      // charge right strobe
      __delay_ms(50);        // wait 
    RSTRTRIG = FALSE;
    printf("\r\nRight Strobe Triggered \r\n");
   
    
}
void trigLStrobe (void){
    LSTRTRIG = TRUE;      // charge right strobe
      __delay_ms(50);     // wait 
    LSTRTRIG = FALSE;
    printf("\r\nLeft Strobe Triggered \r\n");
   
    
}

void trigShutter(char cams){
    if (cams & FFCAM) FIRESHTR = TRUE;
    if (cams & NFCAM) NFIRESHTR = TRUE;
      __delay_ms(100);    // wait 
    FIRESHTR = NFIRESHTR = FALSE;
    printf("\r\nShutters %0x triggered\r\n", cams);
}

void takeTestImage(char cams){
    unsigned int secsElapsed;
    unsigned int CameraStartUpSecs = 7;
    unsigned int CameraWriteSecs = 10;

    lStrobeOn();
    __delay_ms(5);
    rStrobeOn();

    printf("\r\nStrobes Charging for %d seconds...\r\n",
           gDeployParams.chargeSecs);
    for(secsElapsed = 0; secsElapsed < gDeployParams.chargeSecs; secsElapsed++) {
        CLRWDT();
       __delay_ms(1000);
    } // end for

    lStrobeOff();
    rStrobeOff();

    __delay_ms(100);
    printf("\r\nLeft Strobe Voltage:\r\n");
    readLVmon();
    printf("\r\nRight Strobe Voltage:\r\n");
    readRVmon();

    printf("\r\nTurn On Camera\r\n");
    cameraOn();
    for(secsElapsed = 0; secsElapsed < CameraStartUpSecs; secsElapsed++) {
        CLRWDT();
        __delay_ms(1000);
    }
    printf("\r\nCapture Image\r\n");
    trigShutter(cams);
         
         
    //   __delay_ms(100);
    for(secsElapsed = 0; secsElapsed < CameraWriteSecs; secsElapsed++) {
        CLRWDT();
        __delay_ms(1000);
    }
    cameraOff();
       
    printf("\r\nLeft Strobe Voltage:\r\n");
    readLVmon();
    __delay_ms(20);
    printf("\r\nRight Strobe Voltage:\r\n");
    readRVmon();
}

// Read the reason for the last wakeup
void readWake(void) {

    switch(gWakeCause) {
        case RESETOK:
            printf("\r\nnormal reset\r\n");
            break;
        case RESETWD:
            printf("\r\nwatchdog reset\r\n");
            break;
        case WAKEOK:
            printf("\r\nnormal wakeup\r\n");
            break;
        case WAKEWD:
            printf("\r\nwatchdog wakeup\r\n");
            break;
        case MODEM:
            printf("\r\nmodem wakeup\r\n");
            break;
        case TIMEOUT:
            printf("\r\ntimeout wakeup\r\n");
            break;
        default:
            printf("\r\nunknown\r\n");
            break;
    } // end switch
} // end readWake()


// Set the board serial number and save it to EEPROM memory
void setSerno(void) {

    unsigned char serno;
    unsigned int input;
    char inbuf[10];

    printf("\r\nEnter serial number (1 - 255, 0 to abort): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input > 0 && input <= 255) {
        serno = input;
        eeprom_write(SERNOADD, serno);
        printf("\r\nSerial number %u saved to EEPROM\r\n", serno);
    } else {
        printf("\r\nInvalid serial number!\r\n");
    } // end if

}; // end setSerno()


// Read the board serial number
void readSerno(void) {

    unsigned char serno;

    serno = eeprom_read(SERNOADD);
    printf("\r\n%u\r\n", serno);

}; // end readSerno()


// Accessor function for non-atomic read of gEpochSecs. This prevents the
//  ISR from modifying the variable while the variable is being read.
time_t getEpochSecs(void) {
    time_t       epoch;
    static bit   intState;

    intState = TMR1IE;      // save current state of interrupt enable
    TMR1IE = 0;             // disable timer1 interrupts
    epoch = gEpochSecs;       // get the value
    TMR1IE = intState;      // restore state of interrupt enable
    return(epoch);
} // end getEpochSecs()

// Accessor function for non-atomic write gEpochSecs. This prevents the
//  ISR from modifying the variable while the variable is being modified.
void setEpochSecs(char y, char mon, char d, char h, char min, char s, char dst)
{
    time_t       epoch;
    static bit   intState;

    intState = TMR1IE;      // save current state of interrupt enable
    TMR1IE = 0;             // disable timer1 interrupts
    
    struct tm now;
    now.tm_sec   = s;
    now.tm_min   = min;
    now.tm_hour  = h;
    now.tm_mday  = d;
    now.tm_mon   = mon;
    now.tm_year  = y + 100;
    now.tm_isdst = dst;
    gEpochSecs = mktime(&now);       // set the value
    
    TMR1IE = intState;      // restore state of interrupt enable
} // end setEpochSecs()

// Accessor function for non-atomic read of gAwakeSecs. This prevents the
//  ISR from modifying the variable while the variable is being read.
unsigned int getAwakeSecs(void) {
    unsigned int    awakeSecs;
    static bit      intState;

    intState = TMR1IE;      // save current state of interrupt enable
    TMR1IE = 0;             // disable timer1 interrupts
    awakeSecs = gAwakeSecs; // get the value
    TMR1IE = intState;      // restore state of interrupt enable
    return(awakeSecs);
} // end getAwakeSecs()


// Accessor function for non-atomic clear of gAwakeSecs. This prevents the
//  ISR from modifying the variable while the variable is being cleared.
void clrAwakeSecs(void) {
    static bit      intState;

    intState = TMR1IE;      // save current state of interrupt enable
    TMR1IE = 0;             // disable timer1 interrupts
    gAwakeSecs = 0;         // clear the value
    TMR1IE = intState;      // restore state of interrupt enable
} // end clrAwakeSecs()


// Set up Timer1 to be used as the sleep timer
void timer_setup(void) {

    // Timer1 initialization. Timer1 runs at 32,768 Hz.

    T1CON =     0b00001111;
    //            \/\/||||_ power on timer
    //             | ||||__ select external clock source
    //             | |||___ don't synchronize external clock input
    //             | ||____ power up oscillator
    //             | |_____ divide by 1 prescaler
    //             |_______ not used

    TMR1ON = 0;         // stop timer1
    TMR1 = TMR1DLY;     // load the timeout value
    TMR1ON = 1;         // start timer1
    TMR1IE = 1;         // enable Timer1 interrupt
    PEIE = 1;           // enable peripheral interrupts
} // end timer_setup()


// Interrupt service routine. Every interrupt will call this routine.
void interrupt isr(void) {

    ser_int();      // service serial port (this macro defined in intserial.h)

    // This timer1 code only executes when PIC is awake since global interrupts
    // are disabled when sleeping.
    if ((TMR1IE) && (TMR1IF)) {
        TMR1ON = 0;         // stop timer1
        TMR1 = TMR1DLY;     // load the timeout value
        TMR1ON = 1;         // start timer1
        gAwakeSecs++;       // count seconds since wakeup
        gEpochSecs++;       // increment wall-clock second hand
        TMR1IF = 0;         // clear timer1 interrupt flag
    } // end if

} // end isr()
