pull/30/head
			
			
		
		
							parent
							
								
									c39391f4a0
								
							
						
					
					
						commit
						e617b4f283
					
				@ -0,0 +1,144 @@ | 
				
			|||||||
 | 
					<?php | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require '_test_env.php'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$prod = defined('STDIN'); | 
				
			||||||
 | 
					$root = $prod ? '' : ('http://' . ESP_IP); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$menu = [ | 
				
			||||||
 | 
						'home'        => [ $prod ? '/status' : '/page_status.php',      'Home'          ], | 
				
			||||||
 | 
						'wifi'        => [ $prod ? '/wifi' : '/page_wifi.php',          'WiFi config'   ], | 
				
			||||||
 | 
						'about'       => [ $prod ? '/about' : '/page_about.php',        'About'         ], | 
				
			||||||
 | 
					]; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$appname = 'Current Analyser'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function e($s) { | 
				
			||||||
 | 
						return htmlspecialchars($s, ENT_HTML5|ENT_QUOTES); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					?><!doctype html> | 
				
			||||||
 | 
					<html> | 
				
			||||||
 | 
					<head> | 
				
			||||||
 | 
						<meta charset="utf-8"> | 
				
			||||||
 | 
						<meta http-equiv="X-UA-Compatible" content="IE=edge"> | 
				
			||||||
 | 
						<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<title><?= e($menu[$page][1]) ?> - <?= e($appname) ?></title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<link href="/css/app.css" rel="stylesheet"> | 
				
			||||||
 | 
						<script src="/js/all.js"></script> | 
				
			||||||
 | 
						<script> | 
				
			||||||
 | 
							// server root (or URL) - used for local development with remote AJAX calls | 
				
			||||||
 | 
							// (this needs CORS working on the target - which I added to esp-httpd) | 
				
			||||||
 | 
							var _root = <?= json_encode($root) ?>;
 | 
				
			||||||
 | 
						</script> | 
				
			||||||
 | 
					</head> | 
				
			||||||
 | 
					<body class="page-<?=$page?>">
 | 
				
			||||||
 | 
					<div id="outer"> | 
				
			||||||
 | 
						<nav id="menu"> | 
				
			||||||
 | 
							<div id="brand" onclick="$('#menu').toggleClass('expanded')"><?= e($appname) ?></div>
 | 
				
			||||||
 | 
							<?php | 
				
			||||||
 | 
							// generate the menu | 
				
			||||||
 | 
							foreach($menu as $k => $m) { | 
				
			||||||
 | 
								$sel = ($page == $k) ? ' class="selected"' : ''; | 
				
			||||||
 | 
								$text = e($m[1]); | 
				
			||||||
 | 
								$url = e($m[0]); | 
				
			||||||
 | 
								echo "<a href=\"$url\"$sel>$text</a>"; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							?> | 
				
			||||||
 | 
						</nav> | 
				
			||||||
 | 
						<div id="content"> | 
				
			||||||
 | 
							<img src="/img/loader.gif" alt="Loading…" id="loader"> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!doctype html> | 
				
			||||||
 | 
					<html> | 
				
			||||||
 | 
					<head> | 
				
			||||||
 | 
						<meta charset="utf-8"> | 
				
			||||||
 | 
						<meta name="viewport" content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<title>WiFi Settings - ESP8266 Remote Terminal</title> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<link rel="stylesheet" href="/css/app.css"> | 
				
			||||||
 | 
						<script src="/js/app.js"></script> | 
				
			||||||
 | 
					</head> | 
				
			||||||
 | 
					<body class="page-wifi"> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img src="/img/loader.gif" alt="Loading…" id="loader"> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h1 onclick="location.href='/'">WiFi settings</h1> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="Box" id="wificonfbox"> | 
				
			||||||
 | 
						<table> | 
				
			||||||
 | 
							<tr> | 
				
			||||||
 | 
								<th>WiFi mode</th> | 
				
			||||||
 | 
								<td id="opmodebox">%WiFiMode%</td> | 
				
			||||||
 | 
							</tr> | 
				
			||||||
 | 
							<tr class="x-hide-noip x-hide-2"> | 
				
			||||||
 | 
								<th>IP</th> | 
				
			||||||
 | 
								<td>%StaIP%</td> | 
				
			||||||
 | 
							</tr> | 
				
			||||||
 | 
							<tr> | 
				
			||||||
 | 
								<th>Switch to</th> | 
				
			||||||
 | 
								<td id="modeswitch"></td> | 
				
			||||||
 | 
							</tr> | 
				
			||||||
 | 
							<tr class="x-hide-1"> | 
				
			||||||
 | 
								<th><label for="channel">AP channel</label></th> | 
				
			||||||
 | 
								<td> | 
				
			||||||
 | 
									<form action="/wifi/setchannel" method="GET"> | 
				
			||||||
 | 
										<input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%"><!-- | 
				
			||||||
 | 
										--><input type="submit" value="Set" class="narrow btn-green x-hide-3"> | 
				
			||||||
 | 
									</form> | 
				
			||||||
 | 
								</td> | 
				
			||||||
 | 
							</tr> | 
				
			||||||
 | 
							<tr class="x-hide-1"> | 
				
			||||||
 | 
								<th><label for="channel">AP name</label></th> | 
				
			||||||
 | 
								<td> | 
				
			||||||
 | 
									<form action="/wifi/setname" method="GET"> | 
				
			||||||
 | 
										<input name="name" type="text" value="%APName%"><!-- | 
				
			||||||
 | 
										--><input type="submit" value="Set" class="narrow btn-green"> | 
				
			||||||
 | 
									</form> | 
				
			||||||
 | 
								</td> | 
				
			||||||
 | 
							</tr> | 
				
			||||||
 | 
							<tr><td colspan=2 style="white-space: normal;"> | 
				
			||||||
 | 
									<p>Some changes require a reboot, dropping connection. It can take a while to re-connect.</p> | 
				
			||||||
 | 
									<p> | 
				
			||||||
 | 
										<b>If you lose access</b>, hold the BOOT button for 2 seconds (the Tx LED starts blinking) to re-enable AP mode. | 
				
			||||||
 | 
										If that fails, hold the BOOT button for over 5 seconds (rapid Tx LED flashing) to perform a factory reset. | 
				
			||||||
 | 
									<p> | 
				
			||||||
 | 
								</td></tr> | 
				
			||||||
 | 
						</table> | 
				
			||||||
 | 
					</div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="Box" id="ap-box"> | 
				
			||||||
 | 
						<h2>Select AP to join</h2> | 
				
			||||||
 | 
						<div id="ap-loader" class="x-hide-2">Scanning<span class="anim-dots">.</span></div> | 
				
			||||||
 | 
						<div id="ap-noscan" class="x-hide-1 x-hide-3">Can't scan in AP-only mode.</div> | 
				
			||||||
 | 
						<div id="ap-list" style="display:none"></div> | 
				
			||||||
 | 
					</div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<nav id="botnav"> | 
				
			||||||
 | 
						<a href="/">Terminal</a><!-- | 
				
			||||||
 | 
							--><a href="/help">Help</a><!-- | 
				
			||||||
 | 
							--><a href="/about">About</a> | 
				
			||||||
 | 
					</nav> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="Modal hidden" id="psk-modal"> | 
				
			||||||
 | 
						<div class="Dialog"> | 
				
			||||||
 | 
							<form action="/wifi/connect" method="post" id="conn-form"> | 
				
			||||||
 | 
								<input type="hidden" id="conn-essid" name="essid"><!-- | 
				
			||||||
 | 
								--><label for="conn-passwd">Password:</label><!-- | 
				
			||||||
 | 
								--><input type="password" id="conn-passwd" name="passwd"><!-- | 
				
			||||||
 | 
								--><input type="submit" value="Connect!"> | 
				
			||||||
 | 
							</form> | 
				
			||||||
 | 
						</div> | 
				
			||||||
 | 
					</div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
						_root = window.location.host; | 
				
			||||||
 | 
						wifiInit({staSSID: '%StaSSID%', staIP: '%StaIP%', mode: '%WiFiModeNum%'}); | 
				
			||||||
 | 
					</script> | 
				
			||||||
 | 
					</body> | 
				
			||||||
 | 
					</html> | 
				
			||||||
@ -1 +1 @@ | 
				
			|||||||
Subproject commit 03003ea591a272df50159ba52f84ca84c5cad78e | 
					Subproject commit 38c6c91f50e5a5cfba8df8309a95e814695accba | 
				
			||||||
@ -0,0 +1,654 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					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. 
 | 
				
			||||||
 | 
					 * ---------------------------------------------------------------------------- | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * File adapted and improved by Ondřej Hruška <ondra@ondrovo.com> | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO convert to work with WiFi Manager
 | 
				
			||||||
 | 
					// TODO make changes write to wificonf and apply when a different CGI is run (/wifi/apply or something)
 | 
				
			||||||
 | 
					// TODO (connection will trigger this immediately, with some delayto show the connecting page. Then polling cna proceed as usual)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <esp8266.h> | 
				
			||||||
 | 
					#include "cgi_wifi.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** WiFi access point data */ | 
				
			||||||
 | 
					typedef struct { | 
				
			||||||
 | 
						char ssid[32]; | 
				
			||||||
 | 
						char bssid[8]; | 
				
			||||||
 | 
						int channel; | 
				
			||||||
 | 
						char rssi; | 
				
			||||||
 | 
						char enc; | 
				
			||||||
 | 
					} ApData; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Scan result type */ | 
				
			||||||
 | 
					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; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Progress of connection to AP enum */ | 
				
			||||||
 | 
					typedef enum { | 
				
			||||||
 | 
						CONNTRY_IDLE = 0, | 
				
			||||||
 | 
						CONNTRY_WORKING = 1, | 
				
			||||||
 | 
						CONNTRY_SUCCESS = 2, | 
				
			||||||
 | 
						CONNTRY_FAIL = 3, | 
				
			||||||
 | 
					} ConnTry; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Connection result var */ | 
				
			||||||
 | 
					static ConnTry connTryStatus = CONNTRY_IDLE; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Connection to AP periodic check timer */ | 
				
			||||||
 | 
					static os_timer_t staCheckTimer; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** reset_later() timer */ | 
				
			||||||
 | 
					static ETSTimer resetTmr; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Callback for reset_later() | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					static void ICACHE_FLASH_ATTR resetTmrCb(void *arg) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						system_restart(); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Schedule a reset | 
				
			||||||
 | 
					 * @param ms reset delay (milliseconds) | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					static void ICACHE_FLASH_ATTR reset_later(int ms) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						os_timer_disarm(&resetTmr); | 
				
			||||||
 | 
						os_timer_setfn(&resetTmr, resetTmrCb, NULL); | 
				
			||||||
 | 
						os_timer_arm(&resetTmr, ms, false); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate approximate signal strength % from RSSI | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					int ICACHE_FLASH_ATTR rssi2perc(int rssi) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						int r; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rssi > 200) | 
				
			||||||
 | 
							r = 100; | 
				
			||||||
 | 
						else if (rssi < 100) | 
				
			||||||
 | 
							r = 0; | 
				
			||||||
 | 
						else | 
				
			||||||
 | 
							r = 100 - 2 * (200 - rssi); // approx.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (r > 100) r = 100; | 
				
			||||||
 | 
						if (r < 0) r = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return r; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert Auth type to string | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					const ICACHE_FLASH_ATTR char *auth2str(AUTH_MODE auth) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						switch (auth) { | 
				
			||||||
 | 
							case AUTH_OPEN: | 
				
			||||||
 | 
								return "Open"; | 
				
			||||||
 | 
							case AUTH_WEP: | 
				
			||||||
 | 
								return "WEP"; | 
				
			||||||
 | 
							case AUTH_WPA_PSK: | 
				
			||||||
 | 
								return "WPA"; | 
				
			||||||
 | 
							case AUTH_WPA2_PSK: | 
				
			||||||
 | 
								return "WPA2"; | 
				
			||||||
 | 
							case AUTH_WPA_WPA2_PSK: | 
				
			||||||
 | 
								return "WPA/WPA2"; | 
				
			||||||
 | 
							default: | 
				
			||||||
 | 
								return "Unknown"; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert WiFi opmode to string | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					const ICACHE_FLASH_ATTR char *opmode2str(WIFI_MODE opmode) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						switch (opmode) { | 
				
			||||||
 | 
							case NULL_MODE: | 
				
			||||||
 | 
								return "Disabled"; | 
				
			||||||
 | 
							case STATION_MODE: | 
				
			||||||
 | 
								return "Client"; | 
				
			||||||
 | 
							case SOFTAP_MODE: | 
				
			||||||
 | 
								return "AP only"; | 
				
			||||||
 | 
							case STATIONAP_MODE: | 
				
			||||||
 | 
								return "Client+AP"; | 
				
			||||||
 | 
							default: | 
				
			||||||
 | 
								return "Unknown"; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Callback the code calls when a wlan ap scan is done. Basically stores the result in | 
				
			||||||
 | 
					 * the static cgiWifiAps struct. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * @param arg - a pointer to {struct bss_info}, which is a linked list of the found APs | 
				
			||||||
 | 
					 * @param status - OK if the scan succeeded | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						int n; | 
				
			||||||
 | 
						struct bss_info *bss_link = (struct bss_info *) arg; | 
				
			||||||
 | 
						dbg("wifiScanDoneCb %d", 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++) free(cgiWifiAps.apData[n]); | 
				
			||||||
 | 
							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 **) malloc(sizeof(ApData *) * n); | 
				
			||||||
 | 
						if (cgiWifiAps.apData == NULL) { | 
				
			||||||
 | 
							error("Out of memory allocating apData"); | 
				
			||||||
 | 
							return; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						cgiWifiAps.noAps = n; | 
				
			||||||
 | 
						info("Scan done: found %d APs", 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.
 | 
				
			||||||
 | 
								error("Huh? I have more than the allocated %d aps!", cgiWifiAps.noAps); | 
				
			||||||
 | 
								break; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							// Save the ap data.
 | 
				
			||||||
 | 
							cgiWifiAps.apData[n] = (ApData *) malloc(sizeof(ApData)); | 
				
			||||||
 | 
							if (cgiWifiAps.apData[n] == NULL) { | 
				
			||||||
 | 
								error("Can't allocate mem for ap buff."); | 
				
			||||||
 | 
								cgiWifiAps.scanInProgress = 0; | 
				
			||||||
 | 
								return; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							cgiWifiAps.apData[n]->rssi = bss_link->rssi; | 
				
			||||||
 | 
							cgiWifiAps.apData[n]->channel = bss_link->channel; | 
				
			||||||
 | 
							cgiWifiAps.apData[n]->enc = bss_link->authmode; | 
				
			||||||
 | 
							strncpy(cgiWifiAps.apData[n]->ssid, (char *) bss_link->ssid, 32); | 
				
			||||||
 | 
							strncpy(cgiWifiAps.apData[n]->bssid, (char *) bss_link->bssid, 6); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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(void) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						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. | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						int pos = (int) connData->cgiData; | 
				
			||||||
 | 
						int len; | 
				
			||||||
 | 
						char buff[256]; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2nd and following runs of the function via MORE:
 | 
				
			||||||
 | 
						if (!cgiWifiAps.scanInProgress && pos != 0) { | 
				
			||||||
 | 
							// Fill in json code for an access point
 | 
				
			||||||
 | 
							if (pos - 1 < cgiWifiAps.noAps) { | 
				
			||||||
 | 
								int rssi = cgiWifiAps.apData[pos - 1]->rssi; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								len = sprintf(buff, "{\"essid\": \"%s\", \"bssid\": \"" | 
				
			||||||
 | 
									MACSTR | 
				
			||||||
 | 
									"\", \"rssi\": %d, \"rssi_perc\": %d, \"enc\": %d, \"channel\": %d}%s", | 
				
			||||||
 | 
											  cgiWifiAps.apData[pos - 1]->ssid, | 
				
			||||||
 | 
											  MAC2STR(cgiWifiAps.apData[pos - 1]->bssid), | 
				
			||||||
 | 
											  rssi, | 
				
			||||||
 | 
											  rssi2perc(rssi), | 
				
			||||||
 | 
											  cgiWifiAps.apData[pos - 1]->enc, | 
				
			||||||
 | 
											  cgiWifiAps.apData[pos - 1]->channel, | 
				
			||||||
 | 
											  (pos - 1 == cgiWifiAps.noAps - 1) ? "\n  " : ",\n   "); //<-terminator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								httpdSend(connData, buff, len); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							pos++; | 
				
			||||||
 | 
							if ((pos - 1) >= cgiWifiAps.noAps) { | 
				
			||||||
 | 
								len = sprintf(buff, "  ]\n }\n}"); // terminate the whole object
 | 
				
			||||||
 | 
								httpdSend(connData, buff, len); | 
				
			||||||
 | 
								// Also start a new scan.
 | 
				
			||||||
 | 
								wifiStartScan(); | 
				
			||||||
 | 
								return HTTPD_CGI_DONE; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							else { | 
				
			||||||
 | 
								connData->cgiData = (void *) pos; | 
				
			||||||
 | 
								return HTTPD_CGI_MORE; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// First run of the function
 | 
				
			||||||
 | 
						httpdStartResponse(connData, 200); | 
				
			||||||
 | 
						httpdHeader(connData, "Content-Type", "application/json"); | 
				
			||||||
 | 
						httpdEndHeaders(connData); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cgiWifiAps.scanInProgress == 1) { | 
				
			||||||
 | 
							// We're still scanning. Tell Javascript code that.
 | 
				
			||||||
 | 
							len = sprintf(buff, "{\n \"result\": {\n  \"inProgress\": 1\n }\n}"); | 
				
			||||||
 | 
							httpdSend(connData, buff, len); | 
				
			||||||
 | 
							return HTTPD_CGI_DONE; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else { | 
				
			||||||
 | 
							// We have a scan result. Pass it on.
 | 
				
			||||||
 | 
							len = 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 staCheckConnStatus(void *arg) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						int x = wifi_station_get_connect_status(); | 
				
			||||||
 | 
						if (x == STATION_GOT_IP) { | 
				
			||||||
 | 
							info("Connected to AP."); | 
				
			||||||
 | 
							connTryStatus = CONNTRY_SUCCESS; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// This would enter STA only mode, but that kills the browser page if using STA+AP.
 | 
				
			||||||
 | 
							// Instead we stay in the current mode and let the user switch manually.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//wifi_set_opmode(STATION_MODE);
 | 
				
			||||||
 | 
							//system_restart();
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else { | 
				
			||||||
 | 
							connTryStatus = CONNTRY_FAIL; | 
				
			||||||
 | 
							error("Connection failed."); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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 cgiWiFiConnect_do(void *arg) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						int x; | 
				
			||||||
 | 
						dbg("Try to connect to AP..."); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wifi_station_disconnect(); | 
				
			||||||
 | 
						wifi_station_set_config(&stconf); | 
				
			||||||
 | 
						wifi_station_connect(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						x = wifi_get_opmode(); | 
				
			||||||
 | 
						connTryStatus = CONNTRY_WORKING; | 
				
			||||||
 | 
						if (x != STATION_MODE) { | 
				
			||||||
 | 
							//Schedule check
 | 
				
			||||||
 | 
							os_timer_disarm(&staCheckTimer); | 
				
			||||||
 | 
							os_timer_setfn(&staCheckTimer, staCheckConnStatus, NULL); | 
				
			||||||
 | 
							os_timer_arm(&staCheckTimer, 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. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * Args: | 
				
			||||||
 | 
					 * - essid = SSID to connect to | 
				
			||||||
 | 
					 * - passwd = password to connect with | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						char essid[128]; | 
				
			||||||
 | 
						char passwd[128]; | 
				
			||||||
 | 
						static os_timer_t reassTimer; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (connData->conn == NULL) { | 
				
			||||||
 | 
							//Connection aborted. Clean up.
 | 
				
			||||||
 | 
							return HTTPD_CGI_DONE; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int ssilen = httpdFindArg(connData->post->buff, "essid", essid, sizeof(essid)); | 
				
			||||||
 | 
						int passlen = httpdFindArg(connData->post->buff, "passwd", passwd, sizeof(passwd)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ssilen == -1 || passlen == -1) { | 
				
			||||||
 | 
							error("Not rx needed args!"); | 
				
			||||||
 | 
							httpdRedirect(connData, "/wifi"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else { | 
				
			||||||
 | 
							strncpy((char *) stconf.ssid, essid, 32); | 
				
			||||||
 | 
							strncpy((char *) stconf.password, passwd, 64); | 
				
			||||||
 | 
							info("Try to connect to AP %s pw %s", essid, passwd); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//Schedule disconnect/connect
 | 
				
			||||||
 | 
							os_timer_disarm(&reassTimer); | 
				
			||||||
 | 
							os_timer_setfn(&reassTimer, cgiWiFiConnect_do, NULL); | 
				
			||||||
 | 
							// redirect & start connecting a little bit later
 | 
				
			||||||
 | 
							os_timer_arm(&reassTimer, 2000, 0); // was 500, increased so the connecting page has time to load
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							connTryStatus = CONNTRY_IDLE; | 
				
			||||||
 | 
							httpdRedirect(connData, "/wifi/connecting"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						return HTTPD_CGI_DONE; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Cgi to get connection status. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * This endpoint returns JSON with keys: | 
				
			||||||
 | 
					 * - status = 'idle', 'working' or 'fail', | 
				
			||||||
 | 
					 * - ip = IP address, after connection succeeds | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						char buff[100]; | 
				
			||||||
 | 
						int len; | 
				
			||||||
 | 
						struct ip_info info; | 
				
			||||||
 | 
						int st = wifi_station_get_connect_status(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpdStartResponse(connData, 200); | 
				
			||||||
 | 
						httpdHeader(connData, "Content-Type", "application/json"); | 
				
			||||||
 | 
						httpdEndHeaders(connData); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (connTryStatus == CONNTRY_IDLE) { | 
				
			||||||
 | 
							len = sprintf(buff, "{\"status\": \"idle\"}"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (connTryStatus == CONNTRY_WORKING || connTryStatus == CONNTRY_SUCCESS) { | 
				
			||||||
 | 
							if (st == STATION_GOT_IP) { | 
				
			||||||
 | 
								wifi_get_ip_info(STATION_IF, &info); | 
				
			||||||
 | 
								len = sprintf(buff, "{\"status\": \"success\", \"ip\": \"" | 
				
			||||||
 | 
									IPSTR | 
				
			||||||
 | 
									"\"}", GOOD_IP2STR(info.ip.addr)); | 
				
			||||||
 | 
								os_timer_disarm(&staCheckTimer); | 
				
			||||||
 | 
								os_timer_setfn(&staCheckTimer, staCheckConnStatus, NULL); | 
				
			||||||
 | 
								os_timer_arm(&staCheckTimer, 1000, 0); | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								len = sprintf(buff, "{\"status\": \"working\"}"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else { | 
				
			||||||
 | 
							len = sprintf(buff, "{\"status\": \"fail\"}"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpdSend(connData, buff, len); | 
				
			||||||
 | 
						return HTTPD_CGI_DONE; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Universal CGI endpoint to set WiFi params. | 
				
			||||||
 | 
					 * Note that some may cause a (delayed) restart. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * Args: | 
				
			||||||
 | 
					 * - ap_ch = channel 1-14 | 
				
			||||||
 | 
					 * - ap_ssid = SSID name for AP mode | 
				
			||||||
 | 
					 * - opmode = WiFi mode (resets device) | 
				
			||||||
 | 
					 * - hostname = set client hostname | 
				
			||||||
 | 
					 * - tpw = set transmit power | 
				
			||||||
 | 
					 * - sta_dhcp_lt = DHCP server lease time | 
				
			||||||
 | 
					 * - sta_ip   = station mode static IP | 
				
			||||||
 | 
					 * - sta_mask = station mode static IP mask (apply only if 'ip' is also sent) | 
				
			||||||
 | 
					 * - sta_gw   = station mode default gateway (apply only if 'ip' is also sent) | 
				
			||||||
 | 
					 *              (can be left out, then 0.0.0.0 is used and outbound connections won't work - | 
				
			||||||
 | 
					 *              but we're normally not making any) | 
				
			||||||
 | 
					 * - dhcp = enable or disable DHCP on the station interface | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						int len, len2, len3; | 
				
			||||||
 | 
						char buff[50]; | 
				
			||||||
 | 
						char buff2[50]; | 
				
			||||||
 | 
						char buff3[50]; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO change so that settings are not applied immediately, but persisted first
 | 
				
			||||||
 | 
						// TODO apply temporary changes like static IP in wifi event CBs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (connData->conn == NULL) { | 
				
			||||||
 | 
							//Connection aborted. Clean up.
 | 
				
			||||||
 | 
							return HTTPD_CGI_DONE; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// AP channel (applies in AP-only mode)
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "ap_ch", buff, sizeof(buff)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							info("Setting WiFi channel for AP-only mode to: %s", buff); | 
				
			||||||
 | 
							int channel = atoi(buff); | 
				
			||||||
 | 
							if (channel > 0 && channel < 15) { | 
				
			||||||
 | 
								dbg("Setting channel=%d", channel); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								struct softap_config wificfg; | 
				
			||||||
 | 
								wifi_softap_get_config(&wificfg); | 
				
			||||||
 | 
								wificfg.channel = (uint8) channel; | 
				
			||||||
 | 
								wifi_softap_set_config(&wificfg); | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								warn("Bad channel value %s, allowed 1-14", buff); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SSID name in AP mode
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "ap_ssid", buff, sizeof(buff)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							int i; | 
				
			||||||
 | 
							for (i = 0; i < 32; i++) { | 
				
			||||||
 | 
								char c = buff[i]; | 
				
			||||||
 | 
								if (c == 0) break; | 
				
			||||||
 | 
								if (c < 32 || c >= 127) buff[i] = '_'; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							buff[i] = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							info("Setting SSID to %s", buff); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct softap_config wificfg; | 
				
			||||||
 | 
							wifi_softap_get_config(&wificfg); | 
				
			||||||
 | 
							sprintf((char *) wificfg.ssid, buff); | 
				
			||||||
 | 
							wificfg.ssid_len = strlen((char *) wificfg.ssid); | 
				
			||||||
 | 
							wifi_softap_set_config(&wificfg); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// WiFi mode
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "opmode", buff, sizeof(buff)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							dbg("Setting WiFi opmode to: %s", buff); | 
				
			||||||
 | 
							int mode = atoi(buff); | 
				
			||||||
 | 
							if (mode > NULL_MODE && mode < MAX_MODE) { | 
				
			||||||
 | 
								wifi_set_opmode(mode); | 
				
			||||||
 | 
								reset_later(200); | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								warn("Bad opmode value %s", buff); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Hostname in station mode (for DHCP)
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "hostname", buff, sizeof(buff)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							dbg("Setting station sta_hostname to: %s", buff); | 
				
			||||||
 | 
							wifi_station_set_hostname(buff); | 
				
			||||||
 | 
							// TODO persistency, re-apply on boot
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Hostname in station mode (for DHCP)
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "tpw", buff, sizeof(buff)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							dbg("Setting AP power to: %s", buff); | 
				
			||||||
 | 
							int tpw = atoi(buff); | 
				
			||||||
 | 
							// min tpw to avoid user locking themselves out TODO verify
 | 
				
			||||||
 | 
							if (tpw >= 0 && tpw <= 82) { | 
				
			||||||
 | 
								// TODO persistency, re-apply on boot
 | 
				
			||||||
 | 
								system_phy_set_max_tpw(tpw); | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								warn("tpw %s out of allowed range 0-82.", buff); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DHCP server lease time
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "ap_dhcp_lt", buff, sizeof(buff)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							dbg("Setting DHCP lease time to: %s min.", buff); | 
				
			||||||
 | 
							int min = atoi(buff); | 
				
			||||||
 | 
							if (min >= 1 && min <= 2880) { | 
				
			||||||
 | 
								// TODO persistency, re-apply on boot
 | 
				
			||||||
 | 
								// TODO set only if we're in the right opmode
 | 
				
			||||||
 | 
								wifi_softap_set_dhcps_lease_time(min); | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								warn("Lease time %s out of allowed range 1-2880.", buff); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DHCP enable / disable (disable means static IP is enabled)
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "sta_dhcp", buff, sizeof(buff)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							dbg("DHCP enable =  %s", buff); | 
				
			||||||
 | 
							int enable = atoi(buff); | 
				
			||||||
 | 
							if (enable != 0) { | 
				
			||||||
 | 
								wifi_station_dhcpc_stop(); | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								wifi_station_dhcpc_start(); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							// TODO persistency
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Static IP
 | 
				
			||||||
 | 
						len = httpdFindArg(connData->getArgs, "sta_ip", buff, sizeof(buff)); | 
				
			||||||
 | 
						len2 = httpdFindArg(connData->getArgs, "sta_mask", buff2, sizeof(buff2)); | 
				
			||||||
 | 
						len3 = httpdFindArg(connData->getArgs, "sta_gw", buff3, sizeof(buff3)); | 
				
			||||||
 | 
						if (len > 0) { | 
				
			||||||
 | 
							// TODO set only if we're in the right opmode
 | 
				
			||||||
 | 
							// TODO persistency
 | 
				
			||||||
 | 
							dbg("Setting static IP = %s", buff); | 
				
			||||||
 | 
							struct ip_info ipinfo; | 
				
			||||||
 | 
							ipinfo.ip.addr = ipaddr_addr(buff); | 
				
			||||||
 | 
							ipinfo.netmask.addr = IPADDR_NONE; | 
				
			||||||
 | 
							ipinfo.gw.addr = IPADDR_NONE; | 
				
			||||||
 | 
							if (len2 > 0) { | 
				
			||||||
 | 
								dbg("Netmask = %s", buff2); | 
				
			||||||
 | 
								ipinfo.netmask.addr = ipaddr_addr(buff2); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							if (len3 > 0) { | 
				
			||||||
 | 
								dbg("Gateway = %s", buff3); | 
				
			||||||
 | 
								ipinfo.gw.addr = ipaddr_addr(buff3); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							// TODO ...
 | 
				
			||||||
 | 
							wifi_station_dhcpc_stop(); | 
				
			||||||
 | 
							wifi_set_ip_info(STATION_IF, &ipinfo); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpdRedirect(connData, "/wifi"); | 
				
			||||||
 | 
						return HTTPD_CGI_DONE; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Template code for the WLAN page.
 | 
				
			||||||
 | 
					httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						char buff[500]; | 
				
			||||||
 | 
						int x; | 
				
			||||||
 | 
						int connectStatus; | 
				
			||||||
 | 
						static struct station_config stconf; | 
				
			||||||
 | 
						static struct softap_config apconf; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (token == NULL) { | 
				
			||||||
 | 
							// We're done
 | 
				
			||||||
 | 
							return HTTPD_CGI_DONE; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wifi_station_get_config(&stconf); | 
				
			||||||
 | 
						wifi_softap_get_config(&apconf); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strcpy(buff, "Unknown"); | 
				
			||||||
 | 
						if (streq(token, "WiFiMode")) { | 
				
			||||||
 | 
							x = wifi_get_opmode(); | 
				
			||||||
 | 
							strcpy(buff, opmode2str(x)); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (streq(token, "WiFiModeNum")) { | 
				
			||||||
 | 
							x = wifi_get_opmode(); | 
				
			||||||
 | 
							sprintf(buff, "%d", x); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (streq(token, "WiFiChannel")) { | 
				
			||||||
 | 
							sprintf(buff, "%d", apconf.channel); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (streq(token, "APName")) { | 
				
			||||||
 | 
							sprintf(buff, "%s", apconf.ssid); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (streq(token, "StaIP")) { | 
				
			||||||
 | 
							x = wifi_get_opmode(); | 
				
			||||||
 | 
							connectStatus = wifi_station_get_connect_status(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP) { | 
				
			||||||
 | 
								strcpy(buff, ""); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							else { | 
				
			||||||
 | 
								struct ip_info info; | 
				
			||||||
 | 
								wifi_get_ip_info(STATION_IF, &info); | 
				
			||||||
 | 
								sprintf(buff, IPSTR, GOOD_IP2STR(info.ip.addr)); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (streq(token, "StaSSID")) { | 
				
			||||||
 | 
							connectStatus = wifi_station_get_connect_status(); | 
				
			||||||
 | 
							x = wifi_get_opmode(); | 
				
			||||||
 | 
							if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP) { | 
				
			||||||
 | 
								strcpy(buff, ""); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							else { | 
				
			||||||
 | 
								strcpy(buff, (char *) stconf.ssid); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (streq(token, "WiFiPasswd")) { | 
				
			||||||
 | 
							strcpy(buff, (char *) stconf.password); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else if (streq(token, "WiFiapwarn")) { | 
				
			||||||
 | 
							// TODO get rid of this
 | 
				
			||||||
 | 
							x = wifi_get_opmode(); | 
				
			||||||
 | 
							if (x == SOFTAP_MODE) { // 2
 | 
				
			||||||
 | 
								strcpy(buff, "<a href=\"/wifi/setmode?mode=3\">Enable client</a> for scanning."); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							else if (x == STATIONAP_MODE) { // 3
 | 
				
			||||||
 | 
								strcpy(buff, | 
				
			||||||
 | 
									   "Switch: <a href=\"/wifi/setmode?mode=1\">Client only</a>, <a href=\"/wifi/setmode?mode=2\">AP only</a>"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							else { // 1
 | 
				
			||||||
 | 
								strcpy(buff, | 
				
			||||||
 | 
									   "Switch: <a href=\"/wifi/setmode?mode=3\">Client+AP</a>, <a href=\"/wifi/setmode?mode=2\">AP only</a>"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						httpdSend(connData, buff, -1); | 
				
			||||||
 | 
						return HTTPD_CGI_DONE; | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,33 @@ | 
				
			|||||||
 | 
					#ifndef CGIWIFI_H | 
				
			||||||
 | 
					#define CGIWIFI_H | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "httpd.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert IP hex to arguments for printf. | 
				
			||||||
 | 
					 * Library IP2STR(ip) does not work correctly due to unaligned memory access. | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					#define GOOD_IP2STR(ip) ((ip)>>0)&0xff, ((ip)>>8)&0xff, ((ip)>>16)&0xff, ((ip)>>24)&0xff | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					httpd_cgi_state cgiWiFiScan(HttpdConnData *connData); | 
				
			||||||
 | 
					httpd_cgi_state cgiWiFiConnect(HttpdConnData *connData); | 
				
			||||||
 | 
					httpd_cgi_state cgiWiFiConnStatus(HttpdConnData *connData); | 
				
			||||||
 | 
					httpd_cgi_state cgiWiFiSetParams(HttpdConnData *connData); | 
				
			||||||
 | 
					httpd_cgi_state tplWlan(HttpdConnData *connData, char *token, void **arg); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WiFi config options:
 | 
				
			||||||
 | 
					// - Persistent
 | 
				
			||||||
 | 
					//   - channel
 | 
				
			||||||
 | 
					//   - AP ssid
 | 
				
			||||||
 | 
					//   - opmode
 | 
				
			||||||
 | 
					//   - AP to connect to
 | 
				
			||||||
 | 
					// - Temporary
 | 
				
			||||||
 | 
					//   - sta_hostname (sta)
 | 
				
			||||||
 | 
					//   - tpw (ap, sta+ap?)
 | 
				
			||||||
 | 
					//   - dhcp_lt (ap, sta+ap)
 | 
				
			||||||
 | 
					//   - static IP
 | 
				
			||||||
 | 
					//   - static mask
 | 
				
			||||||
 | 
					//   - static gw
 | 
				
			||||||
 | 
					//   - dhcp enable or disable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif | 
				
			||||||
@ -0,0 +1,194 @@ | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by MightyPork on 2017/07/08.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "wifi_manager.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WiFiSettingsBlock wificonf; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Restore defaults in the WiFi config block. | 
				
			||||||
 | 
					 * This is to be called if the WiFi config is corrupted on startup, | 
				
			||||||
 | 
					 * before applying the config. | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					void wifimgr_restore_defaults(void) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						u8 mac[6]; | 
				
			||||||
 | 
						wifi_get_macaddr(SOFTAP_IF, mac); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wificonf.opmode = STATIONAP_MODE; | 
				
			||||||
 | 
						wificonf.tpw = 20; | 
				
			||||||
 | 
						wificonf.ap_channel = 1; | 
				
			||||||
 | 
						sprintf((char *) wificonf.ap_ssid, "TERM-%02X%02X%02X", mac[3], mac[4], mac[5]); | 
				
			||||||
 | 
						wificonf.ap_password[0] = 0; // PSK2 always if password is not null.
 | 
				
			||||||
 | 
						wificonf.ap_dhcp_lease_time = 120; | 
				
			||||||
 | 
						wificonf.ap_hidden = false; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						IP4_ADDR(&wificonf.ap_ip.ip, 192, 168, mac[5], 1); | 
				
			||||||
 | 
						IP4_ADDR(&wificonf.ap_ip.netmask, 255, 255, 255, 0); | 
				
			||||||
 | 
						IP4_ADDR(&wificonf.ap_ip.gw, 192, 168, mac[5], 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// --- Client config ---
 | 
				
			||||||
 | 
						wificonf.sta_ssid[0] = 0; | 
				
			||||||
 | 
						wificonf.sta_password[0] = 0; | 
				
			||||||
 | 
						//sprintf((char *) wificonf.sta_ssid, "Chlivek");
 | 
				
			||||||
 | 
						//sprintf((char *) wificonf.sta_password, "prase chrochta");
 | 
				
			||||||
 | 
						strcpy((char *) wificonf.sta_hostname, (char *) wificonf.ap_ssid); // use the same value for sta_hostname as AP name
 | 
				
			||||||
 | 
						wificonf.sta_dhcp_enable = true; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						IP4_ADDR(&wificonf.sta_ip.ip, 192, 168, 0, (mac[5]==1?2:mac[5]));// avoid being the same as "default gw"
 | 
				
			||||||
 | 
						IP4_ADDR(&wificonf.sta_ip.netmask, 255, 255, 255, 0); | 
				
			||||||
 | 
						IP4_ADDR(&wificonf.sta_ip.gw, 192, 168, 0, 1); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Event handler | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					void wifimgr_event_cb(System_Event_t *event) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						switch (event->event) { | 
				
			||||||
 | 
					//		case EVENT_STAMODE_CONNECTED:
 | 
				
			||||||
 | 
					//		EVENT_STAMODE_DISCONNECTED,
 | 
				
			||||||
 | 
					//		EVENT_STAMODE_AUTHMODE_CHANGE,
 | 
				
			||||||
 | 
					//		EVENT_STAMODE_GOT_IP,
 | 
				
			||||||
 | 
					//		EVENT_STAMODE_DHCP_TIMEOUT,
 | 
				
			||||||
 | 
					//		EVENT_SOFTAPMODE_STACONNECTED,
 | 
				
			||||||
 | 
					//		EVENT_SOFTAPMODE_STADISCONNECTED,
 | 
				
			||||||
 | 
					//		EVENT_SOFTAPMODE_PROBEREQRECVED,
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void configure_station(void) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						info("[WiFi] Configuring Station mode..."); | 
				
			||||||
 | 
						struct station_config conf; | 
				
			||||||
 | 
						strcpy((char *) conf.ssid, (char *) wificonf.sta_ssid); | 
				
			||||||
 | 
						strcpy((char *) conf.password, (char *) wificonf.sta_password); | 
				
			||||||
 | 
						dbg("[WiFi] Connecting to \"%s\", password \"%s\"", conf.ssid, conf.password); | 
				
			||||||
 | 
						conf.bssid_set = 0; | 
				
			||||||
 | 
						conf.bssid[0] = 0; | 
				
			||||||
 | 
						wifi_station_disconnect(); | 
				
			||||||
 | 
						wifi_station_set_config_current(&conf); | 
				
			||||||
 | 
						dbg("[WiFi] Hostname = %s", wificonf.sta_hostname); | 
				
			||||||
 | 
						wifi_station_set_hostname((char*)wificonf.sta_hostname); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wificonf.sta_dhcp_enable) { | 
				
			||||||
 | 
							dbg("[WiFi] Starting DHCP..."); | 
				
			||||||
 | 
							if (!wifi_station_dhcpc_start()) { | 
				
			||||||
 | 
								error("[WiFi] DHCp failed to start!"); | 
				
			||||||
 | 
								return; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						else { | 
				
			||||||
 | 
							info("[WiFi] Setting up static IP..."); | 
				
			||||||
 | 
							dbg("[WiFi] Client.ip   = "IPSTR, GOOD_IP2STR(wificonf.sta_ip.ip.addr)); | 
				
			||||||
 | 
							dbg("[WiFi] Client.mask = "IPSTR, GOOD_IP2STR(wificonf.sta_ip.netmask.addr)); | 
				
			||||||
 | 
							dbg("[WiFi] Client.gw   = "IPSTR, GOOD_IP2STR(wificonf.sta_ip.gw.addr)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wifi_station_dhcpc_stop(); | 
				
			||||||
 | 
							// Load static IP config
 | 
				
			||||||
 | 
							if (!wifi_set_ip_info(STATION_IF, &wificonf.sta_ip)) { | 
				
			||||||
 | 
								error("[WiFi] Error setting static IP!"); | 
				
			||||||
 | 
								return; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info("[WiFi] Trying to connect to AP..."); | 
				
			||||||
 | 
						wifi_station_connect(); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void configure_ap(void) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						bool suc; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info("[WiFi] Configuring SoftAP mode..."); | 
				
			||||||
 | 
						// AP is enabled
 | 
				
			||||||
 | 
						struct softap_config conf; | 
				
			||||||
 | 
						conf.channel = wificonf.ap_channel; | 
				
			||||||
 | 
						strcpy((char *) conf.ssid, (char *) wificonf.ap_ssid); | 
				
			||||||
 | 
						strcpy((char *) conf.password, (char *) wificonf.ap_password); | 
				
			||||||
 | 
						conf.authmode = (wificonf.ap_password[0] == 0 ? AUTH_OPEN : AUTH_WPA2_PSK); | 
				
			||||||
 | 
						conf.ssid_len = strlen((char *) conf.ssid); | 
				
			||||||
 | 
						conf.ssid_hidden = wificonf.ap_hidden; | 
				
			||||||
 | 
						conf.max_connection = 4; // default 4 (max possible)
 | 
				
			||||||
 | 
						conf.beacon_interval = 100; // default 100 ms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set config
 | 
				
			||||||
 | 
						//ETS_UART_INTR_DISABLE();
 | 
				
			||||||
 | 
						suc = wifi_softap_set_config_current(&conf); | 
				
			||||||
 | 
						//ETS_UART_INTR_ENABLE();
 | 
				
			||||||
 | 
						if (!suc) { | 
				
			||||||
 | 
							error("[WiFi] AP config set fail!"); | 
				
			||||||
 | 
							return; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set IP
 | 
				
			||||||
 | 
						info("[WiFi] Configuring SoftAP local IP..."); | 
				
			||||||
 | 
						dbg("[WiFi] SoftAP.ip   = "IPSTR, GOOD_IP2STR(wificonf.ap_ip.ip.addr)); | 
				
			||||||
 | 
						dbg("[WiFi] SoftAP.mask = "IPSTR, GOOD_IP2STR(wificonf.ap_ip.netmask.addr)); | 
				
			||||||
 | 
						dbg("[WiFi] SoftAP.gw   = "IPSTR, GOOD_IP2STR(wificonf.ap_ip.gw.addr)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wifi_softap_dhcps_stop(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Configure DHCP
 | 
				
			||||||
 | 
						if (!wifi_set_ip_info(SOFTAP_IF, &wificonf.ap_ip)) { | 
				
			||||||
 | 
							error("[WiFi] IP set fail!"); | 
				
			||||||
 | 
							return; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info("[WiFi] Configuring SoftAP DHCP server..."); | 
				
			||||||
 | 
						struct dhcps_lease dhcp_lease; | 
				
			||||||
 | 
						struct ip_addr ip; | 
				
			||||||
 | 
						ip.addr = wificonf.ap_ip.ip.addr; | 
				
			||||||
 | 
						ip.addr = (ip.addr & 0x00FFFFFFUL) | ((((ip.addr >> 24) & 0xFF) + 99UL) << 24); | 
				
			||||||
 | 
						dhcp_lease.start_ip.addr = ip.addr; | 
				
			||||||
 | 
						ip.addr = (ip.addr & 0x00FFFFFFUL) | ((((ip.addr >> 24) & 0xFF) + 100UL) << 24); | 
				
			||||||
 | 
						dhcp_lease.end_ip.addr = ip.addr; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbg("[WiFi] DHCP.start = "IPSTR, GOOD_IP2STR(dhcp_lease.start_ip.addr)); | 
				
			||||||
 | 
						dbg("[WiFi] DHCP.end   = "IPSTR, GOOD_IP2STR(dhcp_lease.end_ip.addr)); | 
				
			||||||
 | 
						dbg("[WiFi] DHCP.lease = %d minutes", wificonf.ap_dhcp_lease_time); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!wifi_softap_set_dhcps_lease(&dhcp_lease)) { | 
				
			||||||
 | 
							error("[WiFi] DHCP address range set fail!"); | 
				
			||||||
 | 
							return; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!wifi_softap_set_dhcps_lease_time(wificonf.ap_dhcp_lease_time)) { | 
				
			||||||
 | 
							error("[WiFi] DHCP lease time set fail!"); | 
				
			||||||
 | 
							return; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// some weird magic shit about router
 | 
				
			||||||
 | 
						uint8 mode = 1; | 
				
			||||||
 | 
						wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!wifi_softap_dhcps_start()) { | 
				
			||||||
 | 
							error("[WiFi] Failed to start DHCP server!"); | 
				
			||||||
 | 
							return; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Register the WiFi event listener, cycle WiFi, apply settings | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					void wifimgr_apply_settings(void) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						info("[WiFi] Initializing WiFi manager..."); | 
				
			||||||
 | 
					//	wifi_set_event_handler_cb(wifimgr_event_cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Force wifi cycle
 | 
				
			||||||
 | 
						dbg("[WiFi] WiFi reset to apply new settings"); | 
				
			||||||
 | 
						wifi_set_opmode(NULL_MODE); | 
				
			||||||
 | 
						wifi_set_opmode(wificonf.opmode); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Configure the client
 | 
				
			||||||
 | 
						if (wificonf.opmode == STATIONAP_MODE || wificonf.opmode == STATION_MODE) { | 
				
			||||||
 | 
							configure_station(); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Configure the AP
 | 
				
			||||||
 | 
						if (wificonf.opmode == STATIONAP_MODE || wificonf.opmode == SOFTAP_MODE) { | 
				
			||||||
 | 
							configure_ap(); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,47 @@ | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by MightyPork on 2017/07/08.
 | 
				
			||||||
 | 
					// This module handles all WiFi configuration and is interfaced
 | 
				
			||||||
 | 
					// by the cgi_wifi functions.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ESP_VT100_FIRMWARE_WIFI_MANAGER_H | 
				
			||||||
 | 
					#define ESP_VT100_FIRMWARE_WIFI_MANAGER_H | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <esp8266.h> | 
				
			||||||
 | 
					#include "cgi_wifi.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A structure holding all configured WiFi parameters | 
				
			||||||
 | 
					 * and the active state. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * This block can be used eg. for WiFi config backup. | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					typedef struct { | 
				
			||||||
 | 
						WIFI_MODE opmode : 32; | 
				
			||||||
 | 
						u8 sta_hostname[32]; | 
				
			||||||
 | 
						u32 tpw; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// --- AP config ---
 | 
				
			||||||
 | 
						u32 ap_channel; // 32 for alignment, needs 8
 | 
				
			||||||
 | 
						u8 ap_ssid[32]; | 
				
			||||||
 | 
						u8 ap_password[32]; | 
				
			||||||
 | 
						u32 ap_hidden; | 
				
			||||||
 | 
						u32 ap_dhcp_lease_time; // in minutes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ip_info ap_ip; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// --- Client config ---
 | 
				
			||||||
 | 
						u8 sta_ssid[32]; | 
				
			||||||
 | 
						u8 sta_password[64]; | 
				
			||||||
 | 
						u32 sta_dhcp_enable; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ip_info sta_ip; | 
				
			||||||
 | 
					} WiFiSettingsBlock; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern WiFiSettingsBlock wificonf; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wifimgr_restore_defaults(void); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wifimgr_apply_settings(void); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //ESP_VT100_FIRMWARE_WIFI_MANAGER_H
 | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue