1 /************************************************************************************************** |
1 /****************************************************************************** |
2 * |
2 * |
3 * msr_module.c |
3 * msr_module.c |
4 * |
4 * |
5 * Kernelmodul für 2.6 Kernel zur Meßdatenerfassung, Steuerung und Regelung |
5 * Kernelmodul für 2.6 Kernel zur Meßdatenerfassung, Steuerung und Regelung. |
6 * Zeitgeber ist der Timerinterrupt (tq) |
6 * Zeitgeber ist der Timerinterrupt (tq) |
7 * |
7 * |
8 * Autor: Wilhelm Hagemeister |
8 * Autor: Wilhelm Hagemeister |
9 * |
9 * |
10 * (C) Copyright IgH 2002 |
10 * (C) Copyright IgH 2002 |
11 * Ingenieurgemeinschaft IgH |
11 * Ingenieurgemeinschaft IgH |
12 * Heinz-Bäcker Str. 34 |
12 * Heinz-Bäcker Str. 34 |
13 * D-45356 Essen |
13 * D-45356 Essen |
14 * Tel.: +49 201/61 99 31 |
14 * Tel.: +49 201/61 99 31 |
15 * Fax.: +49 201/61 98 36 |
15 * Fax.: +49 201/61 98 36 |
16 * E-mail: hm@igh-essen.com |
16 * E-mail: hm@igh-essen.com |
17 * |
17 * |
18 * |
18 * $Id$ |
19 * $RCSfile: msr_module.c,v $ |
19 * |
20 * $Revision: 1.1 $ |
20 *****************************************************************************/ |
21 * $Author: hm $ |
|
22 * $Date: 2005/11/14 20:32:57 $ |
|
23 * $State: Exp $ |
|
24 * |
|
25 * |
|
26 * $Log: msr_module.c,v $ |
|
27 * Revision 1.1 2005/11/14 20:32:57 hm |
|
28 * Initial revision |
|
29 * |
|
30 * Revision 1.13 2005/06/17 11:35:13 hm |
|
31 * *** empty log message *** |
|
32 * |
|
33 * |
|
34 * Hello Emacs: -*- c-basic-offset: 2; -*- |
|
35 * |
|
36 **************************************************************************************************/ |
|
37 |
|
38 |
|
39 /*--includes-------------------------------------------------------------------------------------*/ |
|
40 |
|
41 |
21 |
42 #ifndef __KERNEL__ |
22 #ifndef __KERNEL__ |
43 # define __KERNEL__ |
23 # define __KERNEL__ |
44 #endif |
24 #endif |
45 #ifndef MODULE |
25 #ifndef MODULE |
82 #include "../drivers/ec_types.h" |
62 #include "../drivers/ec_types.h" |
83 #include "../drivers/ec_module.h" |
63 #include "../drivers/ec_module.h" |
84 |
64 |
85 #include "msr_jitter.h" |
65 #include "msr_jitter.h" |
86 |
66 |
87 MODULE_AUTHOR("Wilhelm Hagemeister, Ingenieurgemeinschaft IgH"); |
67 #define TSC2US(T) ((unsigned long) (T) * 1000UL / cpu_khz) |
88 MODULE_LICENSE("GPL"); |
68 |
89 |
69 /*--external data------------------------------------------------------------*/ |
90 /*--external functions---------------------------------------------------------------------------*/ |
|
91 |
|
92 /*--external data--------------------------------------------------------------------------------*/ |
|
93 |
70 |
94 #define HZREDUCTION (MSR_ABTASTFREQUENZ/HZ) |
71 #define HZREDUCTION (MSR_ABTASTFREQUENZ/HZ) |
95 |
72 |
96 extern wait_queue_head_t msr_read_waitqueue; |
73 extern wait_queue_head_t msr_read_waitqueue; |
97 |
74 |
98 extern struct msr_char_buf *msr_kanal_puffer; |
75 extern struct msr_char_buf *msr_kanal_puffer; |
99 |
76 |
100 extern int proc_abtastfrequenz; |
77 extern int proc_abtastfrequenz; |
101 |
78 |
102 /*--public data----------------------------------------------------------------------------------*/ |
79 /*--local data---------------------------------------------------------------*/ |
103 /*--local data-----------------------------------------------------------------------------------*/ |
80 |
104 //struct timer_list timer; |
81 extern struct timeval process_time; |
105 |
82 struct timeval msr_time_increment; // Increment per Interrupt |
106 extern struct timeval process_time; |
|
107 struct timeval msr_time_increment; // Increment per Interrupt |
|
108 |
83 |
109 //adeos |
84 //adeos |
110 |
85 |
111 static struct ipipe_domain this_domain; |
86 static struct ipipe_domain this_domain; |
112 |
87 |
114 |
89 |
115 static EtherCAT_master_t *ecat_master = NULL; |
90 static EtherCAT_master_t *ecat_master = NULL; |
116 |
91 |
117 static EtherCAT_slave_t ecat_slaves[] = |
92 static EtherCAT_slave_t ecat_slaves[] = |
118 { |
93 { |
119 |
|
120 |
|
121 #if 1 |
94 #if 1 |
122 // Block 1 |
95 // Block 1 |
123 ECAT_INIT_SLAVE(Beckhoff_EK1100), |
96 ECAT_INIT_SLAVE(Beckhoff_EK1100, 0), |
124 ECAT_INIT_SLAVE(Beckhoff_EL4102), |
97 ECAT_INIT_SLAVE(Beckhoff_EL4102, 0), |
125 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
98 ECAT_INIT_SLAVE(Beckhoff_EL1014, 0), |
126 ECAT_INIT_SLAVE(Beckhoff_EL3162), |
99 ECAT_INIT_SLAVE(Beckhoff_EL3162, 0), |
127 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
100 ECAT_INIT_SLAVE(Beckhoff_EL2004, 0), |
128 ECAT_INIT_SLAVE(Beckhoff_EL3102), |
101 ECAT_INIT_SLAVE(Beckhoff_EL3102, 0), |
129 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
102 ECAT_INIT_SLAVE(Beckhoff_EL2004, 0), |
130 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
103 ECAT_INIT_SLAVE(Beckhoff_EL2004, 0), |
131 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
104 ECAT_INIT_SLAVE(Beckhoff_EL2004, 0), |
132 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
105 ECAT_INIT_SLAVE(Beckhoff_EL2004, 0), |
133 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
106 ECAT_INIT_SLAVE(Beckhoff_EL2004, 0), |
134 |
107 |
135 // Block 2 |
108 // Block 2 |
136 ECAT_INIT_SLAVE(Beckhoff_EK1100), |
109 ECAT_INIT_SLAVE(Beckhoff_EK1100, 1), |
137 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
110 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1), |
138 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
111 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1), |
139 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
112 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1), |
140 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
113 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1), |
141 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
114 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1), |
142 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
115 ECAT_INIT_SLAVE(Beckhoff_EL2004, 1), |
143 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
116 ECAT_INIT_SLAVE(Beckhoff_EL2004, 1), |
144 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
117 ECAT_INIT_SLAVE(Beckhoff_EL2004, 1), |
145 ECAT_INIT_SLAVE(Beckhoff_EL2004), |
118 ECAT_INIT_SLAVE(Beckhoff_EL2004, 1), |
146 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
119 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1), |
147 ECAT_INIT_SLAVE(Beckhoff_EL1014), |
120 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1), |
148 ECAT_INIT_SLAVE(Beckhoff_EL1014) |
121 ECAT_INIT_SLAVE(Beckhoff_EL1014, 1) |
149 #endif |
122 #endif |
150 |
123 |
151 #if 1 |
124 #if 0 |
152 // Block 3 |
125 // Block 3 |
153 ,ECAT_INIT_SLAVE(Beckhoff_EK1100), |
126 ,ECAT_INIT_SLAVE(Beckhoff_EK1100, 2), |
154 ECAT_INIT_SLAVE(Beckhoff_EL3162), |
127 ECAT_INIT_SLAVE(Beckhoff_EL3162, 2), |
155 ECAT_INIT_SLAVE(Beckhoff_EL3162), |
128 ECAT_INIT_SLAVE(Beckhoff_EL3162, 2), |
156 ECAT_INIT_SLAVE(Beckhoff_EL3162), |
129 ECAT_INIT_SLAVE(Beckhoff_EL3162, 2), |
157 ECAT_INIT_SLAVE(Beckhoff_EL3162), |
130 ECAT_INIT_SLAVE(Beckhoff_EL3162, 2), |
158 ECAT_INIT_SLAVE(Beckhoff_EL3102), |
131 ECAT_INIT_SLAVE(Beckhoff_EL3102, 2), |
159 ECAT_INIT_SLAVE(Beckhoff_EL3102), |
132 ECAT_INIT_SLAVE(Beckhoff_EL3102, 2), |
160 ECAT_INIT_SLAVE(Beckhoff_EL3102), |
133 ECAT_INIT_SLAVE(Beckhoff_EL3102, 2), |
161 ECAT_INIT_SLAVE(Beckhoff_EL4102), |
134 ECAT_INIT_SLAVE(Beckhoff_EL4102, 2), |
162 ECAT_INIT_SLAVE(Beckhoff_EL4102), |
135 ECAT_INIT_SLAVE(Beckhoff_EL4102, 2), |
163 ECAT_INIT_SLAVE(Beckhoff_EL4102), |
136 ECAT_INIT_SLAVE(Beckhoff_EL4102, 2), |
164 ECAT_INIT_SLAVE(Beckhoff_EL4102), |
137 ECAT_INIT_SLAVE(Beckhoff_EL4102, 2), |
165 ECAT_INIT_SLAVE(Beckhoff_EL4132) |
138 ECAT_INIT_SLAVE(Beckhoff_EL4132, 2) |
166 |
|
167 |
|
168 #endif |
139 #endif |
169 }; |
140 }; |
170 |
141 |
171 #define ECAT_SLAVES_COUNT (sizeof(ecat_slaves) / sizeof(EtherCAT_slave_t)) |
142 #define ECAT_SLAVES_COUNT (sizeof(ecat_slaves) / sizeof(EtherCAT_slave_t)) |
172 |
143 |
264 } |
227 } |
265 } |
228 } |
266 } |
229 } |
267 |
230 |
268 if (klemme >= 0) { |
231 if (klemme >= 0) { |
269 EtherCAT_write_value(&ecat_master->slaves[klemme], kanal,up_down); |
232 EtherCAT_write_value(&ecat_slaves[klemme], kanal, up_down); |
270 //printk("ECAT write: Klemme: %d, Kanal: %d, Wert: %d\n",klemme,kanal,up_down); |
|
271 } |
233 } |
272 |
234 |
273 #if 0 |
235 #if 0 |
274 EtherCAT_write_value(&ecat_master->slaves[13], 1, ms > 500 ? 0 : 1); |
236 EtherCAT_write_value(&ecat_master->slaves[13], 1, ms > 500 ? 0 : 1); |
275 EtherCAT_write_value(&ecat_master->slaves[14], 2, ms > 500 ? 0 : 1); |
237 EtherCAT_write_value(&ecat_master->slaves[14], 2, ms > 500 ? 0 : 1); |
276 EtherCAT_write_value(&ecat_master->slaves[15], 3, ms > 500 ? 1 : 0); |
238 EtherCAT_write_value(&ecat_master->slaves[15], 3, ms > 500 ? 1 : 0); |
277 #endif |
239 #endif |
278 |
240 |
279 // Prozessdaten schreiben |
241 // Prozessdaten schreiben |
280 rdtscl(k); |
242 rdtscl(k); |
281 EtherCAT_write_process_data(ecat_master); |
243 rdtscl(t2); |
|
244 |
|
245 EtherCAT_process_data_cycle(ecat_master, 0); |
|
246 |
|
247 t3 = ecat_master->tx_time; |
|
248 t4 = ecat_master->rx_time; |
|
249 tr1 = ecat_master->rx_tries; |
|
250 |
|
251 EtherCAT_process_data_cycle(ecat_master, 1); |
|
252 |
|
253 t5 = ecat_master->tx_time; |
|
254 t6 = ecat_master->rx_time; |
|
255 tr2 = ecat_master->rx_tries; |
|
256 |
|
257 //EtherCAT_process_data_cycle(ecat_master, 2); |
|
258 |
|
259 // Daten lesen und skalieren |
|
260 #ifdef USE_MSR_LIB |
|
261 value = EtherCAT_read_value(&ecat_slaves[5], 0) / 3276.0; |
|
262 dig1 = EtherCAT_read_value(&ecat_slaves[2], 0); |
|
263 #endif |
|
264 |
|
265 rdtscl(t7); |
|
266 |
|
267 if (debug_counter == MSR_ABTASTFREQUENZ) { |
|
268 printk(KERN_DEBUG "%lu: %luŽµs + %luŽµs + %luŽµs + %luŽµs + %luŽµs +" |
|
269 " %luŽµs = %luŽµs (%u %u)\n", |
|
270 TSC2US(t1 - lt), |
|
271 TSC2US(t2 - t1), TSC2US(t3 - t2), TSC2US(t4 - t3), |
|
272 TSC2US(t5 - t4), TSC2US(t6 - t5), TSC2US(t7 - t6), |
|
273 TSC2US(t7 - t1), tr1, tr2); |
|
274 debug_counter = 0; |
|
275 } |
|
276 |
|
277 lt = t1; |
|
278 |
282 firstrun = 0; |
279 firstrun = 0; |
283 |
280 debug_counter++; |
284 } |
281 } |
285 |
282 |
286 /* |
283 /****************************************************************************** |
287 *************************************************************************************************** |
284 * |
288 * |
285 * Function: msr_run(_interrupt) |
289 * Function: msr_run(_interrupt) |
286 * |
290 * |
287 * Beschreibung: Routine wird zyklisch im Timerinterrupt ausgeführt |
291 * Beschreibung: Routine wird zyklisch im Timerinterrupt ausgeführt |
288 * (hier muß alles rein, was Echtzeit ist ...) |
292 * (hier muß alles rein, was Echtzeit ist ...) |
289 * |
293 * |
290 * Parameter: Zeiger auf msr_data |
294 * Parameter: Zeiger auf msr_data |
291 * |
295 * |
292 * Rückgabe: |
296 * Rückgabe: |
293 * |
297 * |
294 * Status: exp |
298 * Status: exp |
295 * |
299 * |
296 *****************************************************************************/ |
300 *************************************************************************************************** |
|
301 */ |
|
302 |
|
303 |
297 |
304 void msr_run(unsigned irq) |
298 void msr_run(unsigned irq) |
305 { |
299 { |
306 |
|
307 static int counter = 0; |
300 static int counter = 0; |
308 #ifdef USE_MSR_LIB |
301 #ifdef USE_MSR_LIB |
309 |
302 |
310 timeval_add(&process_time,&process_time,&msr_time_increment); |
303 timeval_add(&process_time,&process_time,&msr_time_increment); |
311 |
304 |
316 #else |
309 #else |
317 msr_controller_run(); |
310 msr_controller_run(); |
318 #endif |
311 #endif |
319 /* und wieder in die Timerliste eintragen */ |
312 /* und wieder in die Timerliste eintragen */ |
320 /* und neu in die Taskqueue eintragen */ |
313 /* und neu in die Taskqueue eintragen */ |
321 // timer.expires += 1; |
314 //timer.expires += 1; |
322 // add_timer(&timer); |
315 //add_timer(&timer); |
323 |
316 |
324 ipipe_control_irq(irq,0,IPIPE_ENABLE_MASK); //Interrupt bestŽätigen |
317 ipipe_control_irq(irq,0,IPIPE_ENABLE_MASK); //Interrupt bestŽätigen |
325 if(counter++ > HZREDUCTION) { |
318 if(counter++ > HZREDUCTION) { |
326 ipipe_propagate_irq(irq); //und weiterreichen |
319 ipipe_propagate_irq(irq); //und weiterreichen |
327 counter = 0; |
320 counter = 0; |
328 } |
321 } |
329 |
322 } |
330 |
323 |
331 } |
324 void domain_entry (void) |
332 |
325 { |
333 void domain_entry (void) { |
326 printk("Domain %s started.\n", ipipe_current_domain->name); |
334 printk("Domain %s started.\n", ipipe_current_domain->name); |
|
335 |
|
336 |
327 |
337 ipipe_get_sysinfo(&sys_info); |
328 ipipe_get_sysinfo(&sys_info); |
338 ipipe_virtualize_irq(ipipe_current_domain,sys_info.archdep.tmirq, |
329 ipipe_virtualize_irq(ipipe_current_domain,sys_info.archdep.tmirq, |
339 &msr_run, NULL, IPIPE_HANDLE_MASK); |
330 &msr_run, NULL, IPIPE_HANDLE_MASK); |
340 |
331 |
341 ipipe_tune_timer(1000000000UL/MSR_ABTASTFREQUENZ,0); |
332 ipipe_tune_timer(1000000000UL/MSR_ABTASTFREQUENZ,0); |
342 |
333 } |
343 } |
334 |
344 |
335 /****************************************************************************** |
345 /* |
336 * |
346 ******************************************************************************* |
337 * Function: msr_register_channels |
347 * |
338 * |
348 * Function: msr_register_channels |
339 * Beschreibung: KanŽäle registrieren |
349 * |
340 * |
350 * Beschreibung: KanŽäle registrieren |
341 * Parameter: |
351 * |
342 * |
352 * Parameter: |
343 * RŽückgabe: |
353 * |
344 * |
354 * RŽückgabe: |
345 * Status: exp |
355 * |
346 * |
356 * Status: exp |
347 *****************************************************************************/ |
357 * |
|
358 ******************************************************************************* |
|
359 */ |
|
360 |
348 |
361 int msr_globals_register(void) |
349 int msr_globals_register(void) |
362 { |
350 { |
363 #ifdef USE_MSR_LIB |
351 #ifdef USE_MSR_LIB |
364 msr_reg_kanal("/value", "V", &value, TDBL); |
352 msr_reg_kanal("/value", "V", &value, TDBL); |
365 msr_reg_kanal("/dig1", "", &dig1, TINT); |
353 msr_reg_kanal("/dig1", "", &dig1, TINT); |
366 #endif |
354 #endif |
367 /* msr_reg_kanal("/Taskinfo/Ecat/TX-Delay","us",&ecat_tx_delay,TUINT); |
355 #if 0 |
368 msr_reg_kanal("/Taskinfo/Ecat/RX-Delay","us",&ecat_rx_delay,TUINT); |
356 msr_reg_kanal("/Taskinfo/Ecat/TX-Delay","us",&ecat_tx_delay,TUINT); |
369 msr_reg_kanal("/Taskinfo/Ecat/TX-Cnt","",&tx_intr,TUINT); |
357 msr_reg_kanal("/Taskinfo/Ecat/RX-Delay","us",&ecat_rx_delay,TUINT); |
370 msr_reg_kanal("/Taskinfo/Ecat/RX-Cnt","",&rx_intr,TUINT); |
358 msr_reg_kanal("/Taskinfo/Ecat/TX-Cnt","",&tx_intr,TUINT); |
371 msr_reg_kanal("/Taskinfo/Ecat/Total-Cnt","",&total_intr,TUINT); |
359 msr_reg_kanal("/Taskinfo/Ecat/RX-Cnt","",&rx_intr,TUINT); |
372 */ |
360 msr_reg_kanal("/Taskinfo/Ecat/Total-Cnt","",&total_intr,TUINT); |
|
361 #endif |
373 return 0; |
362 return 0; |
374 } |
363 } |
375 |
364 |
376 |
365 /****************************************************************************** |
377 /**************************************************************************************************** |
|
378 * the init/clean material |
366 * the init/clean material |
379 ****************************************************************************************************/ |
367 *****************************************************************************/ |
380 |
|
381 |
368 |
382 int __init init_module() |
369 int __init init_module() |
383 { |
370 { |
|
371 unsigned int i; |
384 struct ipipe_domain_attr attr; //ipipe |
372 struct ipipe_domain_attr attr; //ipipe |
385 |
373 |
386 // Als allererstes die RT-lib initialisieren |
374 // Als allererstes die RT-lib initialisieren |
387 #ifdef USE_MSR_LIB |
375 #ifdef USE_MSR_LIB |
388 if (msr_rtlib_init(1,MSR_ABTASTFREQUENZ,10,&msr_globals_register) < 0) { |
376 if (msr_rtlib_init(1,MSR_ABTASTFREQUENZ,10,&msr_globals_register) < 0) { |
434 |
423 |
435 out_return: |
424 out_return: |
436 return -1; |
425 return -1; |
437 } |
426 } |
438 |
427 |
439 |
428 /*****************************************************************************/ |
440 //**************************************************************************** |
429 |
441 void __exit cleanup_module() |
430 void __exit cleanup_module() |
442 |
431 { |
443 { |
432 unsigned int i; |
|
433 |
444 msr_print_info("msk_modul: unloading..."); |
434 msr_print_info("msk_modul: unloading..."); |
445 |
435 |
446 ipipe_tune_timer(1000000000UL/HZ,0); //alten Timertakt wieder herstellen |
436 ipipe_tune_timer(1000000000UL/HZ,0); //alten Timertakt wieder herstellen |
447 ipipe_unregister_domain(&this_domain); |
437 ipipe_unregister_domain(&this_domain); |
448 |
438 |
449 printk(KERN_INFO "=== Stopping EtherCAT environment... ===\n"); |
439 printk(KERN_INFO "=== Stopping EtherCAT environment... ===\n"); |
450 |
440 |
451 if (ecat_master) |
441 if (ecat_master) |
452 { |
442 { |
453 EtherCAT_clear_process_data(ecat_master); |
|
454 printk(KERN_INFO "Deactivating slaves.\n"); |
443 printk(KERN_INFO "Deactivating slaves.\n"); |
455 EtherCAT_deactivate_all_slaves(ecat_master); |
444 |
|
445 for (i = 0; i < ECAT_SLAVES_COUNT; i++) { |
|
446 if (EtherCAT_deactivate_slave(ecat_master, ecat_slaves + i) < 0) { |
|
447 printk(KERN_WARNING "Warning - Could not deactivate slave!\n"); |
|
448 } |
|
449 } |
|
450 |
456 EtherCAT_release(ecat_master); |
451 EtherCAT_release(ecat_master); |
457 } |
452 } |
458 |
453 |
459 printk(KERN_INFO "=== EtherCAT environment stopped. ===\n"); |
454 printk(KERN_INFO "=== EtherCAT environment stopped. ===\n"); |
460 |
455 |
461 #ifdef USE_MSR_LIB |
456 #ifdef USE_MSR_LIB |
462 msr_rtlib_cleanup(); |
457 msr_rtlib_cleanup(); |
463 #endif |
458 #endif |
464 } |
459 } |
|
460 |
|
461 /*****************************************************************************/ |
465 |
462 |
466 MODULE_LICENSE("GPL"); |
463 MODULE_LICENSE("GPL"); |
467 MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>"); |
464 MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>"); |
468 MODULE_DESCRIPTION ("EtherCAT test environment"); |
465 MODULE_DESCRIPTION ("EtherCAT test environment"); |
469 |
466 |
470 module_init(init_module); |
467 module_init(init_module); |
471 module_exit(cleanup_module); |
468 module_exit(cleanup_module); |
472 |
469 |
473 |
470 /*****************************************************************************/ |
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|