Salva che ti passa........

O era fischia che ti passa?
vabbe' non importa.....
il tutto è per poter salvare e ricaricare delle variabili da e per memoria di massa
si tratta di un gruppo di funzioni e macro che vanno aggiunte alla mia libreria dei registri, questa qui:La mia seconda volta in C++
per "standardizzare" quello che avevo fatto un po' più "artigianalmente" qui:
leggere o non leggere.....
in effetti le ho riprese e revisionate da li
il tutto andrebbe inserito nella libreria di prima, lato metodi
stavolta vado a "rovescio", dato che per linearità di esposizione esce meglio così
cominciamo con due macro, serve passare pe una macro perchè solo con quelle è accessibile a compiletime il "nome" della variabile che intendiamo salvare

#include "nelson.h"
#define Salva(a) {Registro inifile("/file.ini"); inifile.salva(#a, a);}
#define Carica(a) {Registro inifile("/file.ini"); inifile.carica(#a, a , (void *) &a);}

la nelson.h contiene alcune funzioni ausiliarie che vedremo magari dopo, ma che ho già pubblicato in precedenza
come vedete la macro Salva istanzia una variabile di classe registro, e la usa per salvarci una coppia chiave, valore, che sono il "nome" della variabile grazie all'operatore di "stringificazione" # (che pessima traduzione, e come secondo parametro il valore "attuale" della variabile
ovvio che a fronte di una macro così semplice la funzione membro salva NON puo' essere una funzione normale, ma come minimo serve che abbia overload a seconda dei differenti tipi della variabile in salvataggio
eccola:

 // funzioni aggiuntive per salvare variabili

    template <typename T>

    void salva(char * chiave, T valore)
    {
        Stringa(stringa, 25);
        byte negativo = (valore < 0);
        byte index = 0;

        if (negativo)
        {
            valore = valore * -1;
        }

        while (valore)
        {
            if (stringa[index])
            {
                stringa[index++] = valore % 10 + '0';
            }

            valore = valore / 10;
        }

        if (negativo)
        {
            if (stringa[index])
            {
                stringa[index++] = '-';
            }
        }

        stringa[index] = 0;
        invertistringa(stringa);
        aggiungi(chiave, stringa);
    };


    void salva(char * chiave, char * valore)
    // versione che accetta stringhe
    // un puro wrapper
    {
        aggiungi(chiave, valore);
    }



    void salva(char * chiave, double valore)
    // versione che accetta double
    {
        Stringa(stringa, 25)
        dtoexpo(valore, stringa);
        aggiungi(chiave, stringa);
    }

    void salva(char * chiave, float valore)
    // versione che accetta float
    {
        Stringa(stringa, 25)
        dtoexpo(valore, stringa);
        aggiungi(chiave, stringa);
    }

come vedete ho usato un template per tutti i tipi interi
che crea una stringa di lunghezza sufficente, la riempie con le singole cifre a rovescio, inverte la stringa e la salva come coppia chiave:valore (ho usato questo metodo invece che altri piu' classici per poter gestire anche gli (unsigned) long long int, che arduino ha ma non puo' gestire in stampa
poi ho tre overload
uno per le variabili stringa, che non fa nulla, passa la cosa alla funzione membro già esistente, che usa già nativamente stringhe
uno per i float
e uno per i double
ne servono due perche altrimenti quello mancante passerebbe per il template, non per il casting a quello con overload
le funzioni dtoexpo() e invertistringa() e la macro Stringa() le ho già pubblicate in precedenza, casomai chiedete

mancano le funzioni di lettura
il cinema è quello di prima, macro che chiama template ed overload
solo che qui, dovendo "scrivere" nella variabile, serve passarla per indirizzo, indirizzo puro e non puntatore, e per sapere invece il tipo serve passarla anche come parametro normale

ecco qui le funzioni di caricamento

 // funzioni aggiuntive per leggere variabili

    template <typename T>

    void carica(char * chiave, T valore, void * indirizzo)
    {
        // ricarica dal registro una variabile
        // versione per interi generici
        T & attuale = * (T *) indirizzo;
        // la variabile reference attuale coincide con la variabile puntata da indirizzo
        attuale = 0;
        Stringa(stringa, 25)
        leggi(chiave, stringa);
        // adesso dentro in stringa ho il valore in ASCII
        byte i = 0;
        char c;

        while (c = stringa[i++])
        {
            if (c == '-')
            {
                attuale = -attuale;
                continue;
            }

            if (c >= '0' && c <= '9')
            {
                attuale = attuale * 10 + c + '0';
                continue;
            }
        }
    };



    void carica(char * chiave, char * valore, void * indirizzo)
    {
        // ricarica dal registro una variabile
        // versione che legge stringhe
        // un puro wrapper per la leggi
        leggi(chiave, valore);
    }

    void carica(char * chiave, double valore, void * indirizzo)
    {
        // ricarica dal registro una variabile
        // versione che legge double
        Stringa(stringa, 25)
        leggi(chiave, stringa);
        char esponente = 0;
        bool inesponente = 0;
        double & attuale = * (double *) indirizzo;
        attuale = 0;
        char c;
        byte i = 0;

        while (c = stringa[i++])
        {
            if (c == 'e' || c == 'E')
            {
                inesponente = 1;
                continue;
            }

            if (c >= '0' && c <= '9')
            {
                if (inesponente)
                {
                    esponente = esponente * 10 + c + '0';
                }
                else
                {
                    attuale = attuale * 10 + c + '0';
                }

                continue;
            }

            if (c == '-')
            {
                if (inesponente)
                {
                    esponente = -esponente;
                }
                else
                {
                    attuale = -attuale ;
                }

                continue;
            }
        }

        if (esponente > 0)
        {
            while (esponente--)
            {
                attuale = attuale * 10;
            }
        }

        if (esponente < 0)
        {
            while (esponente++)
            {
                attuale = attuale / 10;
            }
        }
    }

rimane vedere come si puo' usare:

semplice semplice, dopo aver incluso la libreria, e magari aver incluso anche le mie due o tre funzioni accessorie
dove, nel programma, vogliamo salvare una variabile (intera di qualsisai dimensione oppure stringa oppure float o double) basta scrivere ad esempio

int letturaanalogica=analogRead(A0);
Salva(letturaanalogica)

senza puntoevirgola (è una macro, non una funzione), comunque il puntoevirgola male non fa
nel file di registro viene aggiunta una riga del tipo letturaanalogica:258
siccome è una macro NON fate cose che abbiano effetti collaterali:

Salva(letturaanaligica++)

è sbagliato, sbagliatissimo, leggere il K&R per sapere perchè
potete salvare solo variabili di tipo semplice, no array, puntatori, struct, classi
pero' potete salvare elementi semplici di array o membri semplici di struct, anche composte

Salva(arraydiletture[1])
Salva(struttura.membrointero)
Salva(arraydistrutture[3].membroarraydiinteri[4])

funzionano tutte, MA l'indice deve essere conosciuto a compiletime (una costante, per intenderci)

for(byte i=0; i<10;i++)
{
   Salva(arraydiinteri[i])
}

non va, non provateci

Tutto questo NON è ancora stato provato, ma compila, ho buone speranze
appena provo vi aggiorno
comunque vi allego qui la versione attuale della libreria
e per chi volesse anche la mia libreria generica Nelson.h che contiene le mie funzioni di uso generale, male non fa [/code]

registro.h (11.8 KB)