Add Wificfg
Uses the sysparam store to save the wifi configuration. Adds a basic http server for configuration.
This commit is contained in:
parent
af4ac44cb5
commit
8b0a1ae362
17 changed files with 2596 additions and 0 deletions
1
examples/wificfg/.gitignore
vendored
Normal file
1
examples/wificfg/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
!local.mk
|
7
examples/wificfg/FreeRTOSConfig.h
Normal file
7
examples/wificfg/FreeRTOSConfig.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#define configUSE_TRACE_FACILITY 1
|
||||||
|
#define configGENERATE_RUN_TIME_STATS 1
|
||||||
|
#define portGET_RUN_TIME_COUNTER_VALUE() (RTC.COUNTER)
|
||||||
|
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() {}
|
||||||
|
|
||||||
|
/* Use the defaults for everything else */
|
||||||
|
#include_next<FreeRTOSConfig.h>
|
5
examples/wificfg/Makefile
Normal file
5
examples/wificfg/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Makefile for wificfg example
|
||||||
|
PROGRAM=wificfg
|
||||||
|
EXTRA_COMPONENTS=extras/dhcpserver extras/wificfg
|
||||||
|
|
||||||
|
include ../../common.mk
|
18
examples/wificfg/content/index.html
Normal file
18
examples/wificfg/content/index.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
"<!DOCTYPE html><html lang=\"en\">"
|
||||||
|
"<head>"
|
||||||
|
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||||
|
"<script src=\"/script.js\"></script>"
|
||||||
|
"<title>",
|
||||||
|
"</title>"
|
||||||
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||||
|
"<li class=\"active\"><a href=\"/\">Home</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li><a href=\"/tasks.html\">Tasks</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>",
|
||||||
|
"</body></html>"
|
1
examples/wificfg/local.mk
Normal file
1
examples/wificfg/local.mk
Normal file
|
@ -0,0 +1 @@
|
||||||
|
FLASH_SIZE ?= 32
|
94
examples/wificfg/wificfg.c
Normal file
94
examples/wificfg/wificfg.c
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Example Wifi configuration via an access point.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 OurAirQuality.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0, January 2004 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS WITH THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
#include <espressif/user_interface.h>
|
||||||
|
#include <esp/uart.h>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
|
||||||
|
#include "wificfg/wificfg.h"
|
||||||
|
|
||||||
|
#include "sysparam.h"
|
||||||
|
|
||||||
|
static const char http_success_header[] = "HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
|
"Cache-Control: no-store\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n";
|
||||||
|
static const char *http_index_content[] = {
|
||||||
|
#include "content/index.html"
|
||||||
|
};
|
||||||
|
|
||||||
|
static int handle_index(int s, wificfg_method method,
|
||||||
|
uint32_t content_length,
|
||||||
|
wificfg_content_type content_type,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (wificfg_write_string(s, http_success_header) < 0) return -1;
|
||||||
|
|
||||||
|
if (method != HTTP_METHOD_HEAD) {
|
||||||
|
if (wificfg_write_string_chunk(s, http_index_content[0], buf, len) < 0) return -1;
|
||||||
|
if (wificfg_write_html_title(s, buf, len, "Home") < 0) return -1;
|
||||||
|
if (wificfg_write_string_chunk(s, http_index_content[1], buf, len) < 0) return -1;
|
||||||
|
|
||||||
|
socklen_t addr_len;
|
||||||
|
struct sockaddr addr;
|
||||||
|
addr_len = sizeof(addr);
|
||||||
|
getpeername(s, (struct sockaddr*)&addr, &addr_len);
|
||||||
|
|
||||||
|
if (wificfg_write_string_chunk(s, "<dl class=\"dlh\">", buf, len) < 0) return -1;
|
||||||
|
if (addr.sa_family == AF_INET) {
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in *)&addr;
|
||||||
|
if (wificfg_write_string_chunk(s, "<dt>Peer address</dt>", buf, len) < 0) return -1;
|
||||||
|
snprintf(buf, len, "<dd>" IPSTR " : %d</dd>",
|
||||||
|
IP2STR((ip4_addr_t *)&sa->sin_addr.s_addr), ntohs(sa->sin_port));
|
||||||
|
if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wificfg_write_string_chunk(s, "</dl>", buf, len) < 0) return -1;
|
||||||
|
if (wificfg_write_string_chunk(s, http_index_content[2], buf, len) < 0) return -1;
|
||||||
|
if (wificfg_write_chunk_end(s) < 0) return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const wificfg_dispatch dispatch_list[] = {
|
||||||
|
{"/", HTTP_METHOD_GET, handle_index, false},
|
||||||
|
{"/index.html", HTTP_METHOD_GET, handle_index, false},
|
||||||
|
{NULL, HTTP_METHOD_ANY, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
void user_init(void)
|
||||||
|
{
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||||
|
|
||||||
|
sdk_wifi_set_sleep_type(WIFI_SLEEP_MODEM);
|
||||||
|
|
||||||
|
wificfg_init(80, dispatch_list);
|
||||||
|
}
|
10
extras/wificfg/component.mk
Normal file
10
extras/wificfg/component.mk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Component makefile for extras/wificfg
|
||||||
|
|
||||||
|
# Expected anyone using wificfg includes it as 'wificfg/wificfg.h'
|
||||||
|
INC_DIRS += $(wificfg_ROOT)..
|
||||||
|
|
||||||
|
# args for passing into compile rule generation
|
||||||
|
wificfg_INC_DIR =
|
||||||
|
wificfg_SRC_DIR = $(wificfg_ROOT)
|
||||||
|
|
||||||
|
$(eval $(call component_compile_rules,wificfg))
|
30
extras/wificfg/content/challenge.html
Normal file
30
extras/wificfg/content/challenge.html
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
"<!DOCTYPE html><html lang=\"en\">"
|
||||||
|
"<head>"
|
||||||
|
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||||
|
"<script src=\"/script.js\"></script>"
|
||||||
|
"<title>",
|
||||||
|
"</title>"
|
||||||
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||||
|
"<li><a href=\"/\">Home</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<form action=\"/challenge.html\" method=\"post\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Unlock the configuration interface</legend>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"pw\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||||
|
"placeholder=\"unlock-password\" value=\"\"></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<center><input type=\"submit\" value=\"Unlock\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"</form>"
|
||||||
|
"</body></html>"
|
11
extras/wificfg/content/favicon.ico
Normal file
11
extras/wificfg/content/favicon.ico
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
"HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: image/svg+xml\r\n"
|
||||||
|
"Cache-Control: max-age=900\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n",
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
|
||||||
|
"<svg xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" version=\"1.1\">"
|
||||||
|
"<defs><linearGradient id=\"g1\" y2=\"248.63\" gradientUnits=\"userSpaceOnUse\" x2=\"153\" gradientTransform=\"matrix(.20068 0 0 .20068 -54.336 -1.0508)\" y1=\"15.424\" x1=\"99.777\"><stop style=\"stop-color:#0088FF\" offset=\"0\"/><stop style=\"stop-color:#b2dbff\" offset=\"1\"/></linearGradient></defs>"
|
||||||
|
"<path style=\"stroke-linejoin:round;color:#000000;stroke:#aaaaaa;stroke-linecap:round;fill:url(#g1)\" d=\"m22.7 0.94747c-0.474 0.03238-0.934 0.10563-1.398 0.15883h-0.032l-1.112 6.068c-1.812 0.4127-3.517 1.1132-5.051 2.065l-4.988-3.59c-1.3485 1.0468-2.5754 2.2677-3.6536 3.59l3.4628 5.0517c-1.0514 1.606-1.842 3.441-2.2874 5.369v0.031l-6.0361 0.953c-0.1104 0.902-0.1589 1.833-0.1589 2.764 0 0.762 0.021 1.514 0.0953 2.256l6.0362 1.08c0.4293 2.096 1.2448 4.054 2.3827 5.782l-3.5899 4.924c1.0281 1.277 2.2151 2.439 3.4946 3.463l5.0833-3.494c1.776 1.133 3.759 1.928 5.909 2.319l0.953 6.004c0.677 0.062 1.372 0.064 2.065 0.064 0.979 0 1.914-0.037 2.859-0.159l1.144-6.132c2.041-0.507 3.958-1.389 5.623-2.573l4.893 3.558c1.268-1.079 2.429-2.32 3.431-3.653l-3.558-5.147c0.963-1.664 1.631-3.5 1.969-5.464l6.005-0.953c0.052-0.627 0.063-1.234 0.063-1.875 0-1.112-0.129-2.203-0.286-3.272l-6.099-1.112c-0.478-1.765-1.263-3.412-2.256-4.892l3.59-4.9245c-1.113-1.3608-2.382-2.618-3.781-3.6852l-5.178 3.5581c-1.488-0.8802-3.09-1.5556-4.829-1.9379l-0.953-6.0362c-0.868-0.102-1.742-0.15883-2.637-0.15883-0.242 0-0.491-0.00761-0.731 0-0.117 0.00371-0.232-0.00681-0.349 0-0.032 0.00184-0.064-0.00216-0.095 0zm0.826 15.44c0.116-0.006 0.231 0 0.349 0 3.761 0 6.83 3.07 6.83 6.831 0 3.76-3.069 6.798-6.83 6.798s-6.799-3.038-6.799-6.798c0-3.643 2.852-6.648 6.45-6.831z\"/>"
|
||||||
|
"</svg>"
|
8
extras/wificfg/content/script.js
Normal file
8
extras/wificfg/content/script.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
"HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: text/javascript\r\n"
|
||||||
|
"Cache-Control: max-age=900\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n",
|
||||||
|
"function myFunction() { var x = document.getElementById(\"myTopnav\");"
|
||||||
|
"if (x.className === \"topnav\") { x.className += \" responsive\"; } else { x.className = \"topnav\"; } }"
|
19
extras/wificfg/content/style.css
Normal file
19
extras/wificfg/content/style.css
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
"HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: text/css\r\n"
|
||||||
|
"Cache-Control: max-age=900\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"\r\n",
|
||||||
|
".dlh dd,h1{font-weight:300}.dlh{font-size:0;text-align:center}"
|
||||||
|
".dlh dd,.dlh dt{width:48%;width:calc(50% - 10px);margin:8px 0;display:inline-block;font-size:16px;vertical-align:middle}"
|
||||||
|
".dlh dt{text-align:right;padding-right:10px}"
|
||||||
|
".dlh dd{font-size:18px;text-align:left;padding-left:10px}"
|
||||||
|
"ul.topnav{list-style-type:none;margin:0;padding:0;overflow:hidden;background-color:#bbb}"
|
||||||
|
"ul.topnav li{float:left}"
|
||||||
|
"ul.topnav li a{display:inline-block;color:#444;text-align:center;padding:14px 16px;text-decoration:none;transition:.3s;font-size:17px}"
|
||||||
|
"ul.topnav li a:hover{background-color:#ddd}ul.topnav li.icon{display:none}"
|
||||||
|
"@media screen and (max-width:680px){ul.topnav li:not(.active){display:none}ul.topnav li.icon{float:right;display:inline-block}ul.topnav.responsive{position:relative}ul.topnav.responsive li.icon{position:absolute;right:0;top:0}ul.topnav.responsive li{float:none;display:inline}ul.topnav.responsive li a{display:block;text-align:left}}"
|
||||||
|
"html{min-height:100%}"
|
||||||
|
"body{background:#d0e4f7;background:-moz-linear-gradient(top, #d0e4f7 0%, #73b1e7 24%, #0a77d5 50%, #539fe1 79%, #87bcea 100%);background:-webkit-linear-gradient(top, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);background:linear-gradient(to bottom, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0e4f7', endColorstr='#87bcea',GradientType=0)}"
|
||||||
|
"body{font-family:helvetica,arial,sans-serif;font-size:16px}"
|
||||||
|
"h1{font-size:26px}"
|
||||||
|
"p{font-size:14px}"
|
18
extras/wificfg/content/tasks.html
Normal file
18
extras/wificfg/content/tasks.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
"<!DOCTYPE html><html lang=\"en\">"
|
||||||
|
"<head>"
|
||||||
|
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||||
|
"<script src=\"/script.js\"></script>"
|
||||||
|
"<title>",
|
||||||
|
"</title>"
|
||||||
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||||
|
"<li><a href=\"/\">Home</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/tasks.html\">Tasks</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>",
|
||||||
|
"</body></html>"
|
90
extras/wificfg/content/wificfg/ap.html
Normal file
90
extras/wificfg/content/wificfg/ap.html
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
"<!DOCTYPE html><html lang=\"en\">"
|
||||||
|
"<head>"
|
||||||
|
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||||
|
"<script src=\"/script.js\"></script>"
|
||||||
|
"<title>",
|
||||||
|
"</title>"
|
||||||
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||||
|
"<li><a href=\"/\">Home</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<form action=\"/wificfg/ap.html\" method=\"post\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>WiFi Access Point configuration</legend>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"enable\">Enable AP mode</label></dt>"
|
||||||
|
"<dd><input id=\"enable\" type=\"checkbox\" name=\"ap_enable\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"disable_if_sta\">Auto disable if station connection</label></dt>"
|
||||||
|
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_disable_if_sta\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||||
|
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||||
|
"name=\"ap_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||||
|
"\"/></dd>"
|
||||||
|
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||||
|
"<dd><input id=\"ssid\" type=\"text\" minlength=\"1\" maxlength=\"31\" name=\"ap_ssid\" "
|
||||||
|
"placeholder=\"my access point\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"ap\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"ap\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"ap_password\" "
|
||||||
|
"placeholder=\"password\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"hidden\">SSID Hidden</label></dt>"
|
||||||
|
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_ssid_hidden\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"ch\">Channel</label></dt>"
|
||||||
|
"<dd><input id=\"ch\" type=\"number\" size=\"2\" min=\"1\" max=\"14\" step=\"1\" "
|
||||||
|
"name=\"ap_channel\" placeholder=\"6\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"am\">Authentication Mode</label></dt>"
|
||||||
|
"<dd><select id=\"am\" name=\"ap_authmode\">"
|
||||||
|
"<option value=\"0\"",
|
||||||
|
">Open</option>"
|
||||||
|
"<option value=\"1\"",
|
||||||
|
">WEP</option>"
|
||||||
|
"<option value=\"2\"",
|
||||||
|
">WPA_PSK</option>"
|
||||||
|
"<option value=\"3\"",
|
||||||
|
">WPA2_PSK</option>"
|
||||||
|
"<option value=\"4\"",
|
||||||
|
">WPA_WPA2_PSK</option></select></dd>"
|
||||||
|
"<dt><label for=\"mc\">Max connections</label></dt>"
|
||||||
|
"<dd><input id=\"mc\" type=\"number\" size=\"2\" min=\"1\" max=\"8\" step=\"1\" "
|
||||||
|
"name=\"ap_max_conn\" placeholder=\"3\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"bi\">Beacon interval</label></dt>"
|
||||||
|
"<dd><input id=\"bi\" type=\"number\" size=\"6\" min=\"0\" max=\"10000\" step=\"1\" "
|
||||||
|
"name=\"ap_beacon_interval\" placeholder=\"100\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"ip\">IP Address</label></dt>"
|
||||||
|
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"ap_ip_addr\" placeholder=\"192.168.4.1\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"nm\">Netmask</label></dt>"
|
||||||
|
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"ap_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"dhcp\">DHCP Server Max Leases</label></dt>"
|
||||||
|
"<dd><input id=\"dhcp\" type=\"number\" size=\"2\" min=\"0\" max=\"16\" step=\"1\" "
|
||||||
|
"name=\"ap_dhcp_leases\" placeholder=\"4\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"dns_en\">DNS enabled</label></dt>"
|
||||||
|
"<dd><input id=\"dns_en\" type=\"checkbox\" name=\"ap_dns\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"<input type=\"hidden\" name=\"done\">"
|
||||||
|
"</form>"
|
||||||
|
"</body></html>"
|
52
extras/wificfg/content/wificfg/index.html
Normal file
52
extras/wificfg/content/wificfg/index.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
"<!DOCTYPE html><html lang=\"en\">"
|
||||||
|
"<head>"
|
||||||
|
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||||
|
"<script src=\"/script.js\"></script>"
|
||||||
|
"<title>",
|
||||||
|
"</title>"
|
||||||
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||||
|
"<li><a href=\"/\">Home</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<h1>WiFi Status</h1>"
|
||||||
|
"<dl class=\"dlh\">",
|
||||||
|
"</dl>"
|
||||||
|
"<br>"
|
||||||
|
"<form action=\"/wificfg/\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to lock the configuration interface, and have you noted the password?');\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Lock the configuration interface</legend>"
|
||||||
|
"<p>These WiFi configuration pages can be disabled for security on a shared network. If a password is supplied then they can be unlocked. Warning: if no password is supplied then it will not be possible to unlock these pages via this interface.</p>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"pw\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||||
|
"placeholder=\"unlock-password\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<input type=\"hidden\" name=\"cfg_enable\" value=\"0\">"
|
||||||
|
"<center><input type=\"submit\" value=\"Lock\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"</form>"
|
||||||
|
"<form action=\"/wificfg/restart.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to restart the device?');\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Restart device</legend>"
|
||||||
|
"<p>A restart is necessary for some changes to take effect.</p>"
|
||||||
|
"<center><button>Restart</button></center>"
|
||||||
|
"</fieldset></form>"
|
||||||
|
"<form action=\"/wificfg/erase.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to erase the configuration?');\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Erase configuration</legend>"
|
||||||
|
"<p>Erases the device configuration stored in the flash memory and restarts the device. "
|
||||||
|
"This might be useful to clear stored passwords and private configuration information."
|
||||||
|
"</p>"
|
||||||
|
"<center><button>Erase Configuration</button></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"</form>",
|
||||||
|
"</body></html>"
|
68
extras/wificfg/content/wificfg/sta.html
Normal file
68
extras/wificfg/content/wificfg/sta.html
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
"<!DOCTYPE html><html lang=\"en\">"
|
||||||
|
"<head>"
|
||||||
|
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||||
|
"<script src=\"/script.js\"></script>"
|
||||||
|
"<title>",
|
||||||
|
"</title>"
|
||||||
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||||
|
"<li><a href=\"/\">Home</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<form action=\"/wificfg/sta.html\" method=\"post\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>WiFi Station configuration</legend>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"enable\">Enable Station mode</label></dt>"
|
||||||
|
"<dd><input id=\"enable\" type=\"checkbox\" name=\"sta_enable\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||||
|
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||||
|
"name=\"sta_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||||
|
"\" /></dd>"
|
||||||
|
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||||
|
"<dd><input id=\"ssid\" minlength=\"1\" maxlength=\"31\" type=\"text\" name=\"sta_ssid\" "
|
||||||
|
"placeholder=\"my access point\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"pw\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"pw\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"sta_password\" "
|
||||||
|
"placeholder=\"password\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"hostname\">Hostname</label></dt>"
|
||||||
|
"<dd><input id=\"hostname\" type=\"text\" maxlength=\"63\" name=\"hostname\" "
|
||||||
|
"placeholder=\"device-hostname\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"dhcp\">Enable DHCP</label></dt>"
|
||||||
|
"<dd><input id=\"dhcp\" type=\"radio\" name=\"sta_dhcp\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"static\">Disable DHCP (static address below)</label></dt>"
|
||||||
|
"<dd><input id=\"static\" type=\"radio\" name=\"sta_dhcp\" value=\"0\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"ip\">Static IP Address</label></dt>"
|
||||||
|
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"sta_ip_addr\" placeholder=\"192.168.1.50\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"nm\">Static Netmask</label></dt>"
|
||||||
|
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"sta_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"gw\">Static Gateway</label></dt>"
|
||||||
|
"<dd><input id=\"gw\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"sta_gateway\" placeholder=\"192.168.1.1\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"<input type=\"hidden\" name=\"done\">"
|
||||||
|
"</form>"
|
||||||
|
"</body></html>"
|
2027
extras/wificfg/wificfg.c
Normal file
2027
extras/wificfg/wificfg.c
Normal file
File diff suppressed because it is too large
Load diff
137
extras/wificfg/wificfg.h
Normal file
137
extras/wificfg/wificfg.h
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* WiFi configuration via a simple web server.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 OurAirQuality.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0, January 2004 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS WITH THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WIFICFG_H__
|
||||||
|
#define __WIFICFG_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Printf format used to initialize a default AP ssid. It is passed the last
|
||||||
|
* three bytes of the mac address. This may be NULL to not default the ssid,
|
||||||
|
* but the AP network will not run without a ssid.
|
||||||
|
*/
|
||||||
|
extern char *wificfg_default_ssid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A default password for the AP interface. This may be NULL to not default the
|
||||||
|
* password, but the AP network will not run without a password. The minimum
|
||||||
|
* length is 8 characters.
|
||||||
|
*/
|
||||||
|
extern char *wificfg_default_password;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A default hostname printf format string. This may be NULL to not default the
|
||||||
|
* hostname.
|
||||||
|
*/
|
||||||
|
extern char *wificfg_default_hostname;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The web server parses the http method string in these enums. The ANY method
|
||||||
|
* is only use for dispatch. The method enum is passed to the handler functions.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
HTTP_METHOD_GET,
|
||||||
|
HTTP_METHOD_POST,
|
||||||
|
HTTP_METHOD_HEAD,
|
||||||
|
HTTP_METHOD_OTHER,
|
||||||
|
HTTP_METHOD_ANY,
|
||||||
|
} wificfg_method;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The web server parses these content-type header values. This is passed to the
|
||||||
|
* dispatch function.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED,
|
||||||
|
HTTP_CONTENT_TYPE_OTHER
|
||||||
|
} wificfg_content_type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The function signature for the http server request handler functions.
|
||||||
|
*
|
||||||
|
* The buffer, with its length, is usable by the handler.
|
||||||
|
*/
|
||||||
|
typedef int (* wificfg_handler)(int s, wificfg_method method,
|
||||||
|
uint32_t content_length,
|
||||||
|
wificfg_content_type content_type,
|
||||||
|
char *buf, size_t len);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *path;
|
||||||
|
wificfg_method method;
|
||||||
|
wificfg_handler handler;
|
||||||
|
bool secure;
|
||||||
|
} wificfg_dispatch;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the Wifi Configuration http server task. The IP port number
|
||||||
|
* and a path dispatch list are needed. The dispatch list can not be
|
||||||
|
* stack allocated as it is passed to another task.
|
||||||
|
*/
|
||||||
|
void wificfg_init(uint32_t port, const wificfg_dispatch *dispatch);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support for reading a form name or value from the socket. The name or value
|
||||||
|
* is truncated to the buffer length. The number of characters read is limited
|
||||||
|
* to the remainder which is updated. The 'valp' flag is set if a value follows.
|
||||||
|
*/
|
||||||
|
int wificfg_form_name_value(int s, bool *valp, size_t *rem, char *buf, size_t len);
|
||||||
|
|
||||||
|
/* Support for form url-encoding decoder. */
|
||||||
|
void wificfg_form_url_decode(char *string);
|
||||||
|
|
||||||
|
/* Support for html-escaping of form values. */
|
||||||
|
void wificfg_html_escape(char *string, char *buf, size_t len);
|
||||||
|
|
||||||
|
/* Support for writing a string in a response. */
|
||||||
|
int wificfg_write_string(int s, const char *str);
|
||||||
|
|
||||||
|
/* Support for writing a string in a response, with chunk transfer encoding.
|
||||||
|
* An optional buffer may be supplied to use to construct a chunk with the
|
||||||
|
* header and trailer, reducing the number of write() calls, and the str may be
|
||||||
|
* at the start of this buffer.
|
||||||
|
*/
|
||||||
|
int wificfg_write_string_chunk(int s, const char *str, char *buf, size_t len);
|
||||||
|
|
||||||
|
/* Write a chunk transfer encoding end marker. */
|
||||||
|
int wificfg_write_chunk_end(int s);
|
||||||
|
|
||||||
|
/* Write a chunk offset 4 bytes into the buffer. */
|
||||||
|
int wificfg_write_buffer_chunk(int s, char *buf);
|
||||||
|
|
||||||
|
/* Write a html title meta data, using the hostname or AP SSI. */
|
||||||
|
int wificfg_write_html_title(int s, char *buf, size_t len, const char *str);
|
||||||
|
|
||||||
|
/* Callback to notify the wificfg logic that a station connection has been
|
||||||
|
* successfully established. It might use this to disable the AP interface after
|
||||||
|
* a restart.
|
||||||
|
*/
|
||||||
|
void wificfg_got_sta_connect(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __WIFICFG_H__
|
Loading…
Reference in a new issue