Sunteți pe pagina 1din 74

Programarea sistemelor de masura II - LABORATOR

Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Programarea sistemelor
de masura II
Lucrari de laborator

Version no.: 1 Page 1 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Cuprins
1 INTRODUCERE........................................................................................................................................................5
2 PREZENTAREA MEDIULUI DE PROGRAMARE VISUAL STUDIO .NET................................................6
2.1 PRINCIPALELE FERESTRE DE LUCRU DIN VISUAL STUDIO..................................................................................7
2.2 COMENZILE DE LUCRU UTILIZATE IN VS............................................................................................................8
3 DEFINIREA CLASELOR IN OOP - CREAREA PROIECTULUI “SENSOR” DE SIMULARE A
SENZORILOR...............................................................................................................................................................10
3.1 PROPRIETATI, CONSTRUCTORI. TIPUL ENUM SI DATETIME.............................................................................10
3.2 INSTANTIEREA CLASELOR.................................................................................................................................14
3.3 CONSTRUCTORI PRIVATI. OBIECTELE TIMER SI RANDOM................................................................................15
4 PREZENTAREA DATELOR...............................................................................................................................19
4.1 SOLUTII CU PROIECTE MULTIPLE. IERARHIZAREA PROIECTELOR......................................................................19
4.2 FEREASTRA OUTPUT.........................................................................................................................................20
4.3 PROGRAMARE BAZATA PE EVENIMENTE. OBIECTELE "DELEGATE" SI "EVENT"..............................................21
4.4 PREZENTAREA DATELOR IN DATAGRID............................................................................................................24
4.4.1 Controalele de tip GUI nu sunt thread-safe.............................................................................................26
4.5 CONTROALE VIZUALE: CHECKBOX, TEXTBOX. CLASA DICTIONARY..............................................................28
5 SALVAREA INFORMATIILOR IN BAZA DE DATE.....................................................................................34
5.1 CREAREA BAZEI DE DATE SQLITE....................................................................................................................34
5.2 DATA ACQUISITION LAYER : INTERFATA INTRE BAZA DE DATE SI APLICATIA GUI.........................................35
5.2.1 Definirea string-ului de conectare la baza de date in pagina de proprietati a proiectului.....................36
5.2.2 Stringul de conectare depinde de folderul fizic al bazei de date..............................................................37
5.3 CLASA DE INTERFATA CU BAZA DE DATE.........................................................................................................39
5.3.1 Salvarea informatiilor in baza de date.....................................................................................................39
5.3.2 Citirea informatiilor din baza de date......................................................................................................42
6 TRANSMITEREA DATELOR INTRE APLICATII. SOCKET TCP/IP........................................................46
6.1 OBIECTUL TCPCOMMCLIENT...........................................................................................................................47
6.1.1 Impachetarea datelor pentru transmisie..................................................................................................47
6.1.2 Crearea unui nou fir de executie pentru fiecare dialog cu serverul........................................................49
6.1.3 Trimiterea datelor catre server................................................................................................................50
6.1.4 Functia Dispose inchide firele de executie suspendate............................................................................51
6.2 OBIECTUL TCPCOMMSERVER..........................................................................................................................52
6.3 STARTAREA SERVERULUI INTR-UN FIR DE EXECUTIE PROPRIU.........................................................................53
6.4 GESTIONAREA THREAD-URILOR INCHISE DE GARBAGE COLLECTION...............................................................54
6.5 RECEPTIONAREA DATELOR VENITE DE LA CLIENT PRIN TCP/IP.......................................................................55
6.6 DESPACHETAREA DATELOR SI TRIMITEREA LOR IN SISTEM PENTRU AFISARE..................................................56
7 REALIZAREA PROIECTULUI DE SETUP......................................................................................................59
7.1 O APLICATIE INCLUDE MAI MULTE FISIERE DE TIP DLL SAU EXE...................................................................59
7.2 PROIECTUL DE SETUP........................................................................................................................................59
7.2.1 Selectarea fisierelor adaugate in arhiva de setup....................................................................................60
7.2.2 Stabilirea meniului pentru rularea aplicatiei...........................................................................................61
7.2.3 Proprietatile proiectului de setup.............................................................................................................62

Version no.: 1 Page 2 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

7.3 INSTALAREA APLICATIEI “HEALTHMONITOR”..................................................................................................64


7.4 LANSAREA APLICATIEI HEALTHMONITOR IN EXECUTIE...................................................................................67
8 Concluzii...................................................................................................................................................................68

Version no.: 1 Page 3 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Lista de figuri
Figura 1: Visual Studio apare ca devenv.exe in lista de procese din Task Manager......................................6
Figura 2: Crearea unui nou proiect de tip "Console Application" in Visual Studio .NET..................................7
Figura 3: Principalele ferestre de lucru ale mediului Visual Studio.................................................................8
Figura 4: Clasa "SensorValue" si enumerarea "SensorType".......................................................................13
Figura 5: Constructorii clasei SensorValue................................................................................................... 13
Figura 6: Selectarea unei valori dintr-o enumerare.......................................................................................14
Figura 7: Instantierea clasei "SensorValue" folosind constructorul implicit...................................................15
Figura 8: Constructorii clasei PumpSensorValues........................................................................................16
Figura 9: Functia de generare si afisare a valorile aleatoare pentru senzori.................................................17
Figura 10: Intantierea clasei "PumpSensorValues" si pornirea ceasului in clasa Program...........................17
Figura 11: Selectarea unui proiect ca referinta pentru proiectul curent.........................................................20
Figura 12: Lansarea in executie a functiei de simulare a senzorilor..............................................................20
Figura 13: Fereastra Output afiseaza mesajele trimise la consola................................................................21
Figura 14: atasarea functiei "bTest_Click" la evenimentul "bTest.Click".......................................................22
Figura 15: Definirea obiectelor de tip delegate si event in clasa de generare a datelor de masurare...........22
Figura 16: Lansarea evenimentului "newSensorValueEvent".......................................................................22
Figura 17:Atasarea functiei "OnNewSensorValueHandler" la evenimentul "newSensorValueEvent"...........23
Figura 18:Valorile primite prin eveniment de la clasa "PumpSensorValue" sunt afisate in MessageBox......23
Figura 19: Controlul DataGridView din ToolBox...........................................................................................24
Figura 20:Setarea sursei de date pentru gridul de afisare............................................................................24
Figura 21: Popularea listei sensorValueList si setarea ei ca DataSource pentru grid...................................25
Figura 22: Eroare: un alt thread acceseaza datagridul.................................................................................26
Figura 23: Fereastra principala de prezentare a datelor cu datagrid-ul legat la lista de valori......................28
Figura 24: Adaugarea codului de pacient in clasa cu valorile senzorilor.......................................................29
Figura 25: Patient code trebuie adaugat si in clasa PumpSensorValues......................................................29
Figura 26: Evenimentul "newSensorValueEvent" include si codul de pacient..............................................29
Figura 27: Adaugarea coloanei PatientCode in datagrid...............................................................................30
Figura 28: Fereastra DataPresentation cu butoanele de startare si oprire a monitorizarii............................30
Figura 29: Enumerarea ce include codurile de pacienti................................................................................31
Figura 30: Atasarea unei enumerari la un CheckBox....................................................................................31
Figura 31: Codul aferent butonului "Start Monitoring"...................................................................................31
Figura 32: Functia StartPumping cu parametrii cod pacient si perioada de timp..........................................32
Figura 33: Oprirea monitorizarii pentru un pacient si eliminarea lui din dictionarul pacientilor activi.............32
Figura 34: Crearea bazei de date “PatientData” in SQLite Administrator......................................................34
Figura 35: Crearea tabelului “PatientData” pentru salvarea datelor ce vin de la pacienti..............................35
Figura 36: Adaugarea proiectului “DataStore” de tip “Class Library” la solutie.............................................36
Figura 37: Definirea string-ului de conectare la baza de date SQLite in pagina de proprietati a proiectului. 37
Figura 38: Adaugarea unui fisier existent la proiectul “DataStore”................................................................38
Figura 39: Adaugarea sub forma de link a fisierului bazei de date la proiectul curent..................................38
Figura 40: Fisierul bazei de date va fi copiat in directorul curent..................................................................39
Figura 41: Functia de inserare a unei valori de masurare in baza de date...................................................40
Figura 42: Tratarea evenimentului “newSensorValueEvent”: salvare in baza si afisare in datagrid..............41
Figura 43: Comanda SQL de vizualizare a datelor din tabela PatientData...................................................41
Figura 44: Vizualizarea datelor din baza in SQLite Administrator.................................................................41
Figura 45: Fereastra DataPresentation dupa ce s-a adaugat sectiunea de filtrare......................................42
Figura 46: Functia de citire din baza de date a datelor de masurare pentru un pacient si o zi stabilita........43
Figura 47: Proiectul “CommonReferences” contine toate definitiile particulare ale tipurilor de date.............44
Figura 48: Afisarea valorilor din baza de date...............................................................................................45
Figura 49: Functia handler pentru butonul “Display Received Data”.............................................................45
Figura 50: Proiectul Data Presentation cu posibilitatea de a alege canalul de comunicare a datelor...........46
Figura 51:Solutia "HealthMonitor" cu toate proiectele componente..............................................................47

Version no.: 1 Page 4 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 52: Constructorii clasei TCPCommClient...........................................................................................48


Figura 53: Functiile de primire si impachetare a datelor ce trebuie trimise la server.....................................48
Figura 54: Startarea unui nou thread pentru trimiterea datelor.....................................................................49
Figura 55: Inchiderea firelor de executie inactive..........................................................................................50
Figura 56: Dialogul cu serverul..................................................................................................................... 51
Figura 57: Tratarea evenimentului "FormClosing" in clasa "DataPresentation"............................................51
Figura 58: Componentele interne ale clasei "TCPCommClient"...................................................................52
Figura 59: Inchiderea firelor de executie la terminarea programului.............................................................52
Figura 60: Clasa TCPCommServer: componentele interne, constructorul si proprietatile............................53
Figura 61: Functiile de startare a serverului TCP/IP.....................................................................................54
Figura 62: Functiile de oprire a firelor de executie si a serverului TCP.........................................................55
Figura 63: Functia de receptionare a datelor de la client..............................................................................56
Figura 64: Functia de despachetare a datelor.............................................................................................. 57
Figura 65: Functia de transmitere a evenimentului cu datele primite de TCPServer....................................57
Figura 66: Tratarea evenimentului provenit de la TCPCommServer in DataPresentation............................58
Figura 67: Compilatorul aduce toate proiectele din referinte in directorul proiectului tata.............................59
Figura 68: Adaugarea proiectului de setup la solutie....................................................................................60
Figura 69: Fereastra de afisare a fisierelor atasate proiectului de setup.......................................................60
Figura 70: Adaugarea unui proiect din solutie la aplicatia de setup..............................................................61
Figura 71: Proiectul DataPresentation este adaugat la folderul de aplicatii..................................................61
Figura 72: Adaugarea shortcut-ului de lansare a aplicatiei in meniul Start/Programs...................................62
Figura 73: Fisierele de instalare a aplicatiei.................................................................................................. 62
Figura 74: Fereastra de proprietati a proiectului de setup.............................................................................63
Figura 75: Adaugarea librariei “.NET Framework 3.5 SP1” la programul de instalare..................................64
Figura 76: Fisierele DotNetFX sunt adaugate pachetului de instalare..........................................................64
Figura 77: Pasul 1: Fereastra de Wellcome a pachetului de instalare..........................................................65
Figura 78: Pasul 2: Alegerea locatiei de instalare.........................................................................................65
Figura 79: Pasul 3: Confirmarea instalarii..................................................................................................... 66
Figura 80: Pasul 4: Fereastra de inchidere a instalarii..................................................................................66
Figura 81: Fereastra de actiuni suplimentare atasate procesului de instalare..............................................67
Figura 82: Cum se starteaza programul HealthMonitor................................................................................67

Version no.: 1 Page 5 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

1 Introducere
Scopul lucrarilor de laborator prezentate in acest document este de familiariza studentul cu mediul de
programare Visual Studio .NET si aplicarea practica a cunostintelor prezentate la curs.

In acest scop, se propune in cele ce urmeaza realizarea unei miniaplicatii numite "HealthMonitor" care sa
monitorizeze de la distanta starea unui pacient cu probleme de sanatate, in sensul ca pacientul poate sa
ramana acasa purtand cu el diversi senzori de masurare a bio-parametrilor (temperatura, ritm cardiac,
glicemie, etc) si aceste valori sunt trimise prin internet la cabinetul doctorului care urmareste astfel starea
pacientului si se deplaseaza numai la aparitia unei alarme.
Ce presupune aceasta monitorizare?
 Citirea parametrilor bio
 Salvarea valorilor masurate intr-o baza de date locala
 Transmisia valorilor la aplicatia ce ruleaza in cabinetul doctorului
 Afisarea acestor valori sub forma grafica sau text pentru ca doctorul sa poata trage concluziile
corecte referitoare la starea de sanatate a pacientului

Prin implementarea acestor taskuri, studentul va trebui sa-si insuseasca si sa lucreze cu urmatoarele
concepte:
 Definirea claselor in OOP
 Instantierea claselor
 Mostenire
 Controale grafice
 Salvarea datelor in baza de date
 Comunicatii TCP/IP
 Multithreading
 Programare bazata pe evenimente
 ...

Evident ca aceste concepte nu pot fi acoperite in totalitate intr-un numar atat de mic de ore, dar acest
exemplu poate reprezenta un punct de plecare pentru dezvoltarea de alte aplicatii serioase si aprofundarea
cunostintelor legate de programare obiect si Visual Studio .NET.

Version no.: 1 Page 6 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

2 Prezentarea mediului de programare Visual Studio .NET


Mediul Visual Studio se deschide prin lansarea in executie a programului "C:\Program Files\Microsoft Visual
Studio 9.0\Common7\IDE\devenv.exe". Trebuie retinut numele programului "devenv.exe" deoarece de
multe ori este util sa deschidem aplicatia "Task Manager" din Windows si sa analizam modul de ocupare a
memoriei si a microprocesorului in timpul rularii unui program. Faptul ca apare "devenv.exe" in capul listei
din tab-ul "Processes" cu o portiune mare de memorie utilizata, inseamna de multe ori ca programul a
ramas agatat pe un fir de executie infinit si trebuie oprit din TaskManager.

Figura 1: Visual Studio apare ca devenv.exe in lista de procese din Task Manager

Dupa lansarea VS, primul pas este de a deschide un proiect deja existent pe dicul local, sau putem crea un
nou proiect (meniul File/New/Project..")

Version no.: 1 Page 7 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 2: Crearea unui nou proiect de tip "Console Application" in Visual Studio .NET

Putem alege din mai multe tipuri de proiecte, dupa cum urmeaza:
 Windows Form application: este pentru dezvoltarea de aplicatii de tip GUI, bazate pe ferestre,
controale grafice, etc.
 WPF Application: dezvolta acelasi tip de aplicatii de tip GUI, dar bazate pe noua tehnologie WPF
(Windows Presentation Foundation) ce expune posibilitati mult mai largi de desenare grafica a
interfetelor utilizator. WPF lucreaza cu limbajul XAML prin care se pot descrie imagine grafice de pe
ecran. Folosind acest limbaj, utilizatorul are posibilitatea sa deseneze interfata grafica intr-o
aplicatie specifica de desenare, exporta imaginea in format XAML si aceasta se importa in Visual
Studio unde i se poate atasa evenimente si logica necesara aplicatiei.
 Console Application: cel mai simplu proiect, nu are interfata grafica, este foarte util in testarea
rapida a unor concepte de tip OOP.
 Windows Service: dezvoltarea unui serviciu Windows. Serviciile sunt acele aplicatii care pornesc
automat la deschiderea calculatorului si ofera suport in background pentru diverse functionalitati ale
sistemului. De exemplu, baza de date Oracle lucreaza ca un serviciu, porneste odata cu sistemul si
deschide un "Listener" ce asculta in mod permanent la un port pentru a raspunde eventualelor
comenzi SQL trimise de un client.
 Proiecte de tip "Library": nu au interfata cu utilizatorul, nu pot fi pornite direct pentru ca nu contin
functia "Main". Ele sunt folosite doar pentru crearea diverselor functii de biblioteca ce vor fi utilizate
in programele de tip "application". Librariile sunt salvate pe disc sub forma de fisiere DLL ce trebuie
importate in spatiul de lucru al proiecteor ce vor face apel la ele.

Version no.: 1 Page 8 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

2.1 Principalele ferestre de lucru din Visual Studio


Dupa deschiderea unui proiect, Visual Studio afiseaza un ecran de lucru ce cuprinde urmatoarele ferestre
utile:

Figura 3: Principalele ferestre de lucru ale mediului Visual Studio

 Fereastra "Toolbox": contine majoritatea controalelor utilizate in crearea aplicatiilor: butoane,


TextBox-uri, grid-uri, conexiuni,etc. Sunt foarte multe controale implicite ale mediului VS, dar pot fi
adaugate de asemenea alte controale din diverse librarii sau instalari de aplicatii.
 Fereastra de editare a codului de program: aici se introduce efectiv codul sursa al programului
 Fereastra "Solution Explorer" afiseaza structura solutiei: proiectele ce apartin de aceasta solutie,
proprietatile fiecarui proiect in parte, fisierele ce compun proiectul.
 Properties: este fereastra ce afiseaza proprietatile si evenimentele asociate obiectului curent
selectat in pagina de lucru
 Error List: listeaza erorile aparute la compilarea sau executia programului

2.2 Comenzile de lucru utilizate in VS


Comenzile des folosite in editarea si rularea unui program sunt:
 F5: compileaza si lanseaza in executie programul curent (in modul Debug)
 CTRL+S: salveaza fisierele de lucru
 F6 (Build solution): compileaza solutia

Version no.: 1 Page 9 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

 SHIFT+F5: opreste executia programului din modul Debug


 F10: executie pas cu pas (functia apelata se considera a fi un pas)
 F11: executie pas cu pas cu intrarea in functia apelata
 F9: defineste sau sterge un breakpoint in linia curenta

Version no.: 1 Page 10 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

3 Definirea claselor in OOP - crearea proiectului “Sensor” de


simulare a senzorilor
Scopul acestui proiect (Sensor) este de a simula functionalitatea senzorilor concreti din lumea reala.
Deoarece nu avem astfel de senzori, se construieste un proiect care sa simuleze existenta acestora.
Proiectul trebuie sa trimita periodic catre alta aplicatie valorile bio pe care le-ar trimite un senzor real prin
masurare concreta. Trebuie simulati 3 categorii de senzori:
 HeartRate: (Ritm cardiac): senzorul ce trimite valorile ritmului cardiac al pacientului
 SkinTemperature: temperatura pacientului
 BloodGlucose: concentratia de glucoza din sangele pacientului

Proiectul trebuie sa implementeze urmatoarele functionalitati:


 Defineste structura informatiei trimisa de senzor (clasa “SensorValue”) cu urmatoarele campuri:
o Tipul senzorului care trimite informatia (HeartRate, SkinTemperature, BloodGlucose)
o Valoarea masurata
o Timpul masurarii
 Construieste o clasa “PumpSensorValue” care va trimite instante ale clasei “SensorValue” cu o
anumita periodicitate. Pentru o simulare cat mai eficienta, valorile trimise vor fi create prin functia
“Random” ce returneaza valori aleatorii intr-un interval dat.
Include urmatoarele functii:
o Start pumping
o Stop pumping
o Pumping period

3.1 Proprietati, Constructori. Tipul Enum si DateTime


Se deschide mediul VS si creaza un nou proiect de tip "Console Application":
 Name: "Sensor" (numele proiectului)
 Location: D:\PSM\Ionescu (aici inlocuiti “Ionescu” cu numele propriu, este folderul unde se va salva
aplicatia si unde veti construi la fiecare laborator noi faze din proiect). Pentru a nu pierde aceasta
munca (printr-o eventuala stergere facuta de un alt coleg), este bine sa salvati folderul pe un stick
sau attachment la un mail.
 Solution Name: HealthMonitor. Este numele solutiei care va cuprinde mai multe proiecte: proiectul
de simulare al senzorului, proiectul de salvare a datelor pe disc, proiectul de afisare a rezultatelor,
etc. Toate aceste proiecte impreuna formeaza solutia “HealthMonitor”.

Version no.: 1 Page 11 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Dupa crearea proiectului “Sensor” se construieste prima clasa numita “SensorValue” in cadrul acestui
proiect: click dreapta pe numele proiectului in fereastra “Solution Explorer” si se alege Add/Class:

Version no.: 1 Page 12 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Fig: Adaugarea clasei “SensorValue” la proiectul “Sensor”

In cadrul acestei clase se definesc urmatoarele componente:


 Membri privati: type, value, timeStamp
 Proprietatile publice Type, Value, TimeStamp
 Constructorii:
- Implicit
- public SensorValue(SensorType type, double value, DateTime timeStamp)
- public SensorValue(SensorType type, double value, string timeStamp)

Version no.: 1 Page 13 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 4: Clasa "SensorValue" si enumerarea "SensorType"

Figura 5: Constructorii clasei SensorValue

Lista de senzori potentiali cu care poate lucra programul este tinuta de o enumerare publica numita
"SensorType". Enumerarile sunt constructii simple in care se pot da nume sugestive pentru numerele
naturale. De exemplu, este mult mai sugestiv sa primesti un parametru numit "HeartRate" decat numarul 2
cat reprezinta acel parametru. Mai mult, daca se sterge sau se adauga un termen din enum, programul nu
se modifica cu nimic, in continuare functia va primi parametrul "HeartRate", chiar daca acum acel
parametru are valoarea 1.
Alegerea unei valori din enum se face simplu, se scrie numele enum-ului si se alege valoarea
corespunzatoare:

Version no.: 1 Page 14 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 6: Selectarea unei valori dintr-o enumerare

Se observa ca in lista de proprietati a clasei proprietatea TimeStamp (timpul la care s-a facut masurarea)
apare de doua ori. Prima varianta TimeStamp primeste si returneaza o clasa de tip DateTime, iar a doua
varianta primeste un string si converteste acel string intr-o structura DateTime. Conversia unei date in string
se face cu metoda ToString (timeStamp.ToString("dd-MMM-yy HH:mm") ), metoda ce primeste ca
parametru stringul de formatare a datei calendaristice. Conversia inversa se face cu functia statica a clasei
DateTime numita ParseExact :
DateTime.ParseExact(value, "dd-MMM-yy HH:mm",CultureInfo.InvariantCulture)

3.2 Instantierea claselor


Se deschide fereastra programului principal (Program.cs) si se scrie codul pentru instantierea clasei
SensorValue folosind constructorul implicit. Dupa crearea obiectului "sensor1" se folosesc proprietatile
acestuia pentru introducerea valorile de masurare (Type, TimeStamp si Value). Toate aceste valori se
afiseaza apoi la consola prin apelul functiei DisplaySensorValue. Aceasta functie primeste doi parametri:
o un string numit "headerText" care va fi afisat in capul listei de valori
o o instanta a clasei "SensorValue" care contine informatiile de afisat

Version no.: 1 Page 15 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 7: Instantierea clasei "SensorValue" folosind constructorul implicit

 Sa se defineasca un alt obiect de tip "SensorValue", dar utilizand de data aceasta constructorul cu
parametri
 Sa se afiseze valorile acestui obiect prin apelul functiei "DisplaySensorValue()".
 Intrebare: de ce a fost necesar sa se declare functia "DisplaySensorValue()" de tip static? Stergeti
atributul "static" din definitia functiei si observati rezultatul.

3.3 Constructori privati. Obiectele Timer si Random


Cum nu avem senzorii in mod efectiv, va trebui sa construim o clasa care sa simuleze functionarea reala a
acestor senzori. Aceasta clasa va trebui sa instantieze in mod aleatoriu un senzor din lista "SensorType" si
apoi sa genereze o valoare aleatoare intr-un domeniu specific acelui senzor:
 Temperatura poate varia intre 36 si 40 de grade
 Glicemia intre 80 si 300 mg/dl
 Pulsul inimii intre 30 si 200

Functia de simulare trebuie sa creeze aceasta valoare aleatoare in mod continuu cu o frecventa data de
functia principala Main.

In folderul "Sensor" se creeaza o noua clasa numita "PumpSensorValues". Aceasta va avea doar un singur
constructor public, cel ce primeste numarul de secunde intre doua valori ale senzorilor.

Version no.: 1 Page 16 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 8: Constructorii clasei PumpSensorValues

Constructorul implicit va fi declarat privat pentru a nu permite instantierea unei clase fara sa se stabileasca
perioada intre doua valori.
 Incercati sa creati un obiect de tipul "PumpSensorValues" prin constructorul implicit si observati
eroarea generata de VS

In constructorul clasei sunt create doua obiecte de uz general.


 Prima clasa instantiata este de tipul Random. Acesta clasa este folosita pentru generarea
numerelor aleatoare. Se instantiaza o singura data la intrarea in constructor si se poate apela
oriunde in program pentru a obtine un numar aleator intre doua limite date. Generarea numarului
aleator se face prin apelul functiei Next cu cele doua variante:
 Next(intMax): genereaza un intreg aleator mai mic decat intMax
 Next(intMin, intMax): numarul aleator este cuprins intre intMin si intMax.
 Al doilea obiect utilizat este de tipul System.Timers.Timer. Acest obiect lucreaza ca un ceas ce
poate fi programat sa apeleze o functie periodic la un interval de timp dat. De fapt, la sfarsitul
fiecarui interval de timp, timerul va genera un eveniment "Elapsed" la care noi trebuie sa ne
abonam ca sa-l interceptam in mometul emiterii:
timerBase.Elapsed += new ElapsedEventHandler(timerBase_Elapsed);
Functia ce va fi apelata la fiecare tact al timerului este "timerBase_Elapsed". In aceasta functie trebuie sa
selectam in mod aleator un tip de senzor si sa-i dam o valoare, apoi sa afisam proprietatile senzorului la
consola.

Version no.: 1 Page 17 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 9: Functia de generare si afisare a valorile aleatoare pentru senzori

Tot ce mai trebuie facut ca sa apara valorile la consola, este sa instantiem in clasa Program obiecte din
clasa PumpSensorValues si sa pornim ceasul la acele obiecte:

Figura 10: Intantierea clasei "PumpSensorValues" si pornirea ceasului in clasa Program

Nu trebuie uitat la iesirea din program sa se opreasca ceasul pentru a nu mai trimite evenimente pe care sa
nu le intercepteze nimeni.

 Intrebare: de ce am putut apela functia "DisplaySensorValues" in clasa "PumpSensorValues" fara


sa am vreo instanta la clasa "Program" ?

Version no.: 1 Page 18 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Functiile StartPumping si StopPumping sunt urmatoarele:

public void StartPumping()


{
timerBase.Start();
}
public void StopPumping()
{
timerBase.Stop();
}

In functia "StartPumping()" pornesc ceasul timerBase si acesta imi va trimite evenimente la fiecare
"Interval" de timp.
"StopPumping" trebuie apelata la sfarsitul programului pentru a opri ceasul sa mai trimita evenimente.

Version no.: 1 Page 19 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

4 Prezentarea datelor

4.1 Solutii cu proiecte multiple. Ierarhizarea proiectelor


Pana acum am reusit sa generam date pentru senzorii de masurare si sa le afisam in fereastra de tip
consola. Dar acest tip de afisare nu este convenabila pentru doctor. Doctorul ar avea nevoie de un ecran
care sa-i afiseze valorile sosite continuu de la senzor, sa le poata sorta dupa tipul de senzor, sa-i fie
semnalate alarme in cazul unei valori ce depaseste anumite limite.

In acest scop vom dezvolta un nou proiect de tip Windows Form Application care va avea drept scop
afisarea intr-o maniera grafica a rezultatelor de masurare.
Mai intai, se redenumeste (in caz ca nu s-a pornit cu aceste denumiri de la inceput) solutia in
"HealthMonitor" (click dreapta pe numele solutiei si alegem meniul "Rename"), iar proiectul TestOOP se
redenumeste "SensorValue". Deci ne propunem o solutie pentru monitorizarea starii de sanatate a
pacientului, iar in cadrul acestei solutii proiectul deja construit are rol de a simula functionarea reala a
senzorilor.

Se deschide un nou proiect in cadrul solutiei pentru prezentarea datelor venite de la senzori. Acest nou
proiect se denumeste "DataPresentation" si se alege sa fie proiectul de pornire a solutiei. Cand o solutie
contine mai multe proiecte trebuie ales proiectul de pornire, cel ce va lansa functia Main():

Setarea proiectului “DataPresentation” ca proiect de pornire a solutiei “HealthMonitor”

Acest nou proiect trebuie sa afiseze datele furnizate de celalalt proiect (SensorValue). Totusi, proiectele
sunt independente si nu se pot apela in mod direct functii dintr-un proiect in altul. De aceea, trebuie
alcatuita o ierarhie de proiecte, in care un proiect tata poate face apel la clasele dintr-un alt proiect fiu aflat
pe o ramura inferioara in cadrul ierarhiei. Includerea unui proiect copil in cadrul ierarhiei se face prin
adaugarea acelui proiect la referintele proiectului tata. Se face click dreapta pe "References" la proiectul
"DataPresentation" si se alege Add Reference:

Version no.: 1 Page 20 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 11: Selectarea unui proiect ca referinta pentru proiectul curent

Referintele pot fi adaugate din universul .NET unde se gasesc majoritatea bibliotecilor de programe utile,
sau din tab-ul "COM" ce contine controale particularizate, sau "Projects" unde sunt listate toate proiectele
curente ale solutiei curente.
Se alege tab-ul "Projects" si se selecteaza proiectul "SensorValue" pentru a se adauga la referintele
proiectului curent.

Din acest moment proiectul "DataPresentation" poate instantia si utiliza toate clasele publice declarate in
proiectul "SensorValue".

4.2 Fereastra Output


Se modifica constructorul proiectului "DataPresentation" pentru a lansa in executie functia "StartPumping"
din clasa "PumpSensorValues":

Figura 12: Lansarea in executie a functiei de simulare a senzorilor

Version no.: 1 Page 21 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Chiar daca functia de simulare a senzorilor a pornit, in fereastra "DataPresentation" nu se vede nimic. Nici
nu are cum, din moment ce functia de simulare trimite valorile generate la consola. Iar acum consola nu
este vizibila pentru ca proiectul curent "DataPresentation" este de tip "Windows Form Application" si nu
afiseaza consola.
Totusi, putem vedea toate mesajele trimise la consola in timpul executiei unui proiect daca se activeaza
fereastra "Output" (meniul View/Output din VS). Aceasta fereastra se deschide in timpul executiei
programului si afiseaza mesajele de consola ale aplicatiei:

Figura 13: Fereastra Output afiseaza mesajele trimise la consola

4.3 Programare bazata pe evenimente. Obiectele "Delegate" si "Event"


Am vazut ca clasa "PumpSensorValues" afiseaza datele doar la consola. Si totusi, noi am dori ca aceste
date sa fie afisate de fereastra "DataPresentation". In schimb, "PumpSensorValues" nu are nici o informatie
despre clasa container in care va fi utilizata, deci nu are acces la nici un obiect din aceasta clasa. Este
aceeasi problema pe care o are obiectul "Button" dintr-o forma oarecare. In momentul cand utilizatorul face
click pe buton, acesta ar trebui sa execute o actiune in clasa container, cea care il contine. Dar evident,
butonul nu stie nimic despre clasa container, el este un obiect din biblioteca .NET si este instantiat in mii de
aplicatii de tipul "Windows Form".

Tot ce poate sa faca un buton in momentul cand user-ul face "click" este sa lanseze evenimentul "Click".
Daca este cineva sa-l asculte (adica s-a scris o functie care sa prinda evenimentul) atunci actiunea click va
avea afect, altfel evenimentul se pierde in eter. Se poate face o asemanare cu actiunile unui catel de paza.
Catelul de paza (ca si butonul) cand se naste, nu stie unde va pazi si cine-l va asculta. Daca este pus sa
pazeasca o vie de exemplu, tot ce poate el este sa faca galagie, adica sa emita evenimente (in cazul de
fata evenimentul "Thief_Inside"). Daca este cineva sa-l asculte bine, daca nu, evenimentele se pierd.

Pentru a putea lansa si prinde evenimente, trebuie realizate cateva actiuni:


 Definirea obiectulului "Delegate": reprezinta amprenta functiei care trebuie sa prinda acel
eveniment.
 Definirea obiectulului "Event": este evenimentul propriu-zis.
 Lansarea evenimentului
 Prinderea evenimentului de functia "handler"

Toate aceste actiuni se fac automat cand se face double-click pe un buton in fereastra de design. VS-ul
creeaza automat o functie (handler) care sa trateze evenimentul trimis de buton si tot ce avem noi de facut

Version no.: 1 Page 22 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

este sa introducem cod in acea functie. Daca ne uitam in background (Designer.cs), observam ca in acel
fisier ,VS-ul introduce cod pentru legarea evenimentului la functie:

Figura 14: atasarea functiei "bTest_Click" la evenimentul "bTest.Click"

Revenim la aplicatia noastra si sa parcurgem pasii pentru lansarea si prinderea evenimentului ce anunta o
noua valoare de la senzori.
Mai intai, in clasa ce pompeaza date definim delegatul si evenimentul:

Figura 15: Definirea obiectelor de tip delegate si event in clasa de generare a datelor de masurare

Intai se defineste delegatul in afara oricarei clase. Este ca orice definitie de functie, numai ca i se pune in
fata termenul "delegate". In acest fel se defineste amprenta functiei care trebuie sa prinda evenimentul.
Evenimentul se declara in interiorul clasei si trebuie sa fie public pentru a fi cunoscut si in afara clasei.
Lansarea acestuia se face simplu, este ca un apel de functie:

Figura 16: Lansarea evenimentului "newSensorValueEvent"

Intotdeauna, inainte de lansare trebuie verificat daca evenimentul este diferit de null. Un eveniment este nul
pana in momentul cand se ataseaza un handler la el. Daca nu are atasat nici un handler care sa-l
intercepteze, nu are sens sa se trimita evenimentul, de aceea VS-ul il mentine nul.

Atasarea handler-ului la eveniment se face in clasa container "DataPresentation":

Version no.: 1 Page 23 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 17:Atasarea functiei "OnNewSensorValueHandler" la evenimentul "newSensorValueEvent"

In constructorul clasei "DataPresentation" se instantiaza clasa "PumpServerValues(3)", se porneste functia


de generare a datelor (StartPumping) si se ataseaza handlerul la eveniment.
La fiecare 3 secunde functia "StartPumping" va genera un eveniment avand valorile senzorului ca argument
care in final va fi tratat in handler. Pentru moment, handler-ul doar afiseaza un "MessageBox" cu valorile
senzorului.

Dupa lansarea in executie a proiectului, in fereastra clasei "DataPresentation" va aparea la fiecare 3


secunde un mesaj cu valorile primite in argument.

Figura 18:Valorile primite prin eveniment de la clasa "PumpSensorValue" sunt afisate in


MessageBox

Version no.: 1 Page 24 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

4.4 Prezentarea datelor in DataGrid


Scopul final al proiectului e sa prezentam datele nu prin mesaje, ci folosind un grid care sa se populeze cu
datele venite de la senzori.
Proiectul "DataPresentation" este de tip "Windows Form Application", deci in cadrul lui avem acces la
controalele vizuale din ToolBox. Putem gasi la sectiunea "Data" un control de vizualizare de tip grid:

Figura 19: Controlul DataGridView din ToolBox

Selectam acest control si facem drag-and-drop in fereastra principala a proiectului. El va fi instantiat


automat in functia "InitializeComponents" a formei, noi trebuie doar sa-i setam proprietatile in stilul dorit. Dar
in primul rand trebuie setate numele gridului si "DataSource", adica sursa de unde gridul isi va lua datele ca
sa le afiseze:

Figura 20:Setarea sursei de date pentru gridul de afisare

Se pune numele "dgSensorValueList" iar pentru DataSource se merge pe butonul de rulare in jos si se
alege din fereastra aparuta linkul "Add project data source..". Se alege apoi data source de tip Object unde
regasim toate clasele definite de noi si care pot juca rolul de sursa pentru grid. Din namespace-ul
"SensorValue" alegem clasa "SensorValue" drept sursa pentru grid.

Version no.: 1 Page 25 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Odata selectata sursa, VS-ul creeaza automat un obiect de legatura intre grid si clasa sursa. Acest obiect
este de tipul "BindingSource" si apare automat in partea de jos a ferestrei de design. Daca ne uitam in
functia "InitializeComponents" putem gasi codul scris in mod automat pentru legarea gridului la
BindingSource si BindingSource la SensorValue:

 Se creeaza un obiect de tipul BindingSource:


this.SensorValueBindingSource = new Forms.BindingSource(this.components);
 Se alege SensorValue ca DataSource pentru acest BindingSource:
this.SensorValueBindingSource.DataSource = typeof(SensorInput.SensorValue);
 Se ataseaza BindingSource la datagrid:
this.dgSensorValueList.DataSource = this.SensorValueBindingSource;

Dupa aceasta bindare gridul va avea coloanele setate dupa proprietatile publice din SensorValue. Se poate
modifica modul de prezentare a datelor (coloanele afisate, fontul dorit, headere si multe altele) din fereastra
de proprietati a gridului.

Dupa setarea tuturor proprietatilor pentru datagrid se ruleaza programul si se observa ca gridul apare in
fereastra cu toate coloanele stabilite in design. Si totusi, nu are nici o linie de date inclusa.Si asta deoarece
clasa "SensorValue" este doar o definitie, ea nu are efectiv date in ea.
Se populeaza gridul cu date numai daca ii dam ca sursa o lista de obiecte de tip SensorValue, fiecare
obiect avand valorile date de clasa PumpSensorValues.

Figura 21: Popularea listei sensorValueList si setarea ei ca DataSource pentru grid

Definim in clasa DataPresentation o lista de tipul SensorValue

List<SensorValue> sensorValueList = new List<SensorValue>();

Iar in handler-ul de tratare a evenimentului primit de la sensor, comentam linia cu MessageBox-ul (nu mai
vreau sa afisez informatia prin mesaj) si inserez linia:

this.BeginInvoke(new VoidFunctionDelegate(BindDataGridToListOfValues));

unde VoidFunctionDelegate este un delegate ce defineste o functie ce nu primeste nici un parametru, nici
nu returneaza o valoare. Se introduce aceasta definitie a delegatului in clasa DataPresentation:

public delegate void VoidFunctionDelegate();

Version no.: 1 Page 26 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Observatie: VoidFunctionDelegate poate fi inlocuit cu delegatul standard Action, care nu trebuie


definit, ci doar utilizat:

this.BeginInvoke(new Action(BindDataGridToListOfValues));

4.4.1 Controalele de tip GUI nu sunt thread-safe

In loc de linia cu BeginInvoke, as fi vrut sa apelez direct functia BindDataGridToListOfValues(). Dar daca
facem asa ceva, apare o eroare foarte interesanta la executie:

Figura 22: Eroare: un alt thread acceseaza datagridul

Care este problema de fapt? Eroare spune ca un alt thread (fir de executie) decat cel care l-a creat,
acceseaza datagridul. Ce sunt thread-urile sau firele de executie? Se stie ca Windows-ul poate lansa mai
multe aplicatii simultan. Pentru ficare aplicatie cand e pornita, Windows-ul creeaza un nou fir de executie
pentru acea aplicatie si-i da drumul sa ruleze. In acest fel se aduna mai multe fire de executie, toate cerand
timp microprocesor pentru executie. In functie de prioritatea lor, Windows-ul le acorda la fiecare un timp
microprocesor in care acel thread sa-si faca treaba. Deci microprocesorul porneste un thread, apoi il
opreste si da microprocesorul la alt thread, apoi la altul, apoi se intoarce iar la primul si tot asa.

Acelasi multithreading se intampla si-n aplicatia noastra. Clasa PumpSensorValues are o functie de pornire
a ceasului:

public void StartPumping()


{
timerBase.Start();
}

Aceasta functie aparent nevinovata de fapt creeaza un alt thread in care va lucra ceasul. Ceasul este un
obiect ce lucreaza in background si nu are sens sa ocupe din threadul curent de executie. El isi deschide
un thread separat de unde trimite din cand in cand evenimente de tip "Time_Elapsed".

Tehnica programarii de tip multithreading este foarte utila atunci cand trebuie indeplinite taskuri mari
consumatoare de timp: download-area unui fisier mare de pe internet, accesul la o baza de date,

Version no.: 1 Page 27 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

deschiderea de fisiere mari, etc. Daca aceste taskuri s-ar executa in acelasi fir de executie cu cel pricipal ce
raspunde de interfata cu utilizatorul, atunci aceasta interfata ar fi inghetata (froozen) pe timpul rularii lor.
Adica programul nu mai raspunde la nici o actiune a utilizatorului deoarece este captiv in acel task lung. De
aceea se prefera ca acel task se porneasca pe un alt thread, iar threadul principal sa ramana activ pentru a
raspunde la comenzile utilizatorului, si cand threadul secundar se termina, sa trimita un eveniment catre
threadul principal.

Cam asa lucreaza si Timer-ul, el ruleaza pe un thread secundar de unde trimite evenimente catre threadul
nostru principal: cel ce afiseaza fereastra si raspunde la butoane. Toate bune si frumoase pana cand
threadul secundar arunca un eveniment, acesta este prins intr-o functie si acea functie vrea sa acceseze
datagrid-ul (sau orice alt control vizual din fereastra). In acel moment apare eroarea descrisa mai sus,
deoarece controalele vizuale nu sunt "thread-safe", adica nu lucreaza bine pe mai multe fire de executie.
Nici nu au cum daca ne gandim ca threadurile lucreaza intretesut, adica se intrerup unul pe altul in mod
permanent. Si se pot intampla situatii cand un thread modifica culoarea la un control in verde de exemplu si
este intrerupt in acest timp de un alt thread care modifica in rosu. Ce culoare ar trebui sa aiba controlul la
sfarsit? De aceea s-a hotarat ca toate controalele vizuale nu lucreaza multithreading si nu accepta controlul
decat de la threadul care l-a instantiat.

Pentru a sari in threadul principal din threadul secundar, apelam functia BeginInvoke, care pune in coada
de mesaje al threadului principal functia ce trebuie executata. Este aceeasi functie
"BindDataGridToListOfValues", dar prin apelul BeginInvoke eu o trimit spre executie thread-ului
principal. Fiind executata de thread-ul principal, se poate umbla la controlul datagrid si sa-i setam
DataSource pe lista de valori obtinuta in celalalt thread.

private void BindDataGridToListOfValues()


{
dgSensorValueList.DataSource = null;
dgSensorValueList.DataSource = sensorValueList;
}

Deci, la fiecare eveniment primit de la celalalt thread, eveniment ce vine dupa el cu o noua valoare de
senzor, noi adaugam in lista acea valoare si reconectam lista la datagrid pentru afisare.

Version no.: 1 Page 28 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 23: Fereastra principala de prezentare a datelor cu datagrid-ul legat la lista de valori

4.5 Controale vizuale: CheckBox, TextBox. Clasa Dictionary

4.5.1 Adaugarea codului de pacient in clasele de lucru

In constructorul clasei de prezentare a datelor se starteaza o singura instanta a clasei PumpSensorValues.


In realitate sunt mai multi pacienti conectati la aplicatia de monitorizare ce ruleaza pe calculatorul
doctorului. In afara de valorile de masurare, gridul de vizualizare a datelor trebuie sa afiseze si codul
pacientului de la care provin datele.

4.5.1.1 Adaugarea codului de pacient in clasa SensorValue


Se adauga in clasa "SensorValue" o proprietate care sa contina codul pacientului pentru care trimite
valorile:

Version no.: 1 Page 29 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 24: Adaugarea codului de pacient in clasa cu valorile senzorilor

Respectiv, se adauga un constructor in clasa SensorValue care primeste si codul pacientului ca parametru:

4.5.1.2 Adaugarea codului de pacient in clasa PumpSensorValues


Clasa "PumpSensorValues" se modifica pentru a primi in plus parametrul codul pacientului:
 Se adauga un string privat numit “patientCode”.
 Se adauga un constructor care primeste in plus si codul pacientului:

Figura 25: Patient code trebuie adaugat si in clasa PumpSensorValues

Observatie: noul constructor trebuie sa includa si functionalitatea din vechiul constructor (cel care primeste
perioada de timp). Acele linii de cod nu se rescriu in noul constructor, e mai bine sa se apeleze vechiul
constructor prin constructia: : this(periodSecondsBetweenValues). Dupa ce s-a executat vechiul
constructor, se salveaza codul pacientului in variabila interna.
 Se modifica functia timerBase_Elapsed pentru a trimite prin intermediul evenimentului o instanta
a clasei SensorValue ce include codul pacientului:

Figura 26: Evenimentul "newSensorValueEvent" include si codul de pacient

Version no.: 1 Page 30 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

4.5.1.3 Adaugarea codului de pacient in gridul de prezentare a datelor


Ramane ca si in gridul de prezentare a datelor sa se adauge o coloana de afisare a codului de pacient. Se
deschide fereastra de proprietati a gridului si sa da click pe Add pentru a adauga noua coloana
"PatientCode" definita in clasa "SensorValue" folosita ca sursa de date pentru grid:

Figura 27: Adaugarea coloanei PatientCode in datagrid

4.5.2 Selectarea pacientului ce trebuie monitorizat

Acum ca avem si codul de pacient in SensorValue, putem construi o interfata ce ne permite sa startam un
pacient nou, sau sa oprim trimiterea datelor de la un pacient deja pornit.

Se introduce in fereastra "DataPresentation" un ComboBox numit “cbPatientCodeStart” care sa listeze


pacientii disponibili pentru monitorizare, aceasta lista va fi creata printr-o structura de tip ‘Enum”:

Figura 28: Enumerarea ce include codurile de pacienti

Iar aceasta enumerare se pune (in constructorul clasei) ca sursa de date pentru checkBox:

Figura 29: Atasarea unei enumerari la un CheckBox

Version no.: 1 Page 31 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Vom introduce in fereastra "DataPresentation" doua butoane "Start Pumping" (bStartPumping) si "Stop
Pumping" (bStopPumping) care sa starteze si sa opreasca din monitorizare un pacient selectat din
comboBox.

Figura 30: Fereastra DataPresentation cu butoanele de startare si oprire a monitorizarii

Butonul "Start Monitoring" trebuie sa porneasca monitorizarea pentru pacientul selectat in checkBox avand
ca interval de timp valoarea din textBox-ul aferent (tbTimePeriod) :

Figura 31: Codul aferent butonului "Start Monitoring"

Functia trebuie sa verifice ca checkBox-ul are un pacient selectat si ca textBox-ul pentru numarul de
secunde contine un numar intreg valid. De exemplu, daca utilizatorul introduce numarul "12ax", acest text
nu poate fi convertit la un intreg si trebuie afisat mesj de eroare. Prinderea acestei situatii se face printr-o
constructie de tip try-catch.

Se scrie o functie "startPumping" care primeste ca parametri codul pacientului si numarul de secunde intre
doua masurari pentru acel pacient si aceasta functie trebuie sa starteze monitorizarea pentru acel pacient:

Version no.: 1 Page 32 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 32: Functia StartPumping cu parametrii cod pacient si perioada de timp

Problema care apare in momentul cand se lucreaza cu mai multi pacienti este ca putem din greseala sa
pornim acelasi pacient de mai multe ori si am primi de la acelasi cod de pacient seturi de date diferite.
Putem indrepta aceasta greseala daca construim un dictionar care sa includa toti pacientii activi impreuna
cu obiectul "SensorValue" atasat.

Clasa "Dictionary" lucreaza ca o colectie de perechi de obiecte, primul obiect din pereche avand
semnificatia unei chei. Perechile de obiecte se adauaga in dictionar foarte simplu prin comanda Add si apoi
sa poate cauta o anumita pereche daca se da cheia pentru acea pereche:
 Se defineste o noua instanta a clasei Dictionary pentru perechea de obiecte: PatientCodeEnum si
PumpSensorValues:
Dictionary<PatientCodeEnum, PumpSensorValues> dictPatientPump = new
Dictionary<PatientCodeEnum, PumpSensorValues>();
 Dupa startarea unui nou pacient, perechea pacient-pumpSensorValue se adauga in dictionar:
dictPatientPump.Add(patCodeEnum, sensorValuesPump);
 Inainte de startare se cauta in dictionar daca nu cumva acest pacient este deja activ. In caz
adevarat se da mesaj de eroare:
if (dictPatientPump.ContainsKey(patCodeEnum))
{
MessageBox.Show("The selected patient has the pump already started");
return;
}

Functia aferenta butonului "Stop Monitoring" trebuie sa opreasca monitorizarea pentru acel pacient si apoi
sa elimine pacientul din dictionarul cu pacientii activi:

Version no.: 1 Page 33 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 33: Oprirea monitorizarii pentru un pacient si eliminarea lui din dictionarul pacientilor activi

In sfarsit am obtinut ceva... un grid care se incarca periodic cu o noua linie ce afiseaza ultima masuratoare
obtinuta de la senzori aferenti unui pacient activ, putem de asemenea starta sau stopa monitorizarea unui
pacient cu o perioada de timp programabila.

Totusi treaba nu e gata, mai trebuie lucrat la interfata (butoane de filtrare a informatiei, alarme, etc) cat si
alte taskuri ramase in aer:
 Salvarea datelor intr-o baza de date (ce ne facem daca doctorul vrea sa vada valorile de
acum o saptamana si noi am pierdut lista de valori?)
 Comunicare TCP/IP intre PumpSensorValues si datagrid (sa nu uitam ca in principiu,
pacientul sta acasa si PumpSensorValues ruleaza la pacient acasa, pe cand
DataPresentation ruleaza la doctor in cabinet, deci pe calculatoare diferite).
 Si altele...

Version no.: 1 Page 34 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

5 Salvarea informatiilor in baza de date


Pana in acest moment, datele ce vin de la pacient sunt puse intr-o lista dinamica si afisate in datagrid. Daca
se inchide aplicatia, atunci toate informatiile primite se vor pierde, doctorul nu are nici o posibilitate sa
analizeze o informatie din trecut. Nu este suficient sa afisam datele, trebuie ca aceste date sa fie salvate pe
un suport permanent si sa poata fi restaurate la un moment dat, daca doctorul doreste sa faca o examinare
a pacientului si are nevoie de istoricul datelor de masurare.

In acest capitol vom rezolva problema salvarii datelor intr-o baza de date si problema inversa, de citire a
informatiilor din baza pentru perioade de timp stabilite si un pacient dat.

5.1 Instalare baze de date


Aplicatia se poate conecta la diverse baze de date, in functie de marimea datelor, viteza de lucru, etc. In
acest capitol se prezinta modul de conectare si operare cu doua baze de date: SQLite si Oracle.

Cand nu sunt foarte multe date si foarte complexe de salvat, nu are sens sa ocupam memoria cu motorul
unei bazei de date mari gen Oracle. Mai ales ca, e posibil ca aceasta aplicatie sa ruleze pe un telefon mobil
ce are constrangeri evidente de memorie disponibila. In acest context vom utiliza SQLite, o baza de date
mult mai mica si care nu necesita instalari complexe. Acest SQLite este un simplu DLL care se salveaza
odata cu aplicatia si poate fi apelat in orice moment pentru accesarea bazei de date ce este formata dintr-
un singur fisier.

5.1.1 Crearea bazei de date SQLite

Mai intai se instaleaza SQLite database prin rularea aplicatiei “SQLite-1.0.62.0-setup.exe”. Se deschide
apoi “sqliteadmin.exe”, aplicatia cu care administram baza de date SQLite si se creeaza o noua baza de
date (butonul ).

Version no.: 1 Page 35 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 34: Crearea bazei de date “PatientData” in SQLite Administrator

Se deschide apoi baza de date si se creeaza un tabel pentru salvarea datelor ce vin de la pacient:

Figura 35: Crearea tabelului “PatientData” pentru salvarea datelor ce vin de la pacienti

In afara de cele patru campuri de valori ce vin de la pacient se mai adauga un camp numit id de tip varchar
si care va fi coloana de tip “primary key” pentru acest tabel. Tabelul se mai poate crea si prin instructiunea
SQL specifica:
CREATE TABLE [PatientData] (
[id] VARCHAR(16) PRIMARY KEY NULL,
[patient_code] VARCHAR(10) NULL,

Version no.: 1 Page 36 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

[sensor_type] VARCHAR(20) NULL,


[timestamp] DATE NULL,
[value] NUMERIC NULL
)

5.1.2 Crearea bazei de date Oracle

Instalarea unei baze de date Oracle si definirea tabelelor in aceasta baza a facut obiectul unui alt curs din
curricula studentilor, deci nu vom prezenta aici aceste notiuni.
Pentru studentii ce doresc sa lucreze cu baza Oracle, e suficient sa se conecteze la conturile create in
cursurile precedente pe aceasta baza si sa creeze tabela PatientData:

CREATE TABLE patientdata


(id VARCHAR2(50) NOT NULL,
patient_code VARCHAR2(20),
sensor_type VARCHAR2(20),
timestamp DATE,
value NUMBER(*,0)
);

ALTER TABLE patientdata ADD PRIMARY KEY (id);

5.2 Data Acquisition Layer : interfata intre baza de date si aplicatia GUI
Nu este indicat sa se acceseze direct baza de date din functiile ce apartin de clasa GUI. Conexiunea la
baza de date, functiile SQL, trebuie sa fie create pe un nivel intermediar, de sine statator si care va fi apelat
de clasa superioara de tip GUI pentru orice accesare a bazei de date.

Adaugam un nou proiect la solutie, dar de data aceasta de tip “Class Library” (deci un simplu fisier DLL,
fara nici o interfata cu utilizatorul), pe care-l denumim “DataStore”:

Version no.: 1 Page 37 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 36: Adaugarea proiectului “DataStore” de tip “Class Library” la solutie

5.2.1 Adaugare referinte pentru librariile de lucru

Pentru baza de date SQLite trebuie adaugate la proiect referintele la urmatoarele librarii (sectiunea .Net din
Add references):
 System.Data
 System.Data.SQLite.

Pentru baza de date Oracle se lucreaza cu librariile:


 System.Data
 System.Data.OracleClient

In cadrul proiectului vom utiliza si clasa “SensorValue” definita in proiectul “SensorValue”, deci va trebui
adaugata si aceasta referinta (add reference, sectiunea “Projects”).

5.2.2 Definirea string-ului de conectare la baza de date in pagina de


proprietati a proiectului

String-ul de conectare la baza de date (unde se gaseste baza de date si modul de conectare la ea)
reprezinta o informatie care este accesata ori de cate ori trebuie sa lucram cu baza de date. De aceea,
acesta informatie se salveaza o singura data in pagina de proprietati a proiectului si va fi citita din pagina ori
de cate ori este nevoie de ea. Pagina de proprietati este o modalitate de gestionare simpla si rapida a
resurselor comune proiectului. O resursa (cum este acest string de conectare) se salveaza o singura data
in pagina de proprietati si apoi va fi vizibila pe tot cuprinsul proiectului.

5.2.2.1 Stringul de conectare la baza SQLite

Version no.: 1 Page 38 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Se deschide pagina de proprietati a proiectului si se defineste la sectiunea “Settings” stringul de conectare


la baza de date SQLite:

Figura 37: Definirea string-ului de conectare la baza de date SQLite in pagina de proprietati a
proiectului

Se pune numele proprietatii “ConnStringSQLite”, se alege la “Type” tipul resursei “Connection String”, iar la
“value” se da click pe butonul pentru a defini conexiunea cu ajutorul Wizard-ului. Se deschide Wizard-ul
si se selecteaza la “DataSource” driver-ul “.NET Framework Data Provider for SQLite”, iar la “DataBase” se
merge cu butonul “Browse” si se selecteaza fisierul creat pentru baza de date. La sfarsit se poate face si un
test de verificare daca conexiunea este setata corect (butonul “test Connection”).

5.2.2.2 Stringul de conectare SQLite depinde de folderul fizic al bazei de date


Dupa cum se observa in figura de mai sus, stringul de conectare la baza de date include si denumirea
folderului fizic ce contine baza de date:
“data source= D:\Lucian\scoala\Laborator\HealtMonitor\BazaDate\PatientData.s3db”.
Acest aspect devine incomod atunci cand solutia se muta pe un alt folder sau pe alt calculator. Ar trebui ca
noua sursa sa contina exact aceeasi cale catre baza de date, altfel la rularea aplicatiei, baza de date va
emite eroare in momentul conectarii.

Version no.: 1 Page 39 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Rezolvarea problemei se face prin mutarea bazei de date in folderul curent al proiectului DataStore. In
acest fel, stringul de conectare nu mai include si calea catre fisier, ci doar numele fisierului, iar acesta va fi
gasit deoarece se afla chiar in folderul curent:
“data source=PatientData.s3db”.
Bine, problema e rezolvata doar partial, pentru ca:
1. nu este indicat ca fisierul bazei de date sa se gaseasca in acelasi folder cu alte DLL-uri. Este
bine ca acest fisier sa aiba folderul lui propriu unde poate fi gestionat mai usor, eventual folderul sa contina
si alte fisiere specifice bazei de date ( de exemplu, programul de accesare a bazei de date, SQLite
administrator).
2. in caz ca se face un program de setup, iarasi vor fi probleme cu accesarea bazei de date daca
aceasta nu este inclusa in programul de instalare.

Solutia la aceste probleme este data prin adaugarea fisierului cu baza de date in folderul curent al
proiectului “DataStore” nu prin copiere fizica, ci prin definirea unui link la fisier. In acest caz, fisierul isi poate
schimba oricand locatia fizica, tot ce trebuie sa modificat este doar linkul la acea locatie.

Figura 38: Adaugarea unui fisier existent la proiectul “DataStore”

Se face click dreapta pe proiectul DataStore si se selecteaza Add/Existing Item ...

Version no.: 1 Page 40 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 39: Adaugarea sub forma de link a fisierului bazei de date la proiectul curent
Se merge pe butonul “browse..” pana la folderul ce contine baza de date si se selecteaza fisierul bazei de
date: “PatientData.s3db”. Acest fisier nu este vizibil in mod implicit in fereastra, pentru ca Visual Studio
cauta doar fisierele specifice programarii C# ( *.cs, *.resx, * .settings...), de aceea trebuie selectata optiunea
“All files” din dreapta campului rezervat numelui de fisier.
Dupa selectia fiserului nu se da click pe butonul “Add” implicit, ci se selecteaza sageata de pe acest buton
ce desfasoara toate posibilitatile de adaugare a fisierului si se alege optiunea “Add As Link”. In acest fel,
Visual Studio va face o copie in folderul curent al proiectului DataStore in momentul compilarii daca se
seteaza proprietatea “Copy To Output Directory” la acest link cu valoarea “Copy allways”:

Figura 40: Fisierul bazei de date va fi copiat in directorul curent

5.2.2.3 Stringul de conectare la baza Oracle


Se deschide pagina de proprietati a proiectului si se defineste la sectiunea “Settings” stringul de conectare
la baza de date Oracle:

Version no.: 1 Page 41 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Name: connOracle
Type: (ConnectionString)
Scope: Application
Pentru campul “Value” se face click pe butonul din stanga campului si se alege ca “data source” campul
“Oracle database”:

Se apasa OK si apoi se definesc parametrii de conectare:

Version no.: 1 Page 42 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 41: Definirea string-ului de conectare la baza de date Oracle in pagina de proprietati a
proiectului

Server name: stud_local


User name: contul studentului
Password: parola studentului curent
Se face click pe Test Connection si se verifica ca parametrii de conectare sunt introdusi corect si ca baza
de date Oracle definita prin “stud_local” in fisierul tnsnames.ora este pornita.

Daca nu apare mesajul “test connection succeded” trebuie verificate urmatoarele:


 Exista in fisierul tnsnames.ora un string de conectare numit “stud_local” care face referire la o baza
existenta si functionala
 Baza de date la care se face referitre in “stud_local” este pornita.
 Contul si parola studentului sunt corecte

Eventual se verifica conectarea la baza de date prin programul SQLNavigator sau SQL Plus folosind
aceleasi date de conectare.

5.3 Clasa de interfata cu baza de date


5.3.1 Salvarea informatiilor in baza de date

Odata ce am definit conexiunea cu baza de date, putem construi functia de adaugare a unei valori de
masurare (o instanta de SensorValue) in baza de date. Adaugam o noua clasa la proiectul “DataStore”
numita “DAL_PatientData”.
In aceasta clasa se defineste o functie statica “AddData” ce primeste ca parametru un obiect de tip
SensorValue si salveaza in tabela PatientData valorile acestui obiect.

Etapele ce trebuie parcurse pentru salvarea valorilor de masurare in baza de date sunt urmatoarele:

 Se defineste un obiect de tipul “SQLiteConnection” (sau “OracleConnection”) cu care putem sa ne


conectam la baza de date. String-ul de conectare se citeste din fisierul de proprietati ale proiectului
(Properties.Settings.Default.ConnString…).
 Se defineste obiectul SQLiteCommand cu care vom executa instructiunea SQL de inserare in baza
de date
 Setam instructiunea SQL ce trebuie executata de SQLiteCommand
 Setam parametrii ce trebuie trimisi la SQLiteCommand cu valorile de masurare primite prin obiectul
sensorData.
 Deschidem conexiunea la baza de date si executam comanda SQL
 Inchidem conexiunea la baza de date

Trebuie observat ca accesul la baza de date s-a facut prin constructia try-catch-finally pentru a ne asigura
ca tratam eroarea aparuta in cazul cand baza de date nu raspunde.

In continuare se dau versiunile acestei functii pentru bazele SQLite si Oracle:

 Salvarea datelor in baza SQLite

Version no.: 1 Page 43 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 42: Functia de inserare a unei valori de masurare in baza de date

 Salvarea datelor in baza Oracle

Version no.: 1 Page 44 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Se observa ca diferentele intre cele doua functii de salvare a datelor (SQLite si Oracle) sunt identice ca
structura, singurele diferente fiind date de obiectele de conectare la baza si executie a frazelor SQL: pentru
SQLite folosim clasele SQLiteConnection si SQLiteCommand , in timp ce pentru baza Oracle folosim
OracleConnection si OracleCommand.

Tot ce mai ramane de facut este de a apela functia de salvare in baza de date in momentul cand proiectul
“DataPresentation” primeste o noua valoare de masurare prin evenimentul “newSensorValueEvent”:

Figura 43: Tratarea evenimentului “newSensorValueEvent”: salvare in baza si afisare in datagrid

Nu trebuie sa uitam sa adaugam referinta la proiectul “DataStore” in cadrul proiectului “DataPresentation”.

In sfarsit, putem verifica daca totul lucreaza OK, pornim aplicatia cu F5, startam pacientul 0101 si dupa
catva timp ne uitam in baza de date cu ajutorul programului SQLite Adminstrator pentru SQLite, sau
SQLNavigator pentru Oracle.

 SQLite:
Deschidem o fereastra de comenzi SQL si introducem comanda SQL de vizualizare a tabelei “PatientData”:

Figura 44: Comanda SQL de vizualizare a datelor din tabela PatientData

Executam comanda SQL cu tasta F9 si ar trebui sa observam datele salvate in tabela de aplicatia “Health
Monitor”:

Version no.: 1 Page 45 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 45: Vizualizarea datelor din baza in SQLite Administrator

 Oracle:

Version no.: 1 Page 46 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

5.3.2 Citirea informatiilor din baza de date

Stocarea informatiilor in baza de date permite doctorului in orice moment sa analizeze datele din trecut
pentru un pacient dat. In primul rand trebuie creata o sectiune de filtrare a datelor unde doctorul sa-si
selecteze pacientul pe care vrea sa-l analizeze si intervalul de timp pentru care vrea sa vada datele.

Se adauga un fereastra “DataPresentation” un control de tip GroupBox ce contine doua controle de filtrare:
 comboBox pentru selectia pacientului
 monthCalendar ce selecteaza ziua pentru care se doreste a fi vizualizate datele
 buton pentru efectuarea filtrarii: “Display Selected data”.

Figura 46: Fereastra DataPresentation dupa ce s-a adaugat sectiunea de filtrare

Dupa selectia pacientului si a zilei de vizualizare, utilizatorul face click pe butonul “Display Data” si in acel
moment trebuie citita din baza de date lista tuturor masuratorile salvate in acea zi pentru respectivul
pacient.

In acest scop, clasa “DAL_PatientData” trebuie sa fie completata cu o functie de citire a informatiilor din
baza de date:

 SQLite:

Version no.: 1 Page 47 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 47: Functia de citire din baza de date a datelor de masurare pentru un pacient si o zi stabilita

 Oracle:

Version no.: 1 Page 48 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Functia de citire din baza de date are urmatoarea structura:


 se creeaza o noua lista “sensorValueList” unde vor fi salvate informatiilor gasite in baza
 se defineste un nou obiect de tip SQLiteConnection (OracleConnection) si un obiect
SQLiteCommand (OracleCommand)
 se scrie instructiunea SQL de selectie din baza de date si se ataseaza obiectului SQLiteCommand
(OracleCommand)
 se adauga parametrii de filtrare: patient_code, minTime si maxTime
 se deschide un SQLiteDataReader (OracleDataReader) in care se salveaza toate liniile aduse din
baza de date de fraza select (reader = cmd.ExecuteReader();).
 Se parcurge reader-ul linie cu linie, se face conversia datelor aduse de fraza select la tipul
SensorValue si se adauga noul item la lista de valori.
 La sfarsit se inchide conexiunea, reader-ul si se returneaza lista de valori.

Totusi avem o mica problema: proiectul “DataStore” nu cunoaste tipul de date “PatientCodeEnum” cu care
trebuie sa lucreze functia “GetData” pentru ca aceasta enumerare este definita in proiectul
“DataPresentation”. Ar trebui ca proiectul “DataPresentation” sa fie adaugat in lista de referinte a proiectului

Version no.: 1 Page 49 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

“DataStore”. Dar acest lucru nu este posibil pentru ca, deja proiectul “DataStore” este referinta la proiectul
“DataPresentation” si ar rezulta o referinta circulara. Nu este posibil ca un proiect P1 se fie referinta la alt
proiect P2 si in acelasi timp proiectul P2 sa fie referinta la P1. Deci nu se poate sa un proiect sa fie tata la
alt proiect si in acelasi timp sa fie si copil la acelasi proiect.
Din acest motiv, se creeaza un nou proiect numit “CommonReferences” care va contine doar un fisier unde
vor fi definite toate tipurile de obiecte comune celorlalte proiecte. Acest proiect va fi adaugat ca referinta la
toate proiectele ce lucreaza cu acele tipuri de date. Evident, ca acest proiect nu trebuie sa faca referire la
nici un alt proiect din solutie.

Figura 48: Proiectul “CommonReferences” contine toate definitiile particulare ale tipurilor de date

Am mutat definitiile “PatientCodeEnum” si “SensorType” in “CommonReferences” astfel incat acestea sa fie


vizibile in toata solutia fara probleme de referinta circulara.

Tot ce mai ramane pentru vizualizarea datelor din baza de date e sa implementam codul pentru butonul
“Display selected Data”:

Version no.: 1 Page 50 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 49: Afisarea valorilor din baza de date

Afisarea se face in acelasi datagrid, trebuie doar sa schimbam proprietatea “dataSource” pentru acest grid
pe lista de valori adusa de functia DAL_PatientData.GetData(). Totusi, folosind acelasi grid pentru afisarea
ambelor tipuri de valori, atat cele primite online de la patientii activi, cat si cele aduse din baza de date,
trebuie definita a variabila logica care sa specifice tipul de date ce trebuie vizualizate:

private bool displayTheReceivingData = true;

Iar aceasta variabila va fi setata corespunzator pe cele doua butoane “Display Selected Data” si “Display
Received Data”:

Figura 50: Functia handler pentru butonul “Display Received Data”

Version no.: 1 Page 51 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

6 Transmiterea datelor intre aplicatii. Socket TCP/IP


Pana acum, atat proiectul care producea date (SensorInput), cat si proiectul care consuma datele
(DataPresentation), ruleaza sub aceeasi solutie, in acelasi calculator si atunci evenimentele trimise de
furnizorul de date pot fi receptionate de consumatorul de date. Si totusi, realitatea sta un pic altfel: furnizorul
de date ruleaza la pacient acasa, iar receptorul ruleaza la medic in cabinet. Intre ele exista o legatura
internet sau intranet prin care trebuie transmise datele.

In acest capitol vom analiza modul de conectare a celor doua aplicatii printr-o legatura de tip Socket
TCP/IP. Tehnologia Socket lucreaza pe arhitectura client-server. Se deschide un server TCP/IP care
ruleaza un listener ce asculta la un port dat cererile de conectare de la diversi clienti TCP/IP din retea.
Cand soseste o cerere de conectare, se deschide un canal de comunicatii intre cele doua aplicatii prin care
pot fi transferate date in ambele sensuri.

Se modifica proiectul "DataPresentation" prin adaugarea unor radio butoane care sa selecteze modul de
transmitere a datelor:
 prin TCP/IP la un calculator dat de o adresa IP
 direct la calculatorul curent

Figura 51: Proiectul Data Presentation cu posibilitatea de a alege canalul de comunicare a datelor

Version no.: 1 Page 52 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Pentru a realiza o comunicatie TCP/IP trebuie construite urmatoarele obiecte:


 TcpClient ce primeste datele de masurare de la sensor, le impacheteaza intr-un format text si le
transmite la server
 TcpServer care deschide listenerul si accepta cererile de conexiune sosite de la client, primeste
textul de la client, il despacheteaza in format SensorValue si-l trimite mai departe la
"DataPresentation"
 Evenimentul prin care serverul sa transmita la interfata DataPresentation valorile primite de la client

Se creeaza un nou proiect in cadrul solutiei numit "TCPCommunication", proiect ce include doua clase:
TCPCommClient si TCPCommServer:

Figura 52:Solutia "HealthMonitor" cu toate proiectele componente

6.1 Obiectul TCPCommClient


In continuare se prezinta clasa "TCPCommClient" cu urmatoarele functionalitati:

 Primeste data de tip "SensorValue" pentru a fi trimisa la server


 Porneste un nou fir de execuie (thread) care sa se ocupe separat de deschiderea conexiunii si
trimiterea datelor
 Impachetarea clasei "SensorValue" intr-un text dupa un anumit format standard
 Inchiderea firelor de executie ramase suspendate daca serverul refuza sa raspunda la cererea de
dialog
Sa luam aceste functii pe rand:

Version no.: 1 Page 53 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

6.1.1 Impachetarea datelor pentru transmisie

Clasa TCPCommClient afiseaza urmatoarele functii publice:


 Constructorul clasei

Figura 53: Constructorii clasei TCPCommClient

Se observa ca constructorul implicit al clasei a fost declarat privat astfel incat sa nu poata fi posibila o
instantiere a clasei de forma "new TCPCommClient()", adica sa se creeze o instanta fara a da si adresa IP
a serverului la care trebuie sa se conecteze clientul pentru a trimite date. Singurul constructor disponibil din
exterior este cel ce primeste ca parametru adresa IP a serverului. In acest fel ne asiguram ca toti clientii
TCP creati vor avea setata adresa IP a serverului cu care trebuie sa dialogheze.

 "SendSignalData" ce primeste cele patru valori din clasa SensorValue in scopul trimiterii lor catre
server.

Version no.: 1 Page 54 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 54: Functiile de primire si impachetare a datelor ce trebuie trimise la server

Functia ce primeste datele pentru transmisie apeleaza mai intai functia de impachetare a datelor in format
text, dupa care face apel catre functia de trimitere a textului. Este mai avantajoasa trimiterea sub forma de
text a datelor pentru ca pot fi procesate cu ajutorul functiilor de tip string si in plus, sender-ul si receiver-ul
pot avea structuri de date diferite, totul e sa se stabileasca formatul de impachetare care sa fie respectat de
ambele parti.
S-a decis asupra urmatorului format:
- Simbolul "#" semnifica inceputul si sfarsitul mesajului
- Simbolul "," separa campurile de date specifice clasei "SensorValue"
- Ordinea de impachetare este urmatoarea: SensorType, TimeStamp,
PatientCode, Value.
Concatenarea acestor string-uri in mesajul de trimis se face cu jutorul functiei "Append" din cadrul clasei
"StringBuilder".

6.1.2 Crearea unui nou fir de executie pentru fiecare dialog cu serverul

Functia ce trimite efectiv mesajul text catre server este listata in continuare:

Figura 55: Startarea unui nou thread pentru trimiterea datelor

Crearea unui nou fir de executie pentru trimiterea textului la server se face prin apelul constructorului clasei
"Thread" din namespace-ul "using System.Threading;":

 Se creeaza instanta clasei "Thread":


Thread newThread = new Thread(new
ParameterizedThreadStart(SendSignalTextNewThread));

 Se adauga thread-ul format in lista de thread-uri a clasei


myThreadList.Add(newThread);

Version no.: 1 Page 55 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

 se porneste noul fir de executie avand ca parametru textul ce trebuie trimis la server:
newThread.Start(signalText);

Dar mai intai se inchid toate thread-urile ramase in suspensie de la vechile incercari de dialog cu serverul.
Daca serverul nu raspunde in timp util, aceste fire de executie raman suspendate si ocupa memoria in mod
abuziv. Daca sunt mii de date de trimis si in tot acest timp serverul nu raspunde, sunt mii de thread-uri
ramase in suspensie. De aceea trebuie facuta curatenie din cand in cand:

Figura 56: Inchiderea firelor de executie inactive

Se creeaza o noua lista de thread-uri in care sa vor salva toate firele de executie care sunt inca active.
Daca thread-ul nu este activ se inchide prin apelul functiei Abort(). La sfarsit lista de thread-uri a clasei va fi
initializata cu noua lista, fiind alcatuita numai din firele de executie active.

6.1.3 Trimiterea datelor catre server

Trimiterea efectiva a textului catre server se face in functia ce ruleaza in firul de executie nou creat. Aceasta
functie urmeaza urmatorii pasi:

se obtine o instanta a clasei de biblioteca TcpClient cu parametrii: _serverIP si _port;


se obtine un obiect de tip "NetworkStream" pe care-l returneaza acest TcpClient. Acest stream
poate trimite octetii unul dupa altul pe canalul deschis intre client si server
 despachetam mesajul de tip text intr-un sir de octeti ce pot fi trimisi pe canalul de comunicatie:
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] buffer = encoding.GetBytes(signalText);
 Apelam functia stream.Write pentru a trimite datele. Aceasta functie "Write" lucreaza ca si cum am
scrie intr-un fisier, problemele hardware de low level de transmitere efective a datelor fiind
transparente pentru noi ca utilizatori.

Version no.: 1 Page 56 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 57: Dialogul cu serverul

6.1.4 Functia Dispose inchide firele de executie suspendate

Daca utilizatorul inchide brusc aplicatia (cand inca sunt active fire de executie ce trimit date catre server)
atunci trebuie apelata o functie pe evenimentul "DataPresentation_FormClosing" (deci cand fereastra
este pe punctul de a se inchide) care sa inchida toate resursele aferente acestei aplicatii.

Figura 58: Tratarea evenimentului "FormClosing" in clasa "DataPresentation"

Functia apelata la inchiderea aplicatiei pentru inchiderea tuturor firelor de executie aferente clientului este
"Dispose()". Pentru a nu uita ca trebuie sa scrim aceasta functie, am mostenit clasa "TCPCommClient" din
interfata "Idisposable" si astfel, in mod automat VS-ul te obliga sa implementezi functia Dispose():

Version no.: 1 Page 57 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 59: Componentele interne ale clasei "TCPCommClient"

Figura 60: Inchiderea firelor de executie la terminarea programului

6.2 Obiectul TCPCommServer


Acest obiect trebuie sa deschida un listener care sa receptioneze cererile de conectare de la clienti, sa
deschida canalele de comunicatie, sa receptioneze mesajele, sa despacheteze aceste mesaje si sa trimita
valorile primite mai departe la "DataPresentation".

In continuare sunt descrise componentele clasei, proprietatile si functiile de lucru:


 Componente
o private Int16 _port = 1020; //portul la care asculta serverul cererile de conectare
o private string _thisServerIP = "0.0.0.0"; // IP-ul serverului, implicit este al masinii curente
o protected TcpListener server; //obiectul listener server, cel care implementeaza efectiv
serverul
o Protected List<Thread> ServerThreadList = new List<Thread>(); //se creeaza o lista the
fire de executie, fiecare noua cerere de conectare va fi tratata intr-un fir de executie
separat. Inclusiv serverul va primi fir de executie propriu
o private bool _isRunning = false; // flag ce memoreaza starea serverului (pornit/oprit)
o public delegate void NewSignalReceived(SensorValue sesorValue);

Version no.: 1 Page 58 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

o public event NewSignalReceived newSignalReceivedEvent; // delegatul si evenimentul


atasat prin care serverul va trimite mai departe valoarea primita de la un client. Acest
eveniment trebuie interceptat de DataPresentation pentru a afisa valoarea receptionata.

Figura 61: Clasa TCPCommServer: componentele interne, constructorul si proprietatile

6.3 Startarea serverului intr-un fir de executie propriu


 Metode:
o StartTCPServer: porneste un nou thread ce apeleaza functia:
 StartInNewThread():
 Creeaza listenerul pentru adresa si portul curent
 Starteaza serverul
 Porneste o bucla infinita unde astepata cereri de conectare
 Daca vine cererea de conectare atunci:
o Curata lista de fire de executie
o Creeaza un TcpClient care sa preia dialogul cu clientul respectiv
o Porneste un nou thread pentru acel client si-l adauga in lista de fire
de executie

Version no.: 1 Page 59 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 62: Functiile de startare a serverului TCP/IP

6.4 Gestionarea thread-urilor inchise de garbage Collection


o RemouveClosedThreadsFromList(): periodic firele de executie pentru un dialog cu un client
sunt inchise de garbage collection dupa ce termina acel dialog. Daca sunt inchise, atunci si
lista cu firele de executie trebuie refresh-ata.
o CloseTCPServer():
 Opreste serverul TCP
 Opreste toate firele de executie din lista interna

Version no.: 1 Page 60 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 63: Functiile de oprire a firelor de executie si a serverului TCP

6.5 Receptionarea datelor venite de la client prin TCP/IP


o ClientThread(object clientData): aceasta functie receptioneaza datele de la client si le
trimite mai departe la “DataPresentation”
 Deschide o bucla de citire din sirul de date primite de la client. Iesirea din bucla se
realizeaza daca clientul intrerupe conexiunea sau daca s-a tranmis tot sirul de date
 Datele sunt primite sub forma de octeti (Bytes) si de aceea sunt translatate in
coduri Ascii
 Datele sunt dezpachetate si trimise mai departe

Version no.: 1 Page 61 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 64: Functia de receptionare a datelor de la client

6.6 Despachetarea datelor si trimiterea lor in sistem pentru afisare


o UnpackSignalAndRaiseTheEvent(string packedSignalValues): functia despacheteaza
datele si reconstruieste obiectul “SensorValue”. Face operatia inversa realizata de functia
“BuildPacketStringSignalValue” din clasa TCPCommClient.

Version no.: 1 Page 62 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 65: Functia de despachetare a datelor

o SendNewDataReceivedEvent(SensorValue e): trimite evenimentul cu noile date primite

Figura 66: Functia de transmitere a evenimentului cu datele primite de TCPServer

o tcpCommServer_newSignalReceivedEvent(SensorValue sesorValue): evenimentele de tip


newSignalReceivedEvent trimise de TCPCommServer trebuie interceptate de proiectul
“DataPresentation”.

Version no.: 1 Page 63 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

 Functia nu face decat sa apeleze “OnNewSensorValueHandler(sesorValue)”,


aceeasi functie ce trateaza evenimentul venit de la SensorValue. Nu are
importanta de unde au venit datele (de la sensorul intern sau prin TCP/IP), functia
trebuie sa salveze datele si sa le afiseze in grid.

Figura 67: Tratarea evenimentului provenit de la TCPCommServer in DataPresentation

Version no.: 1 Page 64 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

7 Realizarea proiectului de setup

7.1 O aplicatie include mai multe fisiere de tip DLL sau EXE
Orice aplicatie trebuie sa aiba si un program de setup sau de instalare pe un alt calculator. Daca aplicatia
este simpla (un singur fisier .exe) atunci pur si simplu se poate face copy/paste pe un alt calculator si
aceasta trebuie sa ruleze. Problema se complica in cazul cand aplicatia include si alte librarii (DLL-uri) fara
de care nu poate rula. In acest caz, trebuie copiate toate DLL-urile de care depinde aplicatia noastra.

De exemplu, pentru aplicatia “HealthMonitor”, proiectul de start este “DataPresentation”. Este proiectul tata
ce culege informatii din celelalte proiecte fiu (adaugate la referinta) si le afiseaza utilizatorului. In momentul
lansarii in executie a proiectului, acesta apeleaza functii si din celelalte proiecte ce fac parte din solutie
(DataStore, SensorInput, TCPCommunication). Toate aceste proiecte trebuie sa existe sub forma de DLL
sau EXE in folderul curent al proiectului “DataPresentation” ca sa poata fi apelate. Iar acest lucru se face
automat la compilare: compilatorul vede toate referintele din proiectul nostru si pentru fiecare proiect gasit
la referinta, construieste fisierul DLL corespunzator prin compilare si-l copie in directorul curent al
proiectului “DataPresentation”:

Figura 68: Compilatorul aduce toate proiectele din referinte in directorul proiectului tata

De aceea, se intampla ca la compilarea proiectului tata sa apara erori continute in alte proiecte, dar care
sunt referentiate in proiectul tata. Proiectul tata poate fi compilat doar dupa ce toate proiectele fiu sunt
compilate.

7.2 Proiectul de setup


Cand aplicatia construita este relativ complexa, cu mai multe proiecte incluse, plus alte fisiere de resurse,
este mai bine sa se realizeze un proiect de setup care sa gestioneze in mod clar ce fisiere sunt folosite,
unde sunt stocate, care este legatura intre ele.

Visual Studio pune la dispozitia utilizatorilor o facilitate foarte simpla si usor de utilizat pentru realizarea
proiectelor de instalare a aplicatiilor software.
Click dreapta pe solutie si se alege “Add new project”:

Version no.: 1 Page 65 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 69: Adaugarea proiectului de setup la solutie

In fereastra “Other Project Types” se alege template-ul “Setup Project” si se completeaza denumirea
proiectului: “HeathMonitorSetup”.

Dupa ce s-a adaugat proiectul, se selecteaza in cadrul solutiei (click dreapta) si se selecteaza fereastra
“File system” in cadrul meniului “View”.

Figura 70: Fereastra de afisare a fisierelor atasate proiectului de setup

7.2.1 Selectarea fisierelor adaugate in arhiva de setup

Version no.: 1 Page 66 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

In fereastra “File system” se selecteaza “Application Folder” si cu click dreapta se deschide un pop up
menu si se alege optiunea “Add/Project Output...”:

Figura 71: Adaugarea unui proiect din solutie la aplicatia de setup

Se adauga proiectul “DataPresentation” la optiunea “Primary Output” si in acest moment sunt aduse toate
fisierele care sunt referentiate in cadrul proiectului “DataPresentation”:

Figura 72: Proiectul DataPresentation este adaugat la folderul de aplicatii

Fisierul cu baza de date nu este inclus in folderul de aplicatii deoarece nu exista referinta clara la el in
cadrul proiectului “DataPresentation”. Acest fisier se adauga urmarind aceeasi pasi ca la adaugarea
proiectuilui, dar de date aceasta se alege optiunea Add/File.

In urma acestor actiuni, folderul de aplicatii va contine toate fisierele necesare in cursul rularii aplicatiei.
Aceste fisiere se vor copia in arhiva de setup si vor fi dezarhivate automat la instalare in folderul ales de
utilizator.

Mai sunt si alte librarii utilizate de proiect si totusi ele nu apar in folderul de aplicatii. Aceasta deoarece
acele librarii fac parte din biblioteca Framework .Net si ele se regasesc automat pe orice calculator ce are
instalat framework-ul .Net. Sistemele Windows moderne vin cu framework-ul deja instalat, altfel poate fi
download-at gratuit de pe site-ul Microsoft sau se poate atasa la pachetul de instalare al programului.

7.2.2 Stabilirea meniului pentru rularea aplicatiei

Dupa ce s-au stabilit fisierele ce se copie la utilizator, trebuie setat meniul de unde utilizatorul poate starta
aplicatia. Dupa instalare, este de dorit ca programul nostru sa apara in meniul Start/Programs. Pentru
aceasta trebuie stabilit numele aplicatiei (sau mai bine zis, numele shortcut-ului ce starteaza aplicatia) si
folderul de aplicatii de care apartine.

Version no.: 1 Page 67 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Se deschide folderul “User’s Programs Menu” din fereastra “File System on Target Machine” si se creeaza
un folder “IEEIA” (acronimul facultatii). Acest folder va aparea in meniul Start/Programs dupa instalare. In
continuare se adauga in folderul creat toate shorcut-urile la aplicatiile pe care dorim sa le lansam din meniu.
In cazul nostru, shorcut-ul de la proiectul “DataPresentation”.
Click dreapta in fereastra folderului si se alege “Create New Shortcut”:

Figura 73: Adaugarea shortcut-ului de lansare a aplicatiei in meniul Start/Programs

Se alege “primary output” de la proiectul “DataPresentation” gasit in folderul “Application Folder” (unde l-am
adaugat in pasul anterior) si se redenumeste shortcut-ul in “HealthMonitor”.

7.2.3 Proprietatile proiectului de setup

Dupa setarea fisierelor si a shortcut-ului de lansare a aplicatiei se recompileaza proiectul


“HealthMonitorSetup”. Ca rezultat, se vor crea fisierele de instalare pentru aplicatia noastra. Acestea vor fi
gasite in folderul “Debug” ce apartine de proiectul “HealthMonitorSetup”:

Figura 74: Fisierele de instalare a aplicatiei

Sunt doua fisiere de instalare:


 HealthMonitorSetup.msi : arhiva cu toate fisierele ce trebuie copiate la client
 Setup.exe: programul de instalare

Sunt doua foldere pentru orice proiect din solutie unde sunt salvate fisierele exe sau dll rezultate prin
compilare: Debug si Release. Daca configuratia activa setata in proprietatile proiectului este “Debug”, atunci
fisierele vor fi salvate in folderul “Debug”, iar pentru varianta “Release” se completeaza folderul
corespunzator.

Version no.: 1 Page 68 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

In principiu, fisierele din cele doua foldere contin aceeasi informatie, cu deosebirea ca in varianta Debug se
insereaza si informatii specifice modului de lucru pentru depanare (puncte de intrerupere, valori ale
variabilelor, etc.).
Release inseamna ca programul a fost testat si urmeaza sa fie trimis la client. De aceea se sterg toate
informatiile de depanare pentru ca programul sa mearga mai rapid.

La proiectul de setup, in fereastra de proprietati se mai pot seta si alte functionalitati utile:

Figura 75: Fereastra de proprietati a proiectului de setup

Exista posibilitatea sa se modifice numele fisierului de setup si de asemenea, prin butonul de


“Prerequisites...” se adauga la proiectul de setup si alte librarii necesare rularii programului:

Version no.: 1 Page 69 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 76: Adaugarea librariei “.NET Framework 3.5 SP1” la programul de instalare

De exemplu, nu toate calculatoarele au in mod implicit instalat framework-ul de .NET, sau daca este, nu in
versiunea utilizata de noi. Fara acest framework programul nu poate rula, de aceea este necesar sa fie
instalat inainte de a seta aplicatia. Programul de instalare verifica in prealabil existenta acestui framework,
iar daca nu-l gaseste, atunci lanseaza procedura de instalare a framework-ului .NET. Acest dll poate fi
download-at direct de pe site-ul Microsoft, sau poate fi inclus in pachetul de instalare. S-a ales varianta cu
pachetul de instalare ce functioneaza si-n conditiile cand clientul nu are acces la internet in momentul
instalarii. Bine, aceasta varianta creste marimea pachetului de instalare prin adaugarea folderului
“DotNetFX”.
Daca se seteaza aceasta optiune de la Prerequisites, atunci in pachetul de instalare se va gasi si folderul
cu fisierele de framework:

Figura 77: Fisierele DotNetFX sunt adaugate pachetului de instalare

Observatie: pentru versiunea “.NET Framework 3.5 SP1” nu functioneaza decat varianta “Download
prerequisetes from the component vendor’s web site”. Microsoft a considerat ca fisierul este prea mare sa
fie inclus in pachetul de instalare, de aceea permite doar download-area de pe site-ul Microsoft.

7.3 Instalarea aplicatiei “HealthMonitor”

Pachetul de instalare este copiat la client si lansat in executie. Pasii de instalare sunt dati mai jos:

Version no.: 1 Page 70 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 78: Pasul 1: Fereastra de Wellcome a pachetului de instalare

Figura 79: Pasul 2: Alegerea locatiei de instalare

Version no.: 1 Page 71 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 80: Pasul 3: Confirmarea instalarii

Figura 81: Pasul 4: Fereastra de inchidere a instalarii

Toti pasii descrisi mai sus pot fi personalizati prin modificarea ferestrelor din proiectul de setup. Mai pot fi
incluse actiuni suplimentare necesare in timpul instalarii ( de exemplu, instalarea unei baze de date,
stergerea anumitor fisiere, etc.). Aceste actiuni sunt adaugate in fereastra “CustomActionsEditor” din
proiectul de setup:

Version no.: 1 Page 72 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Figura 82: Fereastra de actiuni suplimentare atasate procesului de instalare

7.4 Lansarea aplicatiei HealthMonitor in executie


Dupa instalarea aplicatiei, aceasta se regaseste printre programele ce pot fi lansate din meniul Windows:

Figura 83: Cum se starteaza programul HealthMonitor

Se observa folderul creat de noi “IEEIA” de unde se acceseaza shortcut-ul “HealthMonitor”.

Version no.: 1 Page 73 of 74


Programarea sistemelor de masura II - LABORATOR
Project no. PVS 2008 Product name: Programarea sistemelor de masura II Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

8 Concluzii
In acest proiect s-au prezentat pricipalele etape ce trebuie parcurse pentru realizarea unei aplicatii cu mai
multe proiecte, inclusiv realizarea aplicatiei de setup. Reprezinta un model minim ce trebuie respectat in
dezvoltarea oricarei aplicatii software utilizand tehnologia Visual Studio.

In acelasi timp, proiectul trateaza si unele aspecte comune in majoritatea aplicatiilor moderne de tip “user
Interface”:
 Definirea si instantierea claselor
 Lucrul cu baza de date
 Prezentarea grafica a informatiilor
 Transmiterea informatiilor intre aplicatii
 Instalarea aplicatiilor windows

Version no.: 1 Page 74 of 74

S-ar putea să vă placă și