NuMaker Transfer data UART to Ethernet
Fork of Serial-to-Ethernet by
Diff: uweb_server.cpp
- Revision:
- 0:11bc39d0f367
- Child:
- 6:014b1a469aed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uweb_server.cpp Fri May 05 07:40:19 2017 +0000 @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2017 Nuvoton Tecnology Corp. All rights reserved. + * + * micro web server for serial to Ethernet configuration. + * + * + */ + +#include <string.h> +#include "ste_config.h" + +#ifdef ENABLE_WEB_CONFIG + +#define PAGE_HEADER \ +"<html><head>\r\n" \ +"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n" \ +"<title>Serial to Ethernet Configuration</title>\r\n" \ +"</head>\r\n" + +#define PAGE_HEADER_FOR_REFRESH \ +"<html><head>\r\n" \ +"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n" \ +"<meta http-equiv=\"refresh\" content=\"10; url=index.html\" />\r\n" \ +"<title>Serial to Ethernet Configuration</title>\r\n" \ +"</head>\r\n" + +#define PAGE_RESTART_FORM \ +"<form action=\"/config.html\" method=\"GET\">\r\n" \ +"<input type=\"hidden\" name=\"restart\" value=\"1\">\r\n" \ +"<input type=\"submit\" value=\"Restart\"> </form>\r\n" + +#define PAGE_RESETCONF_FORM \ +"<form action=\"/config.html\" method=\"GET\">\r\n" \ +"<input type=\"hidden\" name=\"resetconf\" value=\"1\">\r\n" \ +"<input type=\"submit\" value=\"Reset Config\"> </form>\r\n" + +#define PAGE_CONFIG_FORM_HEAD \ +"<form action=\"/config.html\" method=\"GET\">\r\n" + +#define PAGE_CONFIG_SERIAL_FORM \ +"<input type=\"hidden\" name=\"uart_port\" value=\"%d\">\r\n" \ +" Baud <select type=\"text\" name=\"baud\">\r\n \ + <option value=\"115200\"%s>115200</option>\r\n \ + <option value=\"9600\"%s>9600</option>\r\n \ + <option value=\"4800\"%s>4800</option>\r\n \ + <option value=\"2400\"%s>2400</option>\r\n \ + </select>   \r\n \ + Data bits <select type=\"text\" name=\"databits\">\r\n \ + <option value=\"8\"%s>8</option>\r\n \ + <option value=\"7\"%s>7</option>\r\n \ + <option value=\"6\"%s>6</option>\r\n \ + <option value=\"5\"%s>5</option>\r\n \ + </select> \r\n \ + Parity <select type=\"text\" name=\"parity\">\r\n \ + <option value=\"0\"%s>None</option>\r\n \ + <option value=\"1\"%s>Odd</option>\r\n \ + <option value=\"2\"%s>Even</option>\r\n \ + </select> \r\n \ + Stop bits <select type=\"text\" name=\"stopbits\">\r\n \ + <option value=\"1\"%s>1</option>\r\n \ + <option value=\"2\"%s>2</option>\r\n \ + </select> <br>\r\n \ +Network mode <select type=\"text\" name=\"netmode\">\r\n \ + <option value=\"0\"%s>Server</option>\r\n \ + <option value=\"1\"%s>Client</option>\r\n \ + </select> <br> Set following fields for Client only. <br>\r\n \ +Server address <input type=\"text\" name=\"sipaddr\" size=\"16\" value=\"%s\">   \r\n \ +Server port <input type=\"text\" name=\"sport\" size=\"5\" value=\"%d\">\r\n" + +#define PAGE_CONFIG_NET_FORM \ +"<input type=\"hidden\" name=\"net_config\" value=\"1\">\r\n \ +IP Address Mode <select type=\"text\" name=\"ipmode\">\r\n \ + <option value=\"0\"%s>Static</option>\r\n \ + <option value=\"1\"%s>DHCP</option>\r\n \ + </select> <br> Set following fields for Static IP only. <br>\r\n \ +IP Address <input type=\"text\" name=\"ipaddr\" size=\"16\" value=\"%s\">\r\n \ +Netmask <input type=\"text\" name=\"mask\" size=\"16\" value=\"%s\">\r\n \ +Gateway Address <input type=\"text\" name=\"gwaddr\" size=\"16\" value=\"%s\">\r\n" + +typedef void (*PROC_PAGE_PFN)(TCPSocket *, char *); + +typedef struct { + const char *vhtmlpage; // virtual page name, eg. index.html ... + PROC_PAGE_PFN pfn; +} S_WEB_PAGE_SETTING; + +extern void process_http_index_html(TCPSocket *, char *); +extern void process_http_restart_html(TCPSocket *, char *); +extern void process_http_resetconf_html(TCPSocket *, char *); +extern void process_http_config_html(TCPSocket *, char *); +extern void process_http_err_html(TCPSocket *, char *); + +#define MAX_WEB_GET_PAGE_SETTINGS 5 +S_WEB_PAGE_SETTING web_get_pages_setings[MAX_WEB_GET_PAGE_SETTINGS] = { + {"/ ", process_http_index_html}, + {"/index.html ", process_http_index_html}, + {"/config.html?restart=1 ", process_http_restart_html}, + {"/config.html?resetconf=1 ", process_http_resetconf_html}, + {"/config.html?", process_http_config_html} +}; + +#define MAX_WEB_POST_PAGE_SETTINGS 1 +S_WEB_PAGE_SETTING web_post_pages_setings[MAX_WEB_POST_PAGE_SETTINGS] = { + {"/config.html ", process_http_config_html}, +}; + +typedef struct { + int type; // 0: integer, 1:string + int value; // integer value for integer type + char *str; // point to string for string type + int min; + int max; // max value of integer or max length of string + const char *cmd; + int cmd_len; +} S_WEB_CMD_PARAMS; + +#define MAX_WEB_CMD_PARAMS 13 +S_WEB_CMD_PARAMS web_cmd_params[MAX_WEB_CMD_PARAMS] = { + {0, 0, NULL, 1, MAX_UART_PORTS, "uart_port=", 10}, + {0, 0, NULL, 2400, 115200, "baud=", 5}, + {0, 0, NULL, 5, 8, "databits=", 9}, + {0, 0, NULL, 0, 2, "parity=", 7}, + {0, 0, NULL, 1, 2, "stopbits=", 9}, + {0, 0, NULL, 0, 1, "netmode=", 8}, + {1, 0, NULL, 0, 16, "sipaddr=", 8}, + {0, 0, NULL, 0, 65535, "sport=", 6}, + {0, 0, NULL, 1, 1, "net_config=", 11}, + {0, 0, NULL, 0, 1, "ipmode=", 7}, + {1, 0, NULL, 0, 1, "ipaddr=", 7}, + {1, 0, NULL, 0, 1, "mask=", 5}, + {1, 0, NULL, 0, 1, "gwaddr=", 7} +}; + +const char *parity_string[] = {"None", "Odd", "Even"}; +const char *netmode_string[] = {"Server", "Client"}; +const char *ipmode_string[] = {"Static", "DHCP"}; + + +int inspect_each_setting(char *pbuf) +{ + int i; + int v; + + for(i=0; i<MAX_WEB_CMD_PARAMS; i++) + { + web_cmd_params[i].value = 0; + web_cmd_params[i].str = NULL; + } + + while(*pbuf != '\0') + { + for(i=0; i<MAX_WEB_CMD_PARAMS; i++) + { + if (strncmp(pbuf, web_cmd_params[i].cmd, web_cmd_params[i].cmd_len) == 0) + { + pbuf += web_cmd_params[i].cmd_len; + + if (web_cmd_params[i].type == 0) + { + v = atoi(pbuf); + if (v >= web_cmd_params[i].min && v <= web_cmd_params[i].max) + web_cmd_params[i].value = v; + } + else + { + web_cmd_params[i].str = pbuf; + } + + for(; *pbuf != '\0'; pbuf++) + { + if (*pbuf == '&') + { + *pbuf++ = '\0'; + break; + } + else if (*pbuf == ' ') + { + *pbuf = '\0'; + break; + } +// else if (*pbuf == '\r') +// { +// *pbuf++ = '\0'; +// if (*pbuf == '\n') +// *pbuf++ = '\0'; +// break; +// } +// else if (*pbuf == '\n' || *pbuf == ' ') +// { +// *pbuf++ = '\0'; +// break; +// } + } + + break; + } + } + + if (i >= MAX_WEB_CMD_PARAMS) + return -1; + } + + return 0; +} + +int process_settings(char *pbuf) +{ + FILE *fp; + + printf("Verify Configure setting...\r\n"); + printf("---Dump Settings---\r\n%s\r\n---End of dump---\r\n", pbuf); + + if (SD_Card_Mounted == FALSE) + { + printf("SD card doesn't exist. Ignore settings.\r\n"); + return -1; + } + + if (inspect_each_setting(pbuf) < 0) + { + printf("Unsupported parameters.\r\n"); + return -1; + } + + if (web_cmd_params[0].value > 0) + { + int port = web_cmd_params[0].value - 1; + port_config[port].baud = web_cmd_params[1].value; + port_config[port].data = web_cmd_params[2].value; + port_config[port].stop = web_cmd_params[4].value; + port_config[port].parity = (mbed::SerialBase::Parity) web_cmd_params[3].value; + port_config[port].mode = (E_NetMode) web_cmd_params[5].value; + + if (web_cmd_params[6].str != NULL) + { + strncpy(port_config[port].server_addr, web_cmd_params[6].str, MAX_SERVER_ADDRESS_SIZE); + port_config[port].server_addr[MAX_SERVER_ADDRESS_SIZE] = '\0'; + } + + port_config[port].server_port = web_cmd_params[7].value; + + printf("Save Serial Config setting...\r\n"); + fp = fopen(SER_CONFIG_FILE, "w"); + if (fp != NULL) + { + char pBuf[2] = {'N', 'T'}; + printf("Write config file to SD card.\r\n"); + fwrite(pBuf, 2, 1, fp); + fwrite(port_config, sizeof(port_config), 1, fp); + fclose(fp); + } + else + { + printf("Can't write to SD card.\r\n"); + } + } + else if (web_cmd_params[8].value > 0) + { + net_config.mode = (E_IPMode)web_cmd_params[9].value; + if (web_cmd_params[10].str != NULL) + { + strncpy(net_config.ip, web_cmd_params[10].str, MAX_IPV4_ADDRESS_SIZE); + net_config.ip[MAX_IPV4_ADDRESS_SIZE] = '\0'; + } + if (web_cmd_params[11].str != NULL) + { + strncpy(net_config.mask, web_cmd_params[11].str, MAX_IPV4_ADDRESS_SIZE); + net_config.mask[MAX_IPV4_ADDRESS_SIZE] = '\0'; + } + if (web_cmd_params[12].str != NULL) + { + strncpy(net_config.gateway, web_cmd_params[12].str, MAX_IPV4_ADDRESS_SIZE); + net_config.gateway[MAX_IPV4_ADDRESS_SIZE] = '\0'; + } + printf("Save Network Config setting...\r\n"); + fp = fopen(NET_CONFIG_FILE, "w"); + if (fp != NULL) + { + char pBuf[2] = {'N', 'T'}; + printf("Write config file to SD card.\r\n"); + fwrite(pBuf, 2, 1, fp); + fwrite(&net_config, sizeof(net_config), 1, fp); + fclose(fp); + } + else + { + printf("Can't write to SD card.\r\n"); + } + } + + return 0; +} + + +void send_web_data(TCPSocket *socket, char *pbuf) +{ + char *p = pbuf; + int size = strlen(pbuf); + + while(size > 0) + { + int ret = socket->send(p, size); + if (ret < 0) + break; + + p += ret; + size -= ret; + } +} + +void send_web_header(TCPSocket *socket, int num) +{ + static const char *webpage_header[] = { + PAGE_HEADER, + PAGE_HEADER_FOR_REFRESH + }; + + send_web_data(socket, (char *)webpage_header[num]); +} + +const char *status_messages[] = { + "\r\n", + "Configuration update successfully. </p>\r\n", + "Configuration setting error.</p>\r\n", + "Reset Configuration successfully. </p>\r\n", + "Web page will reload automatically after 10 seconds. </p>\r\n", + "Unknown settings. </p>\r\n" +}; + +void send_web_body(TCPSocket *socket, int num) +{ + int i; + static char pbuf[3072]; + + /* send page body */ + send_web_data(socket, (char *)"<body>Serial to Ethernet Configuration </p>\r\n"); + + /* send status message */ + send_web_data(socket, (char *)status_messages[num]); + + send_web_data(socket, (char *)PAGE_RESTART_FORM); + send_web_data(socket, (char *)PAGE_RESETCONF_FORM); + + /* send network configuration form */ + send_web_data(socket, (char *)PAGE_CONFIG_FORM_HEAD); + + sprintf(pbuf, PAGE_CONFIG_NET_FORM, + (net_config.mode == IP_STATIC_MODE)?" selected":"", + (net_config.mode == IP_DHCP_MODE)?" selected":"", + net_config.ip, + net_config.mask, + net_config.gateway); + + send_web_data(socket, pbuf); + send_web_data(socket, (char *)"<br><input type=\"submit\" value=\"Config Net\"> </form><br>\r\n"); + + /* send serial ports configuration form */ + send_web_data(socket, (char *)PAGE_CONFIG_FORM_HEAD); + for(i=0; i<MAX_UART_PORTS; i++) + { + S_PORT_CONFIG *s = &port_config[i]; + + sprintf(pbuf, "Serial port #%d<br>\r\n", i+1); + send_web_data(socket, pbuf); + sprintf(pbuf, PAGE_CONFIG_SERIAL_FORM, + i+1, + (s->baud == 115200)?" selected":"", + (s->baud == 9600)?" selected":"", + (s->baud == 4800)?" selected":"", + (s->baud == 2400)?" selected":"", + (s->data == 8)?" selected":"", + (s->data == 7)?" selected":"", + (s->data == 6)?" selected":"", + (s->data == 5)?" selected":"", + (s->parity == 0)?" selected":"", + (s->parity == 1)?" selected":"", + (s->parity == 2)?" selected":"", + (s->stop == 1)?" selected":"", + (s->stop == 2)?" selected":"", + (s->mode == 0)?" selected":"", + (s->mode == 1)?" selected":"", + s->server_addr, + s->server_port); + + send_web_data(socket, pbuf); + +#if MAX_UART_PORTS == 1 + sprintf(pbuf, "<br><input type=\"submit\" value=\"Config Port\"> </form><br>\r\n"); +#else + sprintf(pbuf, "<br><input type=\"submit\" value=\"Config Port #%d\"> </form><br>\r\n", i); +#endif + send_web_data(socket, pbuf); + } + + /* send end of page body */ + send_web_data(socket, (char *)"</body></html>\r\n"); +} + +void process_http_index_html(TCPSocket *socket, char *pbuf) +{ + send_web_header(socket, 0); + send_web_body(socket, 0); +} + +void process_http_restart_html(TCPSocket *socket, char *pbuf) +{ + send_web_header(socket, 1); + send_web_body(socket, 4); + + printf("Restart system...\r\n"); + wait(1); // wait 1 second +// SYS_ResetCPU(); + SYS_ResetChip(); + wait(100); +} + +void process_http_resetconf_html(TCPSocket *socket, char *pbuf) +{ + if (SD_Card_Mounted) + { + remove(SER_CONFIG_FILE); + remove(NET_CONFIG_FILE); + printf("Deleted config files.\r\n"); + } + else + { + printf("SD card doesn't exist.\r\n"); + } + + send_web_header(socket, 0); + send_web_body(socket, 3); +} + +void process_http_config_html(TCPSocket *socket, char *pbuf) +{ + send_web_header(socket, 0); + + if (process_settings(pbuf) >= 0) + send_web_body(socket, 1); + else + send_web_body(socket, 2); +} + +void process_http_err_html(TCPSocket *socket, char *pbuf) +{ + send_web_header(socket, 0); + send_web_body(socket, 5); +} + +void process_http_get_request(TCPSocket *socket, char *pbuf) +{ + int i; + + for(i=0; i<MAX_WEB_GET_PAGE_SETTINGS; i++) + { + int len = strlen(web_get_pages_setings[i].vhtmlpage); + if (strncmp(pbuf, web_get_pages_setings[i].vhtmlpage, len) == 0) + { + if (web_get_pages_setings[i].pfn != NULL) + { + web_get_pages_setings[i].pfn(socket, pbuf+len); + break; + } + } + } +} + +void process_http_post_request(TCPSocket *socket, char *pbuf) +{ +} + +void process_http_request(TCPSocket *socket) +{ + char w_buf[2048]; + int w_len; + + w_len = socket->recv(w_buf, 2047); + if (w_len <= 0) + return; + + w_buf[w_len] = '\0'; + printf("\n\r---DUMP HTTP DATA (%d)---\r\n%s\r\n---END OF DUMP---\r\n", w_len, w_buf); + + if (strncmp(w_buf, "GET ", 4) == 0) + { + process_http_get_request(socket, w_buf+4); + } + else if (strncmp(w_buf, "POST ", 5) == 0) + { + process_http_post_request(socket, w_buf+5); + } + else + { + process_http_get_request(socket, (char *)"/ "); + } +} + +void start_httpd(void) +{ + TCPServer http_server; + TCPSocket http_socket; + SocketAddress http_address; + + if (http_server.open(ð) < 0) + { + printf("http server can't open.\r\n"); + return; + } + if (http_server.bind(eth.get_ip_address(), 80) < 0) + { + printf("http server can't bind address and port.\r\n"); + return; + } + if (http_server.listen(1) < 0) + { + printf("http server can't listen.\r\n"); + return; + } + + printf("Start http server...\r\n"); + + while(1) + { + if (http_server.accept(&http_socket, &http_address) < 0) + { + printf("http server fail to accept connection.\r\n"); + return; + } + + printf("http from %s:%d ...\r\n", http_address.get_ip_address(), http_address.get_port()); + process_http_request(&http_socket); + http_socket.close(); + } +} + +#endif