////////////////////////////////////////////////////////////////////////////////////////
// OVERVIEW
////////////////////////////////////////////////////////////////////////////////////////
/*
DESCRIPTION: Watchdog Timer Demo 1.

AUTHOR: Andre' LaMothe

COMMENTS: 

VT100 commands can be found here:

http://www.braun-home.net/michael/info/misc/VT100_commands.htm

HISTORY: 

*/


////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES 
////////////////////////////////////////////////////////////////////////////////////////

#include <Arduino.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <avr/wdt.h>    // this includes the watchdog timer functionality, constants, etc.

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////
// PROTOTYPES
////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////
// DEFINES AND MACROS
////////////////////////////////////////////////////////////////////////////////////////

const uint8_t button_pin = 7;   // PD7, D7, AIN[1],PCINT[23]
const uint8_t LED_pin    = 8;   // PB0

////////////////////////////////////////////////////////////////////////////////////////
// GLOBALS
////////////////////////////////////////////////////////////////////////////////////////

// buffer for messages, etc.
char gStringBuffer[ 80 ];

////////////////////////////////////////////////////////////////////////////////////////
// ISRs - INTERRUPT SERVICE ROUTINES
////////////////////////////////////////////////////////////////////////////////////////

ISR( WDT_vect ) 
{
// do whatever you wish in here, but do it FAST!
// turn on LED to indicate interrupt occured
digitalWrite( LED_pin, HIGH );
  
} // end ISR( WDT_vect ) 

////////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////

void setup() 
{
// the setup function runs once when you press reset or power the board  

// initialize serial port
Serial.begin(115200);
Serial.write( "\n\rSystem Reset: Watchdog Timer Demo 1 Initializing...\n\r" );

// setup GPIO pins
pinMode( button_pin, INPUT_PULLUP );

digitalWrite( LED_pin, LOW );
pinMode( LED_pin, OUTPUT );

// before anything, temporarily disable interrupts, create a "critical section", so we know we can't be interrupted
// as well as we don't trigger the interrupt we are setting up, we don't HAVE to do this, but it's a nice safety measure
cli();

// reset the WDT timer just in case its about to trigger
wdt_reset();

// WDTCSR - Watchdog timer control register (0x60)
// Step 1: set WDIE (watchdog interrupt enable) and WDE (watchdog change enable) both to 1 in the WDTCSR, 
// this is required by the 328p as a "safety" precaution to indicate that 
// you really want to play with the WDT, after this instruction executes, you must set the WDT settings within 
// 4 clock cycles, see 328p datasheet for more detail.
WDTCSR |= ( 1 << WDCE ) | ( 1 << WDE );


// Step 2: now, we have 4 clocks to get on with manipulating the setting bits, as usual, you can always save the 
// bit field and restore, OR only set/clear bits of interest, but since we are the only app running, we will simply
// over write the register as desired. The WDTCSR controls the interrupt enable, watchdog reset enable, and the prescaler
// values for timeout of the watchdog from 16ms to 8s, refer to datasheet for more detail.
// in our case we are going to enable the watchdog interrupt, the watchdog reset, and set the time out for 4 seconds
// NOTE: Be carefull not to set the time out for too small a value, if so, the WDT will timeout before the 328P boots and
// has time for the bootloader to accept new code. So, 2 seconds is the recommended minimum with Arduino tech, you can
// change this if you know what you are doing, if you brick your arduino, you may need an ISP programmer to reset it.
// these settings enable both interrupt, and reset, and set timeout to 2.0s
//
// Typical Time-out at VCC = 5.0V
// WDP3 WDP2 WDP1 WDP0  Timeout
// 0    0     0   0     16ms
// 0    0     0   1     32ms
// 0    0     1   0     64ms
// 0    0     1   1     0.125s
// 0    1     0   0     0.25s
// 0    1     0   1     0.5s
// 0    1     1   0     1.0s
// 0    1     1   1     2.0s --------- safe time outs 2,4,8
// 1    0     0   0     4.0s
// 1    0     0   1     8.0s

WDTCSR =  ( 1 << WDIE ) | ( 1 << WDE ) | ( 0 << WDP3 ) | ( 1 << WDP2 ) | ( 1 << WDP1 ) | ( 1 << WDP0 );

// finally, be sure that you have defined the interrupt service routine for the WDT_vect, since we enabled it with
// the above bit settings

// Step 3: re-enable interrupts
// nothing will happen until the I flag is set in the SREG, so enable interrupts
sei();

Serial.write( "\n\rWatchdog Timer now running with 2.0s timeout...\n\r" );

} // end setup

////////////////////////////////////////////////////////////////////////////////////////

void loop() 
{
static int loopCounter = 0;

// waiting for external event to reset the watchdog
// build up message string and print
sprintf( gStringBuffer, "\n\r(%d):Waiting for push button to reset...", loopCounter++);
Serial.write( gStringBuffer );

// test if user has pressed the WDT button, LOW means pressed
if ( digitalRead( button_pin ) == 0 )
  {
  // user has pressed the button, so we will reset the WDT
  wdt_reset();

  // echo button press
  Serial.write( "\n\r---------- User pressed button resetting WDT! ----------\n\r" );
  
  } // end if
 
// pause a moment
delay( 100 );

// clear interrupt LED always
digitalWrite( LED_pin, LOW );


} // end loop

////////////////////////////////////////////////////////////////////////////////////////