vrabete Junior 2


Joined: 21 Nov 2017 Posts: 25
|
Posted: 27/04/2019 20:26 Post subject: Profibus Communication |
|
|
COMUNIC.CPP
| Code: | #include "comunic.h"
#include <stdio>
#include <string>
long far* ceas,martor,timp;
unsigned char fc(){
// nu m-am prins cine e fc asa ca e tot timpul 1
return 1;
}
void init_port(int port){
if (port==1) port = 0x3f8;
else if (port==2) port = 0x2f8;
else return;
int DATE = port; //port date
int IER = port+1; //interrupt enable register
// int IIR = port+2; //interrupt identification register
int LCR = port+3; //line control register
int MCR = port+4; //modem control register
// int LSR = port+5; //line status register
// int MSR = port+6; //modem status register
// int SSR = port+7; //status send-rec
outportb(LCR, 0x80);//set Divisor Latch Access Bit (DLAB)
outportb(DATE, 6);//19200 biti/s, divisor latch low byte
outportb(IER, 0);//divisor latch high byte
outportb(LCR, 0x1b);//caracter de 8 biti, paritate pare, 1 bit de stop
// outportb(SSR, 0x01);//rec RS 485
// outportb(IER, 0x0);//dezactiveaza intreruperile
outportb(MCR, 0x0e);//activate OUT1, OUT2, DTR (rec)
// if((inportb(LSR) & 1) != 0) inportb(DATE);
}
unsigned char fcs(unsigned char pachet[])
{
unsigned char fcs = 0;
int i, lung;
switch(pachet[0]){
case SD1:
lung = 3;
i = 1;
break;
case SD2:
lung = pachet[1] + 3;
i = 4;
break;
case SD3:
lung = 11;
i = 1;
}
for (; i <lung>= TMOUT) return TIMEOUT;
}
*ch = inportb(port);
//printf("am primit : %c \n",*ch);
return RECVOK;
}
TEL *recv(int com,int *type){
if (com==1) com=0x3f8;
else if(com==2) com=0x2f8;
else {
*type = UNKNOWN_COM;
return NULL;
}
ceas=(long far *)MK_FP(0x0040,0x006c);
int i;
int front=0;
TEL *tel;
*type = TELEGRAMA_NECUNOSCUTA;
int err;
unsigned char ch; // caracter temp. pt. citire
unsigned char test=0; // tin calculul fcs-ului pt. pachetul primit
do {
err = recv_char(com,&ch);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch==255) front++;
}while (ch==255);
switch (ch) {
case SC: if (front) return NULL;
*type = T_RASPUNS_SCURT;
return NULL;
case SD4: if (!front) return NULL;
tel = (TEL *)malloc(sizeof(TEL));
if (tel==NULL) {
*type = MALLOC_ERROR;
return NULL;
}
err=recv_char(com,&tel->da);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&tel->sa);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
*type = TOKEN;
return tel;
case SD1: tel = (TEL *)malloc(sizeof(TEL));
if (tel==NULL) {
*type = MALLOC_ERROR;
return NULL;
}
*type = TELEGRAM_ERROR;
err=recv_char(com,&tel->da);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&tel->sa);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&ch); //fc
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
test = tel->da + tel->sa + ch;
err=recv_char(com,&ch); //fcs
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch!=test) { // testez fcs-ul
free(tel);
return NULL;
}
err=recv_char(com,&ch); //ED
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch!=ED) { free(tel); return NULL;}
if (front) *type = TI_FARA_DATE;
else *type = TR_FARA_DATE;
return tel;
case SD3: tel = (TEL *)malloc(sizeof(TEL));
if (tel==NULL) {
*type = MALLOC_ERROR;
return NULL;
}
*type = TELEGRAM_ERROR;
err=recv_char(com,&tel->da);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&tel->sa);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&ch); //fc
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
test = tel->da + tel->sa + ch;
tel->length = 8;
tel->data = (char *)malloc(sizeof(unsigned char)*8);
if (tel->data==NULL) {
free(tel);
*type = MALLOC_ERROR;
return NULL;
}
for(i=0;i<8>data[i]));
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
test += tel->data[i];
}
err=recv_char(com,&ch); //fcs
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch!=test) { // testez fcs-ul
free(tel->data);
free(tel);
return NULL;
}
err=recv_char(com,&ch); //ED
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch!=ED) { free(tel->data); free(tel); return NULL;}
if (front) *type = TI_LF_CU_DATE;
else *type = TR_LF_CU_DATE;
return tel;
case SD2: *type = TELEGRAM_ERROR;
unsigned char len;
err=recv_char(com,&len); // len1
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&ch); //len2
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (len!=ch) return NULL;
err=recv_char(com,&ch); //SD2
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch!=SD2) return NULL;
tel = (TEL *)malloc(sizeof(TEL));
if (tel==NULL) {
*type = MALLOC_ERROR;
return NULL;
}
err=recv_char(com,&tel->da);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&tel->sa);
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
err=recv_char(com,&ch); //fc
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
test = tel->da + tel->sa + ch;
tel->length = len-3;
tel->data = (char *)malloc(sizeof(unsigned char)*tel->length);
if (tel->data==NULL) {
*type = MALLOC_ERROR;
free(tel);
return NULL;
}
for(i=0;i<tel>length;i++){
err=recv_char(com,&(tel->data[i]));
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
test += tel->data[i];
}
err=recv_char(com,&ch); //fcs
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch!=test) { // testez fcs-ul
free(tel->data);
free(tel);
return NULL;
}
err=recv_char(com,&ch); //ED
if (err==TIMEOUT) {
*type=TIMEOUT;
return NULL;
}
if (ch!=ED) { free(tel->data); free(tel); return NULL;}
if (front) *type = TI_LV_CU_DATE;
else *type = TR_LV_CU_DATE;
return tel;
default : return NULL;
}
}
int send(int com,TEL *tel,int type){
int lung,i;
unsigned char FC;
int PORT;
if ((type!=T_RASPUNS_SCURT) && (tel==NULL)) return TELEGRAM_ERROR;
if (com==1) PORT=0x3f8;
else if(com==2) PORT=0x2f8;
else return UNKNOWN_COM;
if (((type==TI_LV_CU_DATE) || (type==TR_LV_CU_DATE)) && (tel->length>246)) return TELEGRAM_ERROR;
if (((type==TI_LV_CU_DATE) || (type==TR_LV_CU_DATE) ||
(type==TI_LF_CU_DATE) || (type==TR_LF_CU_DATE))
&& (!tel->data)) return TELEGRAM_ERROR;
switch (type) {
case TI_FARA_DATE : lung = 6; break;
case TR_FARA_DATE : lung = 6; break;
case TI_LF_CU_DATE : lung = 6 + 8; break;
case TR_LF_CU_DATE : lung = 6 + 8; break;
case TI_LV_CU_DATE : lung = 9 + tel->length; break;
case TR_LV_CU_DATE : lung = 9 + tel->length; break;
case TOKEN : lung = 3; break;
case T_RASPUNS_SCURT : lung = 1; break;
default : return TELEGRAMA_NECUNOSCUTA;
}
unsigned char* colet = (unsigned char *) malloc(sizeof(char)*lung);
if (pachet==NULL) return MALLOC_ERROR;
if ((type==TI_FARA_DATE) || (type==TR_FARA_DATE)) {
pachet[0] = SD1;
pachet[1] = tel->da;
pachet[2] = tel->sa;
pachet[3] = FC;
pachet[4] = fcs(pachet);
pachet[5] = ED;
} else if ((type==TI_LF_CU_DATE) || (type==TR_LF_CU_DATE)) {
pachet[0] = SD3;
pachet[1] = tel->da;
pachet[2] = tel->sa;
pachet[3] = FC;
for(int i=0;i<8>data[i];
pachet[12] = fcs(pachet);
pachet[13] = ED;
} else if ((type==TI_LV_CU_DATE) || (type==TR_LV_CU_DATE)) {
pachet[0] = SD2;
pachet[1] = (char) (tel->length+3);
pachet[2] = (char) (tel->length+3);
pachet[3] = SD2;
pachet[4] = tel->da;
pachet[5] = tel->sa;
pachet[6] = FC;
for(int i=0;i<tel>length;i++) pachet[7+i] = tel->data[i];
pachet[7+tel->length] = fcs(pachet);
pachet[7+tel->length+1] = ED;
} else if (type==TOKEN){
pachet[0]=SD4;
pachet[1]=tel->da;
pachet[2]=tel->sa;
} else if (type==T_RASPUNS_SCURT) {
pachet[0]=SC;
}
// init_port(PORT);
if ((type==TI_LV_CU_DATE) || (type==TI_FARA_DATE) || (type==TOKEN) ||
(type==TI_LF_CU_DATE)) for(i=0;i<5;i++) send_char(PORT,255);
for(i=0;i<lung;i++) send_char(PORT,pachet[i]);
free(pachet);
return type;
}
unsigned char *encode(unsigned char *text,int len,int* retlen){
int bitslen = len * 11;
*retlen = bitslen / 8;
int poz,pz,i,tmp,par,j;
if (bitslen % 8) *retlen = *retlen +1;
unsigned char * ret = (unsigned char *) malloc(sizeof(unsigned char) * *retlen);
pz = 7;
poz = 0;
ret[poz] = 0;
for(i = 0;i<len;i++){
ret[poz] = ret[poz] | (0<<pz); // bit START
pz --;
if (pz<0>=0;j--) {
tmp = (text[i]>>j)&1;
par = par ^ tmp;
tmp = tmp<<pz;
ret[poz] = ret[poz] | tmp;
pz --;
if (pz<0) {
poz++;
pz = 7;
ret[poz] = 0;
}
}
ret[poz] = ret[poz] | (par<<pz); // bit paritate
pz --;
if (pz<0) {
poz++;
pz = 7;
ret[poz] = 0;
}
ret[poz] = ret[poz] | (1<<pz); // bit STOP
pz --;
if (pz<0) {
poz++;
pz = 7;
ret[poz] = 0;
}
}
return ret;
}
unsigned char *decode(unsigned char *text,int len,int* retlen, int *error){
*error = 0;
int bitslen = len * 8;
*retlen = bitslen / 11;
int poz,pz,i,tmp,par,j;
unsigned char * ret = (unsigned char *) malloc(sizeof(unsigned char) * *retlen);
pz = 7;
poz = 0;
ret[poz] = 0;
for(i = 0;i<retlen>>pz) & 1;
if (tmp) *error = 1; // test bit start
pz --;
if (pz<0>=0;j--) {
tmp = (text[poz]>>pz)&1;
par = par ^ tmp;
tmp = tmp<<j;
ret[i] = ret[i] | tmp;
pz --;
if (pz<0>>pz) & 1;
if (tmp!=par) *error = 1; // test bit paritate
pz --;
if (pz<0>>pz) & 1;
if (!tmp) *error = 1; // test bit stop
pz --;
if (pz<0>>pz;
if (tmp) *error = 1; // nu a fost umplut cu 0 la sf
return ret;
}
|
COMUNIC.H
| Code: | #include <alloc>
#include <stdlib>
#include <dos>
#include <stdio>
#include <string>
#include <fcntl>
#include <io>
#include <sys>
#ifndef __PROFIBUS_SERIAL_COMUNICATION_H
#define __PROFIBUS_SERIAL_COMUNICATION_H
#define NR 2
//define start delimitators
#define SD1 0x10
#define SD2 0x68
#define SD3 0xa2
#define SD4 0xdc
//define end delimitator
#define ED 0x16
//define single caracter
#define SC 0xE5
//definitii pentru transmisie seriala
#define EMIS_G 0x20
#define RECP_C 0x1
#define TMOUT 1000 //time out pentru recv
//tipuri de telegrame
#define TI_FARA_DATE 1 // telegrama interogare cu lungime fixa fara date
#define TR_FARA_DATE 2 // telegrama raspuns cu lungime fixa fara date
#define TI_LF_CU_DATE 3 // telegrama interogare cu lungime fixa cu camp de date
#define TR_LF_CU_DATE 4 // telegrama raspuns cu extindere fixa cu camp de date
#define TI_LV_CU_DATE 5 // telegrama interogare cu mărime variabila cu camp de date
#define TR_LV_CU_DATE 6 // telegrama raspuns cu lungime variabila cu camp de date
#define TOKEN 11 // token
#define T_RASPUNS_SCURT 12 // telegrama raspuns redus
#define TELEGRAMA_NECUNOSCUTA 21;
#define TELEGRAM_ERROR -1 // formatul telegramei nu corespunde cu tipul ei
#define MALLOC_ERROR -2 // eroare la alocarea spatiului de memorie
#define UNKNOWN_COM -4 // com necunoscut
#define TIMEOUT -8
#define RECVOK 1
// definire structura telegrama...
// la telegramele fara date campurile data si length vor fi NULL, resp. 0
// la cele cu lungime fixa length va fi 8
typedef struct telegrama{
unsigned char sa; // source address
unsigned char da; // destination address
char *data; // the data
int length; // the length of the data
} TEL;
// functii de codare si decodare stringuri
unsigned char *encode(unsigned char *text,int len,int *retlen);
// codifica un text întrebuințând caracterele pe 11 biti ale PROFIBUS-ului
// completeaza cu biti de 0 pana ce umple ultimul caracter
// returneaza sirul codat
// parametrii: text - textul de codat
// len - mărimea textului de codat
// retlen - lungimea textului codat
unsigned char *decode(unsigned char *text,int len,int *retlen,int *error);
// decodifica un text din caracterele pe 11 biti ale PROFIBUS-ului in caractere naturale
// inversul lui encode
// returneaza sirul decodata
// parametrii: text - textul codat
// len - lungimea textului codat
// retlen - lungimea textului returnat
// error - 1 in caz ca a aparut eroare la decodare, 0 altfel
// functii de trimitere si receptie telegrame
int send(int com,TEL *tel,int type);
// parametrii:
// com : numarul comului : 0 pt COM1 si 1 pt COM2
// tel : telegrama... NULL pt TOKEN and SINGLE CHARACTER
// type : tipul telegramei
// returneaza coduri de eroare definite mai sus or tipul telegramei trimise
// or TELEGRAMA_NECUNOSCUTA
TEL *recv(int com,int *type);
// parametrii:
// com : numarul comului : 0 pt COM1 si 1 pt COM2
// type: tipul datagramei primite sau codurile de eroare definite mai sus
// returneaza un pointer la telegrama primita sau NULL in caz de eroare,
// token sau single caracter
// functia asculta pe COM si intoarce tipul telegramei primite in type
// returnand un pointer la telegrama daca e cazul
void init_port(int port);
// initializeaza portul 1 pt COM1 si 2 pt COM2
// functii implementate de modulul master
void init();
// initializeaza portul (apeleaza functia init_port)
// si pune poll_list pe 0
void broadcast();
// face broadcast de master - trimite la toti slaves adresa masterului
int request_status(int i);
// intoarce 1 sau 0 dupa cum slave-ul i este prezent sau nu
TEL* request_data(int i);
// cere slave-ului i sa se identifice
// intoarce telegrama de identificare primita de la slave
TEL* send_request_data(int i, int pos);
// masterul trimite slave-ului numele unui fisier apoi pozitia curenta de citire din acesta
// iar slave-ul ii trimite ce citeste din fisier
// functia intoarce telegrama primita de la slave
void explore_polllist();
// exploreaza poll_list si vede ce slave este prezent
void message_cycle();
// cea mai importanta functie a masterului - ciclul de mesaje
// se realizeaza mai intai servirea cererii de prioritate mare - transmitere fisier
// apoi se exploreaza poll_list
// si in final serviciul de identificare - prioritate joasa
#endif |
MASTER.CPP
| Code: |
#include "comunic.h"
#include "comunic.cpp"
#include <conio>
#define COM 1 //comul pe care se trimite/primeste
#define TS 0 //this station
int poll_list[NR];//poll list - activ=1 / inactiv=0
char *name;//numele fisierului
int slave;//cine este interogat
FILE *file;
void init()
{
int i;
init_port(COM);
poll_list[TS] = 1;
for(i = 0;i <NR>data = decode(telr->data, telr->length, &(telr->length), &error);
if(error == -1)
{
free(telr);
free(teli.data);
return NULL;
}
free(teli.data);
return telr;
}
TEL* send_request_data(int i, int pos)
{
TEL teli;
TEL *telr;
int type;
char *arg;
int error;
teli.sa = TS;
teli.da = i;
if(pos == 0)
{
teli.data = strdup(name);
teli.length = strlen(name);
teli.data = encode(teli.data, teli.length+1, &teli.length);
}
else
{
arg = (char*)malloc(sizeof(char) * 4);
sprintf(arg, "%d", pos);
teli.data = strdup(arg);
teli.length = strlen(arg);
teli.data = encode(teli.data, teli.length+1, &teli.length);
free(arg);
}
send(COM, &teli, TI_LV_CU_DATE);
telr = recv(COM, &type);
if(type != TR_LV_CU_DATE && poll_list[i] == 1)
{
send(COM, &teli, TI_LV_CU_DATE);
telr = recv(COM, &type);
if(type != TR_LV_CU_DATE)
{
free(telr);
free(teli.data);
return NULL;
}
}
if(type != TR_LV_CU_DATE && poll_list[i] == 0)
{
free(telr);
free(teli.data);
return NULL;
}
telr->data = decode(telr->data, telr->length, &(telr->length), &error);
if(error == -1)
{
free(telr);
free(teli.data);
return NULL;
}
free(teli.data);
return telr;
}
void explore_polllist()
{
int i;
for(i = 0;i <NR>data, "gata") != 0 && tel != NULL)
{
printf("Am primit\n");
pos += tel->length;
for(int i = 0;i<tel>length;i++)
if(tel->data[i] == 10) pos++;
//printf("%d ",tel->data[i]);
fwrite(tel->data, sizeof(char), tel->length, file);
free(tel);
tel = send_request_data(slave, pos);
}
if(tel == NULL) printf("\nServire esuata\n");
fclose(file);
//explorare poll list
printf("\nExplorare PollList:\n");
explore_polllist();
printf("\nServiciu de prioritate mica:\n");
for(i = 1;i <NR>data);
free(tel);
}
}
void main(int argc, char *argv[])
{
init();
clrscr();
printf("Vad cine este in retea\n");
int exist = 0;
while(exist == 0)
{
printf("again\n");
explore_polllist();
for(int i = 0;i < NR && exist == 0;i++)
if(poll_list[i] == 1 && i != TS) exist = 1;
}
//broadcast - anunt ca eu sunt master
printf("Broadcast\n");
broadcast();
if(argc == 3)
{
slave = atoi(argv[2]);//slave-ul
name = strdup(argv[1]);//numele fisierului
file = fopen(name, "w");
printf("Message cycle:\n");
message_cycle();
free(name);
}
} |
SLAVE.CPP
| Code: | #include "comunic.h"
#include "comunic.cpp"
#include <conio>
#define COM 1
#define TS 1
int file;
int master;
char *gata = "gata";
char *eu = "Eu_1";
void main()
{
clrscr();
TEL *tel;
TEL telr;
char *name;
int pos = 0;
int type;
int error;
unsigned char *s;
int len;
init_port(COM);
while(1)
{
telr.sa = TS;
//printf("again\n");
tel = recv(COM, &type);
//printf("%s\n",tel->data);
printf("tipul %d\n",type);
if(tel->da!=TS&&tel->da!=127)
{
printf("Ignor pachet adresa diferita\n");
}
else
switch(type)
{
case TI_LF_CU_DATE:
tel->data = decode(tel->data, tel->length, &tel->length, &error);
printf("info = %s %d\n", tel->data,tel->length);
if(error != -1)
if(strcmp(tel->data, "cine") == 0)
{
telr.data = strdup(eu);
telr.length = strlen(eu);
//telr.data[telr.length] = '\0';
telr.data = encode(telr.data, telr.length+1, &telr.length);
send(COM, &telr, TR_LF_CU_DATE);
free(telr.data);
free(tel);
exit(1);
}
else
{
master = atoi(tel->data);
telr.da = master;
free(tel);
printf("Master este %d\n", master);
}
break;
case TI_FARA_DATE:
telr.data = NULL;
telr.length = 0;
send(COM, &telr, TR_FARA_DATE);
free(tel);
//exit(1);
break;
case TI_LV_CU_DATE:
tel->data = decode(tel->data, tel->length, &tel->length, &error);
if(pos == 0)
{
char *name;
name = strdup(tel->data);
//name[tel->length]='\0';
printf("nume %s\n",name);
file = open(name,O_RDONLY);
free(name);
}
if(!eof(file))
{
if(pos == 0) pos++;
else
lseek(file, atol(tel->data), SEEK_SET);
char *buff;
buff=(char*)malloc(20);
int i=read(file,buff, sizeof(char)*20);
telr.data = strdup(buff);
telr.length=i;
telr.data[i]='\0';
for(i=0;i<telr>da == 127)
//la broadcast
{
// s = decode(tel->data, tel->length, &len, &error);
// strcpy(tel->data, s);
// tel->length = len;
// if(error != -1)
// {
master = atoi(tel->data);
telr.da = master;
printf("Master este %d\n", master);
// }
// else telr.da = 0;
}
if (type==21)
{
telr.data = NULL;
telr.length = 0;
send(COM, &telr, TR_FARA_DATE);
}
else
if(tel->da == TS)
{
if(type == TI_FARA_DATE)//la verificare situație de functionare
{
telr.data = NULL;
telr.length = 0;
send(COM, &telr, TR_FARA_DATE);
}
if(type == TI_LV_CU_DATE)//mi se cere fisierul
{
// s = decode(tel->data, tel->length, &len, &error);
// strcpy(tel->data, s);
// tel->length = len;
// if(error != -1)
// {
if(pos == 0)
{
pos++;
file = fopen(tel->data, "r");
}
///else
if(!feof(file))
{
fseek(file, atoi(tel->data), SEEK_SET);
telr.length = fread(telr.data, sizeof(char), 20, file);
//pos+=telr.length;
// telr.data = encode(telr.data, telr.length, &telr.length);
printf("%s\n",telr.data);
send(COM, &telr, TR_LV_CU_DATE);
}
else
{
strcpy(telr.data,gata);
// telr.data = encode(gata, 4, &telr.length);
send(COM, &telr, TR_LV_CU_DATE);
}
// }
/* else
{
telr.data = NULL;
telr.length = 0;
send(COM, &telr, TR_FARA_DATE);
}*/
/* }
if(type == TI_LF_CU_DATE)
{
//s = decode(tel->data, tel->length, &len, &error);
//strcpy(tel->data, s);
//tel->length = len;
//tel->data = decode(tel->data, tel->length, &(tel->length), &error);
// if(error != -1)
// {
if(strcmp(tel->data, "Cine esti?") == 0)
{
strcpy(telr.data,eu);
// telr.data = encode(eu, 9, &telr.length);
send(COM, &telr, TR_LF_CU_DATE);
}
/* }
else
{
telr.data = NULL;
telr.length = 0;
send(COM, &telr, TR_FARA_DATE);
}
}
}
}
} */
|
|
|