// 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 <xc.h>		// register definitions for this PIC
#include "intserial.h"	// hardware serial I/O routines
#include "adc.h"        // analog-to-digital converter routines

//__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 NFIELDSHTR  RA5
#define LSTRBCHG    RB4
#define FIRESHTR    RB5

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

#define TRUE    1
#define FALSE   0

enum {RESETOK, RESETWD, WAKEOK, WAKEWD, MODEM, TIMEOUT};    // Cause for last reset or wake

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 read7v(void);
void setBatt(void);
void readBatt(void);
void readLVmon(void);
void readRVmon(void);
void chgRStrobe (void);
void RStrobeOff (void);
void LStrobeOn (void);
void chgLStrobe (void);
void LStrobeOff (void);
void TrigRStrobe (void);
void TrigLStrobe (void);
void TrigShutter (void);
void readWake(void);
void setSerno(void);
void readSerno(void);
void help(void);
void test(void);
unsigned int getAwakeSecs(void);
void clrAwakeSecs(void);
void takeTestImage(void);

void timer_setup(void);
void interrupt isr(void);

// Global vars
unsigned int    gSleepMins = 1; // number of minutes to sleep
unsigned int    gDelaySecs = 0; // number of seconds to wait before sleeping

char            g7VOn;         // status of 7 V power supply
char            gWakeCause;     // reason for last reset or wakeup
unsigned int    gTimeoutMins = 0;   // max minutes awake before going back to sleep
volatile unsigned int    gAwakeSecs;     // number of seconds elapsed since wakeup


// 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
    timer_setup();          // 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 the 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 command
        if(!cmdBuf[0]);     // empty command, do nothing
        else if(!strcmp(cmdBuf, "sleep")) sleep();
        else if(!strcmp(cmdBuf, "setsleep")) setSleep();
        else if(!strcmp(cmdBuf, "setdelay")) setDelay();
        else if(!strcmp(cmdBuf, "settimeout")) setTimeout();
        else if(!strcmp(cmdBuf, "readsleep")) readSleep();
        else if(!strcmp(cmdBuf, "readdelay")) readDelay();
        else if(!strcmp(cmdBuf, "readtimeout")) readTimeout();
        else if(!strcmp(cmdBuf, "set7von")) set7vOn();
        else if(!strcmp(cmdBuf, "set7voff")) set7vOff();
        else if(!strcmp(cmdBuf, "read7v")) read7v();
        else if(!strcmp(cmdBuf, "setbatt")) setBatt();
        else if(!strcmp(cmdBuf, "readbatt")) readBatt();
        else if(!strcmp(cmdBuf, "readlvmon")) readLVmon();
        else if(!strcmp(cmdBuf, "readrvmon")) readRVmon();
        else if(!strcmp(cmdBuf, "chgrstrobe"))chgRStrobe ();
        else if(!strcmp(cmdBuf, "rstrobeoff"))RStrobeOff ();
        else if(!strcmp(cmdBuf, "lstrobeon")) LStrobeOn ();
        else if(!strcmp(cmdBuf, "chglstrobe"))chgLStrobe ();
        else if(!strcmp(cmdBuf, "lstrobeoff"))LStrobeOff ();
        else if(!strcmp(cmdBuf, "trigright"))TrigRStrobe ();
        else if(!strcmp(cmdBuf, "trigleft"))TrigLStrobe ();
        else if(!strcmp(cmdBuf, "trigshutter"))TrigShutter ();
        else if(!strcmp(cmdBuf, "readwake")) readWake();
        else if(!strcmp(cmdBuf, "setserno")) setSerno();
        else if(!strcmp(cmdBuf, "readserno")) readSerno();
        else if(!strcmp(cmdBuf,"takeimage"))takeTestImage();
        else if(!strcmp(cmdBuf, "help") || !strcmp(cmdBuf, "?")) help();
        else if(!strcmp(cmdBuf, "test")) test();
        else printf("\r\nInvalid command!");
    } // end while
} // end main


// 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
    }; // 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) {

    unsigned int input;
    char inbuf[10];

    printf("\r\nEnter delay time in seconds (0 - 60): ");
    gets(inbuf);
    input = atoi(inbuf);
    if(input >= 0 && input <= 60) {
        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) {

    unsigned 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 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 chgRStrobe (void){
   //declare charge time 
     unsigned int secsElapsed;
     unsigned int ChargeSecs;
    
     ChargeSecs=30;
    
     RSTRBCHG = TRUE;      // charge right strobe
      printf("\r\nRight Strobe Charging\r\n");
      
      for(secsElapsed = 0; secsElapsed < ChargeSecs; secsElapsed++) {
        CLRWDT();
       __delay_ms(1000);
    } // end for
    RSTRBCHG = FALSE; 
   
};

void RStrobeOff (void){
    
    RSTRBCHG = FALSE;      // charge right strobe
    printf("\r\nRight Strobe Off\r\n");
  
};
void LStrobeOn (void){
    LSTRBCHG = TRUE;      // charge right strobe
    printf("\r\nLeft Strobe On\r\n");

}
void chgLStrobe (void){
    unsigned int secsElapsed;
    unsigned int ChargeSecs;
    
    ChargeSecs=30;
    LSTRBCHG = TRUE;      // charge right strobe
    printf("\r\Left Strobe Charging\r\n");
    for(secsElapsed = 0; secsElapsed < ChargeSecs; secsElapsed++) {
        CLRWDT();
       __delay_ms(1000);
    } // end for
     LSTRBCHG = FALSE;      // charge left strobe
   
};
void LStrobeOff (void){
    
    LSTRBCHG = FALSE;      // charge right strobe
    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 Trigger \r\n");
   
    
}
void TrigLStrobe (void){
    LSTRTRIG = TRUE;      // charge right strobe
      __delay_ms(50);        // wait 
    LSTRTRIG = FALSE;
    printf("\r\Left Strobe Trigger \r\n");
   
    
}

void TrigShutter (void){
    FIRESHTR = TRUE;      // charge right strobe
    NFIELDSHTR = TRUE;
      __delay_ms(300);        // wait 
    FIRESHTR = FALSE;
    NFIELDSHTR= FALSE;
    
    
    printf("\r\Trigger Shutter \r\n");
   
    
}

void takeTestImage(void){
    unsigned int secsElapsed;
    unsigned int ChargeSecs;
    unsigned int CameraStartUpSecs;
    unsigned int  CameraWriteSecs;
    ChargeSecs=30;
    CameraStartUpSecs=7;
    CameraWriteSecs=10;
    LSTRBCHG = TRUE;      // charge right strobe
    __delay_ms(5);
    RSTRBCHG = TRUE;
    
    printf("\r\Strobes Charging\r\n");
    for(secsElapsed = 0; secsElapsed < ChargeSecs; secsElapsed++) {
        CLRWDT();
       __delay_ms(1000);
    } // end for
     LSTRBCHG = FALSE;      // stop charging left strobe
     RSTRBCHG = FALSE;   // stop charging right strobe
     
     __delay_ms(100);
       printf("\r\Left Strobe Voltage:\r\n");
       readLVmon();
        printf("\r\Right Strobe Voltage:\r\n");
       readRVmon();
       set7vOn();
       
       printf("\r\Turn On Camera\r\n");
    for(secsElapsed = 0; secsElapsed < CameraStartUpSecs; secsElapsed++) {
        CLRWDT();
       __delay_ms(1000);
    }
         printf("\r\Capture Image\r\n");
         TrigShutter();
         
         
      //   __delay_ms(100);
        for(secsElapsed = 0; secsElapsed < CameraWriteSecs; secsElapsed++) {
        CLRWDT();
       __delay_ms(1000);
    }
       set7vOff();
       
         printf("\r\Left Strobe Voltage:\r\n");
       readLVmon();
        __delay_ms(20);
        printf("\r\Right 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()


// Print help text
void help(void) {
    printf("\r\nValid commands are:\r\n");
    printf("sleep\t\tsleep after delay\r\n");
    printf("setsleep\tset sleep time in minutes\r\n");
    printf("setdelay\tset delay time in seconds\r\n");
    printf("settimeout\tset max time awake in minutes\r\n");
    printf("readsleep\tread sleep time\r\n");
    printf("readdelay\tread delay time\r\n");
    printf("readtimeout\tread max time awake\r\n");
    printf("set7von\t\tturn 7V on\r\n");
    printf("set7voff\tturn 7V off\r\n");
    printf("read7v\t\tread state of 7V\r\n");
    printf("setbatt\t\tset battery voltage calibration\r\n");
    printf("readbatt\tread battery voltage\r\n");
    printf("readlvmon\tread left strobe voltage\r\n");
    printf("readrvmon\tread right strobe voltage\r\n");
    printf("chgrstrobe\tcharge right strobe voltage\r\n");
    printf("rstrobeoff\t right strobe charging off\r\n");
    printf("lstrobeon\t turn left strobe on\r\n");
    printf("chglstrobe\tcharge left strobe voltage\r\n");
    printf("lstrobeoff\t left strobe charging off\r\n");
    printf("trigright\t trigger right strobe\r\n");
    printf("trigleft\t trigger left strobe\r\n");
    printf("trigshutter\t trigger camera shutter\r\n");
    printf("takeimage\t take test image\r\n");
   
    printf("setserno\tset serial number\r\n");
    printf("readserno\tread serial number\r\n");
    printf("help or ?\tprint command list\r\n");
} // end help()


// Test command for testing various functions during development
void test(void) {
    //while(1);   // cause a watchdog reset
    printf("\r\n%u\r\n", getAwakeSecs());

} // end test()


// 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
        TMR1IF = 0;         // clear timer1 interrupt flag
    } // end if

} // end isr()
