389 lines
9.1 KiB
C
389 lines
9.1 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "pico/stdlib.h"
|
|
#include "lwip/apps/httpd.h"
|
|
#include "lwip/ip4_addr.h"
|
|
#include "pico/cyw43_arch.h"
|
|
#include "hardware/watchdog.h"
|
|
#include "hardware/flash.h"
|
|
#include "hardware/sync.h"
|
|
#include "pico/multicore.h"
|
|
|
|
#include "server.h"
|
|
#include "parse_keys.h"
|
|
#include "dhcpserver.h"
|
|
|
|
uint8_t led_code = 0;
|
|
static uint8_t ip[4];
|
|
static uint8_t mask[4];
|
|
static uint8_t gw[4];
|
|
static absolute_time_t lastCheck;
|
|
static absolute_time_t lastActive;
|
|
static net_config wifi;
|
|
static bool clientmode = false;
|
|
static bool config_loaded = false;
|
|
static bool bad_config = false;
|
|
static bool reboot = false;
|
|
|
|
const char * __not_in_flash("httpd") ssi_tags[] = {
|
|
"num",
|
|
"caps",
|
|
"scroll",
|
|
"ssid",
|
|
"pass",
|
|
"host",
|
|
"ip0",
|
|
"ip1",
|
|
"ip2",
|
|
"ip3",
|
|
"mask0",
|
|
"mask1",
|
|
"mask2",
|
|
"mask3",
|
|
"gw0",
|
|
"gw1",
|
|
"gw2",
|
|
"gw3",
|
|
"dhcp"
|
|
};
|
|
|
|
|
|
static const tCGI cgi_handlers[] = {
|
|
{ "/sendkeys.cgi", sendkeys_cgi },
|
|
{ "/wifi.cgi", save_wifi },
|
|
{ "/reboot.cgi", reboot_cgi },
|
|
};
|
|
|
|
void run_http_server() {
|
|
//sleep_ms(5000);
|
|
|
|
if (cyw43_arch_init_with_country(CYW43_COUNTRY_USA)) {
|
|
printf("failed to initialize\n");
|
|
return;
|
|
}
|
|
|
|
clientmode = false;
|
|
|
|
config_loaded = net_config_load(&wifi);
|
|
|
|
if ( config_loaded ){
|
|
printf("read config file\n");
|
|
cyw43_arch_enable_sta_mode();
|
|
|
|
// set hostname
|
|
//cyw43_arch_lwip_begin();
|
|
struct netif *n = &cyw43_state.netif[CYW43_ITF_STA];
|
|
if (wifi.host) {
|
|
netif_set_hostname(n, wifi.host);
|
|
} else {
|
|
netif_set_hostname(n, DEFAULTHOST);
|
|
}
|
|
if (wifi.manual) {
|
|
dhcp_release_and_stop(n);
|
|
netif_set_addr(n, &(wifi.ip), &(wifi.mask), &(wifi.gw));
|
|
dhcp_inform(n);
|
|
}
|
|
netif_set_up(n);
|
|
//cyw43_arch_lwip_end();
|
|
|
|
if(cyw43_arch_wifi_connect_timeout_ms(wifi.ssid, wifi.pass, CYW43_AUTH_WPA2_AES_PSK, 10000)){
|
|
printf("failed to connect to %s\n", wifi.ssid);
|
|
} else{
|
|
clientmode = true;
|
|
}
|
|
}
|
|
|
|
if (!clientmode) {
|
|
//start AP mode
|
|
cyw43_arch_enable_ap_mode(DEFAULTHOST, DEFAULTPASS, CYW43_AUTH_WPA2_AES_PSK);
|
|
|
|
ip4_addr_t ip, mask, gw;
|
|
IP4_ADDR(&ip, 192, 168, 0, 1);
|
|
IP4_ADDR(&mask, 255, 255, 255, 0);
|
|
IP4_ADDR(&gw, 192, 168, 0, 1);
|
|
netif_set_ipaddr(netif_default, &ip);
|
|
netif_set_up(netif_default);
|
|
|
|
dhcp_server_t dhcp;
|
|
dhcp_server_init(&dhcp, &gw, &mask);
|
|
printf("launched in AP mode\n");
|
|
}
|
|
|
|
// start the server
|
|
httpd_init();
|
|
http_set_cgi_handlers(cgi_handlers, 3);
|
|
for (size_t i = 0; i < LWIP_ARRAYSIZE(ssi_tags); i++) {
|
|
LWIP_ASSERT("tag too long for LWIP_HTTPD_MAX_TAG_NAME_LEN",
|
|
strlen(ssi_tags[i]) <= LWIP_HTTPD_MAX_TAG_NAME_LEN);
|
|
}
|
|
http_set_ssi_handler(ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags));
|
|
printf("HTTP server initialized\n");
|
|
|
|
watchdog_enable(8000,1);
|
|
|
|
if (clientmode) {
|
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN,1);
|
|
while(true) {
|
|
if ( absolute_time_diff_us(lastCheck, get_absolute_time()) > 5000000) {
|
|
if ( cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) == 3 ) {
|
|
lastCheck = get_absolute_time();
|
|
if(!reboot){
|
|
watchdog_update();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
lastActive = get_absolute_time(); //initialize activity timer
|
|
static int led = 1;
|
|
while(true) {
|
|
if (absolute_time_diff_us(lastCheck, get_absolute_time()) > 1000000) {
|
|
led = !led;
|
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led);
|
|
lastCheck = get_absolute_time();
|
|
if ( config_loaded && (absolute_time_diff_us(lastActive, lastCheck) > 600000000)) {
|
|
reboot = true;
|
|
}
|
|
if(!reboot) {
|
|
watchdog_update();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const char * sendkeys_cgi (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
|
|
for (int i=0; i < iNumParams; i++) {
|
|
if (strcmp(pcParam[i], "keys") == 0 ) {
|
|
//printf("Web input: %s\n", pcValue[i]);
|
|
parse_key_list(pcValue[i]);
|
|
}
|
|
}
|
|
|
|
lastActive= get_absolute_time();
|
|
|
|
// send return page
|
|
return "/success.html";
|
|
}
|
|
|
|
const char * save_wifi (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
|
|
// clear all values in manual network settings
|
|
memset(ip, 0, sizeof(ip));
|
|
memset(mask, 0, sizeof(mask));
|
|
memset(gw, 0, sizeof(gw));
|
|
|
|
bad_config = false;
|
|
wifi.manual = true;
|
|
|
|
for (int i=0; i < iNumParams; i++) {
|
|
if (strcmp(pcParam[i], "ssid") == 0){
|
|
if (pcValue[i][0] == "\0") {
|
|
bad_config = true;
|
|
} else {
|
|
urldecode(pcValue[i], wifi.ssid);
|
|
}
|
|
} else if (strcmp(pcParam[i], "pass") == 0) {
|
|
urldecode(pcValue[i], wifi.pass);
|
|
} else if (strcmp(pcParam[i], "host") == 0) {
|
|
urldecode(pcValue[i], wifi.host);
|
|
} else if (strcmp(pcParam[i], "dhcp") == 0) {
|
|
wifi.manual = false;
|
|
} else if (strncmp(pcParam[i], "ip", 2) ==0 ) {
|
|
uint8_t part = atoi(&(pcParam[i][2]));
|
|
int val = atoi(pcValue[i]);
|
|
if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) {
|
|
bad_config = true;
|
|
} else {
|
|
ip[part] = (uint8_t) val;
|
|
}
|
|
} else if (strncmp(pcParam[i], "gw", 2) ==0 ) {
|
|
uint8_t part = atoi(&(pcParam[i][2]));
|
|
int val = atoi(pcValue[i]);
|
|
if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) {
|
|
bad_config = true;
|
|
} else {
|
|
gw[part] = (uint8_t) val;
|
|
}
|
|
} else if (strncmp(pcParam[i], "mask", 4) ==0 ) {
|
|
uint8_t part = atoi(&(pcParam[i][4]));
|
|
int val = atoi(pcValue[i]);
|
|
if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) {
|
|
bad_config = true;
|
|
} else {
|
|
mask[part] = (uint8_t) val;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bad_config) {
|
|
return "/wifi.shtml";
|
|
} else {
|
|
IP4_ADDR(&(wifi.ip), ip[0], ip[1], ip[2], ip[3]);
|
|
if(!wifi.ip.addr) {
|
|
wifi.ip.addr = IPADDR_NONE;
|
|
}
|
|
IP4_ADDR(&(wifi.mask), mask[0], mask[1], mask[2], mask[3]);
|
|
if(!wifi.mask.addr) {
|
|
wifi.mask.addr = IPADDR_NONE;
|
|
}
|
|
IP4_ADDR(&(wifi.gw), gw[0], gw[1], gw[2], gw[3]);
|
|
if(!wifi.gw.addr) {
|
|
wifi.gw.addr = IPADDR_NONE;
|
|
}
|
|
wifi.header = STARTFILE;
|
|
wifi.footer = ENDFILE;
|
|
config_loaded = true;
|
|
|
|
watchdog_update();
|
|
|
|
net_config_write(&wifi);
|
|
|
|
printf("wifi settings saved\n");
|
|
|
|
return "/success.html";
|
|
}
|
|
}
|
|
|
|
const char * reboot_cgi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
|
|
reboot = true;
|
|
|
|
return "/success.html";
|
|
}
|
|
|
|
|
|
void net_config_write(net_config *config) {
|
|
multicore_lockout_start_blocking();
|
|
|
|
uint8_t buf[FLASH_PAGE_SIZE];
|
|
memset(buf, 0x00, FLASH_PAGE_SIZE);
|
|
memcpy(buf, config, sizeof(net_config));
|
|
|
|
uint32_t interrupts = save_and_disable_interrupts();
|
|
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
|
|
flash_range_program(FLASH_TARGET_OFFSET, buf, FLASH_PAGE_SIZE);
|
|
restore_interrupts(interrupts);
|
|
|
|
multicore_lockout_end_blocking();
|
|
}
|
|
|
|
bool net_config_load(net_config *config) {
|
|
const uint8_t *data = (const uint8_t *) (XIP_BASE+FLASH_TARGET_OFFSET);
|
|
memcpy(config, data, sizeof(net_config));
|
|
|
|
return ( (config->header == STARTFILE) && (config->footer == ENDFILE) );
|
|
}
|
|
|
|
uint16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen) {
|
|
size_t printed;
|
|
switch (iIndex) {
|
|
case 0: //num
|
|
if (led_code & 1) {
|
|
printed = snprintf(pcInsert, iInsertLen, "on");
|
|
} else {
|
|
printed = snprintf(pcInsert, iInsertLen, "off");
|
|
}
|
|
break;
|
|
case 1: //caps
|
|
if (led_code & 2) {
|
|
printed = snprintf(pcInsert, iInsertLen, "on");
|
|
} else {
|
|
printed = snprintf(pcInsert, iInsertLen, "off");
|
|
}
|
|
break;
|
|
case 2: //scroll
|
|
if (led_code & 4) {
|
|
printed = snprintf(pcInsert, iInsertLen, "on");
|
|
} else {
|
|
printed = snprintf(pcInsert, iInsertLen, "off");
|
|
}
|
|
break;
|
|
case 3: //ssid
|
|
if (config_loaded && wifi.ssid) {
|
|
printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.ssid);
|
|
} else {
|
|
printed = 0;
|
|
}
|
|
break;
|
|
case 4: //pass
|
|
if (config_loaded && wifi.pass) {
|
|
printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.pass);
|
|
} else {
|
|
printed = 0;
|
|
}
|
|
break;
|
|
case 5: //host
|
|
if (config_loaded && wifi.host) {
|
|
printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.host);
|
|
} else {
|
|
printed = 0;
|
|
}
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9: //ip0-3
|
|
if (config_loaded && wifi.ip.addr) {
|
|
printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.ip), iIndex-6));
|
|
} else {
|
|
printed = 0;
|
|
}
|
|
break;
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13: //mask0-3
|
|
if (config_loaded && wifi.mask.addr) {
|
|
printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.mask), iIndex-10));
|
|
} else {
|
|
printed = 0;
|
|
}
|
|
break;
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
case 17: //gw0-3
|
|
if (config_loaded && wifi.gw.addr) {
|
|
printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.gw), iIndex-14));
|
|
} else {
|
|
printed = 0;
|
|
}
|
|
break;
|
|
case 18: // dhcp
|
|
if ((!config_loaded) || !(wifi.manual) ){
|
|
printed = snprintf(pcInsert, iInsertLen, "checked");
|
|
} else {
|
|
printed = 0;
|
|
}
|
|
break;
|
|
default: //undefined tag
|
|
printed = 0;
|
|
break;
|
|
}
|
|
LWIP_ASSERT("illegal length returned", printed <= 0xFFFF);
|
|
return (uint16_t)printed;
|
|
}
|
|
|
|
void set_indicator(uint8_t const* buffer) {
|
|
led_code = *buffer;
|
|
}
|
|
|
|
void urldecode(char *urlstring, char *decoded) {
|
|
uint8_t conv;
|
|
while(*urlstring) {
|
|
if(*urlstring == '+') {
|
|
*decoded=' ';
|
|
} else if (*urlstring == '%') {
|
|
urlstring++;
|
|
sscanf(urlstring, "%02hhx", &conv);
|
|
*decoded = conv;
|
|
urlstring++;
|
|
} else {
|
|
*decoded = *urlstring;
|
|
}
|
|
urlstring++;;
|
|
decoded++;
|
|
}
|
|
*decoded = '\0';
|
|
}
|