__ __ 
___            
____  _____
       
/ // / /   |_   _______/ __ \/ ___/
      
/ // /_/ /| | | / / ___/ / / /\__ \ 
     
/__  __/ ___ | |/ / /  / /_/ /___/ / 
       
/_/ /_/  |_|___/_/   \____//____/
       
____                   
____      
_             
_       _
      
/ ___|___   ___  _ __   /
___|  ___| |__   ___  __|
|_   _| | ___ _ __
     
| |   / _ \ / _ \| '_ \  \___ \ / __| '_ \ /
_ \/ _` | | | | |/ _ \ '__|
     
| |__| (_) | (_) | |_) |  ___) | (__| | | |  __/ (_|
| |_| | |  __/ |
      
\____\___/ \___/| .__/  |____/ \___|_|
|_|\___|\__,_|\__,_|_|\___|_|
                      
|_|
        
__                      
__
       
/ /  __ __  ______ ______/ /__  ____ _
      
/ _ \/ // / / __/ // / __/ __/ |/ /  ' \
     
/_.__/\_, /  \__/\_,_/_/  \__/|___/_/_/_/
          
/___/
Copyright (c) 2007,2008, Curt Van Maanen
Permission to use, copy, modify, and/or
distribute this software for
any purpose with or without
fee is hereby granted, provided that the
above copyright notice and this permission notice appear
in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE
AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS
SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS
SOFTWARE.
 
                                                                                                        #ifndef _4AVROS_H
    #define _4AVROS_H
            #if (SEMAPHORES_ON)
    extern uint8_t semaOwner[];
    #endif
        extern uint8_t thisTaskN;
            void    __save_goto     (uint8_t *gl);
    uint8_t __get_priority  (uint8_t tn);
    void    __set_priority  (uint8_t tn, uint8_t pri);
    void    __set_rtr       (uint8_t tn, uint8_t i);
    void    __clear_rtr     (uint8_t tn);
    void    __wait          (uint8_t nTicks);
    #if (SEMAPHORES_ON)
    uint8_t __getSema       (uint8_t n);
    void    __releaseSema   (uint8_t n);
    #endif
            #define MY_CONCAT2(s,L)                 __CONCAT(s,L)
    #define MY_CONCAT(s,L)                   MY_CONCAT2(s,L)
        #define BEGIN_TASK(name)                void (name)(uint8_t *gl){\
                                            if (gl) goto *gl;\
                                            for(;;) {
    #define END_TASK                        } }
            #define osWAIT(ticks)                   { __save_goto(&&MY_CONCAT(L,__LINE__));\
                                            __wait(ticks);\
                                            return; }\
                                            MY_CONCAT(L,__LINE__):
        #define osWAIT_WHILE(statement)         { __save_goto(&&MY_CONCAT(L,__LINE__));\
                                            MY_CONCAT(L,__LINE__):\
                                            if(statement) { __wait(1); return; } }
        #define osWAIT_UNTIL(statement)         { __save_goto(&&MY_CONCAT(L,__LINE__));\
                                            MY_CONCAT(L,__LINE__):\
                                            if(!(statement)) { __wait(1); return; } }
        #define osWAIT_IRQ(statement)           { __clear_rtr(thisTaskN);\
                                            {statement}\
                                            __save_goto(&&MY_CONCAT(L,__LINE__));\
                                            return; }\
                                            MY_CONCAT(L,__LINE__):
        #define osYIELD                         { __save_goto(&&MY_CONCAT(L,__LINE__));\
                                            return; }\
                                            MY_CONCAT(L,__LINE__):
        #define osSUSPEND                       { __save_goto(&&MY_CONCAT(L,__LINE__));\
                                            __wait(0);\
                                            return; }\
                                            MY_CONCAT(L,__LINE__):
        #define osGET_PRIORITY(taskname)        __get_priority(taskname ## NUMBER)
        #define osSET_PRIORITY(taskname,pri)    __set_priority(taskname ## NUMBER,pri)
        #define osCLEAR_RTR(taskname)           __clear_rtr(taskname ## NUMBER)
    #define osDISABLE_TASK(taskname)        __clear_rtr(taskname ## NUMBER)
        #if (SEMAPHORES_ON)
    #define osGET_SEMA(semaNum)             { __save_goto(&&MY_CONCAT(L,__LINE__));\
                                            if(!(__getSema(semaNum))) return;}\
                                            MY_CONCAT(L,__LINE__):
    #endif
        #if (SEMAPHORES_ON)
    #define osRELEASE_SEMA(semaNum)         __releaseSema(semaNum);
    #endif
        #if (SEMAPHORES_ON)
    #define osSET_SEMA_OWNER_RTR(semaNum)   __set_rtr(semaOwner[semaNum],1)
    #define osENABLE_SEMA_OWNER(semaNum)    __set_rtr(semaOwner[semaNum],1)
    #endif
        #if (SEMAPHORES_ON)
    #define osSET_RTR(taskname)             __set_rtr(taskname ## NUMBER,nSemas)
    #define osENABLE_TASK(taskname)         __set_rtr(taskname ## NUMBER,nSemas)
    #else
    #define osSET_RTR(taskname)             __set_rtr(taskname ## NUMBER,1)
    #define osENABLE_TASK(taskname)         __set_rtr(taskname ## NUMBER,1)
    #endif
        #endif 
                                                                                                            #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>
    #include <avr/wdt.h>
    #include "4AvrOS_Tasks.h"                               #include "4AvrOS.h"
            #define ERR__getSema            0x11          #define ERR__releaseSema        0x12          #define ERR__releaseSemaTN      0x13          #define ERR__set_rtr            0x14          #define ERR__clear_rtr          0x15          #define ERR__get_priority       0x16          #define ERR__set_priority       0x17          #define ERR__set_priorityP      0x18                  #ifdef TCCR0B
        #define Timer0_Control      TCCR0B
        #define Timer0_Irq_Mask     TIMSK0
        #define Timer0_Counter      TCNT0
    #elif defined TCCR0
        #define Timer0_Control      TCCR0
        #define Timer0_Irq_Mask     TIMSK
        #define Timer0_Counter      TCNT0
    #else
        #error "Timer0 register names unknown."
    #endif
        #define Timer0_Prescale         0x02                                    #define Timer0_tp10ms           (uint16_t)(F_CPU/8/100)                     #define RTR_ON                  0x80                    #define RTR_OFF                 0x00                    #define SEMA_BITS               0x0F                                                                                    uint16_t timer0_acc;
        struct ts {
        uint8_t *goto_label;                                    volatile uint8_t status;                                uint8_t sch_count;                                      volatile uint8_t ticks;                             } myTasks[nTasks];
        struct ts *thisTaskP = myTasks;
        uint8_t thisTaskN;
        #if (SEMAPHORES_ON)
    uint8_t semaOwner[nSemas];
    #endif
        const struct PROGMEM ta {
        uint16_t addr;                                          uint8_t init;                                       } taskAddress[nTasks] = {
        #ifdef __Task0
        { (uint16_t)__Task0,
        (__Task0_init | ((__Task0_priority & 7) << 4)) },
        #endif
        #ifdef __Task1
        { (uint16_t)__Task1,
        (__Task1_init | ((__Task1_priority & 7) << 4)) },
        #endif
        #ifdef __Task2
        { (uint16_t)__Task2,
        (__Task2_init | ((__Task2_priority & 7) << 4)) },
        #endif
        #ifdef __Task3
        { (uint16_t)__Task3,
        (__Task3_init | ((__Task3_priority & 7) << 4)) },
        #endif
        #ifdef __Task4
        { (uint16_t)__Task4,
        (__Task4_init | ((__Task4_priority & 7) << 4)) },
        #endif
        #ifdef __Task5
        { (uint16_t)__Task5,
        (__Task5_init | ((__Task5_priority & 7) << 4)) },
        #endif
        #ifdef __Task6
        { (uint16_t)__Task6,
        (__Task6_init | ((__Task6_priority & 7) << 4)) },
        #endif
        #ifdef __Task7
        { (uint16_t)__Task7,
        (__Task7_init | ((__Task7_priority & 7) << 4)) },
        #endif
        #ifdef __Task8
        { (uint16_t)__Task8,
        (__Task8_init | ((__Task8_priority & 7) << 4)) },
        #endif
        #ifdef __Task9
        { (uint16_t)__Task9,
        (__Task9_init | ((__Task9_priority & 7) << 4)) },
        #endif
        #ifdef __Task10
        { (uint16_t)__Task10,
        (__Task10_init | ((__Task10_priority & 7) << 4)) },
        #endif
        #ifdef __Task11
        { (uint16_t)__Task11,
        (__Task11_init | ((__Task11_priority & 7) << 4)) },
        #endif
        #ifdef __Task12
        { (uint16_t)__Task12,
        (__Task12_init | ((__Task12_priority & 7) << 4)) },
        #endif
        #ifdef __Task13
        { (uint16_t)__Task13,
        (__Task13_init | ((__Task13_priority & 7) << 4)) },
        #endif
        #ifdef __Task14
        { (uint16_t)__Task14,
        (__Task14_init | ((__Task14_priority & 7) << 4)) },
        #endif
        #ifdef __Task15
        { (uint16_t)__Task15,
        (__Task15_init | ((__Task15_priority & 7) << 4)) },
        #endif
    };
            static void __osError(uint8_t err,uint8_t bad_num);
    static void __restore_priority(uint8_t tn);
    static void __inc_sch_count(uint8_t tn);
    static void __schedule(void);
            void __save_goto(uint8_t *gl){
        thisTaskP->goto_label = gl;
    }
        static void __osError(uint8_t err,uint8_t bad_num){                        cli();
        while(1);     }
        static void __restore_priority(uint8_t tn){
        __set_priority(tn, (pgm_read_byte(&taskAddress[tn].init))>>4 & 7 );
    }
        uint8_t __get_priority(uint8_t tn){
        if(tn >= nTasks){                                           __osError(ERR__get_priority,tn);                        return 0;
        }
        else{
            return ((myTasks[tn].status >> 4) & 7);             }
    }
        void __set_priority(uint8_t tn, uint8_t pri){
        if(tn >= nTasks){                                           __osError(ERR__set_priority,tn);                    }
        else if(pri > 7){                                           __osError(ERR__set_priorityP,pri);                  }
        else{
            uint8_t temp_s;                                         temp_s = myTasks[tn].status & 0x8F;                     pri <<= 4;                                              myTasks[tn].status = temp_s | pri;                  }
    }
        void __set_rtr(uint8_t tn, uint8_t i){
        if(tn >= nTasks){                                           __osError(ERR__set_rtr,tn);                         }
        else{
            #if (SEMAPHORES_ON)
                                                while(--i){                                                 if(semaOwner[i] == tn){                                    return;                                             }
            }
                        if(myTasks[tn].status & 0x0F){                              return;                                             }
            #endif
            myTasks[tn].status |= RTR_ON;                           myTasks[tn].ticks = 0;                                                                                      }
    }
        void __clear_rtr(uint8_t tn){
        if(tn >= nTasks){                                           __osError(ERR__clear_rtr,tn);                       }
        else{
            myTasks[tn].status &= ~RTR_ON;
            myTasks[tn].ticks = 0;                              }                                                   }
        static void __inc_sch_count(uint8_t tn){
        struct ts *mt;                                          mt = &myTasks[tn];                                      if(mt->sch_count < 0xFF){                                   mt->sch_count++;                                    }
    }
        static void __schedule(void){
        uint8_t highestPriority;                                uint8_t i;                                              uint8_t this_pri;                                       uint8_t save_tn=0;                                      uint8_t this_cnt;                                       uint8_t save_cnt=0;                                     for(;;){                                                                                        highestPriority=8;                                                                          for(i=0; i < nTasks; i++){                                  this_pri = myTasks[i].status >> 4;                      this_cnt = myTasks[i].sch_count;                                                                        if(this_pri & 8){                                           this_pri &= 7;                                                                                                                          if(this_pri < highestPriority){                                                                                                                                                     if(highestPriority!=8){                                     __inc_sch_count(save_tn);                           }
                        highestPriority = this_pri;                             save_tn = i;                                            save_cnt = this_cnt;                                }
                                                                                                    else if(this_pri == highestPriority){                                                                                                 if(this_cnt > save_cnt){                                    __inc_sch_count(save_tn);                               save_tn = i;                                            save_cnt = this_cnt;                                }
                        else{                                                       __inc_sch_count(i);                                 }
                    }
                                                                                else{                                                       __inc_sch_count(i);                                 }
                }                                                                 else{                                                       if(myTasks[i].status & 0x0F){                               __inc_sch_count(i);                                 }
                }
            }             wdt_reset();                                                                                                                                                                                                                                                                                                                                                                        if(highestPriority != 8){                                   thisTaskN = save_tn;                                    thisTaskP = &myTasks[save_tn];                          thisTaskP->sch_count=0;                                                                                                 (  (void (*)(uint8_t *)) pgm_read_word(&taskAddress[save_tn].addr) ) (thisTaskP->goto_label);
            }
                                                                                                                    }     }         void __wait(uint8_t nTicks){
        thisTaskP->status &= ~RTR_ON;                           thisTaskP->ticks = nTicks;                          }
        
    #if (SEMAPHORES_ON)    
    uint8_t __getSema(uint8_t n){
        if((n == 0) || (n >= nSemas)){                              __osError(ERR__getSema,n);                              return 0;                                           }
        else if(semaOwner[n] == thisTaskN){                         return 1;                                           }
        else if(semaOwner[n] == 0xFF){                              semaOwner[n] = thisTaskN;                               return 1;                                           }
        else{                                                       thisTaskP->status &= ~RTR_ON;                           thisTaskP->status |= n;                                 if(__get_priority(thisTaskN) < __get_priority(semaOwner[n])){                  __set_priority(semaOwner[n],__get_priority(thisTaskN));             }
            return 0;                                           }
    }
    #endif
        #if (SEMAPHORES_ON)    
    void __releaseSema(uint8_t n){
        uint8_t i;                              uint8_t this_pri;                       uint8_t this_cnt;                       uint8_t save_tn=0;                      uint8_t save_cnt=0;                     uint8_t highestPriority=8;              if((n==0) || (n>=nSemas)){                                  __osError(ERR__releaseSema,n);                      }
        else if(semaOwner[n] != thisTaskN){                         __osError(ERR__releaseSemaTN,n);                    }
        else{
            __restore_priority(semaOwner[n]);             semaOwner[n] = 0xFF;                                    for(i = 0; i < nTasks; i++){                                    this_pri = myTasks[i].status;                               if((this_pri & SEMA_BITS) == n){                                this_pri = (this_pri >> 4) & 0x07;                          this_cnt = myTasks[i].sch_count;                            if(this_pri < highestPriority){                                 highestPriority = this_pri;                                 save_tn = i;                                                save_cnt = this_cnt;                                    }
                    else if(this_pri == highestPriority){                           if(this_cnt > save_cnt){                                        save_tn = i;                                                save_cnt = this_cnt;                                    }
                    }
                }
            }
            if(highestPriority != 8){                                       myTasks[save_tn].status |= RTR_ON;                          myTasks[save_tn].status &= ~SEMA_BITS;                      semaOwner[n] = save_tn;                                 }
        }
    }
    #endif
            ISR(TIMER0_OVF_vect){                                       timer0_acc += 256;                                      if(timer0_acc >= Timer0_tp10ms){                            TIMSK0 |= (1<<OCIE0A);                              }
    }
        
    ISR(TIMER0_COMPA_vect){                                     uint8_t i;                                              TIMSK0 &= ~(1<<OCIE0A);                                 timer0_acc -= Timer0_tp10ms;                            for (i = 0; i < nTasks; i++){                               if (myTasks[i].ticks){                                      if (--myTasks[i].ticks==0){                                 myTasks[i].status |= RTR_ON;                        }
            }
        }
    }
        int main(void){
                                                                MCUSR = 0;                                              wdt_disable();                                              init_mystuff();                                            #if (SEMAPHORES_ON)
        thisTaskN=nSemas;
        while(--thisTaskN){
            semaOwner[thisTaskN]=0xFF;
        }
        #endif
            Timer0_Control = Timer0_Prescale;
        Timer0_Irq_Mask |= (1<<TOIE0);
            thisTaskN=nTasks;
        do{
            thisTaskN--;
            myTasks[thisTaskN].status = pgm_read_byte(&taskAddress[thisTaskN].init);
        }while(thisTaskN);
            sei();
        __schedule();
        return 0;                                           }
                                                                                                        #ifndef _4AVROS_TASKS_H
    #define _4AVROS_TASKS_H
            #define __Task0                 demoLed1_Task
    #define __Task0_priority        2
    #define __Task0_init            RTR_ON
    #define __Task1                 demoLed2_Task
    #define __Task1_priority        2
    #define __Task1_init            RTR_ON
            #define SEMAPHORES_ON           1                                       
    enum {do_not_remove,semaTX,nSemas};
        void init_mystuff(void);                                                        #define SETUP_TASK2(name,num)           void name(uint8_t *gl);\
                                            enum{name ## NUMBER = num};
    #define SETUP_TASK(name,num)            SETUP_TASK2(name,num)
        #define nTasks 0                                                        #ifdef __Task0                                                          SETUP_TASK(__Task0,nTasks)                                              #undef nTasks                                                           #define nTasks 1                                                        #endif
    
    #ifdef __Task1                                                          SETUP_TASK(__Task1,nTasks)                                              #undef nTasks                                                           #define nTasks 2                                                        #endif
    #ifdef __Task2                                                          SETUP_TASK(__Task2,nTasks)
    #undef nTasks
    #define nTasks 3
    #endif
    #ifdef __Task3
    SETUP_TASK(__Task3,nTasks)
    #undef nTasks
    #define nTasks 4
    #endif
    #ifdef __Task4
    SETUP_TASK(__Task4,nTasks)
    #undef nTasks
    #define nTasks 5
    #endif
    #ifdef __Task5
    SETUP_TASK(__Task5,nTasks)
    #undef nTasks
    #define nTasks 6
    #endif
    #ifdef __Task6
    SETUP_TASK(__Task6,nTasks)
    #undef nTasks
    #define nTasks 7
    #endif
    #ifdef __Task7
    SETUP_TASK(__Task7,nTasks)
    #undef nTasks
    #define nTasks 8
    #endif
    #ifdef __Task8
    SETUP_TASK(__Task8,nTasks)
    #undef nTasks
    #define nTasks 9
    #endif
    #ifdef __Task9
    SETUP_TASK(__Task9,nTasks)
    #undef nTasks
    #define nTasks 10
    #endif
    #ifdef __Task10
    SETUP_TASK(__Task10,nTasks)
    #undef nTasks
    #define nTasks 11
    #endif
    #ifdef __Task11
    SETUP_TASK(__Task11,nTasks)
    #undef nTasks
    #define nTasks 12
    #endif
    #ifdef __Task12
    SETUP_TASK(__Task12,nTasks)
    #undef nTasks
    #define nTasks 13
    #endif
    #ifdef __Task13
    SETUP_TASK(__Task13,nTasks)
    #undef nTasks
    #define nTasks 14
    #endif
    #ifdef __Task14
    SETUP_TASK(__Task14,nTasks)
    #undef nTasks
    #define nTasks 15
    #endif
    #ifdef __Task15
    SETUP_TASK(__Task15,nTasks)
    #undef nTasks
    #define nTasks 16
    #endif
    #if (!(nTasks))
    #error No Tasks Defined in 4AvrOS_Tasks.h (you want a taskless os?)
    #endif
        #endif 
                                                                                                            #include <avr/io.h>
    #include "4AvrOS_Tasks.h"                               #include "4AvrOS.h"
                    void init_mystuff(void){
        DDRB |= ((1<<PB0) | (1<<PB1));     }
                BEGIN_TASK(demoLed1_Task)                                   osWAIT(100);                                            PORTB ^= (1<<PB0);                                  END_TASK
        BEGIN_TASK(demoLed2_Task)                                   static uint8_t i;
        for(i=1; i<15; i++){
            osWAIT(i);                                              PORTB ^= (1<<PB1);                                  }
    END_TASK