__ __
___
____ _____
/ // / / |_ _______/ __ \/ ___/
/ // /_/ /| | | / / ___/ / / /\__ \
/__ __/ ___ | |/ / / / /_/ /___/ /
/_/ /_/ |_|___/_/ \____//____/
____
____
_
_ _
/ ___|___ ___ _ __ /
___| ___| |__ ___ __|
|_ _| | ___ _ __
| | / _ \ / _ \| '_ \ \___ \ / __| '_ \ /
_ \/ _` | | | | |/ _ \ '__|
| |__| (_) | (_) | |_) | ___) | (__| | | | __/ (_|
| |_| | | __/ |
\____\___/ \___/| .__/ |____/ \___|_|
|_|\___|\__,_|\__,_|_|\___|_|
|_|
__
__
/ / __ __ ______ ______/ /__ ____ _
/ _ \/ // / / __/ // / __/ __/ |/ / ' \
/_.__/\_, / \__/\_,_/_/ \__/|___/_/_/_/
/___/
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