Come funziona il codice sorgente di OPGUI, OP, e OpenProg (v. 0.9)

Divisione del codice

Il codice sorgente dei programmi OPGUI e OP è diviso in file separati a seconda delle funzioni; i file comuni sono:
progAVR.c (.h)algoritmi per ATMEL AVR
progEEPROM.c (.h)algoritmi per memorie seriali
progP12.c (.h) algoritmi per PIC12/16 con memoria a 12 bit
progP16.c (.h) algoritmi per PIC12/16 con memoria a 14 bit
progP18.c (.h) algoritmi per PIC18
progP24.c (.h) algoritmi per PIC24 e PIC33
I2CSPI.c (.h)funzioni di comunicazione I2C e SPI
fileIO.c (.h)gestione file: caricamento e salvataggio .hex e .bin
coff.c (.h)lettura file .coff (per debugging ICD)
icd.c (.h)gestione debugging ICD
icons.c (.h)sorgente icone
deviceRW.c (.h)selezione della funzione giusta con i parametri adatti al dispositivo.
Qui c'è l'elenco di tutti i dispositivi supportati
strings.c (.h)stringhe di testo delle varie interfacce utente
common.h variabili e funzioni globali
instructions.h comandi a basso livello del programmatore
Makefile serve per compilare il progetto

Il programma principale vero e proprio risiede a seconda dell'applicazione in opgui.c oppure in op.c.
Anche OpenProg utilizza lo stesso codice, ma l'estensione dei file è .cpp per compatibilità col VC++.
Ogni funzione ha infatti una doppia dichiarazione del tipo:
#ifdef _MSC_VER
void COpenProgDlg::DisplayCODE16F(int size){
#else
void DisplayCODE16F(int size){
#endif

Struttura generale

In tutte e tre le applicazioni (OPGUI, OP, OpenProg) l'interfaccia utente prima verifica le varie opzioni selezionate, poi chiama le stesse funzioni base.
Caricare un file fileIO.c -> Load(dev,loadfile)riempie gli array memCODE_W (per i PIC12-16) o memCODE, mem_EE, mem_CONFIG, mem_ID con i dati da scrivere
Scrivere o leggere deviceRW.c -> Write(dev,ee)/Read(dev,ee,r) cerca la giusta funzione (definita nei vari file progXX.c) e la chiama; i dati sono in memXX
Salvare un file fileIO.c -> Save(dev,savefile)scrive su un file i dati degli array memCODE_W (per i PIC12-16) o memCODE, mem_EE, mem_CONFIG, mem_ID

Selezione della giusta funzione di lettura/scrittura

La scelta dell'algoritmo adatto avviene in deviceRW.c: qui è definito l'array DEVLIST[] in cui a ogni gruppo di dispositivi sono associate le funzioni di lettura e scrittura corrispondenti con i parametri giusti.
Un esempio di elemento dell'array:
{"12F1822,16F1823,16F1826",PIC16,8.5,1,Read16F1xxx,{0x800,0x100,11,0},0x200,Write16F1xxx,{0x800,0x100,0},0}
Le funzioni Read(dev,ee,r) e Write(dev,ee) scorrono l'array fino a trovare il dispositivo selezionato e chiamano la giusta finzione di lettura o scrittura con i parametri indicati nell'array.

Comunicazione col programmatore

Il programmatore comunica per mezzo di pacchetti dati via USB; un pacchetto può contenere fino a 64 byte di istruzioni.
La descrizione dettagliata delle istruzioni si trova nella pagina principale.
A ogni pacchetto in uscita corrisponde uno di ritorno che viene spedito una volta terminata l'elaborazione del primo.
Le istruzioni sono definite in instructions.c; la loro lunghezza è variabile, come pure la relativa risposta.
Nel codice è definito un array bufferU di DIMBUF byte da riempire con le istruzioni da spedire, e un altro della stessa dimensione, bufferI, in cui si trova il pacchetto di risposta.
DIMBUF vale 64 sotto Linux e 65 sotto Windows; sotto Windows la prima locazione è sempre 0 perchè indica il report HID da usare; per semplicità in tutte le versioni il primo byte è 0.
Un tipico esempio di comunicazione è:
bufferU[0]=0;
j=1;
bufferU[j++]=SET_PARAMETER;
....
bufferU[j++]=FLUSH;
for(;j<DIMBUF;j++) bufferU[j]=0x0;
write();
msDelay(2);
read();
Da notare l'istruzione FLUSH che fa terminare l'esecuzione pacchetto immediatamente; in assenza di questa il programmatore eseguirebbe una serie di NOP (codice 0) fino alla fine del buffer, e successivamente risponderebbe.
write() e read() sono non bloccanti su Linux, e bloccanti con timeout su Windows; ciò significa che se il ritardo in msDelay() non è sufficiente all'esecuzione delle istruzioni, su Linux verrà riletto il pacchetto di ritorno precedente.
Nelle sezioni in cui è critico aspettare il meno possibile viene usata la funzione PacketIO(delay), che integra read-delay-write ed è bloccante con timeout anche su Linux; questa sostituirà progressivamente le altre in tutto il codice.

Messaggi e stringhe

Per mantenere lo stesso codice in tutte le applicazioni sono definite una serie di funzioni PrintMessage(msg), PrintMessage1(msg,par), ecc., che scrivono messaggi all'utente.
L'array strings[] contiene tutte le stringhe nella lingua giusta; per esempio:
PrintMessage2(strings[S_ConfigWordX],1,memCODE_W[0x8007]);

Compilare il progetto

OPGUI sfrutta le librerie GTK, per cui su Windows è necessario installare anche il Runtime Environment GTK.
E' inoltre necessario un ambiente GNU compatibile, con il compilatore GCC; su Windows basta installare il pacchetto MinGW.
OP ha solo bisogno dell'ambiente GNU e GCC.
Per compilare:
> make
Successivamente per installare (su Linux, ma non è obbligatorio):
> make install

Per quanto riguarda OpenProg bisogna installare il Visual C++ 6.
Lo sviluppo di questo programma è sostanzialmente terminato; le nuove versioni sono solo aggiornate negli algoritmi ma l'interfaccia utente è la stessa e consente solo le operazioni essenziali.
Il solo vantaggio è che l'eseguibile non richiede alcuna libreria aggiuntiva.