trasmissione dati lenta

ciao a tutti sto lavorando con un Mega e gli devo passare una serie di numeri int float e long ho provato in vari modi ad estrarre i dati:

  1. leggo l'intera stringa che gli passo con readString, la spezzo con sibstring, trasformo i pezzi con toCharArray e poi con atoi,atof,atol estraggo i vari numeri

  2. passo i dati separati da , e uso direttamente parseint e parsefloat per ricavare i numeri

inviando 1 int e 3 float ci impiega circa un secondo, misurato usando la funzione millis prima e dopo l'estrazione dei dati, esiste un sistema più veloce per estrarre i dati dalla stringa che gli passo?

anche cambiando la baude rate la differenza di tempo è minima

esempio di stringa: 19,1234.56,9876.54,3396.01

E dove é il sketch da te usato?
Ciao Uwe

dipende dal baund e io consiglio 500000 se supportato dal PC, magari usare direttamente i valori "reali" senza la doppia conversione in stringa che rallenta notevolmente la comunicazione.

Astrobeed qualche tempo fa segnalò un metodo molto elegante per problemi simili al tuo.

In pratica, si prepara un frame di dati usando una struttura ed un buffer usando la union.

In questo modo, sia la trasmissione che la ricezione e la relativa decodifica diventano un gioco da ragazzi.

Ecco un esempio:

typedef struct {        // Frame
 char Chr1;
 char Chr2;
 char Chr3;
 char Chr4;
 char Arr[4];
 unsigned long Val1;
 unsigned long Val2;
} Frame;

union Gest_Dati {       // union che gestisce il buffer
 Frame Dati;
 char Buffer[16]; 
} Dati_U;

// CodeDecode.buffer_s[0]

void setup() {
 Serial.begin(115200);

 Dati_U.Dati.Chr1 = 'a';
 Dati_U.Dati.Chr2 = 'b';
 Dati_U.Dati.Chr3 = 'c';
 Dati_U.Dati.Chr4 = 'd';

 Dati_U.Dati.Arr[0] = 'T';
 Dati_U.Dati.Arr[1] = 'e';
 Dati_U.Dati.Arr[2] = 's';
 Dati_U.Dati.Arr[3] = 't';
 
 Dati_U.Dati.Val1 = 123456;
 Dati_U.Dati.Val2 = 654321;

 Serial.println(Dati_U.Buffer);
}

void loop() {

}

mmmm, mi lascia un pò perplesso quel codice.
Sopratutto nell'invio dei dati con la .println()
per inviare una struttura si potrebbe usare semplicemente:

Frame a;
....
Serial.write(a,sizeof(Frame));

Questo però è sconsigliato perché non tiene in considerazione il marshalling dei dati e altre cose fondamentali sulle strutture, ad esempio se si inviasse con quel metodo la struttura ad un PC e lo si ricevesse nello stesso modo sicuramente non funzionerebbe.
Quindi sarebbe da preferire sempre la forma espansa, ovvero l'invio di dato per dato singolo con il marshalling gestito manualmente.

vbextreme:
mmmm, mi lascia un pò perplesso quel codice.
Sopratutto nell'invio dei dati con la .println()

Infatti l'invio non si fa con la println(), nel mio esempio serviva solo per visualizzare il risultato dell'operazione e non per l'invio dei dati, anche perché dipende dal mezzo trasmissivo.

Questo però è sconsigliato perché non tiene in considerazione il marshalling dei dati e altre cose fondamentali sulle strutture,

Forse volevi parlare di endianness, il marshalling non c'entra proprio nulla in questo caso, gli Atmega, o meglio il gcc perché gli AVR sono processori a singolo byte, usano lo stesso endianness (little endian) degli X86 pertanto se trasferisci tra pc e Arduino, o viceversa, con questa tecnica la cosa funziona perfettamente, da notare che tutti i compilatori per X86 lavorano in little endian perché questo è il modo nativo del micro.
Semmai il problema si pone se trasferisci tra Arduino e altre mcu/micro con endianess diverso, però in questo caso basta invertire l'ordine dei dati prima di inviarli, oppure dopo la ricezione, e il problema è risolto.
Per tua informazione, l'uso della struct e della union per inviare pacchetti dati complessi è usatissimo nel mondo embedded, non è una mia invenzione, anzi è una delle prime cose che ti insegnano quando studi programmazione embedded.

Infatti l'invio non si fa con la println(), nel mio esempio serviva solo per visualizzare il risultato dell'operazione e non per l'invio dei dati, anche perché dipende dal mezzo trasmissivo.

Immaginavo, mi sembrava strano ne.....

@Astrobeed:
Forse volevi parlare di endianness, il marshalling non c'entra proprio nulla in questo caso

No, parlavo proprio del marshalling dei dati, ovvero la loro serializzazione, come fai notare dipende dal tipo di endianess ma anche da come il compilatore gestisce la struttura, questo per le architetture a 8 bit non è un problema ma quando si va a comunicare con piattaforme diverse, tipo la classica a 32 bit lo diventa.
Il compilatore su 32 bit potrebbe allineare gentiente la struttura "Frame" per occupare il minimo spazio e usare realmente 16 byte allineati ma spesso invece non succede ciò e il compilatore sceglie di usare 4byte anche per i char usando così 16byte per i primi 4 char poi naturalmente ottimizzerá il vettore di 4 elementi con un'unica allocazione e più le successive due restituirà una struttura di ben 19 byte.
Ora se noi inviamo solo 16byte e li salviamo consecutivamente ricreando dunque la struttura il marshalling sarà errato.
L'unica maniera per usare un corretto marshalling dei dati è il controllo manuale della serializzazione di essi.

vbextreme:
Il compilatore su 32 bit potrebbe allineare gentiente la struttura "Frame" per occupare il minimo spazio e usare realmente 16 byte allineati ma spesso invece non succede ciò e il compilatore sceglie di usare 4byte anche per i char usando così 16byte per i primi 4 char poi naturalmente ottimizzerá il vettore di 4 elementi con un'unica allocazione e più le successive due restituirà una struttura di ben 19 byte.

Non funziona come dici tu, provare per credere, nel momento in cui usi struttura e unione non ha alcuna importanza come il compilatore ottimizza l'uso della memoria, fortemente legato anche al livello di ottimizzazione scelto per la compilazione.
La definizione stessa di union scioglie ogni dubbio, tutte le variabili dichiarate al suo interno condividono la stessa area di allocazione dei tipi definiti, questo indipendentemente da come sono realmente gestiti nella ram, il vero problema è l'ordine con cui sono gestiti, ascendente o discendente, l'endianess, se non è identico per tutti e due i sistemi questo porta ad errori.
Come ho già fatto notare tra pc X86, non importa se 32 o 64 bit, e gli AVR, più che altro con avrgcc, il problema non esiste in quanto l'endianess è identico, non importa qualche compilatore C/C++ usi sul PC, lavorano tutti in little endian.
Stessa cosa vale per Linux, non posso mettere la mano sul fuoco per il MAC, quello è un mondo che segue regole sue, però quasi sicuramente non cambia nulla, al limite basta invertire l'ordine dei dati, cosa che si fa con poche righe di codice.
Da notare che l'uso della struct+union riduce notevolmente i'overhead sul bus quando si inviano valori numerici visto che viaggiano sotto forma di valori binari e non come stringhe ascii.

Astro, visto che ci siamo, ci sono problemi ad usare float nel frame?

cyberhs:
Astro, visto che ci siamo, ci sono problemi ad usare float nel frame?

No, nessun problema a patto che la rappresentazione sia identica per i compilatori utilizzati, se trasferisci tra Arduino e Arduino il problema non c'è, se trasferisci tra Arduino e PC, o altro micro, è necessario verificare che il compilatore dall'altra parte usi il formato IEEE 754, è lo standard da molto tempo però è meglio verificare.
E' importante anche la dimensione, deve essere a 32 bit e non 64 bit, alcuni compilatori per pc forzano di default il 64 bit anche se dichiari come float normale, basta controllare le opzioni di compilazione.
Ovviamente se il sistema viene usato per trasferire dati tra pc è possibile usare il formato double a 64 bit, su Arduino no perché sebbene presente come tipo dato, per compatibilità, viene comunque declassato a float 32 bit.

@astro mi servirebbe più tempo, il discorso è molto ma molto lungo, per quanto riguarda la struttura presa in esame è sicuramente solida, ma questo non significa che sia una tecnica portabile.
Tanto per la cronaca i sistemi unix Like usano salvare le configurazioni in modalità testuale e non binario proprio per evitare il difficilissimo marshalling dei dati!
Non è poi scritto su nessuno standard come il compilatore debba gestire i dati e dunque gli errori sono dietro all'angolo!
Pertanto come i professori insegnano, mai usare una struttura per inviare/ricevere direttamente da un dispositivo, naturalmente questo problema per chi vive racchiuso in un 8bit è inesistente ma per chi fa porting su multipiattaforma dai 8 ai 64bit siano essi ARM, x86 e altre tipologie di architetture il problema si fa sentire.

Comunque il problema è complesso per essere affrontato in 3 battute su di un forum.

Per tua informazione la union che hai definito su un sistema a 64bit è altamente pericolosa, in prima analisi il tipo long è fuorviante, alcuni compilatori lo interpretano sempre come 32bit e altri come 64, dunque se lo si compila su GCC on linux la struttura sarà di dimensione 24byte, dato che la dimensione dell'Unione è la dimensione minima atta a contenere tutti dati il campo buffer verrà espanso come
char buffer[24]
in maniera automatica e invisibile al programmatore.
Questo è solo un chicco di sabbia nel deserto, la cosa è molto complicata.

vbextreme:
Questo è solo un chicco di sabbia nel deserto, la cosa è molto complicata.

No sei tu che la fai complicata, quella tecnica è ampiamente utilizzata nel mondo embedded, ovviamente parliamo di codice scritto in C/C++, con altri linguaggi o non è fattibile oppure si va realmente incontro a problemi.
Nessun professore degno di questo nome, a meno che non sono quelli dei corsi per "corrispondenza", ti dice di non usare questa tecnica, semmai è l'opposto.
Sottolineo quanto detto prima, l'uso di struct+union per impacchettare/spacchettare i dati è una delle prime cose che ti insegnano quando studi programmazione C/C++ per sistemi embedded, parliamo di corsi di alto livello per programmatori C/C++, non certo dei workshop per Arduino. :slight_smile:

Alcuni professori si ostinano a far installare ed usare il dev-c++, ma questo non significa che sia da usare.
Ovvio poi che parlo di c/c++.....
Nel mio primo post ho scritto che è sconsigliato sopratutto quando si dialoga con un PC.
Infine la cosa è complicata, non sono io, infine giusto per farti arrabbiare un pò quella unione è altresì inutile dato che la struttura stessa è un buffer di byte adiacenti, ovvero:

for(i=0; i<16; ++i)
    Dati_U.buffer[i] = Serial.read();

è uguale a scrivere:

byte* b = (byte*)&Dati_U.Dati;
for(i=0; i<16; ++i)
    *b++ = Serial.Read();

pure la sua versione per la write come già illustrata, quella unione non fa niente di magico, aiuta solo il programmatore a scrivere il codice.

vbextreme:
Infine la cosa è complicata, non sono io, infine giusto per farti arrabbiare un pò quella unione è altresì inutile dato che la struttura stessa è un buffer di byte adiacenti, ovvero:

Peccato che senza la union nessuno scrive/legge quello che serve, come serve, nel array, mi sa che hai le idee un pochino confuse sulla cosa. :slight_smile:
Quanto ho indicato è al di sopra dei modo di trasmissione, con relativo protocollo, infatti può essere usato con qualunque tipo di bus, è un modo per impacchettare/spacchettare i dati in un array, poi come lo trasmetti/ricevi è un altro paio di maniche.

la union non fa niente! non fa nessuna sorta di conversione e non accede ai dati in maniera diversa che la canonica!
il codice postato fa vedere proprio quello!
Dopotutto una struttura altro non è che un vettore che può contenere tipi di dati diversi.

vbextreme:
la union non fa niente! non fa nessuna sorta di conversione e non accede ai dati in maniera diversa che la canonica!

Sbagliato, la union fa una cosa importantissima, rende comune l'area di memorizzazione dei dati per tutti gli elementi inclusi, ovvero contengono tutti lo stesso valore, ovviamente devono essere tra loro compatibili come dimensione.
Puoi indirizzare i singoli byte degli elementi che compongono la struttura, come serve per una trasmissione seriale, se la cosa non ti sembra utile è perché sicuramente stai ragionando su stringhe ascii, dove la union realmente non serve a nulla, ma qui si parla di inviare valori numerici, sia interi che float, più grossi di un singolo byte e scomporli/ricomporli con altre mezzi comporta spreco di tempo macchina e risorse.

PARTE 1/2 (causa limiti del forum)

Prima di proseguire consiglierei a tutti di leggere due articoli che riguardano l'argomento.
Il primo è IBM Writing endian-independent code in c.
Il secondo è The Lost Art of C Structure Packing

Ora bisogna analizzare cosa sia una struttura, una stuttura è un vettore ma si differenzia per due caratteristiche fondametali, la prima è che può contenere variabili di tipo diverso e la seconda è che l'indice non è numerico ma viene dato da una label.
Ricopitolando mentre un vettore potrà contenere solo un tipo di dato la struttura potrà contenere uno o piu' tipi e mentre nel vettore possiamo accedere ai suoi elementi tramite un indice numerico nella struttura invece accederemo tramite un indice "letterario".
Ora verifichiamo che una struttura sia realmente un vettore, per far ciò creiamo una struttura e un vettore di char dato che stiamo solo verificando la veridicità dell'affermazione analizzeremo il caso piu semplice.

struct simple
{
 char a;
 char b;
 char c;
 char d;
};

int main()
{
 struct simple st;
 char vector[4];
 
 char* ptr;
 int i;
 
 for(ptr = vector, i= 0; i < 4; ++i, ++ptr)
 *ptr = i;
 printf("%d %d %d %d\n",vector[0],vector[1],vector[2],vector[3]);
 
 for(ptr = (char*) &st, i = 0; i < 4; ++i, ++ptr)
 *ptr = i;
 printf("%d %d %d %d\n",st.a,st.b,st.c,st.d);
 
 
 memset(vector,7,sizeof vector);
 printf("%d %d %d %d\n",vector[0],vector[1],vector[2],vector[3]);
 
 memcpy(&st,vector,sizeof vector);
 printf("%d %d %d %d\n",st.a,st.b,st.c,st.d);
 
 
 return 0;
}

Prima di tutto creiamo una struttura di 4 elementi del tipo char, poi creiamo un vettore sempre di 4 elementi char.
Assegnamo il vettore ad un puntatore e tramite un ciclo assegnamo ai suoi elementi il valore del loro indice, visualizziamo il vettore.
Ora verifichiamo che la struttura si comporti come un vettore e usiamo la struttura esattamente alla stessa maniera e quindi la passiamo al nostro puntatore e scriviamo e visualizziamo proprio come abbiamo fatto col vettore.
Nel caso specifico ho preferito scrivere la printf() in maienra estesa e non usare un ciclo basato su ptr solo perchè mi sembrava piu significativa, lo lascio come esercizio per chi si voglia allenare.
Infine setto tutto il vettore al valore di 7 e lo copio pari pari nella struttura in modo da eseguire con due funzione dello standard c ciò che ho fatto manualmente.
Analizziamo semoplicemente (ricordo di leggere i due link che ho postato) come viene dimensionata una struttura su un'architettura a 32bit:

struct teoric
{
 char a; // 1 byte
 int b; // 4 byte
};

la struttura avrà teoricamente la dimensione di 1 + 4 = 5 byte, ma in realtà se la dichiariamo in quel modo il compilatore modificherà quella struttura in questo modo:

struct teoric
{
 char a; // 1 byte
 char pad[3]; // 3 byte
 int b; // 4 byte
};

questo per allineare i dati all'interno della struttura stessa e renderla piu performante, questa opzione è possibile disabilitarla all'interno del compilatore di solito tramite l'utilizzo dei pragma.
S volete piu dettagli ricordo di rileggere i due link postati.
Per verificare ciò usiamo questo codice:

struct simple
{
 char a;
 int b;
};

int main()
{
 struct simple st;
 
 printf("szof()::%d\n",sizeof(struct simple));
 printf("szof  ::%d\n\n",sizeof st);
 
 char* ptr;
 int i;
 
 st.a = ~0;
 st.b = ~0;
 
 printf("a::%d\n",st.a);
 printf("b::%d\n\n",st.b);
 
 for ( ptr = (char*) & st, i = 0; i < 5; ++i, ++ptr)
 *ptr = 0;
 
 printf("a::%d\n",st.a);
 printf("b::%d\n\n",st.b);
 
 
 return 0;
}

Già la visualizzazione della sizeof ritorna il valore esatto della struttura ovvero 8 byte e infatti proseguendo nella lettura del codice si vede che settando a 1 tutti i bit delle variabili e tornando a settare a 0 solo i 5 byte teorici la seconda printf non visualizza il valore desiderato.
Ora che abbiamo analizzato sommariamente le strutture passiamo alle unioni.

Se le strutture sono paragonabili ai vettori le unioni sono paragonabili alle variabili, nonstante esse si dichiarino proprio come le strutture in realtà non lo sono ma sono semplici variabili che possono contenere piu tipi ma con dimensione tale da contenere la dimensione del dato piu grande.
Un esempio toglie ogni sorta di dubbio:

union teoric
{
    char a; //1 byte
    int  b; //4 byte
};

Mentre nella struttura avremmo allocato 5 byte di memoria nella unione no, ne allochiamo solo 4 perchè la "union teoric" è una variabile e non un vettore e dovrà essere abbastanza grande da poter contenere il dato piu grande che nel nostro caso è int che sui 32bit vale 4byte.

PARTE 2/2 (causa limiti del forum)

Ora che abbiamo un'infarinatura generale vediamo cosa ha combinato @astrobeed:

typedef struct {        // Frame
 char Chr1; //1 byte
 char Chr2; //1 byte
 char Chr3; //1 byte
 char Chr4; //1 byte 
 char Arr[4]; // 4 byte
 unsigned long Val1; // 4byte
 unsigned long Val2; // 4byte
} Frame; //16 byte

è stata creata una struttura solida, non portabile ma non ne è stata spiegata bene, ecco perchè del mio "punzecchiamento".
Perchè questa struttura è abbastanza solida?
Perchè quella struttura su qualsiasi compilatore(odierno) microsoft restituirà 16 byte dunque è compatibile con la dichiarazione del chip a 8 bit che restituisce sempre 16byte.
Ma non può essere modificata senza rispettare alcune regole elencate sempre nel link in maniera dettagliata, pena il non corretto funzionamento del codice!
e l'unione?

union Gest_Dati {       // union che gestisce il buffer
 Frame Dati; //16 byte
 char Buffer[16]; //16 byte
} Dati_U;

l'unione in questo caso non fa niente dato che frame ha la stessa dimensione di buffer l'unione creerà una varibile di 16 byte, perchè ha usato l'unione? semplicemente perchè è una tecnica di sile, tale unione rende il codice piu leggibile e dunque è piu difficile fare errori.
ora dobbiamo verificare che quello appena detto sia tutto vero, iniziamo dalla cosa piu semplice, l'unione è solo uno stile?

typedef struct {        // Frame
 char Chr1; //1 byte
 char Chr2; //1 byte
 char Chr3; //1 byte
 char Chr4; //1 byte 
 char Arr[4]; // 4 byte
 unsigned long Val1; // 4byte
 unsigned long Val2; // 4byte
} Frame; //16 byte


union Gest_Dati {       // union che gestisce il buffer
 Frame Dati; //16 byte
 char Buffer[16]; //16 byte
};


int main()
{
 union Gest_Dati un;
 int i;
 
 //Style
 for ( i = 0; i < sizeof(union Gest_Dati); ++i )
 un.Buffer[i] = 1;
 
 printf("%d %d %d %d %d %d %d %d %d %d\n",un.Dati.Chr1,un.Dati.Chr2,un.Dati.Chr3,un.Dati.Chr4,
             un.Dati.Arr[0],un.Dati.Arr[1],un.Dati.Arr[2],un.Dati.Arr[3],
             un.Dati.Val1,un.Dati.Val2);
 
 
 //VS obfuscated C
 char* p;
 for ( p = (char*)&un.Dati, i = 0; i < sizeof(union Gest_Dati); ++i )
 *p++ = 0;
 
 printf("%d %d %d %d %d %d %d %d %d %d\n",un.Dati.Chr1,un.Dati.Chr2,un.Dati.Chr3,un.Dati.Chr4,
             un.Dati.Arr[0],un.Dati.Arr[1],un.Dati.Arr[2],un.Dati.Arr[3],
             un.Dati.Val1,un.Dati.Val2);
 
 
 
 return 0;
}

Settiamo dunque a 1 usando il metodo della unione e visualizziamo che ralmente sia avvenuto tutto ciò e verifichiamo che accedendo direttamente alla struttura eseguiamo la stessa identica cosa settando tutto a 0 e visualizzando.

Ora verifichiamo la reale instabilità della tecnica mal spiegata, creiamo un nostro frame che debba contenere un valore char e un valore int, vogliamo inviare il valore ad una arduino uno, una due e al pc con windows a 32bit.

Su arduino uno: teorico == reale grazie all'architettura 8bit

typedef struct {        // Frame
 char Chr1; //1 byte
 int Val1; //2byte
} Frame; //3 byte

union Gest_Dati {       // union che gestisce il buffer
 Frame Dati; //3 byte
 char Buffer[3]; //3 byte
};// 3byte

Su arduino due/PC: teorico != reale causa all'architettura 32bit
Terorico:

typedef struct {        // Frame
 char Chr1; //1 byte
 int Val1; //4byte
} Frame; //5 byte

union Gest_Dati {       // union che gestisce il buffer
 Frame Dati; //5 byte
 char Buffer[3]; //5 byte
};// 5byte

l'instabilità dell'uso classico dei tipi del c ci ha già creato dei problemi, la struttura non è piu compatibile con quella della uno!, nonostante il buffer sia di 3 elementi l'unione risulterà di 5 byte teorici.
in piu la cigliegina nasce da come il compilatore modifica il tutto:

typedef struct {        // Frame
 char Chr1; //1 byte
 char pad[3] //3 byte
 int Val1; //4byte
} Frame; //8 byte

union Gest_Dati {       // union che gestisce il buffer
 Frame Dati; //8 byte
 char Buffer[3]; //3 byte
};// 8byte

e qui nasce un casino! infatti il compilatore interviene ad aggiungere lo spazio per il padding subito dopo la variabile Chr1
allineando la struttura da 5byte a 8! si capisce bene che si la struttura di @Astrobeed è solida ma solo se non viene toccata e la si usa cosi comè su architetture a 32bit o 64 con compilatori microsoft, l'uso dell'unione in questo caso poi non ci aiuta anzi potrebbe erroneamente sviarci.

Ecco perchè ho consigliato di inviare i dati semplicemente in maniera estesa, perchè non bisogna tenere conto di ciò che un compilatore può fare e di ciò che un'architettura richiede, semplificando e rafforzando il nostro codice.

Nota finale l'accesso alla struttura sia tramite puntatore sia tramite union richiede lo stesso numero di clock, l'invio in modalità estesa o l'invio diretto di una struttura richiede lo stesso numero di clock.
Cosa significa modalità estesa?
significa inviare membro per membro in modalità byte, dunque nessuna conversione.

Spero di essermi riuscito a spiegare nonostante il discorso sia lungo, complesso e molto articolato per essere trattato su di un forum.(per di piu con il limite forse "ridicolo" di 9000 caratteri)
Ops mi sono dimenticato di parlare dell'endianness, a quanto pare @astrobeed non era solo quello il problema......

vbextreme:
Spero di essermi riuscito a spiegare nonostante il discorso sia lungo, complesso e molto articolato per essere trattato su di un forum.(per di piu con il limite forse "ridicolo" di 9000 caratteri)

Tante parole e tanta fuffa, tipico discorso in stile complottista.
Tutta la dimostrazione si regge su una incongruenza, ovvero che su un pc un "int" è da 32 bit, questo lo sanno tutti, infatti sulla struttura per pc, o micro 32/64 bit, è da usare l'uint16, ovvero lo "short int", e non l'int normale.
Altro dettaglio, mi pare più che ovvio che una struttura, dal punto di vista del micro, è solo un array di lunghezza pari alla somma dei singolo componenti, anche questa è una cosa che sanno tutti.

@astrobeed:
Tante parole e tanta fuffa, tipico discorso in stile complottista.

Sarai mica parente del berlusca?ahahhaha

@astrobeed:
Tutta la dimostrazione si regge su una incongruenza, ovvero che su un pc un "int" è da 32 bit

Assolutamente no! ciò che tu chiami "fuffa" e "semplice incongruenza con i 32 bit" "NOI" la chiamiamo portabilità, ovvero fare il famoso "cut/paste" senza la necessità di dover modificare profondamente il codice, come ho detto nel post precedente il tuo codice è perfetto se confinato nel mondo a 8 bit, ma spesso viene usato anche il pc che ormai non sono piu nemmeno a 32 bit aggiungendo ulteriore complessità, per non parlare di due o della tua scheda che tanto acclami, la uno non potrebbe comunicare con quel codice con la 3.1 se non tramite PROFONDE MODIFICHE.
Non accendere la tua coda, dopotutto ho elogiato la stabilità del tuo codice!(sempre tu abbia avuto il coraggio di leggere tutto.)
Ripeto, dovevi spiegarti meglio, tutto qui! non sono io il complesso, non ho inventato proprio niente io.

Oltre alle tue fuffe di polemiche hai dimostrato il contrario?