leOS - un semplice OS per schedulare piccoli task

Un test.... una prova... un commento... :cold_sweat:

:fearful:

Ho letto la discussione che ha portato a leos2. Tanto di cappello per questo nuovo lavoro sul "wdt-based scheduler" :slight_smile:
Ho letto anche l'articolo sul tuo sito: interessante e ben scritto IMHO.

Appena ho un minuto voglio provare con calma il leos2.

Nel frattempo ti segnalo un typo:

core Tiny per i microcontrollorti Attiny

tuxduino:
Nel frattempo ti segnalo un typo:

core Tiny per i microcontrollorti Attiny

Corretto.

ciao, con la versione 1 come faccio ad aumentare l'intervallo minimo da 1000 a 2000 millisecondi?
ho guardato in leOS.cpp ma l'unico 1000 che trovo è F_CPU == 1000000UL

d407336:
ciao, con la versione 1 come faccio ad aumentare l'intervallo minimo da 1000 a 2000 millisecondi?
ho guardato in leOS.cpp ma l'unico 1000 che trovo è F_CPU == 1000000UL

Domanda sibillina :sweat_smile:
Se intendi aumentare l'intervallo di esecuzione di uno sketch, questo lo imposti tu durante l'aggiunta del task allo scheduler:
myOS.addTask(funzione, intervallo)
Basta mettere "intervallo" a 2000 ed il task sarà eseguito ogni 2000 millisecondi.

Se stai guardando nel file .cpp, cosa stai cercando? L'impostazione del timer 2 è fatta per avere un overflow ogni millisecondo, quindi 1 ms è l'intervallo minimo.

Quindi mi basta mettere 2000 come intervallo in addTask() ?
Sul tuo sito però ho letto una cosa diversa: leOS, un semplice SO per Arduino – Leonardo Miliani

Con miaFunzione indicate la funzione che volete schedulare, con intervallo un numero non più grande di 1000 (potete modificare questo valore nel file leOS.cpp) che indica ogni quanti ms volete far ripetere la vostra funzione.

E' una refuso probabilmente di vecchie versioni. Quella pagina la aggiorno via via, ma qualcosa mi può essere scappato. Correggo subito :wink:

PS: ricordati che puoi anche cambiare questo valore "in corsa", ossia anche dopo che il task è stato inserito nello scheduler, usando la funzione modifyTask e passando il nuovo intervallo.

ok, grazie mille!

per il problema dei lavori gravosi che avevo chiesto qualche pagina fà, è una buona idea fare con leOS i compiti meno gravosi che voglio siano fatti sempre con un intervallo preciso, e fare con looper il resto?

leOS e looper sono incompatibili perché entrambi basati sull'uso del timer 2.
Potresti provare looper e leOS2 ma, alla fine, forse incasini tutto e basta. Tanto vale strutturare meglio il codice, perché forse se hai bisogno di una gestione così articolata il problema potrebbe risiedere nella logica del programma.

il mio problema è che devo aggiornare un display lcd, e lo vorrei fare non più velocemente di ogni secondo, perchè se no non si leggerebbe bene e non mi serve istantaneamente vedere le variazioni.
farò con il metodo blinkwithoutdelay, è una buona idea secondo te?

d407336:
il mio problema è che devo aggiornare un display lcd, e lo vorrei fare non più velocemente di ogni secondo, perchè se no non si leggerebbe bene e non mi serve istantaneamente vedere le variazioni.
farò con il metodo blinkwithoutdelay, è una buona idea secondo te?

leo mi pare che leOS sia preemptive quindi sia possibile usare la delay(), giusto ?

con leOS il delay non influisce sui task, con looper influisce solo quando supera le tempistiche dei task (vediamo se leo mi bacchetta :))

Io ho fato la tua stessa cosa del display con blinkwithout delay, prima che leo inventasse looper.
Ora mi chiedevo se e' piu' facile usare looper o il blinkwithout delay, leo che dici quale e' piu' intuitivo-userfriendly ?

Purtroppo ancora non e' stato inventato il "mio" mitico delay2() dove basterebbe scrivere delay2(1000) per avere un blinkwithoutdelay facile da usare.

Leo ma questa mi idea e' informaticamente irrealizzabile ?

d407336:
il mio problema è che devo aggiornare un display lcd, e lo vorrei fare non più velocemente di ogni secondo, perchè se no non si leggerebbe bene e non mi serve istantaneamente vedere le variazioni.
farò con il metodo blinkwithoutdelay, è una buona idea secondo te?

Secondo me la soluzione più semplice è quella di crearsi un buffer video e poi di riversare ogni xxx ms tale buffer sul display.
Cos'è un buffer video? E' una memoria tampone usata per scrivere le informazioni che poi devono essere visualizzate. Chi ha usato un Commodore ai tempi degli anni '80 sa di cosa parlo: lì esisteva una parte della RAM riservata alla memoria video suddivisa in 1024 byte per i dati e 1024 byte per gli attributi colore. L'utente poteva scrivere direttamente in quel buffer, era compito del chip video generare l'immagine video da spedire alla TV per la visualizzazione.
Tu puoi fare così, simulando appunto un buffer video in cui scrivi le tue informazioni.
Ad esempio, hai un display LCD 20x4? Ti crei un array di 20x4 caratteri.
Quando tu vuoi scrivere qualcosa a video NON spedisci i dati direttamente all'LCD ma li scrivi in questo buffer con la stessa tecnica. Ad esempio, se sulla 1a riga, dalla 1a colonna, vuoi scrivere "CIAO" basterà scrivere la stringa a partire dalla locazione 0,0 dell'array.
Il task si preoccuperà, al suo intervallo, di spedire le 4 righe di 20 caratteri l'una al display. In questo modo l'operazione sarà più rapida.

Se hai voglia di approfondire, puoi guardare il mio sketch "Gamepack":
http://www.leonardomiliani.com/?page_id=374
si tratta di una raccolta di 3 giochini che scrissi 1 anno e mezzo fa per l'Arduino ed uno shield LCD con minijoystick di Nuelectronics dove usai il concetto di buffer video. Quel codice, a distanza di 1 anno e mezzo, mi fa ridere (fu il mio primo lavoro serio fatto con l'Arduino), non avevo minimamente conoscenze sui timer quindi aggiornavo il display a mano. Però ti può risultare utile per capire il concetto.

tuxduino:
leo mi pare che leOS sia preemptive quindi sia possibile usare la delay(), giusto ?

No, nulla di tutto questo. :sweat_smile:
Il leOS semplicemente esegue una funzione richiamandola all'interno della ISR del timer 2 o del watchdog.
Il leOS è di tipo cooperativo, nel senso che il controllo allo scheduler viene reso dal task quando questo ha terminato la sua esecuzione. Quindi è una terminazione "volontaria".
Nei SO con prelazione (preemptive) quali FemtoOS, FreeRTOS ecc... è il SO che congela il task se questo è ancora in esecuzione terminato il tempo a sua disposizione.

Nel leOS2 si ha un controllo rudimentale sul task in esecuzione, nel senso che se questo resta in esecuzione oltre un certo periodo fissato in precedenza, il microcontrollore si resetta. Questo è utile per evitare che un task congeli la CPU bloccando tutto il microcontrollore o l'Arduino di turno.

Testato:
con leOS il delay non influisce sui task, con looper influisce solo quando supera le tempistiche dei task (vediamo se leo mi bacchetta :))

In un certo senso è così.
All'atto pratico, ossia agli occhi di ciò che vede l'utente, l'unica differenza fra il leOS ed il looper pare essere appunto il non congelamento del looper rispetto al leOS. In realtà la differenza è molto più radicale. Il looper altro non è che una semplice che non fa altro che, quando viene richiamata, controllare se è passato l'intervallo di esecuzione di una funzione.
Con il leOS imposti un valore, allo scoccare del suo tempo il task in oggetto verrà eseguito. Punto.
Col looper puoi anche infilare dentro ad una funzione (non parliamo di task) delay e quant'altro. L'unica cosa che otterrai sarà il rallentamento generale ed il salto del tempo a cui erano stati programmati i richiami delle funzioni utente.

Io ho fato la tua stessa cosa del display con blinkwithout delay, prima che leo inventasse looper.
Ora mi chiedevo se e' piu' facile usare looper o il blinkwithout delay, leo che dici quale e' piu' intuitivo-userfriendly ?

Se devi eseguire 1 solo compito, puoi farlo col metodo del controllo del tempo basato su millis(), è ciò che fa il looper.
Se devi eseguire più di 1 compito, anche solo 2, allora il looper fa i controlli al posto tuo e tutto diventa semplificato. Immagina alla mole di if da inserire nel codice se devi ad esempio fare 10 azioni con tempistiche differenti.

Purtroppo ancora non e' stato inventato il "mio" mitico delay2() dove basterebbe scrivere delay2(1000) per avere un blinkwithoutdelay facile da usare.

Leo ma questa mi idea e' informaticamente irrealizzabile ?

Ma col leOS non hai più bisogno del delay2(1000).
Dimmi ad oggi dov'è il vantaggio di delay2(1000) quando fai un addTask(blink, 1000) ed hai risolto. :stuck_out_tongue:

leo72:

tuxduino:
leo mi pare che leOS sia preemptive quindi sia possibile usare la delay(), giusto ?

No, nulla di tutto questo. :sweat_smile:
Il leOS semplicemente esegue una funzione richiamandola all'interno della ISR del timer 2 o del watchdog.
Il leOS è di tipo cooperativo, nel senso che il controllo allo scheduler viene reso dal task quando questo ha terminato la sua esecuzione. Quindi è una terminazione "volontaria".
Nei SO con prelazione (preemptive) quali FemtoOS, FreeRTOS ecc... è il SO che congela il task se questo è ancora in esecuzione terminato il tempo a sua disposizione.

Beh, mi sono espresso in modo un po' approssimativo, lo ammetto :slight_smile:
So bene che non si tratta di un OS né che è preeptive nel senso proprio del termine :slight_smile:
Tuttavia rispetto a robe come la SimpleTimer e tante altre simili che sono sostanzialmente la "librerizzazione" del blink without delay, ho notato che qui il task viene chiamato all'interno della timer2 ISR.
Con due blink task, uno ogni 1000ms e uno ogni 500ms, se in quest'ultimo metto un delay(1000) il lampeggio funziona comunque correttamente. Sembra quasi da alcuni esperimenti che delay() ritorni immediatamente...
Ma non voglio fare l'hijack del thread :wink: c'è un megatopic apposta per queste cose, vado a studiare :smiley:

(edit: ma siamo nel megatopic O_o )

tuxduino:
Tuttavia rispetto a robe come la SimpleTimer e tante altre simili che sono sostanzialmente la "librerizzazione" del blink without delay, ho notato che qui il task viene chiamato all'interno della timer2 ISR.

Sì i task sono richiamati all'interno della ISR, ecco perché dico sempre di farli il più snelli possibile, per non rallentare eccessivamente la CPU nell'esecuzione del codice principale.

Con due blink task, uno ogni 1000ms e uno ogni 500ms, se in quest'ultimo metto un delay(1000) il lampeggio funziona comunque correttamente. Sembra quasi da alcuni esperimenti che delay() ritorni immediatamente...

Non ho capito... :sweat_smile:

Ma non voglio fare l'hijack del thread :wink: c'è un megatopic apposta per queste cose, vado a studiare :smiley:

(edit: ma siamo nel megatopic O_o )

Sì, saremmo nel Megatopic :stuck_out_tongue_closed_eyes:

leo72:

Con due blink task, uno ogni 1000ms e uno ogni 500ms, se in quest'ultimo metto un delay(1000) il lampeggio funziona comunque correttamente. Sembra quasi da alcuni esperimenti che delay() ritorni immediatamente...

Non ho capito... :sweat_smile:

Non ho sotto mano una breadboard per fare delle prove con i led. Ho però uno shield con un LCD...

#include <leOS.h>
#include <LiquidCrystal.h>

leOS myOS;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);    // lcd pins for nuelectronics lcd+keypad shield
const short LCD_ROWS = 2;
const short LCD_COLS = 16;

//variables to control the LEDs
byte led1Status = 0;
byte led2Status = 0;
byte led3Status = 0;


void setup() {
    myOS.begin();
    lcd.begin(LCD_COLS, LCD_ROWS);
    lcd.clear();

    myOS.addTask(flashLed1, 500);
    myOS.addTask(flashLed2, 500);
}


//main loop
void loop() {
    lcd.setCursor(0, 0);
    lcd.print(led3Status ? '3' : ' ');
    led3Status ^= 1;    
    delay(1000);
}


//first task
void flashLed1() {
    lcd.setCursor(2, 0);
    lcd.print(led1Status ? '1' : ' ');
    led1Status^=1;
    delay(800);                // <<<<<<<<<<<<<<<< (*)
    lcd.setCursor(4, 0);
    lcd.print(led1Status ? '1' : ' ');
}


//second task
void flashLed2() {
    lcd.setCursor(6, 0);
    lcd.print(led2Status ? '2' : ' ');
    led2Status^=1;
}

Risultato:
A) il numero 3 in posizione 0, 0 lampeggia con T=2000

B) il numero 1 in posizione 2, 0 lampeggia con T=1000
C) il numero 1 in posizione 4, 0 lampeggia insieme a B), ma in controfase

D) il numero 2 in posizione 6, 0 lampeggia in fase con B, in controfase con C

Mi aspetterei invece che il delay (*) alterasse la frequenza dei lampeggi.

Sono a lavoro per cui anch'io non posso fare prove. Oggi a casa indagherò