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.