/*
  Madwizard

  Frequentiedeler en pulsvormer
  We sturen deze avr aan als een schuifregister: data-bit klaarzetten op PD6 en vervolgens
  INT0 even laag en terug hoog maken. Er moeten 20 bit's verzonden worden, eerst 4 bits die de opdracht
  bepalen, en vervolgens 16 bits die als data bedoeld zijn.
  Als laatste stap: INT1 even laag- en terug hoog maken.

  Bereik:
  Geen prescaler; maxcnt = 1:         F_CPU / 2
  Prescaler = 1024; maxcnt = 65535:   F_CPU / 67107840


  Pros 2007
*/


// Dit moet overeenkomen met de define's in Main.h van Grotendikken
#define PWM 0x02
#define MAXCNT 0x03
#define PRESC 0x04

#include <avr/io.h>
#include <compat/deprecated.h>
#include <avr/interrupt.h>

unsigned int commanddata;
unsigned int maxcntpwm;
volatile unsigned char tccr1b;
volatile unsigned char vlag;
volatile unsigned long schuifregister;
volatile unsigned long settings;


// Bij het initialiseren starten we de PWM-klok nog niet.
// We wachten op een signaal van Grotendikken.
void init(void)
{
    tccr1b = _BV(WGM13) | _BV(WGM12);                   // Fast PWM; ICR1 = TOP; no CLK
    maxcnt = 1000;
    pwm = 50;
    vlag = 0;
    sbi(DDRBPB3);                                     // PB3 (OC1A) = PWMA-uitgang
    sbi(DDRBPB4);                                     // PB4 (OC1B) = PWMB-uitgang
    TCCR1A |= _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11);   // Clear AC1A on compare match, set on TOP
    TCCR1B |= tccr1b;                                   // Fast PWM, TOP = ICR1
    ICR1 = maxcnt;                                      // PWM TOP
    OCR1A = maxcnt / 2;                                 // PWM duty cycle A = 50%
    OCR1B = pwm;                                        // PWM duty cycle B = variabel
    cbi(DDRDPD2);                                     // PD2 = INT0
    sbi(PORTDPD2);                                    // Pull-up weerstand activeren
    cbi(DDRDPD3);                                     // PD3 = INT1
    sbi(PORTDPD3);                                    // Pull-up weerstand activeren
    MCUCR |= _BV(ISC11) | _BV(ISC01);
    GIMSK |= _BV(INT0) | _BV(INT1);
    cbi(DDRAPA1);                                     // PD6 = data-ingang
    sbi(PORTAPA1);                                    // Pull-up weerstand activeren
    sei();                                              // Global interrupts on
}


ISR(SIG_INTERRUPT0)                                     // een interrupt op PD2
{
    schuifregister = schuifregister << 1;               // schuifregister 1 plaatsje naar links
    if (bit_is_set(PINAPINA1)) {                      // Als PD6 hoog is,
        schuifregister |= 0x00000001;                   // maken we bit 0 van schuifregister hoog
    }
}


ISR(SIG_INTERRUPT1)                                     // een interrupt op PD3
{
    settings = schuifregister;                          // Sata-tranfer is compleet
    vlag = 1;                                           // Geef een seintje aan main
}


// Met maxcnt = 1 en pwm = 0 is de uitgangsfrequentie gelijk aan de helft v/d CPU_CLK
int main(void)
{
    init();

    while (1) {
        while (vlag == 0) {                             // Lekker nietsdoen, zolang vlag 0 is...
        }
        data = settings & 0xFFFF;                       // Bit 15 ... 0 van settings = data
        command = (settings >> 16) & 0x0F;              // Bit 19 ... 16 van settings = command
        switch (command) {
        case PWM:                                       // PWM-verhouding instellen
            pwm = data;
            if (pwm > maxcnt) {
                pwm = maxcnt - 1;
            }
            OCR1B = pwm;
            OCR1A = maxcnt / 2;                         // PWM duty cycle A = 50%
            break;
        case MAXCNT:                                    // Max. count instellen
            maxcnt = data;
            if (maxcnt < pwm) {
                maxcnt = pwm + 1;
            }
            ICR1 = maxcnt;
            OCR1A = maxcnt / 2;                         // PWM duty cycle A = 50%
            break;
        case PRESC:
            tccr1b &= 0xF8;                             // Bits 0, 1 en 2 van TCCR1B bepalen de CLK-bron
            tccr1b |= (unsigned char) (data & 0x07);
            TCCR1B = tccr1b;
            break;
        default:
            break;
        }
        vlag = 0;
    }

    return 0;
}