参考博客:[网络篇]ESP8266-SDK教程(六)之网页配置Wi-Fi名称和密码
ESP8266 设置为 STATION + AP 模式。
STATION 模式又叫做站点工作模式,类似于无线终端,处于 STATION 模式下的 ESP8266,可以连接到 AP。通过 STATION (简称为“STA”)模式,ESP8266 作为客户端连接到路由的 Wi-Fi 信号。
AP 就是 Access Point 接入点。由 ESP8266 自己开启热点,供别的设备接入,组成一个局域网。
流程就是这个样子,手机 / 电脑连接 ESP8266 开启的热点,在浏览器打开配网网页,通过网页发送 SSID 和 PWD 给 ESP8266,ESP8266 解析以后得到 SSID 和 PWD 去连接 Wi-Fi。
我们需要将这个写好的网页,保存到 ESP8266 当中,当 ESP8266 收到 http 请求时,我们再将这个网页发送给浏览器,此时 ESP8266 就是一个很小的 Web Server,处理来自浏览器的 http 请求,然后按照一定格式返回具体的网页,或者其他数据,这些都是通过 TCP 传输的。
程序我们可以通过 NonOS-SDK 自带的 WebServer 进行改动。
//初始化webserver,webserver端口为80,可以通过初始化时传入
void ICACHE_FLASH_ATTR
www_webserver_init(uint32 port) {
LOCAL struct espconn esp_conn;
LOCAL esp_tcp esptcp;
esp_conn.type = ESPCONN_TCP;
esp_conn.state = ESPCONN_NONE;
esp_conn.proto.tcp = &esptcp;
esp_conn.proto.tcp->local_port = port;
espconn_regist_connectcb(&esp_conn, www_webserver_listen);
espconn_accept(&esp_conn);
}
/*
* softAP模式初始化代码
*/
void ICACHE_FLASH_ATTR
www_softAP_init(void){
struct softap_config soft_ap_Config;
//wifi_set_opmode_current(SOFTAP_MODE);//设置为AP模式,不保存到flash
wifi_set_opmode(STATIONAP_MODE);//设置为STATION+AP模式,并保存到flash
os_memset(&soft_ap_Config, 0, sizeof(struct softap_config)); // AP参数结构体 = 0
soft_ap_Config.ssid_len = os_strlen(AP_NAME);//热点名称长度,与你实际的名称长度一致就好
os_strcpy(soft_ap_Config.ssid, AP_NAME);//实际热点名称设置,可以根据你的需要来
os_strcpy(soft_ap_Config.password, AP_PWD);//热点密码设置
soft_ap_Config.authmode = AUTH_OPEN;//若是你的密码为空,加密模式为AUTH_WPA2_PSK,那么ESP8266不会使用你设置的WIFI名称,而是系统生成,因此没有密码就把加密模式改成AUTH_OPEN
soft_ap_Config.beacon_interval = 100;//信标间隔,默认为100
soft_ap_Config.channel = 1;//信道,共支持1~13个信道
soft_ap_Config.max_connection = 4;//最大连接数量,最大支持四个,默认四个
soft_ap_Config.ssid_hidden = 0;//隐藏SSID,0:不隐藏 1:隐藏
//wifi_softap_set_config_current(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,不保存到 Flash
wifi_softap_set_config(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,保存到 Flash
}
//断开重连回调函数
LOCAL ICACHE_FLASH_ATTR
void www_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);
}
//断开连接回调函数
LOCAL ICACHE_FLASH_ATTR
void www_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);
}
//绑定回调函数
LOCAL void ICACHE_FLASH_ATTR
www_webserver_listen(void *arg) {
struct espconn *pesp_conn = arg;
espconn_regist_recvcb(pesp_conn, www_webserver_recv);//数据接收回调函数
espconn_regist_reconcb(pesp_conn, www_webserver_recon);//断开重连回调函数
espconn_regist_disconcb(pesp_conn, www_webserver_discon);//断开连接回调函数
}
//数据接收回调函数
LOCAL void ICACHE_FLASH_ATTR
www_webserver_recv(void *arg, char *pusrdata, unsigned short length) {
URL_Frame *pURL_Frame = NULL;
char *pParseBuffer = NULL;
bool parse_flag = false;
struct espconn *ptrespconn = arg;
uint8 sta;
os_printf("len:%u\n", length);
if (www_check_data(pusrdata, length) == false) {
os_printf("goto\n");
goto _temp_exit;
}
parse_flag = www_save_data(pusrdata, length);
if (parse_flag == false) {
www_response_send(ptrespconn, false);
}
//os_printf(buffer);
pURL_Frame = (URL_Frame *) os_zalloc(sizeof(URL_Frame));
www_parse_url(buffer, pURL_Frame);
//os_printf("recv:%s\n", pusrdata);
os_printf("\r\nType[%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");
os_printf("pURL_Frame->pFilename: %s\n",pURL_Frame->pFilename);
sta = wifi_station_get_connect_status();
os_printf("wifi_station_get_connect_status: %d\n", sta);
if(pURL_Frame->pFilename[0] == 0){
www_data_send(ptrespconn, true, page_html);
}
if(strncmp(pURL_Frame->pFilename, "WebConfig.html", strlen("WebConfig.html")) == 0){
www_data_send(ptrespconn, true, config_html);
}
break;
case POST:
os_printf("We have a POST request.\n");
pParseBuffer = (char *)os_strstr(buffer, "\r\n\r\n");
sta = wifi_station_get_connect_status();
os_printf("wifi_station_get_connect_status: %d\n", sta);
if(sta == STATION_GOT_IP){
//www_data_send(ptrespconn, true, "Connect Success!");
www_data_send(ptrespconn, true, finish_html);
}
else if(sta == STATION_WRONG_PASSWORD){
//www_data_send(ptrespconn, true, "Wrong Password!");
www_data_send(ptrespconn, true, finish_html);
}
else{
www_data_send(ptrespconn, true, config_html);
}
if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){
webconfig_get_wifi_ssid_pwd(pusrdata);
}
if (pParseBuffer == NULL) {
break;
}
os_printf("%s\r\n", pParseBuffer);
break;
}
if (buffer != NULL) {
os_free(buffer);
buffer = NULL;
}
os_free(pURL_Frame);
pURL_Frame = NULL;
_temp_exit: ;
}
/* 功 能:将str字符串中的oldstr字符串替换为newstr字符串
* 参 数:str:操作目标 oldstr:被替换者 newstr:替换者
* 返回值:返回替换之后的字符串
* 版 本: V0.2
*/
static char * ICACHE_FLASH_ATTR
strrpc(char *str, char *oldstr, char *newstr){
char bstr[os_strlen(str)];//转换缓冲区
int len = os_strlen(str);
int i, len2 = 0;
os_memset(bstr, 0, sizeof(bstr));
for(i = 0; i < len; i++){
if(!os_strncmp(str + i, oldstr, os_strlen(oldstr))){
//查找目标字符串
strcat(bstr, newstr);
len2 = os_strlen(oldstr);
i += len2 - 1;
}else{
strncat(bstr, str + i, 1);//保存一字节进缓冲区
}
}
os_strcpy(str,bstr);
return str;
}
//获取网页传过来的 WiFi 账号和密码
static void ICACHE_FLASH_ATTR
webconfig_get_wifi_ssid_pwd(char* urlparam)
{
char *p = NULL, *q = NULL;
char ssid[32], pass[64];
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);
//空格在url参数会转码成+号,+号转码成%2B
strrpc(ssid, "+", " ");
os_printf("ssid[%s], pass[%s]\r\n", ssid, pass);
wifi_set_opmode(STATIONAP_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(pass));
wifi_station_set_config(&stConf);
//重启
system_restart();
}
LOCAL char *buffer;
static uint32 sumlength = 0;
LOCAL bool ICACHE_FLASH_ATTR
www_save_data(char *precv, uint16 length)
{
bool flag = false;
char length_buf[10] = {
0};
char *ptemp = NULL;
char *pdata = NULL;
uint16 headlength = 0;
static uint32 totallength = 0;
ptemp = (char *)os_strstr(precv, "\r\n\r\n");
if (ptemp != NULL) {
length -= ptemp - precv;
length -= 4;
totallength += length;
headlength = ptemp - precv + 4;
pdata = (char *)os_strstr(precv, "Content-Length: ");
if (pdata != NULL) {
pdata += 16;
buffer = (char *)os_strstr(pdata, "\r\n");
if (buffer != NULL) {
os_memcpy(length_buf, pdata, buffer - pdata);
sumlength = atoi(length_buf);
}
} else {
if (totallength != 0x00){
totallength = 0;
sumlength = 0;
return false;
}
}
if ((sumlength + headlength) >= 1024) {
buffer = (char *)os_zalloc(headlength + 1);
os_memcpy(buffer, precv, headlength + 1);
} else {
buffer = (char *)os_zalloc(sumlength + headlength + 1);
os_memcpy(buffer, precv, os_strlen(precv));
}
} else {
if (buffer != NULL) {
totallength += length;
os_memcpy(buffer + os_strlen(buffer), precv, length);
} else {
totallength = 0;
sumlength = 0;
return false;
}
}
if (totallength == sumlength) {
totallength = 0;
sumlength = 0;
return true;
} else {
return false;
}
}
LOCAL bool ICACHE_FLASH_ATTR
www_check_data(char *precv, uint16 length)
{
//bool flag = true;
char length_buf[10] = {
0};
char *ptemp = NULL;
char *pdata = NULL;
char *tmp_precvbuffer;
uint16 tmp_length = length;
uint32 tmp_totallength = 0;
ptemp = (char *)os_strstr(precv, "\r\n\r\n");
if (ptemp != NULL) {
tmp_length -= ptemp - precv;
tmp_length -= 4;
tmp_totallength += tmp_length;
pdata = (char *)os_strstr(precv, "Content-Length: ");
if (pdata != NULL){
pdata += 16;
tmp_precvbuffer = (char *)os_strstr(pdata, "\r\n");
if (tmp_precvbuffer != NULL){
os_memcpy(length_buf, pdata, tmp_precvbuffer - pdata);
sumlength = atoi(length_buf);
os_printf("A_dat:%u,tot:%u,lenght:%u\n",sumlength,tmp_totallength,tmp_length);
if(sumlength != tmp_totallength){
return false;
}
}
}
}
return true;
}
LOCAL void ICACHE_FLASH_ATTR
www_parse_url(char *precv, URL_Frame *purl_frame)
{
char *str = NULL;
uint8 length = 0;
char *pbuffer = NULL;
char *pbufer = NULL;
if (purl_frame == NULL || precv == NULL) {
return;
}
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;
}
pbuffer ++;
str = (char *)os_strstr(pbuffer, "HTTP");
if (str != NULL) {
length = str - pbuffer - 1;
os_memcpy(purl_frame->pFilename, pbuffer, length);
}
os_free(pbufer);
} else {
return;
}
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);
}
}
//发送html网页数据
LOCAL void ICACHE_FLASH_ATTR
www_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_sprintf(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\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\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_sprintf(httphead + os_strlen(httphead), "\n");
length = os_strlen(httphead);
}
} else {
os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\
Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n");
length = os_strlen(httphead);
}
if (psend) {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, pbuf, length);
#else
espconn_sent(ptrespconn, pbuf, length);
#endif
} else {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, httphead, length);
#else
espconn_sent(ptrespconn, httphead, length);
#endif
}
if (pbuf) {
os_free(pbuf);
pbuf = NULL;
}
}
//发送json数据
LOCAL void ICACHE_FLASH_ATTR
www_data_send_json(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_sprintf(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: application/json\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\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_sprintf(httphead + os_strlen(httphead), "\n");
length = os_strlen(httphead);
}
} else {
os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\
Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n");
length = os_strlen(httphead);
}
if (psend) {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, pbuf, length);
#else
espconn_sent(ptrespconn, pbuf, length);
#endif
} else {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, httphead, length);
#else
espconn_sent(ptrespconn, httphead, length);
#endif
}
if (pbuf) {
os_free(pbuf);
pbuf = NULL;
}
}
//发送响应成功数据
LOCAL void ICACHE_FLASH_ATTR
www_response_send(void *arg, bool responseOK)
{
struct espconn *ptrespconn = arg;
www_data_send(ptrespconn, responseOK, NULL);
}
不知道为啥,meta 标签里我都设置为 utf-8 了,中文输出还是乱码,所以网页里用的全部都是英文。
//欢迎页面代码
char* page_html = "\r\n"
"\r\n"
" \r\n"
" \r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
"
\r\n"
" \r\n"
" E-mail: [email protected]\r\n"
" \r\n"
"
\r\n"
"
\r\n"
" \r\n"
"
" Start Config\r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" \r\n"
"";
//配网页面
char* config_html = "\r\n"
"\r\n"
" \r\n"
" \r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
"
\r\n"
" \r\n"
" E-mail: [email protected]\r\n"
" \r\n"
"
\r\n"
"
\r\n"
" \r\n"
"
" \r\n"
" \r\n"
" \r\n"
" Wi-Fi Name:\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
" Wi-Fi Pwd:\r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
"
" Confirm\r\n"
" \r\n"
" \r\n"
" \r\n"
"";
//配网完成
char* finish_html = "\r\n"
"\r\n"
" \r\n"
" \r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
"
\r\n"
" \r\n"
" E-mail: [email protected]\r\n"
" \r\n"
"
\r\n"
"
\r\n"
" \r\n"
" Connecting to Wi-Fi, the connection is complete after the LED flashes three times!\r\n"
"
\r\n"
" Steady on means the connection failed, please re-enter!\r\n"
"
\r\n"
" \r\n"
"
" Re-distribution Network\r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" Back Home\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
"";
/*
* webserver.c
*
* Created on: 2021年4月8日
* Author: wxhntmy
*/
#include "espconn.h"
#include "mem.h"
#include "ets_sys.h"
#include "osapi.h"
#include "user_interface.h"
#include "user_devicefind.h"
#include "user_webserver.h"
#include "user_esp_platform.h"
#include "user_tcpclient.h"
#include "webserver.h" //头文件只声明了几个函数
char* AP_NAME = "zcm_iot_wifi"; //wifi名字
char* AP_PWD = "123456"; //wifi密码
//欢迎页面代码
char* page_html = "\r\n"
"\r\n"
" \r\n"
" \r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
"
\r\n"
" \r\n"
" E-mail: [email protected]\r\n"
" \r\n"
"
\r\n"
"
\r\n"
" \r\n"
"
" Start Config\r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" \r\n"
"";
//配网页面
char* config_html = "\r\n"
"\r\n"
" \r\n"
" \r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
"
\r\n"
" \r\n"
" E-mail: [email protected]\r\n"
" \r\n"
"
\r\n"
"
\r\n"
" \r\n"
"
" \r\n"
" \r\n"
" \r\n"
" Wi-Fi Name:\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
" Wi-Fi Pwd:\r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
"
" Confirm\r\n"
" \r\n"
" \r\n"
" \r\n"
"";
//配网完成
char* finish_html = "\r\n"
"\r\n"
" \r\n"
" \r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" ZCM IOT WiFi Config\r\n"
" \r\n"
"
\r\n"
" \r\n"
" E-mail: [email protected]\r\n"
" \r\n"
"
\r\n"
"
\r\n"
" \r\n"
" Connecting to Wi-Fi, the connection is complete after the LED flashes three times!\r\n"
"
\r\n"
" Steady on means the connection failed, please re-enter!\r\n"
"
\r\n"
" \r\n"
"
" Re-distribution Network\r\n"
" \r\n"
" \r\n"
"
\r\n"
" \r\n"
" Back Home\r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
"";
LOCAL void ICACHE_FLASH_ATTR
www_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_sprintf(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\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\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_sprintf(httphead + os_strlen(httphead), "\n");
length = os_strlen(httphead);
}
} else {
os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\
Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n");
length = os_strlen(httphead);
}
if (psend) {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, pbuf, length);
#else
espconn_sent(ptrespconn, pbuf, length);
#endif
} else {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, httphead, length);
#else
espconn_sent(ptrespconn, httphead, length);
#endif
}
if (pbuf) {
os_free(pbuf);
pbuf = NULL;
}
}
LOCAL void ICACHE_FLASH_ATTR
www_data_send_json(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_sprintf(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: application/json\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\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_sprintf(httphead + os_strlen(httphead), "\n");
length = os_strlen(httphead);
}
} else {
os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\
Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n");
length = os_strlen(httphead);
}
if (psend) {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, pbuf, length);
#else
espconn_sent(ptrespconn, pbuf, length);
#endif
} else {
#ifdef SERVER_SSL_ENABLE
espconn_secure_sent(ptrespconn, httphead, length);
#else
espconn_sent(ptrespconn, httphead, length);
#endif
}
if (pbuf) {
os_free(pbuf);
pbuf = NULL;
}
}
LOCAL void ICACHE_FLASH_ATTR
www_response_send(void *arg, bool responseOK)
{
struct espconn *ptrespconn = arg;
www_data_send(ptrespconn, responseOK, NULL);
}
LOCAL void ICACHE_FLASH_ATTR
www_parse_url(char *precv, URL_Frame *purl_frame)
{
char *str = NULL;
uint8 length = 0;
char *pbuffer = NULL;
char *pbufer = NULL;
if (purl_frame == NULL || precv == NULL) {
return;
}
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;
}
pbuffer ++;
str = (char *)os_strstr(pbuffer, "HTTP");
if (str != NULL) {
length = str - pbuffer - 1;
os_memcpy(purl_frame->pFilename, pbuffer, length);
}
os_free(pbufer);
} else {
return;
}
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);
}
}
LOCAL char *buffer;
static uint32 sumlength = 0;
LOCAL bool ICACHE_FLASH_ATTR
www_save_data(char *precv, uint16 length)
{
bool flag = false;
char length_buf[10] = {
0};
char *ptemp = NULL;
char *pdata = NULL;
uint16 headlength = 0;
static uint32 totallength = 0;
ptemp = (char *)os_strstr(precv, "\r\n\r\n");
if (ptemp != NULL) {
length -= ptemp - precv;
length -= 4;
totallength += length;
headlength = ptemp - precv + 4;
pdata = (char *)os_strstr(precv, "Content-Length: ");
if (pdata != NULL) {
pdata += 16;
buffer = (char *)os_strstr(pdata, "\r\n");
if (buffer != NULL) {
os_memcpy(length_buf, pdata, buffer - pdata);
sumlength = atoi(length_buf);
}
} else {
if (totallength != 0x00){
totallength = 0;
sumlength = 0;
return false;
}
}
if ((sumlength + headlength) >= 1024) {
buffer = (char *)os_zalloc(headlength + 1);
os_memcpy(buffer, precv, headlength + 1);
} else {
buffer = (char *)os_zalloc(sumlength + headlength + 1);
os_memcpy(buffer, precv, os_strlen(precv));
}
} else {
if (buffer != NULL) {
totallength += length;
os_memcpy(buffer + os_strlen(buffer), precv, length);
} else {
totallength = 0;
sumlength = 0;
return false;
}
}
if (totallength == sumlength) {
totallength = 0;
sumlength = 0;
return true;
} else {
return false;
}
}
LOCAL bool ICACHE_FLASH_ATTR
www_check_data(char *precv, uint16 length)
{
//bool flag = true;
char length_buf[10] = {
0};
char *ptemp = NULL;
char *pdata = NULL;
char *tmp_precvbuffer;
uint16 tmp_length = length;
uint32 tmp_totallength = 0;
ptemp = (char *)os_strstr(precv, "\r\n\r\n");
if (ptemp != NULL) {
tmp_length -= ptemp - precv;
tmp_length -= 4;
tmp_totallength += tmp_length;
pdata = (char *)os_strstr(precv, "Content-Length: ");
if (pdata != NULL){
pdata += 16;
tmp_precvbuffer = (char *)os_strstr(pdata, "\r\n");
if (tmp_precvbuffer != NULL){
os_memcpy(length_buf, pdata, tmp_precvbuffer - pdata);
sumlength = atoi(length_buf);
os_printf("A_dat:%u,tot:%u,lenght:%u\n",sumlength,tmp_totallength,tmp_length);
if(sumlength != tmp_totallength){
return false;
}
}
}
}
return true;
}
/* 功 能:将str字符串中的oldstr字符串替换为newstr字符串
* 参 数:str:操作目标 oldstr:被替换者 newstr:替换者
* 返回值:返回替换之后的字符串
* 版 本: V0.2
*/
static char * ICACHE_FLASH_ATTR
strrpc(char *str,char *oldstr,char *newstr){
char bstr[os_strlen(str)];//转换缓冲区
int len = os_strlen(str);
int i, len2 = 0;
os_memset(bstr, 0, sizeof(bstr));
for(i = 0; i < len; i++){
if(!os_strncmp(str + i, oldstr, os_strlen(oldstr))){
//查找目标字符串
strcat(bstr, newstr);
len2 = os_strlen(oldstr);
i += len2 - 1;
}else{
strncat(bstr, str + i, 1);//保存一字节进缓冲区
}
}
os_strcpy(str,bstr);
return str;
}
static void ICACHE_FLASH_ATTR
webconfig_get_wifi_ssid_pwd(char* urlparam)
{
char *p = NULL, *q = NULL;
char ssid[32], pass[64];
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);
//空格在url参数会转码成+号,+号转码成%2B
strrpc(ssid, "+", " ");
os_printf("ssid[%s], pass[%s]\r\n", ssid, pass);
wifi_set_opmode(STATIONAP_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(pass));
wifi_station_set_config(&stConf);
//重启
system_restart();
}
LOCAL void ICACHE_FLASH_ATTR
www_webserver_recv(void *arg, char *pusrdata, unsigned short length) {
URL_Frame *pURL_Frame = NULL;
char *pParseBuffer = NULL;
bool parse_flag = false;
struct espconn *ptrespconn = arg;
uint8 sta;
os_printf("len:%u\n", length);
if (www_check_data(pusrdata, length) == false) {
os_printf("goto\n");
goto _temp_exit;
}
parse_flag = www_save_data(pusrdata, length);
if (parse_flag == false) {
www_response_send(ptrespconn, false);
}
//os_printf(buffer);
pURL_Frame = (URL_Frame *) os_zalloc(sizeof(URL_Frame));
www_parse_url(buffer, pURL_Frame);
//os_printf("recv:%s\n", pusrdata);
os_printf("\r\nType[%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");
os_printf("pURL_Frame->pFilename: %s\n",pURL_Frame->pFilename);
sta = wifi_station_get_connect_status();
if(sta == STATION_GOT_IP){
//www_data_send(ptrespconn, true, "WiFi is connected!");
www_data_send(ptrespconn, true, finish_html);
}
else{
if(pURL_Frame->pFilename[0] == 0){
www_data_send(ptrespconn, true, page_html);
}
if(strncmp(pURL_Frame->pFilename, "WebConfig.html", strlen("WebConfig.html")) == 0){
www_data_send(ptrespconn, true, config_html);
}
}
break;
case POST:
os_printf("We have a POST request.\n");
pParseBuffer = (char *)os_strstr(buffer, "\r\n\r\n");
sta = wifi_station_get_connect_status();
if(sta == STATION_GOT_IP){
//www_data_send(ptrespconn, true, "Connect Success!");
www_data_send(ptrespconn, true, finish_html);
}
else if(sta == STATION_WRONG_PASSWORD){
//www_data_send(ptrespconn, true, "Wrong Password!");
www_data_send(ptrespconn, true, finish_html);
}
else{
www_data_send(ptrespconn, true, config_html);
}
if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){
webconfig_get_wifi_ssid_pwd(pusrdata);
}
if (pParseBuffer == NULL) {
break;
}
os_printf("%s\r\n", pParseBuffer);
break;
}
if (buffer != NULL) {
os_free(buffer);
buffer = NULL;
}
os_free(pURL_Frame);
pURL_Frame = NULL;
_temp_exit: ;
}
LOCAL ICACHE_FLASH_ATTR
void www_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);
}
LOCAL ICACHE_FLASH_ATTR
void www_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);
}
//绑定回调函数
LOCAL void ICACHE_FLASH_ATTR
www_webserver_listen(void *arg) {
struct espconn *pesp_conn = arg;
espconn_regist_recvcb(pesp_conn, www_webserver_recv);
espconn_regist_reconcb(pesp_conn, www_webserver_recon);
espconn_regist_disconcb(pesp_conn, www_webserver_discon);
}
/*
* softAP模式初始化代码
*/
void ICACHE_FLASH_ATTR
www_softAP_init(void){
struct softap_config soft_ap_Config;
//wifi_set_opmode_current(SOFTAP_MODE);//设置为AP模式,不保存到flash
wifi_set_opmode(STATIONAP_MODE);//设置为STATION+AP模式,并保存到flash
os_memset(&soft_ap_Config, 0, sizeof(struct softap_config)); // AP参数结构体 = 0
soft_ap_Config.ssid_len = os_strlen(AP_NAME);//热点名称长度,与你实际的名称长度一致就好
os_strcpy(soft_ap_Config.ssid, AP_NAME);//实际热点名称设置,可以根据你的需要来
os_strcpy(soft_ap_Config.password, AP_PWD);//热点密码设置
soft_ap_Config.authmode = AUTH_OPEN;//若是你的密码为空,加密模式为AUTH_WPA2_PSK,那么ESP8266不会使用你设置的WIFI名称,而是系统生成,因此没有密码就把加密模式改成AUTH_OPEN
soft_ap_Config.beacon_interval = 100;//信标间隔,默认为100
soft_ap_Config.channel = 1;//信道,共支持1~13个信道
soft_ap_Config.max_connection = 4;//最大连接数量,最大支持四个,默认四个
soft_ap_Config.ssid_hidden = 0;//隐藏SSID,0:不隐藏 1:隐藏
//wifi_softap_set_config_current(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,不保存到 Flash
wifi_softap_set_config(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,保存到 Flash
}
//初始化webserver
void ICACHE_FLASH_ATTR
www_webserver_init(uint32 port) {
LOCAL struct espconn esp_conn;
LOCAL esp_tcp esptcp;
esp_conn.type = ESPCONN_TCP;
esp_conn.state = ESPCONN_NONE;
esp_conn.proto.tcp = &esptcp;
esp_conn.proto.tcp->local_port = port;
espconn_regist_connectcb(&esp_conn, www_webserver_listen);
espconn_accept(&esp_conn);
}
在主函数中调用以下两个函数即可
//初始化AP模式
www_softAP_init();
//开启webserver
www_webserver_init(SERVER_PORT);
打开浏览器,地址栏输入 192.168.4.1