#include #include #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'; }