/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * Jeroen Domburg 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 example code for the esphttpd library. It's a small-ish demo showing off the server, including WiFi connection management capabilities, some IO and some pictures of cats. */ #include #ifdef USE_AT #include #endif #include "httpd.h" #include "httpdespfs.h" #include "cgiwifi.h" #include "cgiflash.h" #include "auth.h" #include "espfs.h" #include "captdns.h" #include "webpages-espfs.h" #include "cgiwebsocket.h" #include "serbridge.h" #include "uart.h" #include "config.h" #include "status.h" #include "log.h" #define PROPLOADER #ifdef PROPLOADER #include "cgiprop.h" #include "httpdroffs.h" #include "discovery.h" #include "sscp.h" #endif //The example can print out the heap use every 3 seconds. You can use this to catch memory leaks. //#define SHOW_HEAP_USE #define SHOW_HEAP_INTERVAL 3000 //Test WebSockets broadcast messages //#define TEST_BROADCAST //Function that tells the authentication system what users/passwords live on the system. //This is disabled in the default build; if you want to try it, enable the authBasic line in //the builtInUrls below. int ICACHE_FLASH_ATTR myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { if (no==0) { os_strcpy(user, "admin"); os_strcpy(pass, "s3cr3t"); return 1; //Add more users this way. Check against incrementing no for each user added. // } else if (no==1) { // os_strcpy(user, "user1"); // os_strcpy(pass, "something"); // return 1; } return 0; } #ifdef TEST_BROADCAST static ETSTimer websockTimer; //Broadcast the uptime in seconds every second over connected websockets static void ICACHE_FLASH_ATTR websockTimerCb(void *arg) { static int ctr=0; char buff[128]; ctr++; os_sprintf(buff, "Up for %d minutes %d seconds!\n", ctr/60, ctr%60); cgiWebsockBroadcast("/websocket/ws.cgi", buff, os_strlen(buff), WEBSOCK_FLAG_NONE); } #endif //On reception of a message, send "You sent: " plus whatever the other side sent void ICACHE_FLASH_ATTR myWebsocketRecv(Websock *ws, char *data, int len, int flags) { int i; char buff[128]; os_sprintf(buff, "You sent: "); for (i=0; irecvCb=myWebsocketRecv; cgiWebsocketSend(ws, "Hi, Websocket!", 14, WEBSOCK_FLAG_NONE); } //On reception of a message, echo it back verbatim void ICACHE_FLASH_ATTR myEchoWebsocketRecv(Websock *ws, char *data, int len, int flags) { os_printf("EchoWs: echo, len=%d\n", len); cgiWebsocketSend(ws, data, len, flags); } //Echo websocket connected. Install reception handler. void ICACHE_FLASH_ATTR myEchoWebsocketConnect(Websock *ws) { os_printf("EchoWs: connect\n"); ws->recvCb=myEchoWebsocketRecv; } #ifdef ESPFS_POS CgiUploadFlashDef uploadParams={ .type=CGIFLASH_TYPE_ESPFS, .fw1Pos=ESPFS_POS, .fw2Pos=0, .fwSize=ESPFS_SIZE, }; #define INCLUDE_FLASH_FNS #endif #ifdef OTA_FLASH_SIZE_K CgiUploadFlashDef uploadParams={ .type=CGIFLASH_TYPE_FW, .fw1Pos=0x1000, .fw2Pos=((OTA_FLASH_SIZE_K*1024)/2)+0x1000, .fwSize=((OTA_FLASH_SIZE_K*1024)/2)-0x1000, .tagName=OTA_TAGNAME }; #define INCLUDE_FLASH_FNS #endif static int ICACHE_FLASH_ATTR cgiGetFirmwareNextFilter(HttpdConnData *connData) { #ifdef WIFI_BADGE if (connData->conn != NULL && IsAutoLoadEnabled()) { httpdSendResponse(connData, 400, "Not allowed\r\n", -1); return HTTPD_CGI_DONE; } #endif return cgiGetFirmwareNext(connData); } int ICACHE_FLASH_ATTR cgiUploadFirmwareFilter(HttpdConnData *connData) { #ifdef WIFI_BADGE if (connData->conn != NULL && IsAutoLoadEnabled()) { httpdSendResponse(connData, 400, "Not allowed\r\n", -1); return HTTPD_CGI_DONE; } #endif return cgiUploadFirmware(connData); } int ICACHE_FLASH_ATTR cgiWiFiConnectFilter(HttpdConnData *connData) { #ifdef WIFI_BADGE if (connData->conn != NULL && IsAutoLoadEnabled()) { httpdSendResponse(connData, 400, "Not allowed\r\n", -1); return HTTPD_CGI_DONE; } #endif return cgiWiFiConnect(connData); } int ICACHE_FLASH_ATTR cgiWiFiSetModeFilter(HttpdConnData *connData) { #ifdef WIFI_BADGE if (connData->conn != NULL && IsAutoLoadEnabled()) { httpdSendResponse(connData, 400, "Not allowed\r\n", -1); return HTTPD_CGI_DONE; } #endif return cgiWiFiSetMode(connData); } /* This is the main url->function dispatching data struct. In short, it's a struct with various URLs plus their handlers. The handlers can be 'standard' CGI functions you wrote, or 'special' CGIs requiring an argument. They can also be auth-functions. An asterisk will match any url starting with everything before the asterisks; "*" matches everything. The list will be handled top-down, so make sure to put more specific rules above the more general ones. Authorization things (like authBasic) act as a 'barrier' and should be placed above the URLs they protect. */ HttpdBuiltInUrl builtInUrls[]={ {"*", cgiRedirectApClientToHostname, "esp8266.nonet"}, {"/", cgiRedirect, "/index.html"}, #ifdef INCLUDE_FLASH_FNS {"/flash/next", cgiGetFirmwareNextFilter, &uploadParams}, {"/flash/upload", cgiUploadFirmwareFilter, &uploadParams}, #endif {"/flash/reboot", cgiRebootFirmware, NULL}, {"/websocket", cgiRedirect, "/websocket/index.html"}, {"/websocket/", cgiRedirect, "/websocket/index.html"}, {"/websocket/ws.cgi", cgiWebsocket, myWebsocketConnect}, {"/websocket/echo.cgi", cgiWebsocket, myEchoWebsocketConnect}, //Routines to make the /wifi URL and everything beneath it work. //Enable the line below to protect the WiFi configuration with an username/password combo. // {"/wifi/*", authBasic, myPassFn}, {"/wifi", cgiRedirect, "/wifi/wifi.html"}, {"/wifi/", cgiRedirect, "/wifi/wifi.html"}, {"/wifi/wifiscan.cgi", cgiWiFiScan, NULL}, {"/wifi/connect.cgi", cgiWiFiConnectFilter, NULL}, {"/wifi/connstatus.cgi", cgiWiFiConnStatus, NULL}, {"/wifi/setmode.cgi", cgiWiFiSetModeFilter, NULL}, {"/log/text", ajaxLog, NULL }, #ifdef PROPLOADER { "/userfs/format", cgiRoffsFormat, NULL }, { "/userfs/write", cgiRoffsWriteFile, NULL }, { "/propeller/load", cgiPropLoad, NULL }, { "/propeller/load-file", cgiPropLoadFile, NULL }, { "/propeller/reset", cgiPropReset, NULL }, { "/wx/module-info", cgiPropModuleInfo, NULL }, { "/wx/setting", cgiPropSetting, NULL }, { "/wx/save-settings", cgiPropSaveSettings, NULL }, { "/wx/restore-settings", cgiPropRestoreSettings, NULL }, { "/wx/restore-default-settings", cgiPropRestoreDefaultSettings, NULL }, { "/files/*", cgiRoffsHook, NULL }, //Catch-all cgi function for the flash filesystem { "/ws/*", cgiWebsocket, sscp_websocketConnect}, { "*", cgiSSCPHandleRequest, NULL }, //Check to see if MCU can handle the request #endif {"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem {NULL, NULL, NULL} }; #ifdef SHOW_HEAP_USE static ETSTimer prHeapTimer; static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); } #endif //Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. void ICACHE_FLASH_ATTR user_init(void) { int restoreOk; if (!(restoreOk = configRestore())) configSave(); wifi_station_set_hostname(flashConfig.module_name); captdnsInit(); // init UART uart_init(flashConfig.baud_rate, 115200); logInit(); os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); os_printf("Reset Pin: %d\n", flashConfig.reset_pin); os_printf("RX Pullup: %d\n", flashConfig.rx_pullup); statusInit(); // init the wifi-serial transparent bridge (port 23) serbridgeInit(23); uart_add_recv_cb(&serbridgeUartCb); #ifdef PROPLOADER if (flashConfig.sscp_loader == 0) initDiscovery(); cgiPropInit(); sscp_init(); #endif // 0x40200000 is the base address for spi flash memory mapping, ESPFS_POS is the position // where image is written in flash that is defined in Makefile. #ifdef ESPFS_POS espFsInit((void*)(0x40200000 + ESPFS_POS)); #else espFsInit((void*)(webpages_espfs_start)); #endif httpdInit(builtInUrls, 80); #ifdef SHOW_HEAP_USE os_timer_disarm(&prHeapTimer); os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL); os_timer_arm(&prHeapTimer, SHOW_HEAP_INTERVAL, 1); #endif #ifdef TEST_BROADCAST os_timer_disarm(&websockTimer); os_timer_setfn(&websockTimer, websockTimerCb, NULL); os_timer_arm(&websockTimer, 10000, 1); #endif os_printf("\nReady\n"); } void ICACHE_FLASH_ATTR user_rf_pre_init() { //Not needed, but some SDK versions want this defined. } uint32 ICACHE_FLASH_ATTR user_rf_cal_sector_set(void) { enum flash_size_map size_map = system_get_flash_size_map(); uint32 rf_cal_sec = 0; switch (size_map) { case FLASH_SIZE_4M_MAP_256_256: rf_cal_sec = 128 - 8; break; case FLASH_SIZE_8M_MAP_512_512: rf_cal_sec = 256 - 5; break; case FLASH_SIZE_16M_MAP_512_512: case FLASH_SIZE_16M_MAP_1024_1024: rf_cal_sec = 512 - 5; break; case FLASH_SIZE_32M_MAP_512_512: case FLASH_SIZE_32M_MAP_1024_1024: rf_cal_sec = 1024 - 5; break; default: rf_cal_sec = 0; break; } return rf_cal_sec; }