#include  <Arduino.h>

#define LED0 PORTD5  // D5
#define LED1 PORTD6  // D6
#define LED2 PORTB0  // D8
#define LED3 PORTB1  // D9
#define BUILTIN_LED PORTB5  // D13

#define BUTTON_SLOW PINB2  // D10
#define BUTTON_FAST PINB3  // D11

#define COMPARE_MIN 1000
#define COMPARE_MAX 50000

volatile unsigned char counter = 0;
volatile unsigned int compareValue = COMPARE_MAX;

void setupIO() {
  // LEDs output
  DDRD |= (1 << LED0) | (1 << LED1);
  DDRB |= (1 << LED2) | (1 << LED3) | (1 << BUILTIN_LED);

  // Buttons input with pull-up
  DDRB &= ~((1 << BUTTON_SLOW) | (1 << BUTTON_FAST));
  PORTB |= (1 << BUTTON_SLOW) | (1 << BUTTON_FAST);

  // Pin change interrupt for D10/D11
  PCICR |= (1 << PCIE0);
  PCMSK0 |= (1 << PCINT2) | (1 << PCINT3);
}

// Setup Timer1 with COMPA (counter) and COMPB (1Hz LED)
void setupTimer1() {
  TCCR1A = 0;
  TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // CTC, prescaler 64

  OCR1A = compareValue;      // 4-bit counter update speed
  OCR1B = 249999;            // 1 Hz = (16e6 / 64) / 250000
  TIMSK1 = (1 << OCIE1A) | (1 << OCIE1B); 
}

// Show counter value on 4 LEDs
void updateLEDs(unsigned char val) {
  if (val & 0x01) PORTD |= (1 << LED0); else PORTD &= ~(1 << LED0);
  if (val & 0x02) PORTD |= (1 << LED1); else PORTD &= ~(1 << LED1);
  if (val & 0x04) PORTB |= (1 << LED2); else PORTB &= ~(1 << LED2);
  if (val & 0x08) PORTB |= (1 << LED3); else PORTB &= ~(1 << LED3);
}

// Counter interrupt (frequency adjustable)
ISR(TIMER1_COMPA_vect) {
  counter = (counter + 1) & 0x0F;
  updateLEDs(counter);
}

ISR(TIMER1_COMPB_vect) {
  PINB |= (1 << BUILTIN_LED); // Toggle built-in LED
}

// Button interrupt: handle speed control
ISR(PCINT0_vect) {
  static unsigned char lastState = 0xFF;
  unsigned char current = PINB;

  // Falling edge: slow down
  if (!(current & (1 << BUTTON_SLOW)) && (lastState & (1 << BUTTON_SLOW))) {
    if (compareValue < COMPARE_MAX) {
      compareValue <<= 1;
      if (compareValue > COMPARE_MAX) compareValue = COMPARE_MAX;
    }
  }

  // Falling edge: speed up
  if (!(current & (1 << BUTTON_FAST)) && (lastState & (1 << BUTTON_FAST))) {
    if (compareValue > COMPARE_MIN) {
      compareValue >>= 1;
      if (compareValue < COMPARE_MIN) compareValue = COMPARE_MIN;
    }
  }

  lastState = current;
}

void setup() {
  cli();
  setupIO();
  setupTimer1();
  sei();
}

void loop() {
  static unsigned int lastValue = 0;
  cli();
  if (compareValue != lastValue) {
    TIMSK1 &= ~(1 << OCIE1A);    
    OCR1A = compareValue;
    TIMSK1 |= (1 << OCIE1A);
    lastValue = compareValue;
}
sei();
}