一,基本原理
在ESP8266的 FLASH中開辟一塊內存空間用於存儲UTF-8格式的.HTML文件,網頁要展示的內容就在.HTML文件中。
手機或者電腦連接到ESP8266的熱點,訪問ESP8266的設備IP地址,ESP8266返回wifi密碼配置的網頁內容.HTML文件內容在瀏覽器中呈現出來。
ESP8266接收從瀏覽器上傳的數據,切換到Station模式,並連接到網絡。
二,程序運行流程:
1.ESP8266上電啟動配置為SoftAP模式。
2.使用手機或者電腦連接到ESP8266,訪問ESP8266服務IP地址(默認192.168.4.1)。
3.ESP8266下發給電腦配置WIFI.HTML的文件。
4.通過瀏覽器輸入賬號及密碼上傳給ESP8266服務器。
5.ESP8266切換為Station模式並連接到網絡。
三,程序講解及具體實施
1.ESP8266_NONOSDk工程文件目錄
/bin為燒錄檔輸出目錄
/driver_lib驅動目錄GPIO,SPI,SDIO,UART
/examples為樣例demo的目錄
/html 主要是服務使用的.html文件存放目錄
/include 存放驅動頭文件的
/third_party主要存放基於網絡的各種基本服務的驅動lwip,netif,mbedtls,ssl
任務執行為事件型調用
2.用戶程序入口
在user_main.c文件的user_init(void)函數。調用user_webserver_init()
在webserver_listen()回調函數中配置數據發送和接收回調函數
在webserver_recv()函數中主要任務是解析從網絡接收到的信息,從中找到目標信息,並執行相應動作,如數據發送,配置網絡等
這里做簡單展示函數具體請參考下文中。
瀏覽器下發數據如下
先經過parse_url()解析到pURL_Frame結構變量中,在接收回調函數中經過邏輯處理,執行相關應用。
webser.c文件內容主要是TCP服務相關的數據接收與發送回調函數。
#include "webser.h" #include "c_types.h" #include "ip_addr.h" #include "eagle_soc.h" #include "osapi.h" #include "espconn.h" #include "user_interface.h" #include "driver/spi_interface.h" //#include "user_webserver.h" #include "spi_flash.h" #include "mem.h" static struct espconn webserver_espconn; static esp_tcp webserver_esptcp; #define INDEX_SIZE 1437 #define WEBCONFIG_SIZE 1541 #define WIFIDONE_SIZE 1293 static void ICACHE_FLASH_ATTR webserver_listen(); static void webserver_recv(void *arg,char *pusrdata,unsigned short length); //初始化ap模式 static void ICACHE_FLASH_ATTR softAP_init(void) { struct softap_config soft_ap_Config; wifi_set_opmode_current(SOFTAP_MODE); soft_ap_Config.ssid_len = 14; os_strcpy(soft_ap_Config.ssid,"zhihu-IAMLIUBO"); os_strcpy(soft_ap_Config.password,"imliubo123"); soft_ap_Config.authmode = AUTH_WPA2_PSK; soft_ap_Config.beacon_interval = 100; soft_ap_Config.channel = 1; soft_ap_Config.max_connection = 2; soft_ap_Config.ssid_hidden = 0; wifi_softap_set_config_current(&soft_ap_Config); os_printf("\r\n SSID: zhihu-IAMLIUBO \r\n PWD: IMLIUBO123 \r\n"); } static ICACHE_FLASH_ATTR void webserver_recon(void *arg, sint8 err) { struct espconn *pesp_conn = arg; os_printf("webserver's %d.%d.%d.%d:%d err %d reconnect\n", pesp_conn->proto.tcp->remote_ip[0], pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2], pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port, err); } static ICACHE_FLASH_ATTR void webserver_discon(void *arg) { struct espconn *pesp_conn = arg; os_printf("webserver's %d.%d.%d.%d:%d disconnect\n", pesp_conn->proto.tcp->remote_ip[0], pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2], pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port); } void ICACHE_FLASH_ATTR webserver_sent(void *arg){ struct espconn *pesp_conn = arg; os_printf("webserver's %d.%d.%d.%d:%d sent\n", pesp_conn->proto.tcp->remote_ip[0], pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2], pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port); } static void ICACHE_FLASH_ATTR webconfig_get_wifi_ssid_pwd(char * urlparam) { char *p = NULL,*q = NULL; char ssid[10],pass[15]; os_memset(ssid,0,sizeof(ssid)); os_memset(pass,0,sizeof(pass)); p = (char *)os_strstr(urlparam,"SSID="); q = (char *)os_strstr(urlparam,"PASSWORD="); if(p == NULL || q == NULL) { return; } os_memcpy(ssid, p + 5,q-p-6); os_memcpy(pass,q+9,os_strlen(urlparam) - (q - urlparam) - 9); os_printf("ssid[%s]pass[%s]\r\n",ssid,pass); wifi_set_opmode(STATION_MODE); struct station_config stConf; stConf.bssid_set = 0; os_memset(&stConf.ssid,0,sizeof(stConf.ssid)); os_memset(&stConf.password,0,sizeof(stConf.password)); os_memcpy(&stConf.ssid,ssid,os_strlen(ssid)); os_memcpy(&stConf.password,pass,os_strlen(stConf.password)); wifi_station_set_config(&stConf); system_restart(); } static bool ICACHE_FLASH_ATTR parse_url(char *precv, URL_Frame *purl_frame) { char *str = NULL; uint16 length = 0; char *pbuffer = NULL; char *pbufer = NULL; if(purl_frame == NULL || precv == NULL) { return false; } pbuffer = (char *)os_strstr(precv,"Host:"); if(pbuffer != NULL) { length = pbuffer - precv; pbufer = (char *)os_zalloc(length + 1); pbuffer = pbufer; os_memcpy(pbuffer,precv,length); os_memset(purl_frame->pSelect,0,URLSize); os_memset(purl_frame->pCommand,0,URLSize); os_memset(purl_frame->pFilename,0,URLSize); if(os_strncmp(pbuffer,"GET ",4) == 0) { purl_frame->Type = GET; pbuffer += 4; } else if(os_strncmp(pbuffer,"POST ",5) == 0) { purl_frame->Type = POST; pbuffer += 5; } else { return FALSE; } os_printf("\r\n DDD_Type_DDD[%d] \r\n",purl_frame->Type); pbuffer ++; str = (char *)os_strstr(pbuffer, "HTTP"); if(str != NULL) { length = str - pbuffer - 1; os_memcpy(purl_frame->pFilename,pbuffer,length); } os_printf("DDDpFilenameDDD[%s] \r\n",purl_frame->pFilename); os_free(pbufer); } pbuffer = (char *)os_strstr(precv, "SSID"); if (pbuffer != NULL) { purl_frame->Type = POST; os_memcpy(purl_frame->pCommand, "connect-wifi",strlen("connect-wifi")); os_free(pbufer); } } static void ICACHE_FLASH_ATTR data_send(void *arg,bool responseOK,char *psend) { uint16 length = 0 ; char *pbuf = NULL; char httphead[256]; struct espconn *ptrespconn = arg; os_memset(httphead,0,256); if(responseOK) { os_printf(httphead, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n", psend ? os_strlen(psend) : 0); if(psend) { os_sprintf(httphead + os_strlen(httphead), "Content-type: text/html; charset=utf-8\r\nPragma: no-cache\r\n\r\n"); length = os_strlen(httphead) + os_strlen(psend); pbuf = (char *)os_zalloc(length + 1); os_memcpy(pbuf,httphead,os_strlen(httphead)); os_memcpy(pbuf + os_strlen(httphead),psend,os_strlen(psend)); } else { os_printf(httphead + os_strlen(httphead),"\n"); length = os_strlen(httphead); } } else { os_sprintf(httphead,"HTTP/1.0 400 BadRequest\r\nContent-Length: 0\r\nServer: lwIP/1.4.0\r\n"); length = os_strlen(httphead); } if(psend) { espconn_sent(ptrespconn,pbuf,length); } else { espconn_sent(ptrespconn,httphead,length); } if(pbuf) { os_free(pbuf); pbuf = NULL; } } static void ICACHE_FLASH_ATTR webserver_recv(void *arg,char *pusrdata,unsigned short length) { URL_Frame *pURL_Frame = NULL; char *pParseBuffer = NULL; char *html = NULL; SpiFlashOpResult ret = 0; os_printf("\r\n\r\n length:%d \r\n", length); os_printf("recv:%s",pusrdata); pURL_Frame = (URL_Frame *)os_zalloc(sizeof(URL_Frame)); parse_url(pusrdata,pURL_Frame); //解析網頁數據 os_printf("\r\n Type[%d] \r\n",pURL_Frame->Type); os_printf("pSelect[%s] \r\n",pURL_Frame->pSelect); os_printf("pCommand[%s] \r\n",pURL_Frame->pCommand); os_printf("pFilename[%s] \r\n",pURL_Frame->pFilename); switch ( pURL_Frame->Type ) { case GET: os_printf("We have a GET request.\n"); if(pURL_Frame->pFilename[0] == 0) { html = (char *)os_zalloc(INDEX_SIZE); if(html == NULL) { os_printf("os_zalloc error !\r\n"); goto _temp_exit; } ret = spi_flash_read(508*4096,((uint32 *)html),INDEX_SIZE); if(ret != SPI_FLASH_RESULT_OK) { os_printf("spi_flash_read err:%d \r\n",ret); os_free(html); html = NULL; goto _temp_exit; } html[INDEX_SIZE] = 0; data_send(arg,true,html); os_free(html); html = NULL; } if(strncmp(pURL_Frame->pFilename,"WebConfig.html",strlen("WebConfig.html")) == 0) { html = (char *)os_zalloc(WEBCONFIG_SIZE); if(html == NULL) { os_printf("os_zalloc error!\r\n"); goto _temp_exit; } ret = spi_flash_read(510*4096,(uint32 *)html,WEBCONFIG_SIZE); if(ret != SPI_FLASH_RESULT_OK) { os_printf("spi_flash_read err:%d\r\n",ret); os_free(html); html = NULL; goto _temp_exit; } html[WEBCONFIG_SIZE] = 0; data_send(arg,true,html); os_free(html); html = NULL; } break; case POST: os_printf("We have a POST request.\r\n"); if(strncmp(pURL_Frame->pCommand,"connect-wifi",strlen("connect-wifi"))==0) { os_printf("connect wifi \r\n"); html = (char *)os_zalloc(WIFIDONE_SIZE); if(html == NULL) { os_printf("os_zalloc error! \r\n"); goto _temp_exit; } ret = spi_flash_read(512*4096,(uint32 *)html,WIFIDONE_SIZE); if(ret != SPI_FLASH_RESULT_OK) { os_printf("spi_flash_read err:%d \r\n",ret); os_free(html); html = NULL; goto _temp_exit; } html[WIFIDONE_SIZE] = 0; data_send(arg,true,html); os_free(html); html = NULL; //這里要做個等待檢測到wifi發送停止后再進行接下去的動作 webconfig_get_wifi_ssid_pwd(pusrdata); } break; default: break; } _temp_exit: ; if( pURL_Frame != NULL ) { os_free(pURL_Frame); pURL_Frame = NULL; } } static void ICACHE_FLASH_ATTR webserver_listen(void *arg) { struct espconn *pesp_conn = arg; espconn_regist_recvcb(pesp_conn, webserver_recv); espconn_regist_disconcb(pesp_conn, webserver_discon); espconn_regist_sentcb(pesp_conn, webserver_sent); } void ICACHE_FLASH_ATTR user_webserver_init(uint32 port) { softAP_init(); webserver_espconn.type = ESPCONN_TCP; webserver_espconn.state = ESPCONN_NONE; webserver_espconn.proto.tcp = &webserver_esptcp; webserver_espconn.proto.tcp->local_port = port; espconn_regist_connectcb(&webserver_espconn,webserver_listen); espconn_regist_reconcb(&webserver_espconn,webserver_recon); espconn_accept(&webserver_espconn); }
源碼下載地址
https://gitee.com/LogicExpress/esp8266.git
項目合作交朋友扯淡都可以聯系我 18665321219