Automation

Dependencies:   BSP_DISCO_F746NG LCD_DISCO_F746NG TS_DISCO_F746NG

Committer:
FernandoKoyanagi
Date:
Tue Sep 25 20:35:24 2018 +0000
Revision:
0:4b3704fab2b9
Automation First Version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
FernandoKoyanagi 0:4b3704fab2b9 1 #include "mbed.h"
FernandoKoyanagi 0:4b3704fab2b9 2 #include "TS_DISCO_F746NG.h"
FernandoKoyanagi 0:4b3704fab2b9 3 #include "LCD_DISCO_F746NG.h"
FernandoKoyanagi 0:4b3704fab2b9 4 #include "EthernetInterface.h"
FernandoKoyanagi 0:4b3704fab2b9 5 #include "TCPServer.h"
FernandoKoyanagi 0:4b3704fab2b9 6 #include "TCPSocket.h"
FernandoKoyanagi 0:4b3704fab2b9 7 #include <string>
FernandoKoyanagi 0:4b3704fab2b9 8
FernandoKoyanagi 0:4b3704fab2b9 9 #define BTN_R1_X 60 //coordenada X do botão relé 1
FernandoKoyanagi 0:4b3704fab2b9 10 #define BTN_R1_Y 130 //coordenada Y do botão relé 1
FernandoKoyanagi 0:4b3704fab2b9 11
FernandoKoyanagi 0:4b3704fab2b9 12 #define BTN_WIDTH 150 //largura do botão dos relés
FernandoKoyanagi 0:4b3704fab2b9 13 #define BTN_HEIGHT 75 //altura do botão dos relés
FernandoKoyanagi 0:4b3704fab2b9 14
FernandoKoyanagi 0:4b3704fab2b9 15 #define BTN_R2_X 50 + (BTN_R1_X + BTN_WIDTH) //coordenada X do botão relé 2
FernandoKoyanagi 0:4b3704fab2b9 16 #define BTN_R2_Y 130 //coordenada Y do botão relé 1
FernandoKoyanagi 0:4b3704fab2b9 17
FernandoKoyanagi 0:4b3704fab2b9 18 LCD_DISCO_F746NG lcd; //objeto que controla o display
FernandoKoyanagi 0:4b3704fab2b9 19 TS_DISCO_F746NG ts; //objeto que controla o touch do display
FernandoKoyanagi 0:4b3704fab2b9 20
FernandoKoyanagi 0:4b3704fab2b9 21 TCPSocket *clt_sock; //ponteiro para um socket TCP
FernandoKoyanagi 0:4b3704fab2b9 22
FernandoKoyanagi 0:4b3704fab2b9 23 //variáveis de controle de estado dos relés
FernandoKoyanagi 0:4b3704fab2b9 24 bool btnRelay1 = false;
FernandoKoyanagi 0:4b3704fab2b9 25 bool btnRelay2 = false;
FernandoKoyanagi 0:4b3704fab2b9 26
FernandoKoyanagi 0:4b3704fab2b9 27 /* PROTÓTIPO DAS FUNÇÕES */
FernandoKoyanagi 0:4b3704fab2b9 28 //desenha um um botão na tela com uma escrita no meio
FernandoKoyanagi 0:4b3704fab2b9 29 void drawButton(int x, int y, int width, int height, uint32_t color, char* title);
FernandoKoyanagi 0:4b3704fab2b9 30 //verifica se ocorreu um toque na tela
FernandoKoyanagi 0:4b3704fab2b9 31 void verifyTouch(int x, int y);
FernandoKoyanagi 0:4b3704fab2b9 32 //verifica se o toque foi em algum dos botões
FernandoKoyanagi 0:4b3704fab2b9 33 bool verifyTouchButton(int x, int y, int rectX, int rectY);
FernandoKoyanagi 0:4b3704fab2b9 34 //envia um pacote de comandos para o client
FernandoKoyanagi 0:4b3704fab2b9 35 bool sendPacket(char* packet);
FernandoKoyanagi 0:4b3704fab2b9 36 //escreve na tela o status da conexão (client conectado ou desconectado)
FernandoKoyanagi 0:4b3704fab2b9 37 void writeStatus(char* status, uint32_t color);
FernandoKoyanagi 0:4b3704fab2b9 38
FernandoKoyanagi 0:4b3704fab2b9 39
FernandoKoyanagi 0:4b3704fab2b9 40 int main()
FernandoKoyanagi 0:4b3704fab2b9 41 {
FernandoKoyanagi 0:4b3704fab2b9 42 TS_StateTypeDef TS_State; //estado do touch
FernandoKoyanagi 0:4b3704fab2b9 43 uint8_t status;
FernandoKoyanagi 0:4b3704fab2b9 44
FernandoKoyanagi 0:4b3704fab2b9 45 status = ts.Init(lcd.GetXSize(), lcd.GetYSize()); //inicializa o touch na tela toda
FernandoKoyanagi 0:4b3704fab2b9 46 //se deu erro ao inicializar -> mensagem de falha e pára a execução do programa
FernandoKoyanagi 0:4b3704fab2b9 47 if (status != TS_OK) {
FernandoKoyanagi 0:4b3704fab2b9 48 lcd.Clear(LCD_COLOR_RED);
FernandoKoyanagi 0:4b3704fab2b9 49 lcd.SetBackColor(LCD_COLOR_RED);
FernandoKoyanagi 0:4b3704fab2b9 50 lcd.SetTextColor(LCD_COLOR_WHITE);
FernandoKoyanagi 0:4b3704fab2b9 51 lcd.DisplayStringAt(0, LINE(5), (uint8_t *)"TOUCHSCREEN INIT FAIL", CENTER_MODE);
FernandoKoyanagi 0:4b3704fab2b9 52 wait(2);
FernandoKoyanagi 0:4b3704fab2b9 53 return 0;
FernandoKoyanagi 0:4b3704fab2b9 54 }
FernandoKoyanagi 0:4b3704fab2b9 55
FernandoKoyanagi 0:4b3704fab2b9 56 lcd.Clear(LCD_COLOR_BLUE); //limpa a tela e pinta de azul
FernandoKoyanagi 0:4b3704fab2b9 57 lcd.SetBackColor(LCD_COLOR_BLUE); //cor de fundo de texto
FernandoKoyanagi 0:4b3704fab2b9 58 lcd.SetTextColor(LCD_COLOR_YELLOW); //cor do texto
FernandoKoyanagi 0:4b3704fab2b9 59 lcd.DisplayStringAt(0, LINE(5), (uint8_t *)"TOUCHSCREEN INIT OK", CENTER_MODE);
FernandoKoyanagi 0:4b3704fab2b9 60
FernandoKoyanagi 0:4b3704fab2b9 61
FernandoKoyanagi 0:4b3704fab2b9 62 wait(1); //aguarda um segundo
FernandoKoyanagi 0:4b3704fab2b9 63 lcd.Clear(LCD_COLOR_BLUE); //limpa a tela
FernandoKoyanagi 0:4b3704fab2b9 64 lcd.SetTextColor(LCD_COLOR_WHITE); //seta cor do texto
FernandoKoyanagi 0:4b3704fab2b9 65 lcd.SetFont(&Font24); //seta tamanho da fonte
FernandoKoyanagi 0:4b3704fab2b9 66 lcd.DisplayStringAt(0, LINE(1), (uint8_t *)"AUTOMATION", CENTER_MODE);
FernandoKoyanagi 0:4b3704fab2b9 67
FernandoKoyanagi 0:4b3704fab2b9 68 lcd.DisplayStringAt(BTN_R1_X, LINE(4), (uint8_t *)"RELAY 1", LEFT_MODE);
FernandoKoyanagi 0:4b3704fab2b9 69 lcd.DisplayStringAt(BTN_R2_X, LINE(4), (uint8_t *)"RELAY 2", LEFT_MODE);
FernandoKoyanagi 0:4b3704fab2b9 70
FernandoKoyanagi 0:4b3704fab2b9 71 //cria os botões
FernandoKoyanagi 0:4b3704fab2b9 72 drawButton(BTN_R1_X, BTN_R1_Y, BTN_WIDTH, BTN_HEIGHT, LCD_COLOR_RED, "OFF");
FernandoKoyanagi 0:4b3704fab2b9 73 drawButton(BTN_R2_X, BTN_R2_Y, BTN_WIDTH, BTN_HEIGHT, LCD_COLOR_RED, "OFF");
FernandoKoyanagi 0:4b3704fab2b9 74
FernandoKoyanagi 0:4b3704fab2b9 75 //objeto que controla a rede ethernet
FernandoKoyanagi 0:4b3704fab2b9 76 EthernetInterface eth;
FernandoKoyanagi 0:4b3704fab2b9 77 eth.connect(); //conecta à rede
FernandoKoyanagi 0:4b3704fab2b9 78
FernandoKoyanagi 0:4b3704fab2b9 79 string ip = eth.get_ip_address(); //pega o IP recebido
FernandoKoyanagi 0:4b3704fab2b9 80 lcd.SetBackColor(LCD_COLOR_BLUE);
FernandoKoyanagi 0:4b3704fab2b9 81 lcd.SetFont(&Font8);
FernandoKoyanagi 0:4b3704fab2b9 82 //verifica se o IP é válido
FernandoKoyanagi 0:4b3704fab2b9 83 if(ip.length() <= 16 && ip.length() >= 7 ) {
FernandoKoyanagi 0:4b3704fab2b9 84 uint8_t text[18];
FernandoKoyanagi 0:4b3704fab2b9 85 sprintf((char*)text, "%s", eth.get_ip_address());
FernandoKoyanagi 0:4b3704fab2b9 86 lcd.DisplayStringAt(0, LINE(1), (uint8_t *)&text, LEFT_MODE); //imprime na tela o IP
FernandoKoyanagi 0:4b3704fab2b9 87 } else {
FernandoKoyanagi 0:4b3704fab2b9 88 lcd.DisplayStringAt(0, LINE(1), (uint8_t *)"IP Invalido", LEFT_MODE);
FernandoKoyanagi 0:4b3704fab2b9 89 }
FernandoKoyanagi 0:4b3704fab2b9 90
FernandoKoyanagi 0:4b3704fab2b9 91
FernandoKoyanagi 0:4b3704fab2b9 92 TCPServer srv; //objeto de controle do server
FernandoKoyanagi 0:4b3704fab2b9 93
FernandoKoyanagi 0:4b3704fab2b9 94 //abre um server na rede
FernandoKoyanagi 0:4b3704fab2b9 95 srv.open(&eth);
FernandoKoyanagi 0:4b3704fab2b9 96 //configura a porta TCP 80 para o server
FernandoKoyanagi 0:4b3704fab2b9 97 srv.bind(eth.get_ip_address(), 80);
FernandoKoyanagi 0:4b3704fab2b9 98 /* Can handle 1 simultaneous connections */
FernandoKoyanagi 0:4b3704fab2b9 99 //aguarda uma única conexão
FernandoKoyanagi 0:4b3704fab2b9 100 srv.listen(1);
FernandoKoyanagi 0:4b3704fab2b9 101
FernandoKoyanagi 0:4b3704fab2b9 102 while(1) {
FernandoKoyanagi 0:4b3704fab2b9 103 writeStatus("Desconectado", LCD_COLOR_RED); //imprime o estado de desconectado
FernandoKoyanagi 0:4b3704fab2b9 104 TCPSocket socket; //objeto TCPsocket
FernandoKoyanagi 0:4b3704fab2b9 105 SocketAddress clt_addr;
FernandoKoyanagi 0:4b3704fab2b9 106 clt_sock = &socket;
FernandoKoyanagi 0:4b3704fab2b9 107 printf("waiting \n");
FernandoKoyanagi 0:4b3704fab2b9 108 //fica aguardando um client conectar
FernandoKoyanagi 0:4b3704fab2b9 109 srv.accept(clt_sock, &clt_addr);
FernandoKoyanagi 0:4b3704fab2b9 110 printf("accept %s:%d\n", clt_addr.get_ip_address(), clt_addr.get_port());
FernandoKoyanagi 0:4b3704fab2b9 111
FernandoKoyanagi 0:4b3704fab2b9 112 //char buffer[3];
FernandoKoyanagi 0:4b3704fab2b9 113 //int n = clt_sock->recv(buffer, sizeof(buffer));
FernandoKoyanagi 0:4b3704fab2b9 114 //printf("N : %d\n",n);
FernandoKoyanagi 0:4b3704fab2b9 115 //buffer[n] = '\0';
FernandoKoyanagi 0:4b3704fab2b9 116 //printf("Received message from Client : %s\n",buffer);
FernandoKoyanagi 0:4b3704fab2b9 117
FernandoKoyanagi 0:4b3704fab2b9 118
FernandoKoyanagi 0:4b3704fab2b9 119 writeStatus("Conectado", LCD_COLOR_GREEN); //imprime o estado de conectado
FernandoKoyanagi 0:4b3704fab2b9 120 clt_sock->set_timeout(5000); //seta o timeout para o socket
FernandoKoyanagi 0:4b3704fab2b9 121 //enquanto o socket estiver aberto
FernandoKoyanagi 0:4b3704fab2b9 122 while(clt_sock != NULL) {
FernandoKoyanagi 0:4b3704fab2b9 123 ts.GetState(&TS_State); //registra o estado do touch
FernandoKoyanagi 0:4b3704fab2b9 124 //se algum toque na tela foi detectado
FernandoKoyanagi 0:4b3704fab2b9 125 if (TS_State.touchDetected) {
FernandoKoyanagi 0:4b3704fab2b9 126 uint8_t idx;
FernandoKoyanagi 0:4b3704fab2b9 127 //ao tocar a tela, pode ser que múltiplos toques foram dados, portanto faremos uma verificação
FernandoKoyanagi 0:4b3704fab2b9 128 for (idx = 0; idx < TS_State.touchDetected; idx++) {
FernandoKoyanagi 0:4b3704fab2b9 129 //se o evento do toque foi PRESS
FernandoKoyanagi 0:4b3704fab2b9 130 if(TS_State.touchEventId[idx] == TOUCH_EVENT_PRESS_DOWN) {
FernandoKoyanagi 0:4b3704fab2b9 131 verifyTouch(TS_State.touchX[idx], TS_State.touchY[idx]);//verifica se tocou em algum botão
FernandoKoyanagi 0:4b3704fab2b9 132 break;
FernandoKoyanagi 0:4b3704fab2b9 133 }//if
FernandoKoyanagi 0:4b3704fab2b9 134 }//for
FernandoKoyanagi 0:4b3704fab2b9 135 }//if
FernandoKoyanagi 0:4b3704fab2b9 136 }//while NULL
FernandoKoyanagi 0:4b3704fab2b9 137
FernandoKoyanagi 0:4b3704fab2b9 138 }//while 1
FernandoKoyanagi 0:4b3704fab2b9 139 }
FernandoKoyanagi 0:4b3704fab2b9 140
FernandoKoyanagi 0:4b3704fab2b9 141 //desenha um um botão na tela com uma escrita no meio
FernandoKoyanagi 0:4b3704fab2b9 142 void drawButton(int x, int y, int width, int height, uint32_t color, char* title)
FernandoKoyanagi 0:4b3704fab2b9 143 {
FernandoKoyanagi 0:4b3704fab2b9 144 lcd.SetFont(&Font24);
FernandoKoyanagi 0:4b3704fab2b9 145 lcd.SetTextColor(color);
FernandoKoyanagi 0:4b3704fab2b9 146 lcd.SetBackColor(color);
FernandoKoyanagi 0:4b3704fab2b9 147 lcd.FillRect(x, y, width, height);
FernandoKoyanagi 0:4b3704fab2b9 148 lcd.SetTextColor(LCD_COLOR_WHITE);
FernandoKoyanagi 0:4b3704fab2b9 149 uint8_t text[30];
FernandoKoyanagi 0:4b3704fab2b9 150 sprintf((char*)text, "%s", title);
FernandoKoyanagi 0:4b3704fab2b9 151 lcd.DisplayStringAt(x+50, y+(height/2)-10, (uint8_t *)&text, LEFT_MODE);
FernandoKoyanagi 0:4b3704fab2b9 152 }
FernandoKoyanagi 0:4b3704fab2b9 153
FernandoKoyanagi 0:4b3704fab2b9 154 //verifica se ocorreu um toque na tela
FernandoKoyanagi 0:4b3704fab2b9 155 void verifyTouch(int x, int y)
FernandoKoyanagi 0:4b3704fab2b9 156 {
FernandoKoyanagi 0:4b3704fab2b9 157 bool response = false; //guarda o status do envio da mensagem para o client
FernandoKoyanagi 0:4b3704fab2b9 158 //verifica se tocou no botão do relé 1
FernandoKoyanagi 0:4b3704fab2b9 159 if( verifyTouchButton(x, y, BTN_R1_X, BTN_R1_Y) ) {
FernandoKoyanagi 0:4b3704fab2b9 160 char* text;
FernandoKoyanagi 0:4b3704fab2b9 161 uint32_t color;
FernandoKoyanagi 0:4b3704fab2b9 162 //se o relé está ligado então desliga
FernandoKoyanagi 0:4b3704fab2b9 163 if(btnRelay1) {
FernandoKoyanagi 0:4b3704fab2b9 164 text = "OFF";
FernandoKoyanagi 0:4b3704fab2b9 165 color = LCD_COLOR_RED;
FernandoKoyanagi 0:4b3704fab2b9 166 response = sendPacket("#R1|0"); //envia comando para desligar o relé
FernandoKoyanagi 0:4b3704fab2b9 167 } else {
FernandoKoyanagi 0:4b3704fab2b9 168 //se relé está desligado, então liga
FernandoKoyanagi 0:4b3704fab2b9 169 text = "ON";
FernandoKoyanagi 0:4b3704fab2b9 170 color = LCD_COLOR_GREEN;
FernandoKoyanagi 0:4b3704fab2b9 171 response = sendPacket("#R1|1");//envia comando para ligar o relé
FernandoKoyanagi 0:4b3704fab2b9 172 }
FernandoKoyanagi 0:4b3704fab2b9 173 //se o envio foi confirmado
FernandoKoyanagi 0:4b3704fab2b9 174 if(response) {
FernandoKoyanagi 0:4b3704fab2b9 175 drawButton(BTN_R1_X, BTN_R1_Y, BTN_WIDTH, BTN_HEIGHT, color, text); //atualiza o botão
FernandoKoyanagi 0:4b3704fab2b9 176 btnRelay1 = !btnRelay1;
FernandoKoyanagi 0:4b3704fab2b9 177 }
FernandoKoyanagi 0:4b3704fab2b9 178
FernandoKoyanagi 0:4b3704fab2b9 179 }
FernandoKoyanagi 0:4b3704fab2b9 180 //verifica se tocou no botão do relé 1
FernandoKoyanagi 0:4b3704fab2b9 181 else if( verifyTouchButton(x,y,BTN_R2_X,BTN_R2_Y) ) {
FernandoKoyanagi 0:4b3704fab2b9 182 char* text;
FernandoKoyanagi 0:4b3704fab2b9 183 uint32_t color;
FernandoKoyanagi 0:4b3704fab2b9 184 //se o relé está ligado então desliga
FernandoKoyanagi 0:4b3704fab2b9 185 if(btnRelay2) {
FernandoKoyanagi 0:4b3704fab2b9 186 text = "OFF";
FernandoKoyanagi 0:4b3704fab2b9 187 color = LCD_COLOR_RED;
FernandoKoyanagi 0:4b3704fab2b9 188 response = sendPacket("#R2|0"); //envia comando para desligar o relé
FernandoKoyanagi 0:4b3704fab2b9 189 } else {
FernandoKoyanagi 0:4b3704fab2b9 190 //se relé está desligado, então liga
FernandoKoyanagi 0:4b3704fab2b9 191 text = "ON";
FernandoKoyanagi 0:4b3704fab2b9 192 color = LCD_COLOR_GREEN;
FernandoKoyanagi 0:4b3704fab2b9 193 response = sendPacket("#R2|1");//envia comando para ligar o relé
FernandoKoyanagi 0:4b3704fab2b9 194
FernandoKoyanagi 0:4b3704fab2b9 195 }
FernandoKoyanagi 0:4b3704fab2b9 196 //se o envio foi confirmado
FernandoKoyanagi 0:4b3704fab2b9 197 if(response) {
FernandoKoyanagi 0:4b3704fab2b9 198 drawButton(BTN_R2_X, BTN_R2_Y, BTN_WIDTH, BTN_HEIGHT, color, text);//atualiza o botão
FernandoKoyanagi 0:4b3704fab2b9 199 btnRelay2 = !btnRelay2;
FernandoKoyanagi 0:4b3704fab2b9 200 }
FernandoKoyanagi 0:4b3704fab2b9 201 }
FernandoKoyanagi 0:4b3704fab2b9 202 }
FernandoKoyanagi 0:4b3704fab2b9 203
FernandoKoyanagi 0:4b3704fab2b9 204 //verifica se o toque foi em algum dos botões
FernandoKoyanagi 0:4b3704fab2b9 205 bool verifyTouchButton(int x, int y, int rectX, int rectY)
FernandoKoyanagi 0:4b3704fab2b9 206 {
FernandoKoyanagi 0:4b3704fab2b9 207 printf("tocou : %d,%d %d,%d\n",x,y,rectX,rectY);
FernandoKoyanagi 0:4b3704fab2b9 208 if( (x >= rectX) && (x <= rectX + BTN_WIDTH) ) {
FernandoKoyanagi 0:4b3704fab2b9 209 if( (y >= rectY) && (y <= rectY + BTN_HEIGHT) )
FernandoKoyanagi 0:4b3704fab2b9 210 return true;
FernandoKoyanagi 0:4b3704fab2b9 211 }
FernandoKoyanagi 0:4b3704fab2b9 212 return false;
FernandoKoyanagi 0:4b3704fab2b9 213 }
FernandoKoyanagi 0:4b3704fab2b9 214
FernandoKoyanagi 0:4b3704fab2b9 215 //envia um pacote de comandos para o client
FernandoKoyanagi 0:4b3704fab2b9 216 bool sendPacket(char* packet)
FernandoKoyanagi 0:4b3704fab2b9 217 {
FernandoKoyanagi 0:4b3704fab2b9 218 char buffer[256];
FernandoKoyanagi 0:4b3704fab2b9 219 clt_sock->send(packet, strlen(packet)); //envia o comando
FernandoKoyanagi 0:4b3704fab2b9 220 int n = clt_sock->recv(buffer, sizeof(buffer)); //aguarda confirmação
FernandoKoyanagi 0:4b3704fab2b9 221 printf("N : %d\n",n);
FernandoKoyanagi 0:4b3704fab2b9 222 //se não chegou bytes então client não recebeu o pacote
FernandoKoyanagi 0:4b3704fab2b9 223 if (n <= 0) {
FernandoKoyanagi 0:4b3704fab2b9 224 clt_sock->close(); //fecha o socket
FernandoKoyanagi 0:4b3704fab2b9 225 clt_sock = NULL;
FernandoKoyanagi 0:4b3704fab2b9 226 return false;
FernandoKoyanagi 0:4b3704fab2b9 227 }
FernandoKoyanagi 0:4b3704fab2b9 228 // print received message to terminal
FernandoKoyanagi 0:4b3704fab2b9 229 buffer[n] = '\0';
FernandoKoyanagi 0:4b3704fab2b9 230 printf("Received message from Client : %s\n",buffer);
FernandoKoyanagi 0:4b3704fab2b9 231 return true;
FernandoKoyanagi 0:4b3704fab2b9 232 }
FernandoKoyanagi 0:4b3704fab2b9 233
FernandoKoyanagi 0:4b3704fab2b9 234 //escreve na tela o status da conexão (client conectado ou desconectado)
FernandoKoyanagi 0:4b3704fab2b9 235 void writeStatus(char* status, uint32_t color)
FernandoKoyanagi 0:4b3704fab2b9 236 {
FernandoKoyanagi 0:4b3704fab2b9 237 lcd.SetTextColor(color);
FernandoKoyanagi 0:4b3704fab2b9 238 lcd.SetBackColor(LCD_COLOR_BLUE);
FernandoKoyanagi 0:4b3704fab2b9 239 lcd.SetFont(&Font16);
FernandoKoyanagi 0:4b3704fab2b9 240 lcd.ClearStringLine(16); //limpa a linha que escreveremos
FernandoKoyanagi 0:4b3704fab2b9 241 uint8_t text[30];
FernandoKoyanagi 0:4b3704fab2b9 242 sprintf((char*)text, "%s", status);
FernandoKoyanagi 0:4b3704fab2b9 243 lcd.DisplayStringAtLine(16, (uint8_t *)&text);
FernandoKoyanagi 0:4b3704fab2b9 244 }
FernandoKoyanagi 0:4b3704fab2b9 245
FernandoKoyanagi 0:4b3704fab2b9 246
FernandoKoyanagi 0:4b3704fab2b9 247
FernandoKoyanagi 0:4b3704fab2b9 248