text: /*  Copyright (C) 2012  Albert van Dalen http://www.avdweb.nl
   *  This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
   *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
   *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses .
   */
  
  //Original repo: https://github.com/avandalen/avdweb_SAMDtimer
  //Forked by Barna Keresztes https://github.com/kbarni/avdweb_SAMDtimer
  //Modified by Jeremy Paradie for Hampshire College
  
  #include "Timer.h"
  
  void TC3_Handler(){
      Adafruit_ZeroTimer::timerHandler(3);
  }
  
  void TC4_Handler(){
      Adafruit_ZeroTimer::timerHandler(4);
  }
  
  void TC5_Handler(){
      Adafruit_ZeroTimer::timerHandler(5);
  }
  
  Timer::Timer(byte timerNr, tc_counter_size countersize, byte pin, unsigned period_us, int pulseWidth_us, bool timerEnable): 
  Adafruit_ZeroTimer(timerNr), pin(pin), countersize(countersize), period_us(period_us)  
  { if(pulseWidth_us==-1) calc(period_us, period_us/2);
    else calc(period_us, pulseWidth_us);
    init(timerEnable);    
  }
  
  Timer::Timer(byte timerNr, void (*_ISR)(), unsigned period_us, bool ISRenable):
  Adafruit_ZeroTimer(timerNr)  
  { ISR = _ISR;
    pin=-1;
    countersize = TC_COUNTER_SIZE_16BIT; 
    calc(period_us, period_us/2);
    init(1);
    setCallback(ISRenable, TC_CALLBACK_CC_CHANNEL0, ISR);
  }
  
  void Timer::setPulseWidth(unsigned pulseWidth_us)
  { calc(period_us, pulseWidth_us);
    setPeriodMatch(periodCounter, PWcounter, 1); 
  }
  
  void Timer::attachInterrupt(void (*_ISR)(), bool interruptEnable)
  { ISR = _ISR;
    setCallback(interruptEnable, TC_CALLBACK_CC_CHANNEL0, ISR); 
  }
  
  void Timer::enableTimer(bool timerEnable)
  { enable(timerEnable);
  }
  
  void Timer::enableInterrupt(bool interruptEnable)
  { setCallback(interruptEnable, TC_CALLBACK_CC_CHANNEL0, ISR); 
  }
  
  void Timer::init(bool enabled)
  { configure(prescale, countersize, TC_WAVE_GENERATION_MATCH_PWM);
    if(pin>0)PWMout(true, 1, pin); // must be ch1 for 16bit
    setPeriodMatch(periodCounter, PWcounter, 1);
    enable(enabled); 
  }
  
  void Timer::calc(unsigned period_us, unsigned pulseWidth_us)
  { periodCounter = (F_CPU * (signed)period_us) / 1000000; // why signed?
    PWcounter = (F_CPU * (signed)pulseWidth_us) / 1000000; 
    if(periodCounter < 65536) prescale = TC_CLOCK_PRESCALER_DIV1; 
    else if((PWcounter >>= 1, periodCounter >>= 1) < 65536) prescale = TC_CLOCK_PRESCALER_DIV2; // = 256
    else if((PWcounter >>= 1, periodCounter >>= 1) < 65536) prescale = TC_CLOCK_PRESCALER_DIV4; 
    else if((PWcounter >>= 1, periodCounter >>= 1) < 65536) prescale = TC_CLOCK_PRESCALER_DIV8; 
    else if((PWcounter >>= 1, periodCounter >>= 1) < 65536) prescale = TC_CLOCK_PRESCALER_DIV16; 
    else if((PWcounter >>= 2, periodCounter >>= 2) < 65536) prescale = TC_CLOCK_PRESCALER_DIV64; 
    else if((PWcounter >>= 2, periodCounter >>= 2) < 65536) prescale = TC_CLOCK_PRESCALER_DIV256; 
    else if((PWcounter >>= 2, periodCounter >>= 2) < 65536) prescale = TC_CLOCK_PRESCALER_DIV1024; 
  }