• Non ci sono risultati.

Sviluppo del motore di esecuzione delle prove

tri elementi figli; il numero di elementi con un certo nome è uguale al numero di righe della tabella che ha quel nome; • livello 2: elementi figli degli elementi di livello precedente;

rappresentano le colonne della tabella e contengono i dati veri e propri delle tabelle.

2.5

Sviluppo del motore di esecuzione delle prove

Il motore di esecuzione deve effettuare le prove nell’ordine in cui queste appaiono nel piano di prova, rispettando i seguenti vincoli:

• durante l’esecuzione l’interfaccia con l’utente (paragrafo 2.3) deve continuare ad essere responsiva e deve poter eseguire altre operazioni;

• deve essere possibile in ogni momento controllare l’esecuzione (messa in pausa, riavvio, passaggio alla modalità passo-passo, arresto);

• deve essere mostrato in tempo reale il risultato dell’esecuzione dei singoli passi di prova e delle singole prove.

Per soddisfare questi vincoli è stata scelta come soluzione lo svi- luppo del motore di esecuzione in un thread secondario che all’oc- correnza può comunicare in modo asincrono con il thread principale ovvero con il thread che gestisce l’interfaccia grafica con l’utente.

Il flusso di comunicazione dal thread secondario al thread prin- cipale è necessario per controllare l’aggiornamento dell’interfaccia grafica (scrittura di messaggi di servizio per l’utente nell’area de- dicata e/o visualizzazione in tempo reale dell’esito dell’esecuzione di ciascun passo di prova e di ciascuna prova nei controlli ListView corrispondenti). L’accesso ai controlli grafici di Windows Form in applicazioni con thread multipli presenta la seguente problematica: se più thread gestiscono lo stato di un controllo grafico è possibile

che questo venga forzato in uno stato incoerente; inoltre possono ve- rificarsi altri problemi quali condizioni di corsa critica e condizioni di stallo. Per questo motivo, è importante accertarsi che i controlli grafici Windows Form vengano chiamati solamente dal thread che li ha creati. Del resto .NET Framework è predisposto per rilevare ac- cessi non sicuri ai controlli grafici ed a generare in tal caso eccezioni del tipo InvalidOperationException. Per eseguire chiamate sicure ad un controllo Windows Form è necessario seguire i seguenti passi in ordine:

1. leggere la proprietà InvokeRequired del controllo a cui si inten- de accedere;

2. se InvokeRequired restituisce true, chiamare il metodo Invoke o il metodo BeginInvoke per far eseguire la chiamata effettiva al controllo tramite un delegato;

3. se InvokeRequired restituisce false, chiamare direttamente il controllo.

Si noti come sia assolutamente necessario, per evitare condizioni di stallo, utilizzare il metodo BeginInvoke che realizza una chiamata asincrona invece che il metodo Invoke che realizza una chiamata sincrona. Una chiamata sincrona infatti blocca il thread chiamante finchè non è stata completata, mentre una chiamata asincrona non si comporta in modo bloccante.

In Figura 2.12 è mostrato il diagramma di stato per il motore di esecuzione. Gli eventi il cui nome inizia con il prefisso "button" so- no gli eventi associati alla pressione dei quattro pulsanti Run, Pause, Stop e Debug che controllano l’esecuzione del collaudo. L’even- to denominato ExecutionThread_Done invece indica che sono state eseguite tutte le prove previste dal piano di collaudo.

Un secondo diagramma di stato, riportato in Figura 2.13, mostra il meccanismo mediante il quale viene aggiornato l’esito di ciascun

2.5. SVILUPPO DEL MOTORE DI ESECUZIONE DELLE PROVE 51

Figura 2.12: Diagramma di stato per il motore di esecuzione.

passo di prova e di ciascuna prova nell’interfaccia grafica con l’u- tente. Ogni volta che viene caricata da memoria di massa una prova, viene anche registrato per ciascun oggetto TestStep il gestore d’e- vento relativo al cambiamento dell’esito del corrispondente passo di prova. Similmente, ogni volta che viene caricato da memoria di massa un piano di collaudo e ogni volta che viene aggiunta una prova al piano di collaudo, viene anche registrato per ciascun ogget- to TestCase un gestore d’evento relativo al cambiamento dell’esito della prova corrispondente. In questo modo, non appena un passo di prova oppure una prova vengono completati il gestore d’evento re- lativo provvede ad aggiornare i corrispondenti controlli grafici List- View presenti nell’interfaccia grafica in modo da mostrare l’icona colorata corrispondente all’esito.

Quando l’utente avvia l’esecuzione, il thread principale crea un oggetto della classe ExecutionThread (vedasi Figura 2.6) passando come argomenti al costruttore un riferimento all’oggetto MainForm, il piano di prova da eseguire ed altri argomenti relativi ai parame- tri di configurazione. A sua volta l’oggetto ExecutionThread crea

Figura 2.13: Diagramma di stato per l’aggiornamento dell’esito dei passi di prova e delle prove.

un oggetto del tipo Thread e lo avvia. Il thread esegue le seguenti operazioni nell’ordine:

1. avvia il cronometro;

2. azzera gli esiti di tutte le prove e di tutti i passi di prova;

3. inizializza le variabili locali utilizzate per la generazione delle statistiche di esecuzione;

4. calcola il numero totale di prove e di passi di prova consideran- do eventuali iterazioni;

2.5. SVILUPPO DEL MOTORE DI ESECUZIONE DELLE PROVE 53

5. calcola il numero di prove senza considerare eventuali iterazio- ni (per indicare la posizione relativa di una prova nel piano di prova);

6. apre una porta di comunicazione con l’adattatore I2C e lo con- figura con la velocità di comunicazione e l’indirizzo impostati nel menù Config;

7. avvia la scrittura del resoconto se abilitato;

8. legge e visualizza il numero seriale, la versione del firmware e la tipologia di dispositivo connesso;

9. determina il passo di prova da eseguire tenendo conto di even- tuali direttive di iterazione e lo esegue, visualizzando l’esito e l’eventuale causa di esito negativo ed inoltre, se previsto dal- la configurazione, chiede all’utente dopo ogni passo di prova con esito negativo se intende proseguire con l’esecuzione op- pure terminarla; questo viene ripetuto fino a quando non sono finite le prove previste dal piano di prova oppure fino a quando l’utente non arresta l’esecuzione;

10. visualizza le statistiche sull’esecuzione; 11. visualizza l’esito del piano di prova;

12. ferma il cronometro, determina la durata totale dell’esecuzione e la visualizza.

I passi di prova del tipo Sleep, Send Command e User Feedback vengono eseguiti tramite metodi della classe ExecutionThread. I passi di prova Load Image, Capture Image, Analyze Image e User Messageinvece, poichè richiedono l’accesso a variabili globali pri- vate della classe MainForm ed in alcuni casi l’accesso ai controlli grafici (per la gestione delle immagini), chiamano metodi della clas- se MainForm tramite il riferimento che l’oggetto ExecutionThread ha ricevuto nel suo costruttore.

Per realizzare la funzionalità di comunicazione con il motore di scansione, necessaria all’esecuzione dei passi di prova del tipo Send Command e che avviene tramite bus I2C, si è utilizzata la soft- ware Application Programming Interface (API) fornita dallo stes- so produttore del dispositivo Aardvark (descritto nel paragrafo 1.3). Tale interfaccia software viene fornita come una libreria dinamica (Dynamic-Link Library, DLL) precompilata e corredata da codice sorgente di adattamento da compilare insieme al resto del codice sorgente che utilizza l’interfaccia stessa.

L’interfaccia software Aardvark viene incapsulata nel sistema dal- la libreria dinamica già citata nel paragrafo 1.3 e rappresentata in Figura 2.3; ciò rende il software applicativo indipendente dal parti- colare tipo di interfaccia fisica utilizzata a tale scopo, permettendo anche l’estensione in futuro a più tipi di interfacce I2C.

La libreria di incapsulamento, dedicata esclusivamente alle fun- zioni di comunicazione con l’adattatore I2C, è stata sviluppata in C++. Pertanto, il codice gestito dal Common Language Runtime del .NET Framework deve potersi avvalere di appositi meccanismi di interoperabilità con il codice non gestito della sopracitata libreria dinamica per il controllo della interfaccia I2C.

Il Common Language Runtime (CLR) fornisce due meccanismi per l’interoperabilità con il codice non gestito:

• Platform Invoke, che consente la chiamata di funzioni esportate da una libreria non gestita da parte del codice gestito;

• l’interoperabilità COM (Component Object Model), che con- sente l’interazione del codice gestito con oggetti COM median- te interfacce.

Nel caso in oggetto è stato necessario sfruttare il meccanismo Platform Invoke, affidando al CLR la mappatura dei tipi di para- metro di metodo cioè quel processo di conversione e "serializzazio- ne" dei parametri indicato nella terminologia di lingua inglese come

2.5. SVILUPPO DEL MOTORE DI ESECUZIONE DELLE PROVE 55

"marshalling" e necessario per consentirne lo scambio di dati tra i due ambienti.

Per la maggior parte dei tipi di dati, infatti, esistono rappresen- tazioni comuni sia nell’ambiente gestito che in quello non gestito. Questi tipi, denominati tipi copiabili, vengono trattati dal gestore di marshalling di interoperabilità senza conversione. Per altri tipi la mappatura potrebbe essere ambigua oppure essi potrebbero non essere rappresentati affatto nell’ambiente gestito. È possibile per- tanto fornire istruzioni esplicite al gestore di marshalling su come eseguire la mappatura in caso di ambiguità. Esistono molti fattori che influiscono sul modo in cui il CLR esegue il marshalling dei dati tra ambienti gestiti e non gestiti, tra cui la presenza di attributi quali [MarshalAs], [StructLayout], [InAttribute] e [OutAttribute] e di parole chiave del linguaggio quali out e ref in C#.

Per ogni metodo importato dalla libreria dinamica è stato neces- sario utilizzare in C# l’attributo [DllImport], contenuto nello spa- zio dei nomi System.Runtime.InteropServices, al fine di specificare il nome completo della libreria e la convenzione di chiamata dei metodi:

[ D l l I m p o r t ( " d e v i c e . d l l " , C a l l i n g C o n v e n t i o n = C a l l i n g C o n v e n t i o n . C d e c l ) ]

All’attributo è stata fatta seguire la dichiarazione del metodo, nel seguente formato:

e x t e r n s t a t i c t i p o − r e s t i t u i t o nome−metodo ( l i s t a −d i −p a r a m e t r i )

Per esportare i metodi è stato necessario aggiungere, nel sorgente C++ della libreria, l’attributo __declspec(dllexport) prima del loro nome sia nella dichiarazione che nella definizione. Al fine di evitare la cosiddetta decorazione dei nomi dei metodi da parte del compila- tore C++, è stato inoltre necessario definire i metodi esportati come extern "C".

La Figura 2.14 mostra il diagramma di sequenza per un tipico caso in cui l’applicazione viene utilizzata per eseguire un piano di prova che prevede l’invio al dispositivo di due comandi sul canale I2C. Un diagramma di sequenza viene usato per modellare le intera- zioni tra oggetti che realizzano un caso d’uso o una parte di un caso d’uso e rappresenta il modo più semplice per focalizzarsi sull’effetti- va sequenza temporale degli eventi [11]. All’avvio dell’applicazione viene creato un oggetto di tipo TextBox per la casella di testo dedi- cata alla visualizzazione dei messaggi di servizio, un oggetto di tipo TestPlan per contenere il piano di prova, un oggetto di tipo TestCase per contenere l’unica prova presente nel piano di prova ed infine due oggetti di tipo TestStep per contenere i due passi di prova Send Com- mand di cui è costituita tale prova. Successivamente l’utente preme il pulsante Run dell’interfaccia grafica per avviare il collaudo e vie- ne quindi generato un evento del tipo buttonRunExecution_Click. A questo punto, come spiegato poc’anzi, il gestore dell’evento di avvio collaudo crea un oggetto del tipo ExecutionThread il quale a sua vol- ta crea un oggetto della classe Thread fornita dalla Framework Class Library, cioè un thread secondario dedicato al motore di esecuzione che infine avvia. Il thread del motore di esecuzione, prima di ini- ziare l’interpretazione e l’esecuzione del piano di collaudo, tramite funzioni della libreria C++ device.dll apre la porta di comunicazio- ne con l’adattatore I2C e configura quest’ultimo. Terminata questa fase di inizializzazione dell’adattatore, vengono inviati i comandi al modulo di scansione secondo quanto previsto dal piano di collaudo e vengono lette le corrispondenti risposte provenienti dal dispositi- vo. Se le risposte ricevute sono congruenti con quelle previste per il superamento del relativo passo di prova, viene conteggiato un esito positivo altrimenti viene conteggiato un esito negativo. Ogni volta che viene determinato l’esito di un passo di prova o di una prova questo viene visualizzato nella casella di testo riservata ai messag- gi di servizio. Infine, terminata l’esecuzione del piano di collaudo, viene chiusa la porta di comunicazione con l’adattatore I2C.

2.5. SVILUPPO DEL MOTORE DI ESECUZIONE DELLE PROVE 57 Figura 2.14: Diagramma di sequenza per un tipico caso di esecuzione (sessione di in vio comandi).

Figura 2.15: Diagramma di attività per il generatore di resoconto.

Documenti correlati