#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <avr/interrupt.h>

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define delay(ms) _delay_ms(ms)

#define PIN 1
const unsigned char BRIGHT = 20;
int state = 7;

void setup() {
  // Set the clock speed of the ATTiny10 to 8mhz.
  CCP = 0xD8;
  CLKPSR = 0;

  // Set PB1 and PB2 as output and PB0 as input_pullup.
  DDRB = 0b0110;
  PUEB = 0b0001;
}

void sendBit( bool bitVal ) {
  if (bitVal) {
    asm volatile (
      "sbi %[port], %[bit] \n"        
      "nop \n nop \n nop \n nop \n nop \n nop \n"
      "cbi %[port], %[bit] \n"                             
      "nop \n "
      ::
      [port]    "I" (_SFR_IO_ADDR(PORTB)),
      [bit]     "I" (PIN)
    );        
  } else {      
    asm volatile (
      "sbi %[port], %[bit] \n"    
      "nop \n "
      "cbi %[port], %[bit] \n"
      "nop \n nop \n nop \n nop \n nop \n nop \n"
      ::
      [port]    "I" (_SFR_IO_ADDR(PORTB)),
      [bit]     "I" (PIN)
    );
  }
}  

void sendByte( unsigned char byte ) { 
  for( unsigned char bit = 0 ; bit < 8 ; bit++ ) {
    sendBit( bitRead( byte , 7 ) );                                                     
    byte <<= 1;                                  
  }
} 

void sendPixel( unsigned char r, unsigned char g , unsigned char b )  {  
  cli(); // Disable Interrupts
  sendByte(g);
  sendByte(r);
  sendByte(b);   
  sei(); // Enable Interrupts
}

void wheelColor(unsigned char wheelPosition, unsigned char &r, unsigned char &g, unsigned char &b) {
  if(wheelPosition <= 20) {
    r = BRIGHT - wheelPosition;
    g = 0;
    b = wheelPosition;
    _delay_ms(20);
    return;
  }
  if(wheelPosition <= 40) {
    r = 0;
    g = (wheelPosition-20);
    b = BRIGHT - (wheelPosition-20);
    _delay_ms(20);
    return;
  }
   if(wheelPosition <= 60) {
    r = (wheelPosition-40);
    g = BRIGHT - (wheelPosition-40);
    b = 0;
    _delay_ms(20);
    return;
  }
}

void sendColor(unsigned char q,unsigned char w,unsigned char e) {
  //sendPixel(q, w, e);    
  sendPixel(q, w, e);     
  _delay_us(350);
}

void Rainbow(int value) {
  for (unsigned char wheelPos = 0; wheelPos <= 60; wheelPos++)  {
    unsigned char r;
    unsigned char g;
    unsigned char b;
    wheelColor(wheelPos, r, g, b);

    sendColor(r, g, b);
    
    if (!(PINB & 0b0001)) {
    return;
    }
    
    _delay_ms(value);
  }
}

void PulseColor(unsigned char o,unsigned char t,unsigned char f) {
  for (unsigned char i=BRIGHT;i>=10;i--) {
    sendColor(i*o,i*t,i*f);
    _delay_ms(100);
    if (!(PINB & 0b0001)) {
    return;
    }
  }
  for (unsigned char i=10;i<=BRIGHT;i++) {
    sendColor(i*o,i*t,i*f);
    _delay_ms(150);
    if (!(PINB & 0b0001)) {
    return;
    }
  }
  _delay_ms(200);
}

void loop() {
while(1) {
  switch(state) {
    case 0: PORTB = 0b0100;       //set LED HIGH
      PulseColor(1,0,0);          //Red           
      break;
    case 1: PulseColor(0,1,0);    //Green
      break;
    case 2: PulseColor(0,0,1);    //Blue
      break;
    case 3: PulseColor(1,0,1);    //Pink
      break;
    case 4: PulseColor(0,1,1);    //Sky-blue
      break;
    case 5: PulseColor(1,1,0);    //Yellow
      break;
    case 6: Rainbow(150);         //Cycle colors
      break;
    case 7: sendColor(0,0,0);     //
      PORTB = 0b0000;             //set LED LOW to save power
      SMCR = 0b0101;              //sleep mode: Power-Down
      break;
  }
  if (!(PINB & 0b0001)) {         //if Button pin not LOW
    SMCR = 0b0000;                //enter Idle Mode
    state++;
    if (state > 7) state = 0; 
    while(!(PINB & 0b0001)) {}
  }
  delay(10);
}
}

int main() {
  setup();
  for(;;) loop();
}
