Modify the file main.cpp for M487

Dependencies:   BufferedSerial

Committer:
shliu1
Date:
Fri Sep 29 05:45:43 2017 +0000
Revision:
0:c89ccc69a48b
main.cpp adds the setting of TARGET_NUMAKER_PFM_M487 for M487

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shliu1 0:c89ccc69a48b 1 /*
shliu1 0:c89ccc69a48b 2 * Copyright (c) 2017 Nuvoton Tecnology Corp. All rights reserved.
shliu1 0:c89ccc69a48b 3 *
shliu1 0:c89ccc69a48b 4 * The code is forward data from UART port to Ethernet, and vice versa.
shliu1 0:c89ccc69a48b 5 *
shliu1 0:c89ccc69a48b 6 *
shliu1 0:c89ccc69a48b 7 */
shliu1 0:c89ccc69a48b 8
shliu1 0:c89ccc69a48b 9 #include "ste_config.h"
shliu1 0:c89ccc69a48b 10
shliu1 0:c89ccc69a48b 11 /* If define USE_STATIC_IP, specify the default IP address. */
shliu1 0:c89ccc69a48b 12 #if 0
shliu1 0:c89ccc69a48b 13 // private IP address for general purpose
shliu1 0:c89ccc69a48b 14 #define IP_ADDRESS "192.168.1.2"
shliu1 0:c89ccc69a48b 15 #define NETWORK_MASK "255.255.255.0"
shliu1 0:c89ccc69a48b 16 #define GATEWAY_ADDRESS "192.168.1.1"
shliu1 0:c89ccc69a48b 17 #else
shliu1 0:c89ccc69a48b 18 // private IP address only for test with Windows when DHCP server doesn't exist.
shliu1 0:c89ccc69a48b 19 #define IP_ADDRESS "169.254.108.2"
shliu1 0:c89ccc69a48b 20 #define NETWORK_MASK "255.255.0.0"
shliu1 0:c89ccc69a48b 21 #define GATEWAY_ADDRESS "169.254.108.1"
shliu1 0:c89ccc69a48b 22 #endif
shliu1 0:c89ccc69a48b 23
shliu1 0:c89ccc69a48b 24 /* Default configuration for network */
shliu1 0:c89ccc69a48b 25 S_NET_CONFIG net_config = {IP_STATIC_MODE, IP_ADDRESS, NETWORK_MASK, GATEWAY_ADDRESS};
shliu1 0:c89ccc69a48b 26
shliu1 0:c89ccc69a48b 27 #if defined (TARGET_NUMAKER_PFM_M487)
shliu1 0:c89ccc69a48b 28 BufferedSerial serial_0(PH_8, PH_9, 256, 4); // UART1
shliu1 0:c89ccc69a48b 29 BufferedSerial serial_1(PC_12, PC_11, 256, 4); // UART0
shliu1 0:c89ccc69a48b 30 BufferedSerial serial_2(PA_3, PA_2, 256, 4); // UART4
shliu1 0:c89ccc69a48b 31
shliu1 0:c89ccc69a48b 32 #elif defined (TARGET_NUMAKER_PFM_NUC472)
shliu1 0:c89ccc69a48b 33 BufferedSerial serial_0(PH_1, PH_0, 256, 4); // UART4
shliu1 0:c89ccc69a48b 34 BufferedSerial serial_1(PG_2, PG_1, 256, 4); // UART0
shliu1 0:c89ccc69a48b 35 BufferedSerial serial_2(PC_11, PC_10, 256, 4); // UART2
shliu1 0:c89ccc69a48b 36
shliu1 0:c89ccc69a48b 37 #elif defined (TARGET_NUMAKER_PFM_M453)
shliu1 0:c89ccc69a48b 38 #error The board has no Ethernet.
shliu1 0:c89ccc69a48b 39
shliu1 0:c89ccc69a48b 40 #else
shliu1 0:c89ccc69a48b 41 #error define UART ports for your board.
shliu1 0:c89ccc69a48b 42 #endif
shliu1 0:c89ccc69a48b 43
shliu1 0:c89ccc69a48b 44 /* Default configuration for network ports and UART ports, etc. */
shliu1 0:c89ccc69a48b 45 S_PORT_CONFIG port_config[MAX_UART_PORTS] = {
shliu1 0:c89ccc69a48b 46
shliu1 0:c89ccc69a48b 47 #if MAX_UART_PORTS == 1
shliu1 0:c89ccc69a48b 48 {NET_SERVER_MODE, NET_PORT_BASE, &serial_0, DEFAULT_UART_BAUD, 8, 1, SerialBase::None}
shliu1 0:c89ccc69a48b 49
shliu1 0:c89ccc69a48b 50 #elif MAX_UART_PORTS == 2
shliu1 0:c89ccc69a48b 51 {NET_SERVER_MODE, NET_PORT_BASE + 0, &serial_0, DEFAULT_UART_BAUD, 8, 1, SerialBase::None},
shliu1 0:c89ccc69a48b 52 {NET_SERVER_MODE, NET_PORT_BASE + 1, &serial_1, DEFAULT_UART_BAUD, 8, 1, SerialBase::None}
shliu1 0:c89ccc69a48b 53
shliu1 0:c89ccc69a48b 54 #elif MAX_UART_PORTS == 3
shliu1 0:c89ccc69a48b 55 {NET_SERVER_MODE, NET_PORT_BASE + 0, &serial_0, DEFAULT_UART_BAUD, 8, 1, SerialBase::None},
shliu1 0:c89ccc69a48b 56 {NET_SERVER_MODE, NET_PORT_BASE + 1, &serial_1, DEFAULT_UART_BAUD, 8, 1, SerialBase::None},
shliu1 0:c89ccc69a48b 57 {NET_SERVER_MODE, NET_PORT_BASE + 2, &serial_2, DEFAULT_UART_BAUD, 8, 1, SerialBase::None}
shliu1 0:c89ccc69a48b 58
shliu1 0:c89ccc69a48b 59 #else
shliu1 0:c89ccc69a48b 60 #error You have to define ports mapping table.
shliu1 0:c89ccc69a48b 61 #endif
shliu1 0:c89ccc69a48b 62 };
shliu1 0:c89ccc69a48b 63
shliu1 0:c89ccc69a48b 64 /* UART port to output debug message */
shliu1 0:c89ccc69a48b 65 RawSerial output(USBTX, USBRX); // UART3 on NuMaker-PFM-NUC472
shliu1 0:c89ccc69a48b 66 EthernetInterface eth;
shliu1 0:c89ccc69a48b 67
shliu1 0:c89ccc69a48b 68 #ifdef ENABLE_WEB_CONFIG
shliu1 0:c89ccc69a48b 69
shliu1 0:c89ccc69a48b 70 /* Declare the SD card as storage */
shliu1 0:c89ccc69a48b 71 NuSDBlockDevice bd;
shliu1 0:c89ccc69a48b 72 FATFileSystem fs("fs");
shliu1 0:c89ccc69a48b 73 bool SD_Card_Mounted = FALSE;
shliu1 0:c89ccc69a48b 74
shliu1 0:c89ccc69a48b 75 #endif
shliu1 0:c89ccc69a48b 76
shliu1 0:c89ccc69a48b 77 /* --- --- */
shliu1 0:c89ccc69a48b 78
shliu1 0:c89ccc69a48b 79 /*
shliu1 0:c89ccc69a48b 80 * Forward serial port data to ethernet, and vice versa.
shliu1 0:c89ccc69a48b 81 *
shliu1 0:c89ccc69a48b 82 */
shliu1 0:c89ccc69a48b 83 void exchange_data(S_PORT_CONFIG *pmap, TCPSocket *psocket)
shliu1 0:c89ccc69a48b 84 {
shliu1 0:c89ccc69a48b 85 unsigned char n_buf[256];
shliu1 0:c89ccc69a48b 86 unsigned char s_buf[256];
shliu1 0:c89ccc69a48b 87 int n_len = 0, n_index = 0;
shliu1 0:c89ccc69a48b 88 int s_len = 0, s_index = 0;
shliu1 0:c89ccc69a48b 89
shliu1 0:c89ccc69a48b 90 while(1)
shliu1 0:c89ccc69a48b 91 {
shliu1 0:c89ccc69a48b 92 /*** Network to Serial ***/
shliu1 0:c89ccc69a48b 93
shliu1 0:c89ccc69a48b 94 if (n_len < 0 || n_len == n_index)
shliu1 0:c89ccc69a48b 95 {
shliu1 0:c89ccc69a48b 96 // net buffer is empty, try to get new data from network.
shliu1 0:c89ccc69a48b 97 n_len = psocket->recv(n_buf, sizeof(n_buf));
shliu1 0:c89ccc69a48b 98 if (n_len == NSAPI_ERROR_WOULD_BLOCK)
shliu1 0:c89ccc69a48b 99 {
shliu1 0:c89ccc69a48b 100 }
shliu1 0:c89ccc69a48b 101 else if (n_len < 0)
shliu1 0:c89ccc69a48b 102 {
shliu1 0:c89ccc69a48b 103 printf("Socket Recv Err (%d)\r\n", n_len);
shliu1 0:c89ccc69a48b 104 psocket->close();
shliu1 0:c89ccc69a48b 105 break;
shliu1 0:c89ccc69a48b 106 }
shliu1 0:c89ccc69a48b 107 else
shliu1 0:c89ccc69a48b 108 {
shliu1 0:c89ccc69a48b 109 n_index = 0;
shliu1 0:c89ccc69a48b 110 }
shliu1 0:c89ccc69a48b 111 }
shliu1 0:c89ccc69a48b 112 else
shliu1 0:c89ccc69a48b 113 {
shliu1 0:c89ccc69a48b 114 // send data to serial port.
shliu1 0:c89ccc69a48b 115 for(;n_index < n_len && pmap->pserial->writeable(); n_index++)
shliu1 0:c89ccc69a48b 116 {
shliu1 0:c89ccc69a48b 117 pmap->pserial->putc(n_buf[n_index]);
shliu1 0:c89ccc69a48b 118 }
shliu1 0:c89ccc69a48b 119 }
shliu1 0:c89ccc69a48b 120
shliu1 0:c89ccc69a48b 121 /*** Serial to Network ***/
shliu1 0:c89ccc69a48b 122
shliu1 0:c89ccc69a48b 123 if (pmap->pserial->readable())
shliu1 0:c89ccc69a48b 124 {
shliu1 0:c89ccc69a48b 125 // try to get more data from serial port
shliu1 0:c89ccc69a48b 126 for(s_index = 0; s_index < sizeof(s_buf) && pmap->pserial->readable(); s_index++)
shliu1 0:c89ccc69a48b 127 s_buf[s_index] = pmap->pserial->getc();
shliu1 0:c89ccc69a48b 128
shliu1 0:c89ccc69a48b 129 // send all data to network.
shliu1 0:c89ccc69a48b 130 if (s_index > 0)
shliu1 0:c89ccc69a48b 131 {
shliu1 0:c89ccc69a48b 132 s_len = psocket->send(s_buf, s_index);
shliu1 0:c89ccc69a48b 133 if (s_len == NSAPI_ERROR_WOULD_BLOCK)
shliu1 0:c89ccc69a48b 134 {
shliu1 0:c89ccc69a48b 135 printf("Socket Send no block.\r\n");
shliu1 0:c89ccc69a48b 136 }
shliu1 0:c89ccc69a48b 137 else if (s_len < 0)
shliu1 0:c89ccc69a48b 138 {
shliu1 0:c89ccc69a48b 139 printf("Socket Send Err (%d)\r\n", s_len);
shliu1 0:c89ccc69a48b 140 psocket->close();
shliu1 0:c89ccc69a48b 141 break;
shliu1 0:c89ccc69a48b 142 }
shliu1 0:c89ccc69a48b 143 else if (s_len != s_index)
shliu1 0:c89ccc69a48b 144 {
shliu1 0:c89ccc69a48b 145 printf("Socket Send not complete.\r\n");
shliu1 0:c89ccc69a48b 146 psocket->close();
shliu1 0:c89ccc69a48b 147 break;
shliu1 0:c89ccc69a48b 148 }
shliu1 0:c89ccc69a48b 149 }
shliu1 0:c89ccc69a48b 150 }
shliu1 0:c89ccc69a48b 151 }
shliu1 0:c89ccc69a48b 152 }
shliu1 0:c89ccc69a48b 153
shliu1 0:c89ccc69a48b 154 void bridge_net_client(S_PORT_CONFIG *pmap)
shliu1 0:c89ccc69a48b 155 {
shliu1 0:c89ccc69a48b 156 TCPSocket socket;
shliu1 0:c89ccc69a48b 157 SocketAddress server_address;
shliu1 0:c89ccc69a48b 158 nsapi_error_t err;
shliu1 0:c89ccc69a48b 159
shliu1 0:c89ccc69a48b 160 printf("Thread %x in TCP client mode.\r\n", (unsigned int)pmap);
shliu1 0:c89ccc69a48b 161
shliu1 0:c89ccc69a48b 162 if ((err=socket.open(&eth)) < 0)
shliu1 0:c89ccc69a48b 163 {
shliu1 0:c89ccc69a48b 164 printf("TCP socket can't open (%d)(%x).\r\n", err, (unsigned int)pmap);
shliu1 0:c89ccc69a48b 165 return;
shliu1 0:c89ccc69a48b 166 }
shliu1 0:c89ccc69a48b 167
shliu1 0:c89ccc69a48b 168 printf("Connecting server %s:%d ...\r\n", pmap->server_addr, pmap->server_port);
shliu1 0:c89ccc69a48b 169 while(1)
shliu1 0:c89ccc69a48b 170 {
shliu1 0:c89ccc69a48b 171 if ((err=socket.connect(pmap->server_addr, pmap->server_port)) >= 0)
shliu1 0:c89ccc69a48b 172 break;
shliu1 0:c89ccc69a48b 173 }
shliu1 0:c89ccc69a48b 174
shliu1 0:c89ccc69a48b 175 printf("\r\nConnected.");
shliu1 0:c89ccc69a48b 176
shliu1 0:c89ccc69a48b 177 socket.set_timeout(1);
shliu1 0:c89ccc69a48b 178 exchange_data(pmap, &socket);
shliu1 0:c89ccc69a48b 179 }
shliu1 0:c89ccc69a48b 180
shliu1 0:c89ccc69a48b 181 void bridge_net_server(S_PORT_CONFIG *pmap)
shliu1 0:c89ccc69a48b 182 {
shliu1 0:c89ccc69a48b 183 TCPServer tcp_server;
shliu1 0:c89ccc69a48b 184 TCPSocket client_socket;
shliu1 0:c89ccc69a48b 185 SocketAddress client_address;
shliu1 0:c89ccc69a48b 186 nsapi_error_t err;
shliu1 0:c89ccc69a48b 187
shliu1 0:c89ccc69a48b 188 printf("Thread %x in TCP server mode.\r\n", (unsigned int)pmap);
shliu1 0:c89ccc69a48b 189
shliu1 0:c89ccc69a48b 190 if ((err=tcp_server.open(&eth)) < 0)
shliu1 0:c89ccc69a48b 191 {
shliu1 0:c89ccc69a48b 192 printf("TCP server can't open (%d)(%x).\r\n", err, (unsigned int)pmap);
shliu1 0:c89ccc69a48b 193 return;
shliu1 0:c89ccc69a48b 194 }
shliu1 0:c89ccc69a48b 195 if ((err=tcp_server.bind(eth.get_ip_address(), pmap->port)) < 0)
shliu1 0:c89ccc69a48b 196 {
shliu1 0:c89ccc69a48b 197 printf("TCP server can't bind address and port (%d)(%x).\r\n", err, (unsigned int)pmap);
shliu1 0:c89ccc69a48b 198 return;
shliu1 0:c89ccc69a48b 199 }
shliu1 0:c89ccc69a48b 200 if ((err=tcp_server.listen(1)) < 0)
shliu1 0:c89ccc69a48b 201 {
shliu1 0:c89ccc69a48b 202 printf("TCP server can't listen (%d)(%x).\r\n", err, (unsigned int)pmap);
shliu1 0:c89ccc69a48b 203 return;
shliu1 0:c89ccc69a48b 204 }
shliu1 0:c89ccc69a48b 205
shliu1 0:c89ccc69a48b 206 client_socket.set_timeout(1);
shliu1 0:c89ccc69a48b 207
shliu1 0:c89ccc69a48b 208 while(1)
shliu1 0:c89ccc69a48b 209 {
shliu1 0:c89ccc69a48b 210 if ((err=tcp_server.accept(&client_socket, &client_address)) < 0)
shliu1 0:c89ccc69a48b 211 {
shliu1 0:c89ccc69a48b 212 printf("TCP server fail to accept connection (%d)(%x).\r\n", err, (unsigned int)pmap);
shliu1 0:c89ccc69a48b 213 return;
shliu1 0:c89ccc69a48b 214 }
shliu1 0:c89ccc69a48b 215
shliu1 0:c89ccc69a48b 216 printf("Connect (%d) from %s:%d ...\r\n", pmap->port, client_address.get_ip_address(), client_address.get_port());
shliu1 0:c89ccc69a48b 217
shliu1 0:c89ccc69a48b 218 exchange_data(pmap, &client_socket);
shliu1 0:c89ccc69a48b 219 }
shliu1 0:c89ccc69a48b 220 }
shliu1 0:c89ccc69a48b 221
shliu1 0:c89ccc69a48b 222 int main()
shliu1 0:c89ccc69a48b 223 {
shliu1 0:c89ccc69a48b 224 /* Set the console baud-rate */
shliu1 0:c89ccc69a48b 225 output.baud(115200);
shliu1 0:c89ccc69a48b 226 printf("\r\nmbed OS version is %d.\r\n", MBED_VERSION);
shliu1 0:c89ccc69a48b 227 printf("Start Serial-to-Ethernet...\r\n");
shliu1 0:c89ccc69a48b 228
shliu1 0:c89ccc69a48b 229 #ifdef ENABLE_WEB_CONFIG
shliu1 0:c89ccc69a48b 230
shliu1 0:c89ccc69a48b 231 /* Restore configuration from SD card */
shliu1 0:c89ccc69a48b 232
shliu1 0:c89ccc69a48b 233 SD_Card_Mounted = (fs.mount(&bd) >= 0);
shliu1 0:c89ccc69a48b 234 if (SD_Card_Mounted)
shliu1 0:c89ccc69a48b 235 {
shliu1 0:c89ccc69a48b 236 FILE *fd = fopen(SER_CONFIG_FILE, "r");
shliu1 0:c89ccc69a48b 237 if (fd != NULL)
shliu1 0:c89ccc69a48b 238 {
shliu1 0:c89ccc69a48b 239 char pBuf[sizeof(port_config)+2];
shliu1 0:c89ccc69a48b 240 int len = fread(pBuf, 1, sizeof(port_config)+2, fd);
shliu1 0:c89ccc69a48b 241 if (len == (sizeof(port_config)+2) && pBuf[0] == 'N' && pBuf[1] == 'T')
shliu1 0:c89ccc69a48b 242 {
shliu1 0:c89ccc69a48b 243 printf("Set Serial ports from config file in SD card.\r\n");
shliu1 0:c89ccc69a48b 244 memcpy(port_config, pBuf+2, sizeof(port_config));
shliu1 0:c89ccc69a48b 245 }
shliu1 0:c89ccc69a48b 246 else
shliu1 0:c89ccc69a48b 247 printf("Incorrect serial config file.\r\n");
shliu1 0:c89ccc69a48b 248
shliu1 0:c89ccc69a48b 249 fclose(fd);
shliu1 0:c89ccc69a48b 250 }
shliu1 0:c89ccc69a48b 251 else
shliu1 0:c89ccc69a48b 252 printf("Can't open serial config file.\r\n");
shliu1 0:c89ccc69a48b 253
shliu1 0:c89ccc69a48b 254 fd = fopen(NET_CONFIG_FILE, "r");
shliu1 0:c89ccc69a48b 255 if (fd != NULL)
shliu1 0:c89ccc69a48b 256 {
shliu1 0:c89ccc69a48b 257 char pBuf[sizeof(net_config)+2];
shliu1 0:c89ccc69a48b 258 int len = fread(pBuf, 1, sizeof(net_config)+2, fd);
shliu1 0:c89ccc69a48b 259 if (len == (sizeof(net_config)+2) && pBuf[0] == 'N' && pBuf[1] == 'T')
shliu1 0:c89ccc69a48b 260 {
shliu1 0:c89ccc69a48b 261 printf("Set network from config file in SD card.\r\n");
shliu1 0:c89ccc69a48b 262 memcpy(&net_config, pBuf+2, sizeof(net_config));
shliu1 0:c89ccc69a48b 263 }
shliu1 0:c89ccc69a48b 264 else
shliu1 0:c89ccc69a48b 265 printf("Incorrect network config file.\r\n");
shliu1 0:c89ccc69a48b 266
shliu1 0:c89ccc69a48b 267 fclose(fd);
shliu1 0:c89ccc69a48b 268 }
shliu1 0:c89ccc69a48b 269 else
shliu1 0:c89ccc69a48b 270 printf("Can't open network config file.\r\n");
shliu1 0:c89ccc69a48b 271 }
shliu1 0:c89ccc69a48b 272 else
shliu1 0:c89ccc69a48b 273 {
shliu1 0:c89ccc69a48b 274 printf("Can't find SD card.\r\n");
shliu1 0:c89ccc69a48b 275 }
shliu1 0:c89ccc69a48b 276
shliu1 0:c89ccc69a48b 277 #endif
shliu1 0:c89ccc69a48b 278
shliu1 0:c89ccc69a48b 279 printf("Configure UART ports...\r\n");
shliu1 0:c89ccc69a48b 280 for(int i=0; i<MAX_UART_PORTS; i++)
shliu1 0:c89ccc69a48b 281 {
shliu1 0:c89ccc69a48b 282 port_config[i].pserial->baud(port_config[i].baud);
shliu1 0:c89ccc69a48b 283 port_config[i].pserial->format(port_config[i].data, port_config[i].parity, port_config[i].stop);
shliu1 0:c89ccc69a48b 284 }
shliu1 0:c89ccc69a48b 285
shliu1 0:c89ccc69a48b 286 if (net_config.mode == IP_STATIC_MODE)
shliu1 0:c89ccc69a48b 287 {
shliu1 0:c89ccc69a48b 288 printf("Start Ethernet in Static mode.\r\n");
shliu1 0:c89ccc69a48b 289 eth.disconnect();
shliu1 0:c89ccc69a48b 290 ((NetworkInterface *)&eth)->set_network(net_config.ip, net_config.mask, net_config.gateway);
shliu1 0:c89ccc69a48b 291 }
shliu1 0:c89ccc69a48b 292 else
shliu1 0:c89ccc69a48b 293 printf("Start Ethernet in DHCP mode.\r\n");
shliu1 0:c89ccc69a48b 294
shliu1 0:c89ccc69a48b 295 eth.connect();
shliu1 0:c89ccc69a48b 296 printf("IP Address is %s\r\n", eth.get_ip_address());
shliu1 0:c89ccc69a48b 297
shliu1 0:c89ccc69a48b 298 Thread thread[MAX_UART_PORTS];
shliu1 0:c89ccc69a48b 299
shliu1 0:c89ccc69a48b 300 // Folk thread for each port
shliu1 0:c89ccc69a48b 301 for(int i=0; i<MAX_UART_PORTS; i++)
shliu1 0:c89ccc69a48b 302 {
shliu1 0:c89ccc69a48b 303 if (port_config[i].mode == NET_SERVER_MODE)
shliu1 0:c89ccc69a48b 304 {
shliu1 0:c89ccc69a48b 305 thread[i].start(callback(bridge_net_server, &(port_config[i])));
shliu1 0:c89ccc69a48b 306 }
shliu1 0:c89ccc69a48b 307 else // if (port_config[i].mode == TCP_CLIENT_MODE)
shliu1 0:c89ccc69a48b 308 {
shliu1 0:c89ccc69a48b 309 thread[i].start(callback(bridge_net_client, &(port_config[i])));
shliu1 0:c89ccc69a48b 310 }
shliu1 0:c89ccc69a48b 311 }
shliu1 0:c89ccc69a48b 312
shliu1 0:c89ccc69a48b 313 #ifdef ENABLE_WEB_CONFIG
shliu1 0:c89ccc69a48b 314
shliu1 0:c89ccc69a48b 315 /*** main thread to be a web server for configuration ***/
shliu1 0:c89ccc69a48b 316 start_httpd();
shliu1 0:c89ccc69a48b 317
shliu1 0:c89ccc69a48b 318 #endif
shliu1 0:c89ccc69a48b 319
shliu1 0:c89ccc69a48b 320 while(1);
shliu1 0:c89ccc69a48b 321
shliu1 0:c89ccc69a48b 322 /* end of main task */
shliu1 0:c89ccc69a48b 323 //eth.disconnect();
shliu1 0:c89ccc69a48b 324 }