/*
 * File:   main.c
 * Author: lesfo
 *
 * Created on July 11, 2026, 4:17 PM
 */


#include <xc.h>
// ATtiny85 Configuration Bit Settings

// 'C' source line config statements

#include <avr/io.h>

#define FREQ_SETTING 199
#define HALF_DUTY 150
#define LONG_DUTY 250

#define LONG_PERIOD 25000
#define SHORT_PERIOD 50

FUSES = {
	.low = 0xE2, // LOW {SUT_CKSEL=INTRCOSC_8MHZ_6CK_14CK_64MS, CKOUT=CLEAR, CKDIV8=CLEAR}
	.high = 0xDF, // HIGH {BODLEVEL=DISABLED, EESAVE=CLEAR, WDTON=CLEAR, SPIEN=SET, DWEN=CLEAR, RSTDISBL=CLEAR}
	.extended = 0xFF, // EXTENDED {SELFPRGEN=CLEAR}
};

LOCKBITS = 0xFF; // {LB=NO_LOCK}

static void delay(uint16_t t)
{
    for (uint16_t i = 0; i < t; i ++)
    {
        // Expect NOP to last 0.5 µs
        // The loop process probably takes much longer,
        // but the NOP may have to be there so the compiler
        // does not discard the loop.
        // This is a very rough delay loop, for now...
        for (uint8_t j = 0; j < 20; j++)
        {
            NOP();            
        }
    }
}

static void setup_pwm(void)
{
    ADCSRA &= ~(1 << ADEN);       // disable the ADC

    // Clock may be prescaled.
    // fPWM = fTCK1 / (OCR1C + 1)

    // Always use OCR1A for PB1; OCR1B is for PB4
    // Setup timer/counter1
    // Ex: Values of 12 and 25 yield 37.79kHz, for 1MHz.  Approx 38kHz.
    OCR1A = HALF_DUTY;
    OCR1C = FREQ_SETTING;

    TCNT1 = 0;

    // With all bits pre-cleared, CS11 and CS13 are both 0.
    // Prescale is 0101 or PCK/16
    TCCR1 = 0x00;   // Clear all bits prior to setting any

    // See spec sheet Chapter 12
    // Here - use normal operation.  WGM* == 0; non-inverting mode
    TCCR1 = 1 <<COM1A1                // PWM, clear-on-compare
          | 1 <<CS11                  // PCK/2 (in combination with other bits)
//          | 1 <<CS12                  // PCK/16 (or just CLK)
          | 1 <<PWM1A;                // Enable PWM.

    OCR1B = 100;  // PWM mode comparison.

    // Send output from Timer/Counter1 to OC1B
    GTCCR |= (1 <<PWM1B) | (1 <<COM1B1);

}

static void pwm_narrow(void)
{
    OCR1A = HALF_DUTY;
    OCR1B = HALF_DUTY;
}

static void pwm_off(void)
{
    // PB4 not output
    DDRB &= ~(1 << DDB4);
    // PB1 noot output
    DDRB &= ~(1 << DDB1);    
}

static void pwm_on(void)
{
    // PB4 to output
    DDRB |= (1 << DDB4);
    // PB1 to output
    DDRB |= (1 << DDB1);    
}

static void pwm_wide(void)
{
    // Send output from Timer/Counter1 to OC1B
    GTCCR |= (1 <<PWM1B) | (1 <<COM1B1);
    
    OCR1A = LONG_DUTY;
    OCR1B = LONG_DUTY;
}

static void light_pb2(void)
{
    DDRB |= (1 << DDB2);
    PORTB |= (1 << PORTB2);
}

int main(void)
{
    delay(500);
    light_pb2();
    setup_pwm();
    pwm_narrow();
    while (1)
    {
        // Low fan speed
        pwm_narrow();
        pwm_on();
        for (uint8_t i=0; i < 10; i++)
        {
            delay(LONG_PERIOD);
        }

        // Shutdown between
        pwm_off();
        for (uint8_t i=0; i < 10; i++)
        {
            delay(LONG_PERIOD);            
        }

        // High fan speed
        pwm_wide();
        pwm_on();
        for (uint8_t i=0; i < 10; i++)
        {
            delay(LONG_PERIOD);            
        }

        pwm_narrow();
        delay(SHORT_PERIOD);

        // Shutdown between
        pwm_off();
        for (uint8_t i=0; i < 10; i++)
        {
            delay(LONG_PERIOD);            
        }
    }
    return 0;
}
