/* Name: bootloaderconfig.h
 * Micronucleus configuration file. 
 * This file (together with some settings in Makefile.inc) configures the boot loader
 * according to the hardware.
 * 
 * Controller type: ATtiny 84 - 12 MHz
 * Configuration:   Default configuration
 *       USB D- :   PB0
 *       USB D+ :   PB1
 *       Entry  :   Always
 *       LED    :   PB2, Active Low
 *       OSCCAL :   Revert to precalibrated value (8 MHz)
 * Note: can use 12 MHz V-USB without PLL due to stable RC-osc in ATTiny84A
 * Last Change:     Mar 16,2014
 *
 * License: GNU GPL v2 (see License.txt
 */

#ifndef __bootloaderconfig_h_included__
#define __bootloaderconfig_h_included__

/* ------------------------------------------------------------------------- */
/*                       Hardware configuration.                             */
/*      Change this according to your CPU and USB configuration              */
/* ------------------------------------------------------------------------- */

#define USB_CFG_IOPORTNAME      B
  /* This is the port where the USB bus is connected. When you configure it to
   * "B", the registers PORTB, PINB and DDRB will be used.
   */

#define USB_CFG_DMINUS_BIT      0
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
 * This may be any bit in the port.
 */
#define USB_CFG_DPLUS_BIT       1
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
 * This may be any bit in the port, but must be configured as a pin change interrupt.
 */

#define USB_CFG_CLOCK_KHZ       (F_CPU/1000)
/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
 * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code
 * require no crystal, they tolerate +/- 1% deviation from the nominal
 * frequency. All other rates require a precision of 2000 ppm and thus a
 * crystal!
 * Since F_CPU should be defined to your actual clock rate anyway, you should
 * not need to modify this setting.
 */

/* ------------- Set up interrupt configuration (CPU specific) --------------   */
/* The register names change quite a bit in the ATtiny family. Pay attention    */
/* to the manual. Note that the interrupt flag system is still used even though */
/* interrupts are disabled. So this has to be configured correctly.             */


// setup interrupt for Pin Change for D+
#define USB_INTR_CFG            PCMSK1
#define USB_INTR_CFG_SET        (1 << USB_CFG_DPLUS_BIT)
#define USB_INTR_CFG_CLR        0
#define USB_INTR_ENABLE         GIMSK
#define USB_INTR_ENABLE_BIT     PCIE1
#define USB_INTR_PENDING        GIFR
#define USB_INTR_PENDING_BIT    PCIF1
#define USB_INTR_VECTOR         PCINT1_vect
    
/* ------------------------------------------------------------------------- */
/*       Configuration relevant to the CPU the bootloader is running on      */
/* ------------------------------------------------------------------------- */

// how many milliseconds should host wait till it sends another erase or write?
// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms

#define MICRONUCLEUS_WRITE_SLEEP 5

// ATtiny84 does not know WDTCR
#ifndef WDTCR
#define WDTCR WDTCSR
#endif

/* ---------------------- feature / code size options ---------------------- */
/*               Configure the behavior of the bootloader here               */
/* ------------------------------------------------------------------------- */

/*
 *  Define Bootloader entry condition
 * 
 *  If the entry condition is not met, the bootloader will not be activated and the user program
 *  is executed directly after a reset. If no user program has been loaded, the bootloader
 *  is always active.
 * 
 *  ENTRY_ALWAYS        Always activate the bootloader after reset. Requires the least
 *                      amount of code.
 *
 *  ENTRY_WATCHDOG      Activate the bootloader after a watchdog reset. This can be used
 *                      to enter the bootloader from the user program.
 *                      Adds 22 bytes.
 *
 *  ENTRY_EXT_RESET     Activate the bootloader after an external reset was issued by 
 *                      pulling the reset pin low. It may be necessary to add an external
 *                      pull-up resistor to the reset pin if this entry method appears to
 *                      behave unreliably.
 *                      Adds 22 bytes.
 *
 *  ENTRY_JUMPER        Activate the bootloader when a specific pin is pulled low by an 
 *                      external jumper. 
 *                      Adds 34 bytes.
 *
 *       JUMPER_PIN     Pin the jumper is connected to. (e.g. PB0)
 *       JUMPER_PORT    Port out register for the jumper (e.g. PORTB)  
 *       JUMPER_DDR     Port data direction register for the jumper (e.g. DDRB)  
 *       JUMPER_INP     Port inout register for the jumper (e.g. PINB)  
 * 
 */

#define ENTRYMODE ENTRY_ALWAYS

#define JUMPER_PIN    PB0
#define JUMPER_PORT   PORTB 
#define JUMPER_DDR    DDRB 
#define JUMPER_INP    PINB 
 
/*
  Internal implementation, don't change this unless you want to add an entrymode.
*/ 
 
#define ENTRY_ALWAYS    1
#define ENTRY_WATCHDOG  2
#define ENTRY_EXT_RESET 3
#define ENTRY_JUMPER    4

#if ENTRYMODE==ENTRY_ALWAYS
  #define bootLoaderInit()
  #define bootLoaderExit()
  #define bootLoaderStartCondition() 1
#elif ENTRYMODE==ENTRY_WATCHDOG
  #define bootLoaderInit()
  #define bootLoaderExit()
  #define bootLoaderStartCondition() (MCUSR&_BV(WDRF))
#elif ENTRYMODE==ENTRY_EXT_RESET
  #define bootLoaderInit()
  #define bootLoaderExit()
  #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF))
#elif ENTRYMODE==ENTRY_JUMPER
  // Enable pull up on jumper pin and delay to stabilize input    
  #define bootLoaderInit()   {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);}
  #define bootLoaderExit()   {JUMPER_PORT&=~_BV(JUMPER_PIN);}
  #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN)))
#else
   #error "No entry mode defined"
#endif

/*
 * Define bootloader timeout value. 
 * 
 *  The bootloader will only time out if a user program was loaded.
 * 
 *  AUTO_EXIT_NO_USB_MS        The bootloader will exit after this delay if no USB is connected.
 *                             Set to 0 to disable
 *                             Adds ~6 bytes.
 *                             (This will wait for an USB SE0 reset from the host)
 *
 *  AUTO_EXIT_MS               The bootloader will exit after this delay if no USB communication
 *                             from the host tool was received.
 *                             Set to 0 to disable
 *  
 *  All values are approx. in milliseconds
 */

#define AUTO_EXIT_NO_USB_MS    0
#define AUTO_EXIT_MS           6000

 /*
 *  Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL)
 * 
 *  OSCCAL_RESTORE            Set this to '1' to revert to factory calibration, which is 16.0 MHZ +/-10%
 *                            Adds ~14 bytes.
 *
 *  OSCCAL_16.5MHz            Set this to '1' to use the same calibration as during program upload.
 *                            This value is 16.5Mhz +/-1% as calibrated from the USB timing. Please note
 *                            that only true if the ambient temperature does not change.
 *                            This is the default behaviour of the original Digispark and is not recommended
 *                            for use on devices other than the ATtiny85.
 *                            Adds ~38 bytes.
 *
 *  OSCCAL_HAVE_XTAL          Set this to '1' if you have an external crystal oscillator. In this case no attempt
 *                            will be made to calibrate the oscillator. You should deactivate both options above
 *                            if you use this to avoid redundant code.
 *
 *  If both options are selected, OSCCAL_RESTORE takes precedence.
 *
 *  If no option is selected, OSCCAL will be left untouched and stays at either 16.0 Mhz or 16.5 Mhz depending
 *  on whether the bootloader was activated. This will take the least memory. You can use this if your program
 *  comes with its own OSCCAL calibration or an external clock source is used. 
 */
 
#define OSCCAL_RESTORE 1
#define OSCCAL_16_5MHz 0
#define OSCCAL_HAVE_XTAL 0
  
/*  
 *  Defines handling of an indicator LED while the bootloader is active.  
 * 
 *  LED_MODE                  Define behavior of attached LED or suppress LED code.
 *
 *          NONE              Do not generate LED code (gains 18 bytes).
 *          ACTIVE_HIGH       LED is on when output pin is high. This will toggle bettwen 1 and 0.
 *          ACTIVE_LOW        LED is on when output pin is low.  This will toggle between Z and 0.
 *
 *  LED_DDR,LED_PORT,LED_PIN  Where is your LED connected?
 *
 */ 

#define LED_MODE    ACTIVE_LOW

#define LED_DDR     DDRB
#define LED_PORT    PORTB
#define LED_PIN     PB2

/*
 *  This is the implementation of the LED code. Change the configuration above unless you want to 
 *  change the led behavior
 *
 *  LED_INIT                  Called once after bootloader entry
 *  LED_EXIT                  Called once during bootloader exit
 *  LED_MACRO                 Called in the main loop with the idle counter as parameter.
 *                            Use to define pattern.
*/

#define NONE        0
#define ACTIVE_HIGH 1
#define ACTIVE_LOW  2

#if LED_MODE==ACTIVE_HIGH
  #define LED_INIT(x)   LED_DDR   = _BV(LED_PIN); 
  #define LED_EXIT(x)   {LED_DDR  &=~_BV(LED_PIN);LED_PORT  &=~_BV(LED_PIN);}
  #define LED_MACRO(x)  if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);}
#elif LED_MODE==ACTIVE_LOW
  #define LED_INIT(x)   LED_PORT &=~_BV(LED_PIN);   
  #define LED_EXIT(x)   LED_DDR  &=~_BV(LED_PIN);
  #define LED_MACRO(x)  if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);}  
#elif LED_MODE==NONE
  #define LED_INIT(x)
  #define LED_EXIT(x)
  #define LED_MACRO(x)
#endif

/* --------------------------------------------------------------------------- */
/* Micronucleus internal configuration. Do not change anything below this line */
/* --------------------------------------------------------------------------- */

// Microcontroller vectortable entries in the flash
#define RESET_VECTOR_OFFSET         0

// number of bytes before the boot loader vectors to store the tiny application vector table
#define TINYVECTOR_RESET_OFFSET     4
#define TINYVECTOR_OSCCAL_OFFSET    6

/* ------------------------------------------------------------------------ */
// postscript are the few bytes at the end of programmable memory which store tinyVectors
#define POSTSCRIPT_SIZE 6
#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */

#endif /* __bootloader_h_included__ */