Barrette écologique MICROCLUB

Transcription

Barrette écologique MICROCLUB
Barrette écologique MICROCLUB
Hardware
Horloge
Connexion d'un IC DS 1307 + pile
Entrées/sorties nécessaires
8 entrées TOR connectées sur boutons poussoirs BT1..BT8
1 entrés A/D sur l'image courant de la prise #P1
1 entrée A/D sur l'image du courant de #P4 (réserve)
8 sorties TOR commandant les triacs des prises P1..P8
Module – attribution des ports disponibles
En bleu: utilisation prévue
En rouge : imposé par le design du board
Port pin
Board Usage pour / commentaires
Port A
Analogique AN0..AN4
A0
A1
A2
A3
A4
A5
Lecture courant prise P1
Lect. courant prise P4 (réserve)
Port B
B0
B1
B2
B3
B4
B5
B6
B7
OUT, 1-SER Relais (p.u. 4K4)
Clock, 4-SCK Relais (voir « POWER relais »)
Latch, 3-RCK Relais
Enable, 2-G\ Relais
Latch2, 3-RCK seconde carte Relais
B6-LED rouge,
(B7 prog. Par CON3!!)
Port C
- commandes série
LEDs et Dip Sw
- bus série SDI/SDA
C0
C1
C2
C3
C4
C5
C6
C7
C0: OUT serie/ IN serie du board PT32
Clock;
Latch
SCL (EEPROM,horloge) p.u. 2K2
SDI/SDA (horloge) p.u. 2K2
SDD
Ligne sérielle TX1,
RX1
Port D
-
D0..D7 data bus
Port E
-
Adressage + CS + RD + RW
Port F
(ind. T sur board)
- AN5 à 7
T0
T1
T2
T3
T4
T5
T6
T7
Cde LEDs en face des prises P1..P8
(pull-up)
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 1
Port G
- sortie PWM
- Seriel 2
RG0
RG1
RG2
RG3
Programmation avec la page :
Ou une initialisation équivalente en C, au démarrage.
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 2
Logiciel
Horloge
Lecture du DS1307
Maintien d'une horloge en temps réel, comportant une image du temps définie ainsi.
– Jour de la semaine, 1 bit par jour avec 0 indéfini
– heure HH:MM sur 24H, stockés en 2 bytes
Résolution : 1 seconde
échantillonnage/resync : 60 secondes
Écriture du DS1307
Par page WEB ad-hoc + fonction MaJ horloge – à finir
Implémentation
Code à disposition
uDS1307.h
uDS1307.c
uSysClk.h
uSysClk.c
Fonction à disposition, de Omar Zucchiatti:
void DS1307_ReadSysDateTime (void);
void DS1307_WriteSysDateTime(void);
temps réel:
void FC_SystemClock(BOOL Clk10ms);
void interrupt HighISR(void);
Stockage:
Structure DB_SystemClock;
Description
La fonction FC_SystemClock(BOOL Clk10ms) est appelée par interruption toute les 10 ms.
Si le booléen est à 1, une série de compteurs, pour 100 – 250 – 500 ms et 1 seconde sont mis à jour
uSystemTick_xxms); au passage par 0, une série de flags de la structure DB_SystemClock sont
permutés (DB_SystemClock_Wave_xxxms) et positionnés à 1 (DB_SystemClock_Ons_xxxms).
Si le booléen est à 0, le flag DB_SystemClock_ProcessDone est mis à 1; si il est déjà à 1, les
compteurs 100 – 250 – 500 ms et 1 seconde sont mis à 0.
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 3
Toute les 60 secondes, un appel est fait à DS1307_ReadSysDateTime() via un mécanisme de flag,
DB_SystemClock_RequestRTCUpdate positionné à 1. Ceci évite de troubler les échanges I2C
pendant l'interruption.
La fonction void CheckSummerWinterTime(void) commute l'heure d'été ou d'hiver, en
respectivement soustrayant / additionnant une heure, et en mettant le chip DS1307 à jour.
La fct void FixTwoDigit(BYTE NumberToBeFixed, BYTE t) écrit selon le pointeur indexé par 't'
au format 2 digit, en ajoutant le '0' non significatif au besoin, de manière à obtenir un champ fixe.
La fct void InsertTimeDataInHtml(void) sort pour une page HTML la date
complète, dans le tableau strTmp[ ] au format: « Time: 09:12:09 Date: 12-0209 Day: Mon ». Le format est simplifié pour afficher: « 09:12:09 12-02-09
Lu » et tenir dans 20 bytes de la variable strTmp[ ].
Identification des besoins
Affichage de l'horloge
La date et l'heure sont lues de la structure DB_SystemClock.
cmd.h : définir un tag supplémentaire, du VARGROUP_GENERAL ('l'),
VARVAL_CLOCK
cmd.c : augmenter la fct WORD cmdGetTag(GETTAG_INFO* pGetTagInfo), ajouter
les fct void FixTwoDigit(BYTE NumberToBeFixed, BYTE t) et void
InsertTimeDataInHtml(void)
commute.cgi augmenter la page et insérer le tag %lxx pour afficher date et
heure.
Ajustement de l'horloge
Par commande GET 'rr' (voir tableau des commandes GET)
Maintient de l'horloge
La date et l'heure de la structure sont relues à intervalle périodique. Entre deux, la mise à jour est
faite par une fct temps réel qui met à jour les seconde de 0 à 59.
Tags définis pour insertion HTML
N° Syntaxe de tag
Effet
1
Affiche le temps et date courante, jour de la semaine.
l23
Format: 09:12:09 13-10-09 Lu
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 4
Table de commutation
Format
–
–
–
–
–
–
HH:MM: 2 bytes (comme l'horloge)
jour(s) de la semaine: 1=Lundi, 7=Dimanche: 7 bits
Etat EN/HORS: 1 bit
Etat ACT/INACT:1 bit
Priorité de la commande: 0..15; 4 bits
masque des prises actives, P1..P8: 8 bits
Éléments de la structure:
HH MM JS En Act
0
15
3
1
1
Prio
Mask
3
1111'1111
Valeurs programmables: table à 0..31 entrées (lignes de commutation)
+ valeur actuellement active, copiée à la commutation
Taille totale : 5 bytes * 32 = 160 bytes
A cause de la limitation des tags et de la limitation de RAM à dispositions, les lignes sont stockées
en EEPROM et rappelée en RAM dans un buffer, associé à un index.
Commandes GET additionnelles
Le format « get » permet de lire et mettre à jour une ligne de la table en mémoire. Celle-ci peut être
manipulée sans restriction et n'a aucun effet. Lorsqu'elle est prête, on peut donner un n° de ligne à
un index et la sauver en EEPROM. Ainsi, les données sont sans incidence en cas de coupure de
courant.
Tableau des commandes GET additionnelles
1 à 7: action sur la ligne en RAM; 8 à 13 action sur l'EEPROM et le chip RTC
Syntaxe
Commentaires
1
ri=0..31
Index - règle l'index
2
rt=[00:00-24:00]
Time - règle une heure/minute dans l'entrée 1 à 31
3
rd=[000..127]
Days - S'applique aux jours 1..7 en binaire, lu-di
4
re=[0|1]
Enable - Enclenche ou déclenche par la commande indiquée
5
ra=[0|1]
Active - 1=Active la ligne indiquée; 0= inactive (pas d'effet)
6
rp=[0..7]
Prio - Priorité de la commutation (7 = maximum)
7
ro=[0..255]
Output - Applique la commutation sur les prises, en décimal
8
rs
Sort - Tri, selon heure, de la table
9
rc
Commute - force la ligne immédiatement
10 rr=hh:mm-dd-mmyy:wd
RTC - Réglage horloge RTC: heure, minute, mois, année, jour de
la semaine
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 5
11 rg
Get line : lire une ligne de valeurs en EEPROM
12 rw
Write line: écrire la ligne en EEPROM
13 rk=[i|o]
RTC chip – i: lecture en RAM, o: écriture dans DS1307
Syntaxe: le format des nombres entre crochet donne la plage traitée; les '0' non significatifs sont
nécessaires dans les commandes à champs multiples (ex. heure:minute).
Exemples:
http://mxboard/?rs=22:00 règle la ligne à 22:00
http://mxboard/?ro=15 la ligne s'applique aux prise 1 à 4
http://mxboard/?re=1 la ligne enclenche
http://mxboard/?ra=1 la ligne est active
Limitation
L'index et la ligne en RAM sont aussi utilisé par les tags! Si une demande de page concernant
l'affichage de la table, la ligne n'est plus valable, et contient le dernier index et la dernière valeur
demandée!
Code d'erreur
Une variable globale BYTE err permet de connaître la dernière erreur détectée. Un tag permettra
de l'afficher.
Implémentation
rtc.h – définition de la structure RTC_COMMUTATION_LINE, des codes d'erreur, du groupe de
commande 'r' et codes à interpréter
rtc.c – implémentation des fonctions spécifiques rtc_get(BYTE n), rtc_write(BYTE n)
cmd.c – implémentation dans fct cmdGetTag(GETTAG_INFO* pGetTagInfo),
Fonctions de manipulation de la table de commutation
Fait:
void rtc_get(BYTE n);
void rtc_write(BYTE n);
/* lire la ligne n en EEPROM */
/* écrire la ligne n en EEPROM */
A faire:
void rtc_tble_sort(void)
/* tri selon jour/heure */
Test d'écriture dans la table
1) 07:15, 4 prises, prio 1, Lu-Ve, enclencher, actif
rt=07:15&ro=05&rp=1&rd=031&re=1&ra=1&ri=01&rw
2) 23:30, tts prises, prio 1, Lu-Ve, déclencher, actif
rs=23:30&ro=255&rp=1&rd=031&re=0&ra=1&ri=02&rw
3) vide, 1 prise
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 6
rs=00:00&ro=001&rp=0&rd=000&re=0&ra=0&ri=03&rw
4) 07:30, 4 prises, prio 1, Sa, enclencher, actif
rs=07:30&ro=015&rp=1&rd=032&re=1&ra=1&ri=04&rw
5) 01:15, tts prises, prio 1, Di, déclencher, actif
rs=01:15&ro=255&rp=1&rd=064&re=0&ra=1&ri=05&rw
6) vide, 0 prise
rs=00:00&ro=000&rp=0&rd=000&re=0&ra=0&ri=06&rw
7) 08:00, 4 prises, prio 1, Di enclencher, actif
rs=08:00&ro=015&rp=1&rd=064&re=1&ra=1&ri=07&rw
8) 23:50, tts prises, prio 2, Di déclencher, actif
rs=23:50&ro=255&rp=2&rd=064&re=0&ra=1&ri=08&rw
9) vide
rs=00:00&ro=000&rp=0&rd=000&re=0&ra=0&ri=09&rw
10) 03:00 prise 8, prio 0, Ts les jours, enclencher, actif
rs=03:00&ro=128&rp=0&rd=127&re=1&ra=1&ri=10&rw
11) 05:00 prise 8, prio 0, Ts les jours, déclencher, actif
rs=05:00&ro=128&rp=0&rd=127&re=0&ra=1&ri=11&rw
Suivi des lignes de commutation
Principe général
Le maintien en mémoire de:
– la commutation en cours: rtc_line_last
– la prochaine commutation: rtc_line_next
Est faite par un scan régulier de la table, en moins de 30 secondes de manière à pouvoir indiquer le
changement (modifiable par boutons, voir §8). On part du principe qu'elle n'est pas triée, et qu'elle
contient des trous, voire des zone non initalisées.
Pour éviter de lire toute la table et la tester en longuement, on divise le travail en testant une ligne
par appel. De plus, inutile de lancer la recherche si elle vient d'être faite suite à une commutation.
Recherche de la prochaine commutation
Exemple de situation, la commutation de 20h30 vient d'avoir lieu. Lorsque la minute est en cours, la
recherche est faite.
rtc_line_last
20:15
current time:
20:16
rtc_line_next:
23:00
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 7
Toutes les lignes sont passées en revue, et on applique les tests:
– la commutation est active? Si oui:
– Si elle est la plus proche du temps actuel, mémoriser
Ainsi la valeur obsolète sera mise à jour. Celle-ci sera remplacée au fil des scan, si une ligne plus
proche existe dans la table, parcourue de 0 à n.
Par précaution, et pour éviter l'écueil de la commutation à 24:00, on ajoute 24H au temps de
commutation de la ligne lue s'il est inférieur au temps actuel. De ce fait, le test se fait toujours sur
des nombres positifs.
Selon l'exemple, le résultat est:
State
Next
Time
2015
2015
2015
0 – rien à faire... commutation appliquée.
2015
'0630
2016
3030 – 2016 = 1014, voyons le suivant...
...
...
...
2015
2300
2016
...
...
...
2015
'0000
2016
A faire:
rtc_searchNextCommutation()
comments
Ainsi de suite
284, remplace le candidat précédent
...
384, pas retenu distance trop grande
/* met à jour la prochaine commutation */
Commutation, boutons et transitions
La commutation gère les états internes et externes.
L'etat interne dépend de:
– lignes de commutation (à faire)
– de boutons pressés (à faire)
– d'activités réseau (à faire)
Transitions
La commutation de 8 prises nécessite:
– un byte « état désiré », définit par la source de commutation
– un byte « état actuel » (mis a jour régulièrement à la seconde)
– un timer, mis à jour à la seconde
Lors de la transition, on fait clignoter la LED correspondant à la sortie
Structure permettant de gérer les transitions:
typedef struct STR_COMMUTATION_STATE
{
BYTE nextState;
BYTE actuState;
} CMUT_STATE;
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 8
Transition « En »
Etat suivant:
B7 B6 B5
x
x
Etat actuel:
x
x
B4
B3
B2
B1
B0
x
x
x
1
x
x
x
x
x
0
x
x
La différence démarre le timer TmB2, chargé à 10[s].
Tant que CommNextState et CommActState sont différents -ET- que le timer est actif, la LED B2
clignote au rapport 0.25, soit un allumage court
Transition « Hors »
Etat suivant:
B7 B6 B5
x
x
Etat actuel:
x
x
B4
B3
B2
B1
B0
x
x
x
0
x
x
x
x
x
1
x
x
La différence démarre le timer TmB2, chargé à 10[s].
Tant que nextState et actuState sont différents -ET- que le timer est actif, la LED B2 clignote au
rapport 0.75, soit un allumage long
Action des boutons
Les boutons BT1 à BT8, en face des sorties respectives P1 à P8 agissent ainsi:
• Etat « Hors »: force En
• Transition « En »: force En, termine la transition
• Transition « Hors »: force En, termine la transition
• Etat « En »: après confirmation de 5 secondes pressé, force « Hors »
Suivi des boutons
Afin de suivre l'activité des boutons (anti-rebond, délais), une structure permet de connaître leur état
au cours du temps.
Etat
Timer
1
2
1
127
0
0
0
127
1
0
Commentaire
Pression de 0.2 sec, tjrs active
Pression continue de plus de 12,7 sec
Vient d'être relâché
Relâché depuis plus de 12,7 sec
Vient d'être actif
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 9
Mis à jour des I/O (timing)
Chaque 0.1[s] : lecture boutons + timers maj
Chaque 0.25[s] . mise à jour LED clignotant
Chaque minute: mise à jour sorties
Maintient de relais par activité IP
Action de l'activité IP
L'activité IP, détectée par des requêtes triggées, rechargent le compteur de minutes. Le but est de
maintenir certaines prises actives SI la dernière commutation est de priorité suffisante pour l'arrêt,
mais une activité IP est toujours présente.
Cession de toute activité à 00:15, de niveau 3, par ligne de commutation:
HH MM JS En Act Prio
Mask
0
15
3
0
1
3
1111'1111
Masque des sorties maintenue par l'activité Internet:
Mask
Timer
0000'0011
5
Byte final actState :
P8
P7
P6
P5
P4
P3
P2
P1
x
x
x
x
x
x
1
1
Les sorties définies dans InetMask sont maintenues « En » tant que le timer reste actif.
Tester l'activité IP
Dès qu'une connexion réseau est présente, XP, Windows Server 2008 et Windows 7 lancent à
intervalle régulier des requêtes NBNS NetBIOS « ISATAP », afin de détecter si un tunnel IPV6
dans IPV4 doit être monté. Trace du Embedded Debugger:
20:39:57.110 - NBNS: Received NBNS request for NetBIOS name 'ISATAP
'
Ceci devrait suffire pour détecter que des ordinateurs « Windows » sont actifs sur le réseau.
NBNS Debug Tab, code 3,
Code à intégrer dans nbns.c, ligne 151.
Maintient de relais par la prise Maître
Cession de toute activité à 00:15, de niveau 3, par ligne de commutation:
HH MM JS En Act Prio
Mask
0
15
3
0
1
3
1111'1111
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 10
Masque des sorties maintenue par l'activité de senseur de courant de la prise « Master »:
Mask
0000'010x
Byte final actState :
P8
P7
P6
P5
P4
P3
P2
P1
x
x
x
x
x
1
x
1
Les sorties définies dans slaveMask sont maintenues « En » tant que la prise « maître » consomme
du courant.
Utilisation: un PC et son imprimante, ou sa lampe de bureau.
Gestion générale de la commutation
Liste des commutations
Les commutations et leurs interactions sont les suivantes:
–
–
–
–
Par ligne de commutation
Par activité IP
Par fonction prise « maître »
Par bouton
Une ligne de commutation va être activée lorsque rtc_delta s'approche de 0. A 1, nous somme dans
la minute qui précède.
Instant de début de transition: rtc_delta = 1; et nombre de secondes = 50 (60-10).
Calcul de la transition:
– OutRelays.nextState prend la valeur de rtc_line_next
– Initialiser l'état des LEDs (début de clignotement)
– si transition Hors: 75%, si transition En: 25%
Fin de la transition, rtc_delta = 0 :
– rtc_line_act prend la valeur de rtc_line_next
– lancer la recherche de la commutation suivante
– OutRelays.actState prend la valeur de OutRelays.nextState (plus de clignotement des
LEDs)
Modification de la commutation par activité IP
Si OutRelays.actState a les bits du masque InetMask, pas de changement;
Sinon, vérifier le temps restant > 0, forcer les bits de OutRelays.actState à 1.
Modification de la commutation par activité « Master »
Si OutRelays.actState a les bits du masque master.Mask, pas de changement;
Sinon, vérifier le courant de la prise « master » et forcer les bits de OutRelays.actState à 1
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 11
Modification de la commutation par activité bouton
1) Transition en cours
Supprimer la transition, en recopiant le bit de OutRelays.actState sur OutRelays.nextState, et
supprimer clignotement LEDs.
Tags définis pour insertion HTML
Les tags permettent de lire la table par éléments, et d'en extraire la valeur pour l'intégration dans une
page WEB.
Limitation
Les tags sont repérés sur un seul caractère (dû au design du code initial). Le nombre qui suit est en
HEXA, 00 àFF. La casse n'importe pas. Adresser une ligne de la table aurait la fâcheuse limite de 16
éléments, si l'on veut garder un digit pour sélectionner l'élément.
N° Syntaxe de tag
Effet à l'affichage
1
r00
r01
r02
r0f
Lit la ligne de sortie active
Positionne le pointeur à 0 et l'affiche, lit la ligne[0] de l'EEPROM
Incrémente le pointeur, l'affiche, lit la ligne[n] de l'EEPROM
Affiche le n° d'erreur de la dernière commande sur 2 digits
2
r10
Affiche le temps entre 00:00 à 23:59 de l'entrée en RAM
3
r20
Jours programmés, en décimal
4
r30
Jours, en texte: lu-ma-me-je-ve-sa-di
5
r40
Commande état de la sortie: « En » ou « Hors »
6
r50
Commande état de la sortie: '1' ou '0'
7
r60
commande (active ou non) : « Act » ou « Inac »
8
r70
Commande : '1' ou '0'
9
r80
Priorité : 0 à 7
10 r90
Prises activées, binaire: 00000000 à 11111111
11 ra0
Prises activées, Hexa: 00 à FF
Exemple: %r10 dans la page substitue le tag par le temps lu de la ligne de la table de commutation
en mémoire, et affichera p. e. 22:30, soit une commutation à 22h30 .
Implémentation
rtc.h – définition des groupes de commande
cmd.c -augmentation:
– Les chaînes de chr HTML spécifiques sont définies en ROM char
– Les chaines à sortir sont plus longues, Le tableau strTmp[] est augmenté à 21 éléments.
– augmentation de la fct WORD cmdGetTag(GETTAG_INFO* pGetTagInfo)
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 12
– ajout d'un test: else if (tagGroup == VARGROUP_RTC) ...
Méthode d'envoi de la valeur « taggée »
La fonction WORD cmdGetTag(GETTAG_INFO* pGetTagInfo) doit rendre 1 chr à chaque appel.
La structure GETTAG_INFO est copiée dans des variables locales:
• tagGroup: contient le caractère du groupe (ici:'r')
• tagVal contient la valeur qui suit varGroup, 00..FF (0..255)
• ref: index sur la variable texte à sortir
• val: la valeur en sortie (1 chr)
Selon le tag et son sélecteur tagVal, si ref vaut HTTP_START_OF_VAR, la variable texte
strTmp[] est initialisée par des conversions int -> ascii, telle que l'on en a besoin dans la page
WEB; ref est mis à 0 (1 er char).
Ensuite, à chaque appel, la variable val (via *pGetTagInfo->val = strTmp[(BYTE)ref]; ) est
positionnée, et l'indice pGetTagInfo->ref incrémenté.
Arrivé à la fin de la chaîne, par le test: if ( strTmp[(BYTE)ref] == '\0' ), on termine en
positionnant ref à HTTP_END_OF_VAR.
La valeur retournée est quasi toujours 1, soit un chr émit.
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 13
Pages WEB
Identification des besoins
A l'instar de l'exemple de Modtronix, dans \Pic\Soft\websrvr65_v310\src\webpages\default,
il faut définir un volet de sélection, comportant les différentes pages nécessaires:
1. paramètres du serveur/login
2. paramètre du réseau
3. visualisation/forçage état des prises et LEDs
4. commandes directes
5. réglage de l'horloge
6. réglage système
7. réglage sécurité
8. réglage réseau
9. login
Ré-utilisation
Page originales livrées avec le module:
Menus
appel
Transformé pour
Back to main page
Index.htm
Mise en français + agencement menus
System settings
Xscfg.cgi
Francisé
Analog settings
Xacfg.cgi
Adapter pour la prise P1, entrée A0
Network settings
Xncfg.cgi
Francisé
Port settings
Xiocfg.cgi
Adapter pour prises 1..6, port B0..B5
PWM settings
Xpcfg.cgi
(inutilisé)
Commands
Xccfg.cgi
(inutilisé)
USART Settings
Xucfg.cgi
éventuel
WEB server settings
Xwcfg.cgi
Francisé
Log in
Xcfg.htm?m=l (inutilisé)
Menu et appel des pages/scripts:
Menus
appel
utilisation
Introduction
Explication + agencement menus
Index.htm
Seuil d'activation
Etat des prises
Commutations
Régler les seuils des prises « maîtres »
Ioval.cgi
Affiche l'état des prises et des boutons
Xiocfg.cgi
Impose les E/S
Commut.cgi
Liste le tableau des 32 commutations
Forçages
Permet d'imposer une commutation (jusqu'au prochain changement)
Config système
Xscfg.cgi
Affiche les versions, le bootloader et la LED d'activité – reset système
Config sécurité
Xwcfg.cgi
Décl. Des pages accessibles et utilisateur/passwd
Config LAN
Xncfg.cgi
Comme ça se prononce...
Log in
?m=l
Demande l'utilisateur/passwd
Contact
Contact.htm
Infos et liens sur l'équipement
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 14
06.12.09 - YM - C:\Users\Yves\Documents\Pic\barrette.odt - page 15

Documents pareils