Big-arse structure change: readying esphttpd for a split into a library and an usage example
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
#include <esp8266.h>
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
This is a 'captive portal' DNS server: it basically replies with a fixed IP for any and all DNS
|
||||
queries. This can be used to send mobile phones, tablets etc which connect to the ESP in
|
||||
AP mode directly to the internal webserver.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint16_t id;
|
||||
uint8_t flags;
|
||||
uint8_t rcode;
|
||||
uint16_t qdcount;
|
||||
uint16_t ancount;
|
||||
uint16_t nscount;
|
||||
uint16_t arcount;
|
||||
} DnsHeader;
|
||||
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t len;
|
||||
uint8_t data;
|
||||
} DnsLabel;
|
||||
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
//before: label
|
||||
uint16_t type;
|
||||
uint16_t class;
|
||||
} DnsQuestionFooter;
|
||||
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
//before: label
|
||||
uint16_t type;
|
||||
uint16_t class;
|
||||
uint32_t ttl;
|
||||
uint16_t rdlength;
|
||||
//after: rdata
|
||||
} DnsResourceFooter;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint16_t prio;
|
||||
uint16_t weight;
|
||||
} DnsUriHdr;
|
||||
|
||||
|
||||
#define FLAG_QR (1<<7)
|
||||
#define FLAG_AA (1<<2)
|
||||
#define FLAG_TC (1<<1)
|
||||
#define FLAG_RD (1<<0)
|
||||
|
||||
#define QTYPE_A 1
|
||||
#define QTYPE_NS 2
|
||||
#define QTYPE_CNAME 5
|
||||
#define QTYPE_SOA 6
|
||||
#define QTYPE_WKS 11
|
||||
#define QTYPE_PTR 12
|
||||
#define QTYPE_HINFO 13
|
||||
#define QTYPE_MINFO 14
|
||||
#define QTYPE_MX 15
|
||||
#define QTYPE_TXT 16
|
||||
#define QTYPE_URI 256
|
||||
|
||||
#define QCLASS_IN 1
|
||||
#define QCLASS_ANY 255
|
||||
#define QCLASS_URI 256
|
||||
|
||||
|
||||
//Function to put unaligned 16-bit network values
|
||||
static void ICACHE_FLASH_ATTR setn16(void *pp, int16_t n) {
|
||||
char *p=pp;
|
||||
*p++=(n>>8);
|
||||
*p++=(n&0xff);
|
||||
}
|
||||
|
||||
//Function to put unaligned 32-bit network values
|
||||
static void ICACHE_FLASH_ATTR setn32(void *pp, int32_t n) {
|
||||
char *p=pp;
|
||||
*p++=(n>>24)&0xff;
|
||||
*p++=(n>>16)&0xff;
|
||||
*p++=(n>>8)&0xff;
|
||||
*p++=(n&0xff);
|
||||
}
|
||||
|
||||
static uint16_t ICACHE_FLASH_ATTR ntohs(uint16_t *in) {
|
||||
char *p=(char*)in;
|
||||
return ((p[0]<<8)&0xff00)|(p[1]&0xff);
|
||||
}
|
||||
|
||||
|
||||
//Parses a label into a C-string containing a dotted
|
||||
//Returns pointer to start of next fields in packet
|
||||
static char* ICACHE_FLASH_ATTR labelToStr(char *packet, char *labelPtr, int packetSz, char *res, int resMaxLen) {
|
||||
int i, j, k;
|
||||
char *endPtr=NULL;
|
||||
i=0;
|
||||
do {
|
||||
if ((*labelPtr&0xC0)==0) {
|
||||
j=*labelPtr++; //skip past length
|
||||
//Add separator period if there already is data in res
|
||||
if (i<resMaxLen && i!=0) res[i++]='.';
|
||||
//Copy label to res
|
||||
for (k=0; k<j; k++) {
|
||||
if ((labelPtr-packet)>packetSz) return NULL;
|
||||
if (i<resMaxLen) res[i++]=*labelPtr++;
|
||||
}
|
||||
} else if ((*labelPtr&0xC0)==0xC0) {
|
||||
//Compressed label pointer
|
||||
endPtr=labelPtr+2;
|
||||
int offset=ntohs(((uint16_t *)labelPtr))&0x3FFF;
|
||||
//Check if offset points to somewhere outside of the packet
|
||||
if (offset>packetSz) return NULL;
|
||||
labelPtr=&packet[offset];
|
||||
}
|
||||
//check for out-of-bound-ness
|
||||
if ((labelPtr-packet)>packetSz) return NULL;
|
||||
} while (*labelPtr!=0);
|
||||
res[i]=0; //zero-terminate
|
||||
if (endPtr==NULL) endPtr=labelPtr+1;
|
||||
return endPtr;
|
||||
}
|
||||
|
||||
|
||||
//Converts a dotted hostname to the weird label form dns uses.
|
||||
static char ICACHE_FLASH_ATTR *strToLabel(char *str, char *label, int maxLen) {
|
||||
char *len=label; //ptr to len byte
|
||||
char *p=label+1; //ptr to next label byte to be written
|
||||
while (1) {
|
||||
if (*str=='.' || *str==0) {
|
||||
*len=((p-len)-1); //write len of label bit
|
||||
len=p; //pos of len for next part
|
||||
p++; //data ptr is one past len
|
||||
if (*str==0) break; //done
|
||||
str++;
|
||||
} else {
|
||||
*p++=*str++; //copy byte
|
||||
// if ((p-label)>maxLen) return NULL; //check out of bounds
|
||||
}
|
||||
}
|
||||
*len=0;
|
||||
return p; //ptr to first free byte in resp
|
||||
}
|
||||
|
||||
|
||||
//Receive a DNS packet and maybe send a response back
|
||||
static void ICACHE_FLASH_ATTR captdnsRecv(void* arg, char *pusrdata, unsigned short length) {
|
||||
struct espconn *conn=(struct espconn *)arg;
|
||||
char buff[512];
|
||||
char reply[512];
|
||||
int i;
|
||||
char *rend=&reply[length];
|
||||
char *p=pusrdata;
|
||||
DnsHeader *hdr=(DnsHeader*)p;
|
||||
DnsHeader *rhdr=(DnsHeader*)&reply[0];
|
||||
p+=sizeof(DnsHeader);
|
||||
// os_printf("DNS packet: id 0x%X flags 0x%X rcode 0x%X qcnt %d ancnt %d nscount %d arcount %d len %d\n",
|
||||
// ntohs(&hdr->id), hdr->flags, hdr->rcode, ntohs(&hdr->qdcount), ntohs(&hdr->ancount), ntohs(&hdr->nscount), ntohs(&hdr->arcount), length);
|
||||
//Some sanity checks:
|
||||
if (length>512) return; //Packet is longer than DNS implementation allows
|
||||
if (length<sizeof(DnsHeader)) return; //Packet is too short
|
||||
if (hdr->ancount || hdr->nscount || hdr->arcount) return; //this is a reply, don't know what to do with it
|
||||
if (hdr->flags&FLAG_TC) return; //truncated, can't use this
|
||||
//Reply is basically the request plus the needed data
|
||||
os_memcpy(reply, pusrdata, length);
|
||||
rhdr->flags|=FLAG_QR;
|
||||
for (i=0; i<ntohs(&hdr->qdcount); i++) {
|
||||
//Grab the labels in the q string
|
||||
p=labelToStr(pusrdata, p, length, buff, sizeof(buff));
|
||||
if (p==NULL) return;
|
||||
DnsQuestionFooter *qf=(DnsQuestionFooter*)p;
|
||||
p+=sizeof(DnsQuestionFooter);
|
||||
os_printf("DNS: Q (type 0x%X class 0x%X) for %s\n", ntohs(&qf->type), ntohs(&qf->class), buff);
|
||||
if (ntohs(&qf->type)==QTYPE_A) {
|
||||
//They want to know the IPv4 address of something.
|
||||
//Build the response.
|
||||
rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label
|
||||
if (rend==NULL) return;
|
||||
DnsResourceFooter *rf=(DnsResourceFooter *)rend;
|
||||
rend+=sizeof(DnsResourceFooter);
|
||||
setn16(&rf->type, QTYPE_A);
|
||||
setn16(&rf->class, QCLASS_IN);
|
||||
setn32(&rf->ttl, 1);
|
||||
setn16(&rf->rdlength, 4); //IPv4 addr is 4 bytes;
|
||||
//Grab the current IP of the softap interface
|
||||
struct ip_info info;
|
||||
wifi_get_ip_info(SOFTAP_IF, &info);
|
||||
*rend++=ip4_addr1(&info.ip);
|
||||
*rend++=ip4_addr2(&info.ip);
|
||||
*rend++=ip4_addr3(&info.ip);
|
||||
*rend++=ip4_addr4(&info.ip);
|
||||
setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1);
|
||||
// os_printf("Added A rec to resp. Resp len is %d\n", (rend-reply));
|
||||
} else if (ntohs(&qf->type)==QTYPE_NS) {
|
||||
//Give ns server. Basically can be whatever we want because it'll get resolved to our IP later anyway.
|
||||
rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label
|
||||
DnsResourceFooter *rf=(DnsResourceFooter *)rend;
|
||||
rend+=sizeof(DnsResourceFooter);
|
||||
setn16(&rf->type, QTYPE_NS);
|
||||
setn16(&rf->class, QCLASS_IN);
|
||||
setn16(&rf->ttl, 1);
|
||||
setn16(&rf->rdlength, 4);
|
||||
*rend++=2;
|
||||
*rend++='n';
|
||||
*rend++='s';
|
||||
*rend++=0;
|
||||
setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1);
|
||||
// os_printf("Added NS rec to resp. Resp len is %d\n", (rend-reply));
|
||||
} else if (ntohs(&qf->type)==QTYPE_URI) {
|
||||
//Give uri to us
|
||||
rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label
|
||||
DnsResourceFooter *rf=(DnsResourceFooter *)rend;
|
||||
rend+=sizeof(DnsResourceFooter);
|
||||
DnsUriHdr *uh=(DnsUriHdr *)rend;
|
||||
rend+=sizeof(DnsUriHdr);
|
||||
setn16(&rf->type, QTYPE_URI);
|
||||
setn16(&rf->class, QCLASS_URI);
|
||||
setn16(&rf->ttl, 1);
|
||||
setn16(&rf->rdlength, 4+16);
|
||||
setn16(&uh->prio, 10);
|
||||
setn16(&uh->weight, 1);
|
||||
memcpy(rend, "http://esp.local", 16);
|
||||
rend+=16;
|
||||
setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1);
|
||||
// os_printf("Added NS rec to resp. Resp len is %d\n", (rend-reply));
|
||||
}
|
||||
}
|
||||
//Send the response
|
||||
espconn_sent(conn, (uint8*)reply, rend-reply);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR captdnsInit(void) {
|
||||
static struct espconn conn;
|
||||
static esp_udp udpconn;
|
||||
conn.type=ESPCONN_UDP;
|
||||
conn.proto.udp=&udpconn;
|
||||
conn.proto.udp->local_port = 53;
|
||||
espconn_regist_recvcb(&conn, captdnsRecv);
|
||||
espconn_create(&conn);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Some flash handling cgi routines. Used for reading the existing flash and updating the ESPFS image.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "cgiflash.h"
|
||||
#include "espfs.h"
|
||||
|
||||
|
||||
//Cgi that reads the SPI flash. Assumes 512KByte flash.
|
||||
int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) {
|
||||
int *pos=(int *)&connData->cgiData;
|
||||
if (connData->conn==NULL) {
|
||||
//Connection aborted. Clean up.
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
if (*pos==0) {
|
||||
os_printf("Start flash download.\n");
|
||||
httpdStartResponse(connData, 200);
|
||||
httpdHeader(connData, "Content-Type", "application/bin");
|
||||
httpdEndHeaders(connData);
|
||||
*pos=0x40200000;
|
||||
return HTTPD_CGI_MORE;
|
||||
}
|
||||
//Send 1K of flash per call. We will get called again if we haven't sent 512K yet.
|
||||
espconn_sent(connData->conn, (uint8 *)(*pos), 1024);
|
||||
*pos+=1024;
|
||||
if (*pos>=0x40200000+(512*1024)) return HTTPD_CGI_DONE; else return HTTPD_CGI_MORE;
|
||||
}
|
||||
|
||||
|
||||
//Cgi that allows the ESPFS image to be replaced via http POST
|
||||
int ICACHE_FLASH_ATTR cgiUploadEspfs(HttpdConnData *connData) {
|
||||
//Now esphttpd is a lib and doesn't know ESPFS_POS/ESPFS_SIZE, this does not work anymore. ToDo: Find some way
|
||||
//to reinstate it?
|
||||
#if 0
|
||||
if (connData->conn==NULL) {
|
||||
//Connection aborted. Clean up.
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
if(connData->post->len > ESPFS_SIZE){
|
||||
// The uploaded file is too large
|
||||
os_printf("ESPFS file too large\n");
|
||||
httpdSend(connData, "HTTP/1.0 500 Internal Server Error\r\nServer: esp8266-httpd/0.3\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 24\r\n\r\nESPFS image loo large.\r\n", -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
// The source should be 4byte aligned, so go ahead and flash whatever we have
|
||||
int address = ESPFS_POS + connData->post->received - connData->post->buffLen;
|
||||
if(address % SPI_FLASH_SEC_SIZE == 0){
|
||||
// We need to erase this block
|
||||
os_printf("Erasing flash at %d\n", address/SPI_FLASH_SEC_SIZE);
|
||||
spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE);
|
||||
}
|
||||
// Write the data
|
||||
os_printf("Writing at: 0x%x\n", address);
|
||||
spi_flash_write(address, (uint32 *)connData->post->buff, connData->post->buffLen);
|
||||
os_printf("Wrote %d bytes (%dB of %d)\n", connData->post->buffSize, connData->post->received, connData->post->len);//&connData->postBuff));
|
||||
#endif
|
||||
|
||||
if (connData->post->received == connData->post->len){
|
||||
httpdSend(connData, "Finished uploading", -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
} else {
|
||||
return HTTPD_CGI_MORE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
Cgi/template routines for the /wifi url.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "cgiwifi.h"
|
||||
|
||||
//Enable this to disallow any changes in AP settings
|
||||
//#define DEMO_MODE
|
||||
|
||||
//WiFi access point data
|
||||
typedef struct {
|
||||
char ssid[32];
|
||||
char rssi;
|
||||
char enc;
|
||||
} ApData;
|
||||
|
||||
//Scan result
|
||||
typedef struct {
|
||||
char scanInProgress; //if 1, don't access the underlying stuff from the webpage.
|
||||
ApData **apData;
|
||||
int noAps;
|
||||
} ScanResultData;
|
||||
|
||||
//Static scan status storage.
|
||||
static ScanResultData cgiWifiAps;
|
||||
|
||||
#define CONNTRY_IDLE 0
|
||||
#define CONNTRY_WORKING 1
|
||||
#define CONNTRY_SUCCESS 2
|
||||
#define CONNTRY_FAIL 3
|
||||
//Connection result var
|
||||
static int connTryStatus=CONNTRY_IDLE;
|
||||
static ETSTimer resetTimer;
|
||||
|
||||
//Callback the code calls when a wlan ap scan is done. Basically stores the result in
|
||||
//the cgiWifiAps struct.
|
||||
void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) {
|
||||
int n;
|
||||
struct bss_info *bss_link = (struct bss_info *)arg;
|
||||
os_printf("wifiScanDoneCb %d\n", status);
|
||||
if (status!=OK) {
|
||||
cgiWifiAps.scanInProgress=0;
|
||||
return;
|
||||
}
|
||||
|
||||
//Clear prev ap data if needed.
|
||||
if (cgiWifiAps.apData!=NULL) {
|
||||
for (n=0; n<cgiWifiAps.noAps; n++) os_free(cgiWifiAps.apData[n]);
|
||||
os_free(cgiWifiAps.apData);
|
||||
}
|
||||
|
||||
//Count amount of access points found.
|
||||
n=0;
|
||||
while (bss_link != NULL) {
|
||||
bss_link = bss_link->next.stqe_next;
|
||||
n++;
|
||||
}
|
||||
//Allocate memory for access point data
|
||||
cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n);
|
||||
cgiWifiAps.noAps=n;
|
||||
os_printf("Scan done: found %d APs\n", n);
|
||||
|
||||
//Copy access point data to the static struct
|
||||
n=0;
|
||||
bss_link = (struct bss_info *)arg;
|
||||
while (bss_link != NULL) {
|
||||
if (n>=cgiWifiAps.noAps) {
|
||||
//This means the bss_link changed under our nose. Shouldn't happen!
|
||||
//Break because otherwise we will write in unallocated memory.
|
||||
os_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps);
|
||||
break;
|
||||
}
|
||||
//Save the ap data.
|
||||
cgiWifiAps.apData[n]=(ApData *)os_malloc(sizeof(ApData));
|
||||
cgiWifiAps.apData[n]->rssi=bss_link->rssi;
|
||||
cgiWifiAps.apData[n]->enc=bss_link->authmode;
|
||||
strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32);
|
||||
|
||||
bss_link = bss_link->next.stqe_next;
|
||||
n++;
|
||||
}
|
||||
//We're done.
|
||||
cgiWifiAps.scanInProgress=0;
|
||||
}
|
||||
|
||||
|
||||
//Routine to start a WiFi access point scan.
|
||||
static void ICACHE_FLASH_ATTR wifiStartScan() {
|
||||
// int x;
|
||||
if (cgiWifiAps.scanInProgress) return;
|
||||
cgiWifiAps.scanInProgress=1;
|
||||
wifi_station_scan(NULL, wifiScanDoneCb);
|
||||
}
|
||||
|
||||
//This CGI is called from the bit of AJAX-code in wifi.tpl. It will initiate a
|
||||
//scan for access points and if available will return the result of an earlier scan.
|
||||
//The result is embedded in a bit of JSON parsed by the javascript in wifi.tpl.
|
||||
int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
|
||||
int pos=(int)connData->cgiData;
|
||||
int len;
|
||||
char buff[1024];
|
||||
|
||||
if (!cgiWifiAps.scanInProgress && pos!=0) {
|
||||
//Fill in json code for an access point
|
||||
if (pos-1<cgiWifiAps.noAps) {
|
||||
len=os_sprintf(buff, "{\"essid\": \"%s\", \"rssi\": \"%d\", \"enc\": \"%d\"}%s\n",
|
||||
cgiWifiAps.apData[pos-1]->ssid, cgiWifiAps.apData[pos-1]->rssi,
|
||||
cgiWifiAps.apData[pos-1]->enc, (pos-1==cgiWifiAps.noAps-1)?"":",");
|
||||
httpdSend(connData, buff, len);
|
||||
}
|
||||
pos++;
|
||||
if ((pos-1)>=cgiWifiAps.noAps) {
|
||||
len=os_sprintf(buff, "]\n}\n}\n");
|
||||
httpdSend(connData, buff, len);
|
||||
//Also start a new scan.
|
||||
wifiStartScan();
|
||||
return HTTPD_CGI_DONE;
|
||||
} else {
|
||||
connData->cgiData=(void*)pos;
|
||||
return HTTPD_CGI_MORE;
|
||||
}
|
||||
}
|
||||
|
||||
httpdStartResponse(connData, 200);
|
||||
httpdHeader(connData, "Content-Type", "text/json");
|
||||
httpdEndHeaders(connData);
|
||||
|
||||
if (cgiWifiAps.scanInProgress==1) {
|
||||
//We're still scanning. Tell Javascript code that.
|
||||
len=os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"1\"\n }\n}\n");
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
} else {
|
||||
//We have a scan result. Pass it on.
|
||||
len=os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"0\", \n\"APs\": [\n");
|
||||
httpdSend(connData, buff, len);
|
||||
if (cgiWifiAps.apData==NULL) cgiWifiAps.noAps=0;
|
||||
connData->cgiData=(void *)1;
|
||||
return HTTPD_CGI_MORE;
|
||||
}
|
||||
}
|
||||
|
||||
//Temp store for new ap info.
|
||||
static struct station_config stconf;
|
||||
|
||||
//This routine is ran some time after a connection attempt to an access point. If
|
||||
//the connect succeeds, this gets the module in STA-only mode.
|
||||
static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) {
|
||||
int x=wifi_station_get_connect_status();
|
||||
if (x==STATION_GOT_IP) {
|
||||
//Go to STA mode. This needs a reset, so do that.
|
||||
os_printf("Got IP. Going into STA mode..\n");
|
||||
wifi_set_opmode(1);
|
||||
system_restart();
|
||||
} else {
|
||||
connTryStatus=CONNTRY_FAIL;
|
||||
os_printf("Connect fail. Not going into STA-only mode.\n");
|
||||
//Maybe also pass this through on the webpage?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Actually connect to a station. This routine is timed because I had problems
|
||||
//with immediate connections earlier. It probably was something else that caused it,
|
||||
//but I can't be arsed to put the code back :P
|
||||
static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) {
|
||||
int x;
|
||||
os_printf("Try to connect to AP....\n");
|
||||
wifi_station_disconnect();
|
||||
wifi_station_set_config(&stconf);
|
||||
wifi_station_connect();
|
||||
x=wifi_get_opmode();
|
||||
connTryStatus=CONNTRY_WORKING;
|
||||
if (x!=1) {
|
||||
//Schedule disconnect/connect
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, 15000, 0); //time out after 15 secs of trying to connect
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//This cgi uses the routines above to connect to a specific access point with the
|
||||
//given ESSID using the given password.
|
||||
int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
|
||||
char essid[128];
|
||||
char passwd[128];
|
||||
static ETSTimer reassTimer;
|
||||
|
||||
if (connData->conn==NULL) {
|
||||
//Connection aborted. Clean up.
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
httpdFindArg(connData->post->buff, "essid", essid, sizeof(essid));
|
||||
httpdFindArg(connData->post->buff, "passwd", passwd, sizeof(passwd));
|
||||
|
||||
os_strncpy((char*)stconf.ssid, essid, 32);
|
||||
os_strncpy((char*)stconf.password, passwd, 64);
|
||||
os_printf("Try to connect to AP %s pw %s\n", essid, passwd);
|
||||
|
||||
//Schedule disconnect/connect
|
||||
os_timer_disarm(&reassTimer);
|
||||
os_timer_setfn(&reassTimer, reassTimerCb, NULL);
|
||||
//Set to 0 if you want to disable the actual reconnecting bit
|
||||
#ifdef DEMO_MODE
|
||||
httpdRedirect(connData, "/wifi");
|
||||
#else
|
||||
os_timer_arm(&reassTimer, 500, 0);
|
||||
httpdRedirect(connData, "connecting.html");
|
||||
#endif
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
//This cgi uses the routines above to connect to a specific access point with the
|
||||
//given ESSID using the given password.
|
||||
int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
|
||||
int len;
|
||||
char buff[1024];
|
||||
|
||||
if (connData->conn==NULL) {
|
||||
//Connection aborted. Clean up.
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff));
|
||||
if (len!=0) {
|
||||
os_printf("cgiWifiSetMode: %s\n", buff);
|
||||
#ifndef DEMO_MODE
|
||||
wifi_set_opmode(atoi(buff));
|
||||
system_restart();
|
||||
#endif
|
||||
}
|
||||
httpdRedirect(connData, "/wifi");
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
|
||||
char buff[1024];
|
||||
int len;
|
||||
struct ip_info info;
|
||||
int st=wifi_station_get_connect_status();
|
||||
httpdStartResponse(connData, 200);
|
||||
httpdHeader(connData, "Content-Type", "text/json");
|
||||
httpdEndHeaders(connData);
|
||||
if (connTryStatus==CONNTRY_IDLE) {
|
||||
len=os_sprintf(buff, "{\n \"status\": \"idle\"\n }\n");
|
||||
} else if (connTryStatus==CONNTRY_WORKING || connTryStatus==CONNTRY_SUCCESS) {
|
||||
if (st==STATION_GOT_IP) {
|
||||
wifi_get_ip_info(0, &info);
|
||||
len=os_sprintf(buff, "{\n \"status\": \"success\",\n \"ip\": \"%d.%d.%d.%d\" }\n",
|
||||
(info.ip.addr>>0)&0xff, (info.ip.addr>>8)&0xff,
|
||||
(info.ip.addr>>16)&0xff, (info.ip.addr>>24)&0xff);
|
||||
//Reset into AP-only mode sooner.
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, 1000, 0);
|
||||
} else {
|
||||
len=os_sprintf(buff, "{\n \"status\": \"working\"\n }\n");
|
||||
}
|
||||
} else {
|
||||
len=os_sprintf(buff, "{\n \"status\": \"fail\"\n }\n");
|
||||
}
|
||||
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
//Template code for the WLAN page.
|
||||
int ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) {
|
||||
char buff[1024];
|
||||
int x;
|
||||
static struct station_config stconf;
|
||||
if (token==NULL) return HTTPD_CGI_DONE;
|
||||
wifi_station_get_config(&stconf);
|
||||
|
||||
os_strcpy(buff, "Unknown");
|
||||
if (os_strcmp(token, "WiFiMode")==0) {
|
||||
x=wifi_get_opmode();
|
||||
if (x==1) os_strcpy(buff, "Client");
|
||||
if (x==2) os_strcpy(buff, "SoftAP");
|
||||
if (x==3) os_strcpy(buff, "STA+AP");
|
||||
} else if (os_strcmp(token, "currSsid")==0) {
|
||||
os_strcpy(buff, (char*)stconf.ssid);
|
||||
} else if (os_strcmp(token, "WiFiPasswd")==0) {
|
||||
os_strcpy(buff, (char*)stconf.password);
|
||||
} else if (os_strcmp(token, "WiFiapwarn")==0) {
|
||||
x=wifi_get_opmode();
|
||||
if (x==2) {
|
||||
os_strcpy(buff, "<b>Can't scan in this mode.</b> Click <a href=\"setmode.cgi?mode=3\">here</a> to go to STA+AP mode.");
|
||||
} else {
|
||||
os_strcpy(buff, "Click <a href=\"setmode.cgi?mode=2\">here</a> to go to standalone AP mode.");
|
||||
}
|
||||
}
|
||||
httpdSend(connData, buff, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user