Il compilatore XC8, come migrare dal C18

Dopo aver imparato ad usare il nuovo ambiente di sviluppo MPLAB X della Microchip, è bene fare un nuovo salto in avanti e iniziare ad utilizzare anche i nuovi compilatori della famiglia XC. In questo articolo verranno trattate le impostazioni base e cambiamenti da apportare al nostro codice precedentemente scritto in C18. Particolare attenzione verrà posta per facilitare l'adattamento del software presentato nel testo C18 Step by Step e negli esempi del sito LaurTec.


Prima di iniziare...

   La Brief Note introduce le nuove caratteristiche del compilatore XC8 messo a confronto con il compilatore C18. Particolare attenzione è posta per permettere una facile migrazione dal C18 al XC8 rendendo il passaggio semplice ed efficace. Alla fine dell'articolo avrete le giuste conoscenze per iniziare un nuovo progetto direttamente in XC8 e sfruttare dunque i vantaggi introdotti da questo compilatore a supporto del programmatore. Ciononostante molti aspetti più avanzati  non sono trattati e si rimanda per tanto alla user Guide relativa al compilatore utilizzato. In particolare ogni famiglia di PIC, a seconda della sua architettura, 8, 16 o 32 bit, possiede un compilatore della famiglia XC dedicato, ovvero XC8, XC16 e XC32. Nella seguente Brief Note è introdotto solo il compilatore XC8, per cui alcuni aspetti non sono validi per gli altri compilatori.  


Le origini del compilatore XC8

   Sebbene abbia già fatto rifermento al compilatore XC8 come al nuovo compilatore della Microchip, in realtà di nuovo non c'e' moltissimo. Infatti nel 2009 la Microchip ha acquisito la nota società HiTech C, la quale produceva compilatori per diverse famiglie di microcontrollori, tra i quali anche quelli della Microchip. I compilatori HiTech C per PIC erano noti per essere migliori dei compilatori C18, C30 offerti dalla Microchip, inoltre HiTech supportava anche i microcontrollori  ad 8 bit della famiglia Base Line  e Mid-Range. Dopo l'acquisizione, sebbene Microchip abbia iniziato ad offrire direttamente il compilatore HiTech C, si è venuta a creare qualche confusione tra i progettisti che si sono trovati due diversi compilatori non totalmente compatibili tra loro. Per mezzo delle direttive per discriminare il compilatore, molti esempi Microchip supportavano nativamente sia il compilatore HiTech che C18, anche prima dell'acquisizione della società HiTech. Ciononostante avere troppi prodotti da supportare, oltre che creare confusione ai progettisti, risultava difficile per gli sviluppatori, nonché costoso. Per tali ragioni dopo un primo passo nel rinominare semplicemente il Compilatore C18 in compilatore C per PIC18 e ritoccare leggermente le licenze, si è giunti all'avere un unico compilatore che risulta la fusione tra il C18 e l'HiTech C. In realtà, dietro le quinte, il compilatore XC8 non è altro che il compilatore HiTech C, visto che era migliore perché non riutilizzarlo?
    Compilando un sorgente per mezzo del compilatore XC8 apprezzerete la presenza di molte più Warning che prima il C18 non mostrava. La presenza di più Wanring vi permetterà presto di rendere il vostro codice più robusto contro “sviste” di programmazione.    
Da un punto di vista delle configurazioni il C18 ha fatto diciamo da padrone, per cui chi proviene dal C18 forse troverà il compilatore XC8 più familiare alla lettura, rispetto a coloro che sono abituati all'HiTech C. In realtà, sebbene il compilatore XC8 rappresenti una riorganizzazione dei vecchi compilatori e sintassi degli stessi, c'e' stato uno sforzo aggiuntivo. Infatti, ora, ogni microcontrollore Microchip possiede un proprio compilatore il cui nome è XC con relativa dimensione dell'architettura, ovvero XC8, XC16 e XC32. I vari compilatori, sebbene facciano riferimento ad architetture diverse hanno ora molte cose in comune, grazie alla possibilità di usare il CCI (Common C Interface). Questa interfaccia rappresenta un livello di astrazione del compilatore che permette in un certo qual modo di uniformare molte parti del codice non standardizzate in C e poter cosi migrare il codice da un'architettura ad un'altra con un minor sforzo (altri dettagli saranno mostrati a breve). Chi è abituato a programmare in C18 avrà ora il vantaggio di vedere i propri programmi scritti per PIC18, essere eseguiti anche nei PIC16 (almeno fino a quando si fanno uso di moduli e parti dell'architettura in comune ai PIC16 e PIC18). Per passare da un PIC ad un altro basterà cambiare il PIC nelle proprietà del progetto.
I compilatori XC hanno un altro punto attraente se paragonati al C18 e l'HiTech C. Entrambi i compilatori erano a pagamento, sebbene fosse presente una versione gratuita di prova.
    Il compilatore C18 aveva la licenza Student, rinominata accademic in un secondo tempo, mentre l'HiTech possedeva la versione Lite in cui c'era un limite nelle dimensioni del codice, cosa non presente nelle versioni gratuite del compilatore C18 (vecchie versioni del compilatori possono essere ancora scaricate ma non sono più supportate da aggiornamenti). I compilatori della serie XC vengono offerti con licenza Free, Standard e PRO. La versione Free  è totalmente gratuita e può essere utilizzata anche per applicazioni commerciali. Pecca, di questa versione è che il compilatore non effettua praticamente alcuna ottimizzazione, il che si traduce generalmente in codici più grandi e meno efficienti da un punto di vista dell'esecuzione. La versione Standard e PRO sono due versioni a pagamento del compilatore XC e si differenziano nel costo e nella capacità di ottimizzare il codice. Per le applicazioni di studenti, hobbysti o piccole società, la versione Free non pone molti limiti, ma richiede spesso di ottimizzare il codice manualmente rendendolo meno leggibile. Spesso molte ottimizzazioni fatte nella versione Free non sarebbero necessarie se il programma venisse compilato con una licenza Standard o PRO.     

    La Microchip, oltre ad aver introdotto i nuovi compilatori della famiglia XC ha anche rilasciato il nuovo IDE MLAP X, introdotto già nella Brief Note BN0017 - MPLAB X. Grazie a questi due cambiamenti il progettista si trova ora ad avere il meglio dei compilatori precedenti e un ambiente di sviluppo armonizzato basato sull'IDE NetBeans, il quale ha portato un respiro di freschezza a chi era solito programmare utilizzando MPLAB IDE.      


Installare il compilatore XC8

   I compilatori della famiglia XC, come anche in passato, rappresentano applicazioni indipendenti che vengono richiamate per linea di comando dall'ambiente di sviluppo, il quale deve essere installato prima di installare il compilatore XC8. In particolare nel seguito dell'articolo si farà riferimento all'ambiente di sviluppo MPLAB X. Dal momento che l'IDE, come anche il compilatore, supportano sia l'ambiente di sviluppo Windows, Linux che Mac, le immagini che potreste avere nel vostro ambiente operativo potrebbero differire leggermente rispetto a quelle qui presentate (nell'articolo farò riferimento al sistema operativo Windows).   

    Come prima cosa, qualora non si abbia già MPLAB X, si scarichi l'ultima versione dal sito Microchip (si raccomanda la lettura della Brief Note BN0017 MPLAB X, prima di procedere oltre, al fine di avere una miglior familiarità con l'ambiente di sviluppo). Una volta installato l'IDE è possibile procedere all'installazione del compilatore XC8, scaricabile dal sito Microchip. Come licenza scegliere la versione FREE, a meno che non si voglia valutare quella a pagamento, per un tempo limitato e gratuito.   
Come mostrato nella Brief Note BN0017 MPLAB X, una volta che si crea un nuovo progetto, se l'installazione  è andata a buon fine, si avrà la possibilità di selezionare il compilatore XC8 per un progetto che utilizza un PIC ad architettura ad 8 bit. Qualora si abbia già il compilatore C18 installato, oltre al poter scegliere il compilatore XC8, verrà ancora data la possibilità di selezionare il compilatore C18. Quando si installeranno nuove versioni del compilatore, ogni versione sarà disponibile e visualizzata durante la creazione di un progetto. Ogni progetto manterrà selezionata l'opzione della versione del compilatore selezionato durante la creazione del progetto stesso. Qualora si installi una nuova versione e si voglia cambiare la versione del compilatore con cui compilare un progetto, è possibile sempre farlo dalla finestra delle proprietà del progetto, alla voce Conf, come mostrato in Figura 1.

 

Figura 1: Cambio della versione del compilatore per un progetto precedentemente creato

Figura 1: Cambio della versione del compilatore per un progetto precedentemente creato.

   Da questa finestra è anche possibile cambiare lo strumento di programmazione e debug, oltre al chip stesso, che come spiegato nella Brief Note BN0017 appartengono alle informazioni memorizzate in ogni progetto.

Qualora il compilatore XC8 non venga propriamente visto dall'ambiente di sviluppo MPLAB X è necessario impostare manualmente i percorsi per mezzo della finestra di Figura 2, richiamabile dal menu Tools-> Options.

 

Figura 2: Percorsi associati al compilatore XC8

Figura 2: Percorsi associati al compilatore XC8.

Prime impostazioni del compilatore XC8

   Per poter scrivere un programma che sia compilabile per mezzo del compilatore XC8, come per ogni progetto, è necessario impostare i percorsi di libreria per mezzo delle opzioni delle proprietà di progetto. In Figura 3 è possibile vedere che diversamente dal compilatore C18, tutti i percorsi da includere sono da porre all'interno del campo “Include Directories”, sia che si tratti header file che di file di libreria. Le librerie C18 sono state riadattate per il compilatore XC8, gli header file si trovano nel seguente percorso (la radice può cambiare in base al percorso d'installazione che si è scelto) :

C:\Program Files (x86)\Microchip\xc8\v1.12\include\plib

    In Figura 3  è possibile vedere che  è stata abilitata l'opzione “Use CCI syntax”, ovvero  è stata abilitata la sintassi del Common C Interface che permette di forzare la scrittura del codice in maniera che sia più facilmente portabile tra i vari compilatori. Come vedremo a breve, questo non comporta alcun stravolgimento del programma e della sintassi. In particolare la Microchip incoraggia l'utilizzo del CCI, per cui tratterò il caso in cui tale opzione sia abilitata.   

 

Figura 3: Impostazione dei percorsi e abilitazione della sintassi CCI

Figura 3: Impostazione dei percorsi e abilitazione della sintassi CCI.

   La sintassi CCI impone che vengano utilizzati 32bit per le variabili float e double. Tale impostazione è disponibile tra le proprietà del progetto alla voce XC8 linker, tra le opzioni del Memory model, come riportato in Figura 4.  Qualora si attivasse la sintassi CCI e non si cambiasse tale impostazione si avrebbero le seguenti Warning:

:: warning: 24-bit floating point types are not supported; float have been changed to 32-bits
:: warning: 24-bit floating point types are not supported; double have been changed to 32-bits   

 

Figura 4: Impostazione a 32 bit per le variabili double e float

Figura 4: Impostazione a 32 bit per le variabili double e float.

   Un'ultima impostazione che può tornare utile ma che non verrà ulteriormente trattata è l'opzione Codeoffset, presente tra le proprietà XC8 Linker e le configurazioni “Additional Options”. Il codeoffset permette di spostare il codice dell'applicazione, spostando in automatico anche il reset vector e relativi vettori delle interruzioni. Questo risulta particolarmente utile quando si debba scrivere un programma che faccia uso di un bootloader.  

 

Figura 5: Opzione Codeoffset per spostare il vettore di Reset e delle interruzioni

Figura 5: Opzione Codeoffset per spostare il vettore di Reset e delle interruzioni.

Programmare in XC8 facendo uso del CCI

   Una volta effettuate le prime impostazioni nella finestra delle proprietà del progetto, è possibile iniziare a scrivere il nostro codice tenendo conto che scriviamo per il compilatore XC8 e la sintassi CCI. Vediamo i vari punti da tenere a mente...

  • In C18 la prima riga da scrivere in un nuovo codice è #include <p18f4550.h> o altro header file in cui si specifica il PIC che viene utilizzato. Tale file contiene i relativi registri e configurazioni del PIC da utilizzare durante la programmazione. Con XC8 questo non è più necessario, ma bisogna scrivere #include <xc.h>.  Il fatto che non sia più necessario includere l'header file del microcontrollore usato, discende in realtà dal nuovo ambiente di sviluppo MPLAB X che include, tra le configurazioni del progetto, anche il PIC utilizzato. Per tale ragione l'header file e linker file necessari sono automaticamente inclusi in base al PIC selezionato in fase di creazione del progetto.
  • Dopo aver incluso il file xc.h  è necessario includere gli altri file di libreria necessari per il progetto. Nulla di nuovo se non per il fatto che CCI impone di includere i file facendo uso del percorso relativo, ovvero bisogna includere solo il nome del file senza precedere lo stesso con il percorso assoluto. Per esempio, per includere la libreria delay della libreria LaurTec, bisogna includere i file nel seguente modo:

#include “delay.h”
#include “delay.c”

e non

#include “inc/delay.h”
#include “src/delay.c”

    Il percorso della libreria deve essere interamente incluso nelle proprietà del progetto XC8 Compiler, alla voce “Include Directories”. Questa pratica è una buona abitudine di programmazione normalmente già usata dei progetti LaurTec e gli esempi del testo C18 Step by Step.

  • Prima di iniziare a scrivere il nostro programma è necessario configurare il PIC, ovvero impostare tutte le configuration words. Solitamente si impostavano solo quelle base


#pragma config FOSC = HS     
#pragma config WDT = OFF     
#pragma config LVP = OFF     
#pragma config PBADEN = OFF

    Il compilatore C18 era contento e tutto funzionava. Con il compilatore XC8 questo non basta più, infatti scrivendo solo le configurazioni base e lasciando il resto come default si hanno delle Warning. Tutto funziona come prima anche con le Warning, ma dal momento che bisogna scrivere un programma senza Warning “superflue” è necessario scrivere tutte le configurazioni del PIC. La cosa è piuttosto noiosa per cui dalla libreria LaurTec 3.0, che supporta il compilatore C18 e XC8 ho introdotto la directory conf in cui sono presenti gli header file dei PIC usati nei progetti LaurTec. Per cui se si sta scrivendo un programma per PIC18F4550 utilizzato nella scheda Freedom II, basterà includere il file PIC18F4550_config.h. Qualora si voglia cambiare qualche configurazione è consigliabile rinominare il file principale e cambiare la copia.
MLAB IDE permette di configurare le configuration word anche per mezzo di un tool integrato, piuttosto che usare la direttiva #pragma. Questo non è più supportato da MPLAB X, il quale però permette di impostare le varie configurazioni per mezzo della finestra di Figura  6  richiamabile dal menu Window -> Pic Memory Views -> Configuration Bits.

 

Figura 6: Impostazione grafica delle configuration Word

Figura 6: Impostazione grafica delle configuration Word.

   Qualora l'header file non sia presente nella libreria LaurTec, è possibile generare un file header per mezzo di tale tool. Si noti che le configurazioni impostate per mezzo di tale strumento non sono riflesse nel progetto. Lo strumento crea solo un file header o c, da includere nel progetto.
    Sebbene abbia detto che il compilatore XC8, dietro le quinte non è altro che quello Hitech C, è possibile notare che abilitando l'opzione CCI, la sintassi richiesta per le configurazioni C non standard, è quella del C18 per cui questo aspetto della configurazione è piuttosto familiare. La sintassi di configurazione dell'Hitech C è ancora supportata e riconosciuta, ma nella user guide del compilatore XC8 si consiglia di usare la sintassi raccomandata dall'CCI ovvero quella del C18.

  • Una volta effettuate le configurazioni è possibile scrivere il proprio main. In C18 tale funzione è dichiarata nel seguente modo

void main(void) {

}

    
mentre in XC8

int main(void) {

}


ovvero il tipo di ritorno è int e non void.

  • Le variabili dichiarate semplicemente char sono sempre accettate dall'XC8 ma per la sintassi CCI è richiesto che venga specificato se è di tipo signed o unsigned. Tale necessità discende dal fatto che gli altri compilatori della famiglia XC hanno un valore di default, qualora non sia specificato il segno, diverso dall'XC8. In particolare char mia_variabile è unsigned per il compilatore XC8 mentre è signed per il compilatore XC16.
  • Le variabili float e double, se si abilita il CCI, sono supportate solo con formato a 32 bit e non 24bit. Qualora non si cambiasse l'opzione mostrata in Figura 4, si avrebbe una Warning che segnala il fatto che eventuali variabili float o double sono in formato 32 bit e non 24 bit.
  • Qualora una variabile venga dichiarata ma non usata viene sottolineata dal parser. Il parser non è il compilatore per cui questo avviso, sebbene alcuni compilatori segnalino una Warning, non è associata al compilatore XC8.
  • In C18, qualora si volesse scrivere una stringa costante da memorizzare in flash bisogna scrivere:


rom const char [] = “la mia stringa”;

per mezzo del compilatore XC8 non è più necessario scrivere rom ma semplicemente dichiarare una variabile come const :  

const char [] = “la mia stringa”;
 

  • Una volta dichiarate le variabili all'interno del main è possibile iniziare la configurazione dei registri. Il nome dei registri rimane identico al C18 ed in particolare è possibile accedere ai singoli bit dei registri allo stesso modo, ovvero facendo uso della struttura dedicata:

PORTDbits.RD0 = 0x01;

  • Quando si scrive un programma articolato si fa uso di librerie. Qualora si siano usate le librerie delle periferiche offerte per il C18, in XC8 non cambia, in generale, nulla. Lo stesso è valido se si usano le librerie LaurTec, che dalla versione 3.0 supportano indifferentemente sia il C18 l'XC8. Eventuali differenze, come per esempio per la funzione itoa, sono comunque individuate e segnalate dal compilatore.
  • Per armonizzare un programma è spesso necessario utilizzare le interruzioni al fine di ottimizzare il codice, tempi di esecuzione e spesso anche l'energia consumata dal sistema. Il C18 utilizza una sintassi piuttosto organica per dichiarare le Interrupt Service Routine (ISR) eseguite ogni qual volta si verifichi un'interruzione di opportuna priorità. Per esempio, nel caso in cui si faccia uso solo delle interruzioni ad alta priorità si avrebbe:


// Prototipo di funzione
void High_Int_Event (
void);


#pragma code high_vector = 0x08
void high_interrupt (
void) {
    // Salto per la gestione dell'interrupt
    _asm GOTO High_Int_Event _endasm
}

#pragma code


#pragma interrupt High_Int_Event
void High_Int_Event (void) {
    // Programma per la gestione dell'interruzione
}


void main (void) {
..
    // Programma principale
.
}    


La storia diventa più articolata ma analoga, qualora si utilizzi anche il vettore delle interruzioni a bassa priorità posto all'indirizzo 0x18. Con il compilatore XC8 abilitando la sintassi CCI, si semplifica il tutto e le interruzioni sono semplicemente dichiarate come:

__interrupt(low_priority) void nome_funzione_a(void) {

        // gestione delle interruzioni a bassa priorità
}

__interrupt(high_priority) void nome_funzione_b(
void) {
        // gestione delle interruzioni ad alta priorità
}


Qualora si faccia uso di un bootloader, usando la proprietà del progetto codoffset, è possibile sposare il programma senza doversi preoccupare dei vettori delle interruzioni e di Reset, i quali vengono automaticamente traslati in maniera trasparente.  


Vi renderete presto conto, qualora siate abituati al compilatore C18, che il compilatore XC8 vi controllerà il codice in maniera più “attenta”, garantendo una migliore qualità del codice stesso. Alcune differenze tra C18 e XC8 non sono trattate ma le Warning e/o errori vi guideranno alla soluzione necessaria. Maggiori dettagli sono trattati nella user guide del compilatore XC8, di oltre 500 pagine.    

Nota:
Una piccola cosa fastidiosa che troverete in MPLAB X e XC8 con CCI abilitato, sono alcuni errori di parser inesistenti, ovvero il parser sottolinea in rosso alcune funzioni di libreria  dicendo che non  è possibile trovare la loro dichiarazione. Ciononostante il compilatore e linker le trova e il programma funziona correttamente.  Alcuni esempi sono:

e


Compilatore XC8- Errore del parser


In questo secondo caso l'errore è ancora un po' più fastidioso perché la prima funzione per impostare il PWM viene trovata mentre la seconda è sottolineata, pur essendo entrambe dichiarate nello stesso file. L'errore mostrato ponendo il mouse sul punto esclamativo in rosso è:

Unable to resolve identifier

Programma di esempio

   Un semplice esempio di programmazione per Freedom II permette di verificare quanto appena descritto. L'esempio non fa uso delle interruzioni ma illustra come un semplice programma non porti alcun stravogimento nella programmazione del microcontrollore, qualora si stia passando dal C18 al compilatore XC8. Si noti in particolare l'utilizzo dell'header file  PIC18F4550_config.h nel quale sono presenti tutte le configurazioni del microcontrollore. Per la verifica delle configurazioni del programma si raccomanda di scaricare il progetto a fine articolo.

Il programma  è un semplice effetto di un LED a scorrimento.

#include <xc.h>

#include "PIC18F4550_config.h"

// Libreria Laurtec
#include "delay.h"
#include "delay.c"


int main(void) {

    unsigned char counter = 1;
    
    TRISD = 0x00;
    LATD = 0x00;

    while (1) {              
   
        LATD = counter;
        delay_ms (100);

        counter = counter << 1;
        
        if (counter == 128){
            LATD = counter;
            delay_ms (100);
            counter = 1;
        }
    }
}

 

Bibliografia:

1 : MPLAB X :  scarica il nuovo IDE della Microchip

2 : XC8 : Scarica il nuovo compilatore della Microchip

 

Tipo File Scarica File Descrizione

Formato File zip

Download

Esempio di programmazione con compilatore XC8

 

 

 

 

 

 

 

 

 

Gravatar
Stefano
RE: Difficoltà
@ sharky: apri un topic, sarà più comodo aiutarti e più visibile per chi avrà in futuro i tuoi stessi problemi.In questo modo potrai postare il codice o parte di esso per farci comprendere meglio.Sospetto che intestazioni delle funzioni di interrupt non siano scritte in modo corretto.PEr quanto riguarda il registro, non ho trovato nessun TRISO, ma solo TRISIO, vedi se è quello il problema.
0
Gravatar
Igor
Difficoltà
Ciao!Grazie dell articolo!Io sto avendo delle difficoltà in due punti:1) gli interrupt. mi da "main.c:28: error: (1275) only functions may be qualified "interrupt""2) Cerco di scrivere nel settore TRISO (pic 12F683) ma non me lo fa fare. mi dice di non conoscere TRISO (secondo il datasheet esiste)come mai?Grazie!Igor
0
Gravatar
Mauro Laurenti
RE: Il compilatore XC8, come migrare dal C18
Imparare Nuove cose non e' mai indolore....anche se cerco di alleviare il tutto, scottandomi per primo! :)Saluti,Mauro
0
Gravatar
fabio bolognesi
Grazie!!!!
Ciao a tutti, grazie MAURO! :P Mi sono istallato tutto ed ho già iniziato a lanciare le prime maledizioni al nuovo ambiente...ma sono felice di aver potuto fare un "passo avanti".Aspetto con ansia i prossimi tutorial, così anche un "muflone" dell'informatica come me riuscirà a stare un po' al passo coi tempi. :oops: Grazie ancora e buon lavoro!!!
0
Gravatar
Mauro Laurenti
RE: Il compilatore XC8, come migrare dal C18
...piano piano si fa tutto!...anche migrare...Chi resta indietro resta solo! :)Almeno in ambito software.E' chiaro da un punto di vista dei concetti ma non sono uno scrittore! :)Saluti,Mauro
0
Gravatar
Dario Di Turi
RE: Il compilatore XC8, come migrare dal C18
Complimenti Mauro,sempre chiaro ed efficace : :-) Dario
0
Gravatar
Renato
RE: Il compilatore XC8, come migrare dal C18
Hai proprio ragione, ora non abbiamo più scuse :-* non ci rimane che mettere in pratica la tua guida a XC8.Ciao e grazieRenato
0
Gravatar
Mauro Laurenti
RE: Il compilatore XC8, come migrare dal C18
ora non avete piu' scuse...Era mia intenzione colmare la lacuna formatasi con il C18 Step by Step.Ora con questo articolo sul compilatore XC8 e il precedente su MPLAB X si ha un ponte di "aggiornamento". E' mia intenzione aggiornare il testo C18 Step by Step ma avro' bisogno di tempo.Saluti,Mauro
0
Gravatar
Luca
RE: Il compilatore XC8, come migrare dal C18
Gande lavoro, aver riassunto le 500 pagine originali è un bell'impegno. Ottima spiegazione. Ora siamo pronti alla migrazione.
0
Gravatar
Guido
RE: Il compilatore XC8, come migrare dal C18
Ciao, come sempre chiaro e ben fatto.
0

You don`t have permission to comment here!

Registrati al sito

Accedi a tutte le risorse e articoli non visibili pubblicamente, puoi registrarti con pochi passi.

Registrati al sito LaurTec.

Login