/*
    Tutoriaux AvrX

    Utilisation des tâches pour faire clignoter plusieurs LEDs avec des
    motifs différents.
    
    Adapté de l'exemple Timers.c inclus dans la distribution AvrX.     
    
    Cible : ATMega163
    Quartz : 8MHz
    Compilateur : avr-gcc (WInAVR)
    
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include "avrx.h"
#include "hardware.h"

// définition des timers que nous allons utiliser pour nos LEDs

AVRX_TIMER (timer1) ;
AVRX_TIMER (timer2) ;

/*
 Timer 0 Overflow Interrupt Handler

 Structure typique :
 . Switch en contexte kernel 
 . gestion de l'interruption
 . retour au context initial
 */

AVRX_SIGINT(SIG_OVERFLOW0)
{
    IntProlog();                // Switch en contexte et stack kernel
    EndCritical();                // autorise à nouveau les interruptions
    TCNT0 = TCNT0_INIT;            // réinitialise le compteur du timer
    AvrXTimerHandler();         // invoke le manager Time queue d'AvrX
    Epilog();                   // retour au contexte initial
}


/*
 * Définition des tâches
 * 
 * Elles sont au nombre de 3, une par LED
 */
 
/*
     La tâche 1 fait clicnoter avec une période de 1 seconde et un rapport cyclique de 20%
     
     Paramètres de définition de la tâche :
         nom : task 1
         taille du stack : 8 bytes
         priorité : 3
     
 */
AVRX_GCC_TASKDEF(task1, 8, 3)
{
    while (1)
    {
        // première partie du cycle
        
        // démarre un timer de 800ms
        AvrXStartTimer(&timer1, 800); 
        // attend son expiration
        AvrXWaitTimer(&timer1);
        
        // inverse l'état de la LED
        LED = LED ^ 0x01;

        // deuxième partie du cycle

        // démarre un timer de S00ms
        AvrXStartTimer(&timer1, 200);
        // attend son expiration
        AvrXWaitTimer(&timer1);

        // inverse l'état de la LED
        LED = LED ^ 0x01;
    }
}

/*
     La tâche 2 fait clignoter avec une période de 4 secondes
 */
AVRX_GCC_TASKDEF(task2, 8, 2)
{
    while (1)
    {
        // attend 2 secondes
        // AvrXDelay est une simplefication de l'utilisation du timer lorsqu'on
        // a juste besoin de faire une pause. 
        // Elle enchaine simplement AvrXStartTimer et AvrXWaitTimer
        AvrXDelay(&timer2, 2000);           
        
        // bascule l'état de la LED
        LED = LED ^ 0x02;
    }
}

//--------------------------------------------------------------------------------------------

int main(void)                     // Main démarre dans le contexte du kernel AvrX
{
    AvrXSetKernelStack(0);        // définition du stack du kernel

    MCUCR = 1<<SE;                // autorise l'instruction SLEEP
    TCNT0 = TCNT0_INIT;            // initialise le timer 0 (utilisé pour la gestion des timers
    TCCR0 = TMC8_CK256;            // définit son prescaler à CLK/256
    TIMSK = 1<<TOIE0;            // active l'interruption Timer0 Overflow

    LEDDDR = 0xFF;                // configure en sortie le port des LEDs 
    LED   = 0xFF;                // initialise toutes les sortie à 1 
                                // => éteint les LEDs si celles-ci sont reliées à Vcc

    AvrXRunTask(TCB(task1));    // active les 3 tâches
    AvrXRunTask(TCB(task2));

    Epilog();                   // bascule sur le contexte de la première tâche
                                // => active l'ensemble
                                
    while(1);                    // il n'y a plus rien à faire ici
}