Differences

This shows you the differences between two versions of the page.

Link to this comparison view

priot:laboratoare:04 [2024/10/15 11:12]
vlad.radulescu2901
priot:laboratoare:04 [2024/11/05 15:26] (current)
alexandru.bala [Bibliografie]
Line 4: Line 4:
  
 Acest laborator ii va invata pe studenti sa: Acest laborator ii va invata pe studenti sa:
-1. Inteleaga ce este Raspberry Pi Pico si cum functioneaza. +    * Inteleaga ce este Raspberry Pi Pico si cum functioneaza. 
-2. Invete despre senzorii BMP280 (temperatura si presiune) si LDR (lumina). +    ​* ​Invete despre senzorii BMP280 (temperatura si presiune) si LDR (lumina). 
-3. Inteleaga ce este MicroPython,​ cum functioneaza si de ce este folosit. +    ​* ​Inteleaga ce este MicroPython,​ cum functioneaza si de ce este folosit. 
-4. Configureze Raspberry Pi Pico in VS Code folosind extensia MicroPico. +    ​* ​Configureze Raspberry Pi Pico in VS Code folosind extensia MicroPico. 
-5. Gaseasca adresa I2C a senzorului BMP280. +    ​* ​Gaseasca adresa I2C a senzorului BMP280. 
-6. Conecteze si sa programeze senzorii pentru a citi date de la acestia. +    ​* ​Conecteze si sa programeze senzorii pentru a citi date de la acestia. 
-7. Invete cum sa adune informatiile necesare pentru a scrie codul care citeste date de la senzori.+    ​* ​Invete cum sa adune informatiile necesare pentru a scrie codul care citeste date de la senzori.
  
  
Line 16: Line 16:
  
 1. Ce este Raspberry Pi Pico? 1. Ce este Raspberry Pi Pico?
 +
 Raspberry Pi Pico este un microcontroler bazat pe cipul RP2040 dezvoltat de Raspberry Pi. Este ideal pentru proiecte de IoT, automatizari si roboti, fiind conceput pentru a interactiona cu senzori si alte componente electronice. Raspberry Pi Pico este un microcontroler bazat pe cipul RP2040 dezvoltat de Raspberry Pi. Este ideal pentru proiecte de IoT, automatizari si roboti, fiind conceput pentru a interactiona cu senzori si alte componente electronice.
  
 Caracteristici principale: Caracteristici principale:
-Procesor dual-core ARM Cortex-M0+ la 133 MHz. +    * Procesor dual-core ARM Cortex-M0+ la 133 MHz. 
-264 KB RAM. +    ​* ​264 KB RAM. 
-26 pini GPIO care permit conectarea diverselor senzori si dispozitive externe. +    ​* ​26 pini GPIO care permit conectarea diverselor senzori si dispozitive externe. 
-Suport pentru comunicatii I2C, SPI, UART, PWM si ADC.+    ​* ​Suport pentru comunicatii I2C, SPI, UART, PWM si ADC.
  
  
 2. Ce este MicroPython?​ 2. Ce este MicroPython?​
 +
 MicroPython este o implementare usoara a Python, conceputa special pentru microcontrolere. Este eficienta si usor de utilizat, permitand dezvoltatorilor sa controleze senzori si alte componente hardware utilizand un limbaj de nivel inalt. MicroPython este o implementare usoara a Python, conceputa special pentru microcontrolere. Este eficienta si usor de utilizat, permitand dezvoltatorilor sa controleze senzori si alte componente hardware utilizand un limbaj de nivel inalt.
  
Line 31: Line 33:
 ====Partea II: Configurarea mediului de dezvoltare in VS Code==== ====Partea II: Configurarea mediului de dezvoltare in VS Code====
  
-1. Instalarea si configurarea VS Code cu extensia MicroPico +==Instalarea si configurarea VS Code cu extensia MicroPico== 
- +Pas 1: Descarca si instaleaza VS Code 
-Pas 1: Descarca si instaleaza VS Code +  *Acceseaza https://​code.visualstudio.com/​ si descarca Visual Studio Code pentru sistemul tau de operare.
-Acceseaza https://​code.visualstudio.com/​ si descarca Visual Studio Code pentru sistemul tau de operare.+
  
 Pas 2: Instaleaza extensia MicroPico Pas 2: Instaleaza extensia MicroPico
-1. Deschide VS Code. + 
-2. Acceseaza Extensions (Ctrl+Shift+X) si cauta MicroPico. +    * Deschide VS Code. 
-3. Instaleaza extensia si urmeaza instructiunile pentru configurarea mediului de dezvoltare pentru Raspberry Pi Pico.+ 
 +    * Acceseaza Extensions (Ctrl+Shift+X) si cauta MicroPico. 
 + 
 +    * Instaleaza extensia si urmeaza instructiunile pentru configurarea mediului de dezvoltare pentru Raspberry Pi Pico.
  
 Pas 3: Instalarea MicroPython pe Raspberry Pi Pico Pas 3: Instalarea MicroPython pe Raspberry Pi Pico
-1. Conecteaza Pico la computer tinand apasat butonul BOOTSEL. + 
-2. Descarca fisierul MicroPython UF2 pentru Raspberry Pi Pico de pe https://​micropython.org/​download/​rp2-pico/​. +    * Conecteaza Pico la computer tinand apasat butonul BOOTSEL. 
-3. Copiaza fisierul .uf2 in unitatea USB care apare in sistemul tau dupa conectarea Pico. + 
-4. Pico va reporni automat cu MicroPython instalat.+    * Descarca fisierul MicroPython UF2 pentru Raspberry Pi Pico de pe https://​micropython.org/​download/​rp2-pico/​. 
 + 
 +    * Copiaza fisierul .uf2 in unitatea USB care apare in sistemul tau dupa conectarea Pico. 
 + 
 +    * Pico va reporni automat cu MicroPython instalat.
  
 Pas 4: Testarea conexiunii in VS Code Pas 4: Testarea conexiunii in VS Code
-1. In VS Code, deschide un terminal nou (Ctrl + `) si apasa Ctrl + Shift + P pentru a deschide Command Palette. 
-2. Selecteaza MicroPico: List Serial Ports si asigura-te ca portul corect pentru Pico este selectat. 
-3. Daca totul este corect configurat, poti incepe sa rulezi cod pe Raspberry Pi Pico din VS Code. 
  
 +    * In VS Code, deschide un terminal nou (Ctrl + `) si apasa Ctrl + Shift + P pentru a deschide Command Palette.
  
-====Tasks====+    * Selecteaza MicroPico: List Serial Ports si asigura-te ca portul corect pentru Pico este selectat.
  
-===Task 1: Utilizarea senzorilor BMP280 si LDR===+    * Daca totul este corect configurat, poti incepe sa rulezi cod pe Raspberry Pi Pico din VS Code.
  
-1. Conectarea senzorilor la Raspberry Pi Pico 
  
-- Senzorul BMP280 (I2C): +====Exercitii====
-    - SCL -> pin GP21. +
-    - SDA -> pin GP20. +
-    - VCC -> 3.3V. +
-    - GND -> GND.+
  
-- Senzorul LDR: +===Exercitiu 1Utilizarea senzorilor BMP280 si LDR===
-    - Un pin al LDR conectat la 3.3V si celalalt la pinul GP26 (ADC0).+
  
 +1. Conectarea senzorilor la Raspberry Pi Pico
 +
 +  * Senzorul BMP280 (I2C):
 +    * SCL -> pin GP21.
 +    * SDA -> pin GP20.
 +    * VCC -> 3.3V.
 +    * GND -> GND.
 +
 +  * Senzorul LDR:
 +    * Un pin al LDR conectat la 3.3V si celalalt la pinul GP26 (ADC0).
 +    {{:​priot:​laboratoare:​conexiuni_raspberry_1.jpeg?​600|}}{{:​priot:​laboratoare:​conexiuni_raspberry_2.jpeg?​600|}}
 +    ​
  
-===Task 2: Citirea senzorului de lumina (LDR)===+===Exercitiu ​2: Citirea senzorului de lumina (LDR)===
  
 Pentru senzorul LDR, trebuie sa citesti o valoare analogica folosind ADC-ul de pe Raspberry Pi Pico. Urmatorii pasi te vor ajuta sa construiesti codul: Pentru senzorul LDR, trebuie sa citesti o valoare analogica folosind ADC-ul de pe Raspberry Pi Pico. Urmatorii pasi te vor ajuta sa construiesti codul:
  
 Ce trebuie sa stii: Ce trebuie sa stii:
-1. ADC (Analog to Digital Converter) este folosit pentru a converti semnalele analogice in valori numerice pe care Pico le poate procesa. +  * ADC (Analog to Digital Converter) este folosit pentru a converti semnalele analogice in valori numerice pe care Pico le poate procesa. 
-2. In cazul unui LDR, poti citi intensitatea luminii prin intermediul unui pin ADC de pe Pico.+  ​* ​In cazul unui LDR, poti citi intensitatea luminii prin intermediul unui pin ADC de pe Pico.
  
  
-===Task 3: Gasirea adresei senzorului I2C===+===Exercitiu ​3: Gasirea adresei senzorului I2C===
  
 Inainte de a putea citi date de la senzorul BMP280, trebuie sa afli adresa I2C a acestuia. Adresele I2C sunt unice pentru fiecare dispozitiv si pot varia. Procesul de a gasi adresa este esential pentru a comunica corect cu senzorul. Inainte de a putea citi date de la senzorul BMP280, trebuie sa afli adresa I2C a acestuia. Adresele I2C sunt unice pentru fiecare dispozitiv si pot varia. Procesul de a gasi adresa este esential pentru a comunica corect cu senzorul.
  
 Pasul 1: Scrierea codului pentru scanarea dispozitivelor I2C Pasul 1: Scrierea codului pentru scanarea dispozitivelor I2C
-Pentru a gasi adresa senzorului, trebuie sa scrii un cod care sa scaneze dispozitivele I2C conectate la Raspberry Pi Pico.+ 
 +Pentru a gasi adresa senzorului, trebuie sa scrii un cod care sa scaneze dispozitivele I2C conectate la Raspberry Pi Pico.
  
 Ce trebuie sa stii: Ce trebuie sa stii:
-1. I2C este un protocol de comunicatie utilizat pentru a conecta senzori si alte componente la un microcontroler. +  * I2C este un protocol de comunicatie utilizat pentru a conecta senzori si alte componente la un microcontroler. 
-2. In Raspberry Pi Pico, poti utiliza biblioteca machine din MicroPython pentru a comunica cu dispozitivele I2C. +  ​* ​In Raspberry Pi Pico, poti utiliza biblioteca machine din MicroPython pentru a comunica cu dispozitivele I2C. 
-3. Pinul SCL (Serial Clock) si pinul SDA (Serial Data) sunt necesare pentru comunicatia I2C. In acest laborator, vei folosi GP21 pentru SCL si GP20 pentru SDA.+  ​* ​Pinul SCL (Serial Clock) si pinul SDA (Serial Data) sunt necesare pentru comunicatia I2C. In acest laborator, vei folosi GP21 pentru SCL si GP20 pentru SDA.
  
 Informatia necesara pentru a scrie codul: Informatia necesara pentru a scrie codul:
-Foloseste functia scan() din obiectul I2C pentru a obtine o lista cu adresele dispozitivelor conectate.+  * Foloseste functia scan() din obiectul I2C pentru a obtine o lista cu adresele dispozitivelor conectate.
  
-===Task 4: Citirea senzorului de temperatura===+===Exercitiu ​4: Citirea senzorului de temperatura===
  
 Acum ca ai gasit adresa senzorului BMP280, este timpul sa scrii codul care citeste datele de temperatura si presiune de la acesta. Pentru a face asta, trebuie sa intelegi urmatoarele concepte: Acum ca ai gasit adresa senzorului BMP280, este timpul sa scrii codul care citeste datele de temperatura si presiune de la acesta. Pentru a face asta, trebuie sa intelegi urmatoarele concepte:
  
 1. Structura registrului BMP280 1. Structura registrului BMP280
-BMP280 comunica printr-un set de registre. Datele de temperatura si presiune sunt stocate in aceste registre si trebuie citite in format brut. +  * BMP280 comunica printr-un set de registre. Datele de temperatura si presiune sunt stocate in aceste registre si trebuie citite in format brut. 
-Registrele importante pentru acest proiect sunt: +  ​* ​Registrele importante pentru acest proiect sunt: 
-    ​0xFA pana la 0xFC: Temperatura. +    ​0xFA pana la 0xFC: Temperatura. 
-    ​0xF7 pana la 0xF9: Presiune.+    ​0xF7 pana la 0xF9: Presiune.
  
 2. Citirea coeficientilor de calibrare 2. Citirea coeficientilor de calibrare
-Senzorul BMP280 furnizeaza coeficienti de calibrare care sunt esentiali pentru a converti datele brute in valori corecte de temperatura si presiune. +  * Senzorul BMP280 furnizeaza coeficienti de calibrare care sunt esentiali pentru a converti datele brute in valori corecte de temperatura si presiune. 
-Acesti coeficienti se gasesc in registrele de calibrare care incep de la 0x88.+  ​* ​Acesti coeficienti se gasesc in registrele de calibrare care incep de la 0x88.
  
 3. Cum sa scrii functii pentru a citi datele 3. Cum sa scrii functii pentru a citi datele
-- Pasul 1: Citeste datele brute din registre. +  * Citeste datele brute din registre. 
-- Pasul 2: Foloseste coeficientii de calibrare pentru a compensa valorile brute. +  ​* ​Foloseste coeficientii de calibrare pentru a compensa valorile brute. 
-- Pasul 3: Afiseaza rezultatele finale.+  ​* ​Afiseaza rezultatele finale.
  
 Etape: Etape:
-1. Initiaza senzorul: Scrie o functie pentru a seta senzorul in modul de operare normal. Acest lucru se face prin scrierea unei valori in registrul de control al senzorului. +  * Initiaza senzorul: Scrie o functie pentru a seta senzorul in modul de operare normal. Acest lucru se face prin scrierea unei valori in registrul de control al senzorului. 
-2. Citeste coeficientii de calibrare: Aceasta este o alta functie care citeste datele de calibrare de la senzor. Foloseste functia readfrom_mem() pentru a citi din registrele respective. +  ​* ​Citeste coeficientii de calibrare: Aceasta este o alta functie care citeste datele de calibrare de la senzor. Foloseste functia readfrom_mem() pentru a citi din registrele respective. 
-3. Citeste valorile brute de temperatura si presiune: Scrie functii pentru a citi datele brute din registrele 0xF7-0xFC. +  ​* ​Citeste valorile brute de temperatura si presiune: Scrie functii pentru a citi datele brute din registrele 0xF7-0xFC. 
-4. Compenseaza datele: Foloseste formulele de calibrare specificate in documentatia BMP280 pentru a corecta valorile brute.+  ​* ​Compenseaza datele: Foloseste formulele de calibrare specificate in documentatia BMP280 pentru a corecta valorile brute. 
 + 
 +==== Bibliografie ==== 
 + 
 +  - [[https://​datasheets.raspberrypi.com/​rp2040/​rp2040-datasheet.pdf|Datasheet microcontroller RP2040]] 
 +  - [[https://​datasheets.raspberrypi.com/​pico/​pico-datasheet.pdf|Datasheet Raspberry Pi Pico]] 
 +  - [[https://​www.mouser.com/​datasheet/​2/​783/​BST-BME280-DS002-1509607.pdf?​srsltid=AfmBOooMjmGwE224Ybw2eDvbuBsEsAHlDV7tL5KBk68xMOQx-3LOMppJ| Datasheet BME280]] 
 +  - [[https://​www.raspberrypi.com/​documentation/​microcontrollers/​c_sdk.html|Pico-SDK]] 
 +  - [[https://​www.raspberrypi.com/​documentation/​pico-sdk/​hardware.html#​ga71d35b29e897b9bb4fc881b587b08cab|Documentatie Pico-SDK]] 
 +  - [[https://​proto-pic.co.uk/​content/​RPI-PICO-R3-PUBLIC-SCHEMATIC.pdf|Schematic Raspberry Pi Pico]] 
 + 
 + 
 +<​hidden>​ 
 +<code lang light.py>​ 
 +from machine import ADC, Pin 
 +import time 
 + 
 +# Configurare pin pentru citirea senzorului de lumina (LDR) 
 +light_sensor = ADC(0) ​ # Pinul GP26 (A0) 
 + 
 +while True: 
 +    # Citire valoare de la senzor (LDR) 
 +    light_value = light_sensor.read_u16() ​ # Valorile sunt între 0 și 65535 
 +    print("​Valoare lumina:",​ light_value) 
 +    time.sleep(1) 
 + 
 +</​code>​ 
 +<code lang adresa_senzor.py>​ 
 +from machine import ADC, Pin 
 +import time 
 + 
 +# Configurare pin pentru citirea senzorului de lumina (LDR) 
 +# Initializare I2C cu SDA pe GP20 și SCL pe GP21 
 +i2c = I2C(0, scl=Pin(21),​ sda=Pin(20),​ freq=100000) 
 + 
 +# Scanare dispozitive I2C 
 +devices = i2c.scan() 
 + 
 +if devices: 
 +    print("​Dispozitive I2C gasite:"​) 
 +    for device in devices: 
 +        print(hex(device)) ​ # Afiseaza adresa în format hexazecimal 
 +else: 
 +    print("​Niciun dispozitiv I2C gasit"​) 
 +</​code>​ 
 + 
 +<code lang temperature.py>​ 
 +from machine import Pin, I2C 
 +import time 
 + 
 +# Initializare I2C cu SDA pe GP20 si SCL pe GP21 
 +i2c = I2C(0, scl=Pin(21),​ sda=Pin(20),​ freq=50000) 
 + 
 +# Adresa senzorului BMP280/​BME280 
 +address = 0x76 
 + 
 +# Registre pentru citirea temperaturii si presiunii brute 
 +REG_TEMP_MSB = 0xFA 
 +REG_TEMP_LSB = 0xFB 
 +REG_TEMP_XLSB = 0xFC 
 +REG_PRESS_MSB = 0xF7 
 +REG_PRESS_LSB = 0xF8 
 +REG_PRESS_XLSB = 0xF9 
 +REG_CONTROL = 0xF4  # Registrul de control 
 +MODE_NORMAL = 0x27  # Mod normal, oversampling 
 + 
 +# Registre de calibrare 
 +REG_CALIB = 0x88  # De la adresa 0x88 incep coeficientii de calibrare 
 + 
 +# Functie pentru initializarea senzorului 
 +def init_sensor():​ 
 +    # Setam senzorul in modul normal de operare (oversampling pentru temperatura si presiune) 
 +    i2c.writeto_mem(address,​ REG_CONTROL,​ bytes([MODE_NORMAL])) 
 +    time.sleep(0.5) ​ # Pauza scurta pentru a permite initializarea 
 + 
 +# Functie pentru citirea coeficientilor de calibrare 
 +def read_calibration_data():​ 
 +    calib = i2c.readfrom_mem(address,​ REG_CALIB, 24) 
 +     
 +    dig_T1 = calib[0] | (calib[1] << 8) 
 +    dig_T2 = calib[2] | (calib[3] << 8) 
 +    dig_T3 = calib[4] | (calib[5] << 8) 
 +     
 +    dig_P1 = calib[6] | (calib[7] << 8) 
 +    dig_P2 = calib[8] | (calib[9] << 8) 
 +    dig_P3 = calib[10] | (calib[11] << 8) 
 +    dig_P4 = calib[12] | (calib[13] << 8) 
 +    dig_P5 = calib[14] | (calib[15] << 8) 
 +    dig_P6 = calib[16] | (calib[17] << 8) 
 +    dig_P7 = calib[18] | (calib[19] << 8) 
 +    dig_P8 = calib[20] | (calib[21] << 8) 
 +    dig_P9 = calib[22] | (calib[23] << 8) 
 +     
 +    return { 
 +        '​dig_T1':​ dig_T1, '​dig_T2':​ dig_T2, '​dig_T3':​ dig_T3, 
 +        '​dig_P1':​ dig_P1, '​dig_P2':​ dig_P2, '​dig_P3':​ dig_P3, 
 +        '​dig_P4':​ dig_P4, '​dig_P5':​ dig_P5, '​dig_P6':​ dig_P6, 
 +        '​dig_P7':​ dig_P7, '​dig_P8':​ dig_P8, '​dig_P9':​ dig_P9 
 +    } 
 + 
 +# Functie pentru citirea valorilor brute de temperatura 
 +def read_raw_temp():​ 
 +    msb = i2c.readfrom_mem(address,​ REG_TEMP_MSB,​ 1)[0] 
 +    lsb = i2c.readfrom_mem(address,​ REG_TEMP_LSB,​ 1)[0] 
 +    xlsb = i2c.readfrom_mem(address,​ REG_TEMP_XLSB,​ 1)[0] 
 +    raw_temp = (msb << 12) | (lsb << 4) | (xlsb >> 4) 
 +    return raw_temp 
 + 
 +# Functie pentru citirea valorilor brute de presiune 
 +def read_raw_press():​ 
 +    msb = i2c.readfrom_mem(address,​ REG_PRESS_MSB,​ 1)[0] 
 +    lsb = i2c.readfrom_mem(address,​ REG_PRESS_LSB,​ 1)[0] 
 +    xlsb = i2c.readfrom_mem(address,​ REG_PRESS_XLSB,​ 1)[0] 
 +    raw_press = (msb << 12) | (lsb << 4) | (xlsb >> 4) 
 +    return raw_press 
 + 
 +# Functie pentru compensarea temperaturii 
 +def compensate_temperature(raw_temp,​ calib): 
 +    dig_T1 = calib['​dig_T1'​] 
 +    dig_T2 = calib['​dig_T2'​] 
 +    dig_T3 = calib['​dig_T3'​] 
 +     
 +    var1 = (((raw_temp >> 3) - (dig_T1 << 1)) * dig_T2) >> 11 
 +    var2 = (((((raw_temp >> 4) - dig_T1) * ((raw_temp >> 4) - dig_T1)) >> 12) * dig_T3) >> 14 
 +    t_fine = var1 + var2 
 +    temperature = (t_fine * 5 + 128) >> 8 
 +    return temperature / 100.0, t_fine 
 + 
 +# Functie pentru compensarea presiunii 
 +def compensate_pressure(raw_press,​ calib, t_fine): 
 +    dig_P1 = calib['​dig_P1'​] 
 +    dig_P2 = calib['​dig_P2'​] 
 +    dig_P3 = calib['​dig_P3'​] 
 +    dig_P4 = calib['​dig_P4'​] 
 +    dig_P5 = calib['​dig_P5'​] 
 +    dig_P6 = calib['​dig_P6'​] 
 +    dig_P7 = calib['​dig_P7'​] 
 +    dig_P8 = calib['​dig_P8'​] 
 +    dig_P9 = calib['​dig_P9'​] 
 + 
 +    var1 = t_fine - 128000 
 +    var2 = var1 * var1 * dig_P6 
 +    var2 = var2 + ((var1 * dig_P5) << 17) 
 +    var2 = var2 + (dig_P4 << 35) 
 +    var1 = ((var1 * var1 * dig_P3) >> 8) + ((var1 * dig_P2) << 12) 
 +    var1 = (((1 << 47) + var1) * dig_P1) >> 33 
 + 
 +    if var1 == 0: 
 +        return 0  # Pentru a evita diviziunea cu zero 
 + 
 +    pressure = 1048576 - raw_press 
 +    pressure = ((pressure << 31) - var2) * 3125 // var1 
 +    var1 = (dig_P9 * (pressure >> 13) * (pressure >> 13)) >> 25 
 +    var2 = (dig_P8 * pressure) >> 19 
 + 
 +    pressure = ((pressure + var1 + var2) >> 8) + (dig_P7 << 4) 
 +    return pressure / 25600.0 ​ # Conversie in hPa 
 + 
 +# Initializam senzorul si citim coeficientii de calibrare 
 +init_sensor() 
 +calibration_data = read_calibration_data() 
 + 
 +# Citire si afisare valori brute si compensate 
 +try: 
 +    while True: 
 +        raw_temp = read_raw_temp() 
 +        raw_press = read_raw_press() 
 + 
 +        temp, t_fine = compensate_temperature(raw_temp,​ calibration_data) 
 +        press = compensate_pressure(raw_press,​ calibration_data,​ t_fine) 
 + 
 +        print("​Valoare bruta temperatura:",​ raw_temp) 
 +        print("​Valoare bruta presiune:",​ raw_press) 
 +        print("​Temperatura compensata: {:.2f} C"​.format(temp)) 
 +        print("​Presiunea compensata: {:.2f} hPa"​.format(press)) 
 +        time.sleep(2) 
 + 
 +except OSError as e: 
 +    print("​Eroare I2C:", e) 
 + 
 +</​code>​ 
 + 
 +</​hidden>​
  
  
priot/laboratoare/04.1728979927.txt.gz · Last modified: 2024/10/15 11:12 by vlad.radulescu2901
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0