From 2a55d69ac4b8612eeacbe4ca13942eab2f2ccfd4 Mon Sep 17 00:00:00 2001 From: jedi Date: Fri, 9 Jul 2021 21:42:44 +0200 Subject: [PATCH] add basic wifi with station and AP modes --- firmware/fiatlux.c | 13 +- firmware/wifi.cpp | 354 +++++++++++++++++++++++++++++++++++++++++++++ firmware/wifi.h | 2 + 3 files changed, 365 insertions(+), 4 deletions(-) diff --git a/firmware/fiatlux.c b/firmware/fiatlux.c index 1368d86..2ae2637 100644 --- a/firmware/fiatlux.c +++ b/firmware/fiatlux.c @@ -1,13 +1,15 @@ -#include -#include -#include - #include "system.h" #include "wifi.h" #include "web.h" #include "mqtt.h" #include "lux.h" +#include +#include +#include + +#include +#include void user_init(void) { @@ -17,4 +19,7 @@ void user_init(void) sdk_wifi_set_sleep_type(WIFI_SLEEP_MODEM); system_init_config(); + + xTaskCreate(wifi_task, "wifi_task", 512, NULL, 2, NULL); + } diff --git a/firmware/wifi.cpp b/firmware/wifi.cpp index da4c496..5526068 100644 --- a/firmware/wifi.cpp +++ b/firmware/wifi.cpp @@ -3,3 +3,357 @@ // #include "wifi.h" + +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +#include +#include +#include +#include + +const char *wificfg_default_ssid = "fiatlux_%02X%02X%02X"; +const char *wificfg_default_password = "fiatlux02"; +const char *wificfg_default_hostname = "fiatlux-%02x%02x%02x"; + +char *wifi_sta_ssid = nullptr; +char *wifi_sta_password = nullptr; +char *wifi_ap_ssid = nullptr; +char *wifi_ap_password = nullptr; + + +[[noreturn]] static void dns_task(void *pvParameters) { + char *wifi_ap_ip_addr = nullptr; + sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + if(!wifi_ap_ip_addr) { + printf("dns: no ip address\n"); + vTaskDelete(nullptr); + } + ip4_addr_t server_addr; + server_addr.addr = ipaddr_addr(wifi_ap_ip_addr); + +#if LWIP_IPV6 + int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + sockaddr_in6 serv_addr; + memset(&serv_addr, '0', sizeof(serv_addr)); + serv_addr.sin6_family = AF_INET6; + serv_addr.sin6_port = htons(53); + serv_addr.sin6_flowinfo = 0; + serv_addr.sin6_addr = in6addr_any; + serv_addr.sin6_scope_id = IP6_NO_ZONE; +#else + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + sockaddr_in serv_addr; + memset(&serv_addr, '0', sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(53); +#endif + bind(fd, (sockaddr *) &serv_addr, sizeof(serv_addr)); + + const ifreq ifreq0 = {"en0"}; + const ifreq ifreq1 = {"en1"}; + setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, + sdk_wifi_get_opmode() == STATIONAP_MODE ? &ifreq1 : &ifreq0, + sizeof(ifreq0)); + + for (;;) { + uint8_t buffer[96]; + sockaddr_storage src_addr; + socklen_t src_addr_len = sizeof(src_addr); + ssize_t count = recvfrom(fd, buffer, sizeof(buffer), 0, (sockaddr *) &src_addr, &src_addr_len); + + /* Drop messages that are too large to send a response in the buffer */ + if(count > 0 && count + 16 <= (ssize_t) sizeof(buffer)) { + size_t qname_len = strlen((const char *) (buffer + 12)) + 1; + uint32_t reply_len = 2 + 10 + qname_len + 16 + 4; + + uint8_t *head = buffer + 2; + *head++ = 0x80; // Flags + *head++ = 0x00; + *head++ = 0x00; // Q count + *head++ = 0x01; + *head++ = 0x00; // A count + *head++ = 0x01; + *head++ = 0x00; // Auth count + *head++ = 0x00; + *head++ = 0x00; // Add count + *head++ = 0x00; + head += qname_len; + *head++ = 0x00; // Q type + *head++ = 0x01; + *head++ = 0x00; // Q class + *head++ = 0x01; + *head++ = 0xC0; // LBL offs + *head++ = 0x0C; + *head++ = 0x00; // Type + *head++ = 0x01; + *head++ = 0x00; // Class + *head++ = 0x01; + *head++ = 0x00; // TTL + *head++ = 0x00; + *head++ = 0x00; + *head++ = 0x78; + *head++ = 0x00; // RD len + *head++ = 0x04; + *head++ = ip4_addr1(&server_addr); + *head++ = ip4_addr2(&server_addr); + *head++ = ip4_addr3(&server_addr); + *head++ = ip4_addr4(&server_addr); + + sendto(fd, buffer, reply_len, 0, (sockaddr *) &src_addr, src_addr_len); + } + } +} + +extern "C" [[noreturn]] void wifi_task(void *pvParameters) { + (void) pvParameters; + /* Default a hostname. */ + char *hostname = nullptr; + sysparam_get_string("hostname", &hostname); + if(!hostname && wificfg_default_hostname) { + uint8_t macaddr[6]; + char name[32]; + sdk_wifi_get_macaddr(1, macaddr); + snprintf(name, sizeof(name), wificfg_default_hostname, macaddr[3], + macaddr[4], macaddr[5]); + sysparam_set_string("hostname", name); + } + if(hostname) { + free(hostname); + } + + sysparam_get_string("wifi_ap_ssid", &wifi_ap_ssid); + sysparam_get_string("wifi_ap_password", &wifi_ap_password); + sysparam_get_string("wifi_sta_ssid", &wifi_sta_ssid); + sysparam_get_string("wifi_sta_password", &wifi_sta_password); + + int8_t wifi_sta_enable = 1; + int8_t wifi_ap_enable = 1; + sysparam_get_int8("wifi_sta_enable", &wifi_sta_enable); + sysparam_get_int8("wifi_ap_enable", &wifi_ap_enable); + + if(!wifi_sta_enable) + wifi_ap_enable = 1; + + int8_t wifi_sta_disabled_restarts = 0; + sysparam_get_int8("wifi_sta_disabled_restarts", &wifi_sta_disabled_restarts); + if(wifi_sta_disabled_restarts > 0) { + wifi_sta_enable = 0; + wifi_sta_disabled_restarts--; + sysparam_set_int8("wifi_sta_disabled_restarts", wifi_sta_disabled_restarts); + } + + int8_t wifi_ap_disabled_restarts = 0; + sysparam_get_int8("wifi_ap_disabled_restarts", &wifi_ap_disabled_restarts); + if(wifi_ap_disabled_restarts > 0) { + wifi_ap_enable = 0; + wifi_ap_disabled_restarts--; + sysparam_set_int8("wifi_ap_disabled_restarts", wifi_ap_disabled_restarts); + } + + /* Validate the configuration. */ + + if(wifi_sta_enable && (!wifi_sta_ssid || !wifi_sta_password || + strlen(wifi_sta_ssid) < 1 || + strlen(wifi_sta_ssid) > 32 || + !wifi_sta_password || + strlen(wifi_sta_password) < 8 || + strlen(wifi_sta_password) >= 64)) { + wifi_sta_enable = 0; + } + + if(wifi_ap_enable) { + /* Default AP ssid and password. */ + if(!wifi_ap_ssid && wificfg_default_ssid) { + uint8_t macaddr[6]; + char ssid[32]; + sdk_wifi_get_macaddr(1, macaddr); + snprintf(ssid, sizeof(ssid), wificfg_default_ssid, macaddr[3], + macaddr[4], macaddr[5]); + sysparam_set_string("wifi_ap_ssid", ssid); + sysparam_get_string("wifi_ap_ssid", &wifi_ap_ssid); + + if(!wifi_ap_password && wificfg_default_password) { + sysparam_set_string("wifi_ap_password", wificfg_default_password); + sysparam_get_string("wifi_ap_password", &wifi_ap_password); + } + } + printf("ssid: %s\n", wifi_ap_ssid); + + /* If the ssid and password are not valid then disable the AP interface. */ + if(!wifi_ap_ssid || strlen(wifi_ap_ssid) < 1 || strlen(wifi_ap_ssid) >= 32 || + !wifi_ap_password || strlen(wifi_ap_password) < 8 || strlen(wifi_ap_password) >= 64) { + printf("len err\n"); + wifi_ap_enable = 0; + } + } + + int8_t wifi_mode = NULL_MODE; + if(wifi_sta_enable && wifi_ap_enable) + wifi_mode = STATIONAP_MODE; + else if(wifi_sta_enable) + wifi_mode = STATION_MODE; + else if(wifi_ap_enable) + wifi_mode = SOFTAP_MODE; + sdk_wifi_set_opmode(wifi_mode); + + if(wifi_sta_enable) { + printf("try STA Mode: %s %s\n", wifi_sta_ssid, wifi_sta_password); + sdk_station_config config; + strcpy((char *) config.ssid, wifi_sta_ssid); + strcpy((char *) config.password, wifi_sta_password); + config.bssid_set = 0; + + int8_t wifi_sta_dhcp = 1; + sysparam_get_int8("wifi_sta_dhcp", &wifi_sta_dhcp); + + if(!wifi_sta_dhcp) { + char *wifi_sta_ip_addr = nullptr; + char *wifi_sta_netmask = nullptr; + char *wifi_sta_gateway = nullptr; + sysparam_get_string("wifi_sta_ip_addr", &wifi_sta_ip_addr); + sysparam_get_string("wifi_sta_netmask", &wifi_sta_netmask); + sysparam_get_string("wifi_sta_gateway", &wifi_sta_gateway); + + if(wifi_sta_ip_addr && strlen(wifi_sta_ip_addr) > 4 && + wifi_sta_netmask && strlen(wifi_sta_netmask) > 4 && + wifi_sta_gateway && strlen(wifi_sta_gateway) > 4) { + sdk_wifi_station_dhcpc_stop(); + ip_info info; + memset(&info, 0x0, sizeof(info)); + info.ip.addr = ipaddr_addr(wifi_sta_ip_addr); + info.netmask.addr = ipaddr_addr(wifi_sta_netmask); + info.gw.addr = ipaddr_addr(wifi_sta_gateway); + sdk_wifi_set_ip_info(STATION_IF, &info); + } + if(wifi_sta_ip_addr) free(wifi_sta_ip_addr); + if(wifi_sta_netmask) free(wifi_sta_netmask); + if(wifi_sta_gateway) free(wifi_sta_gateway); + } + + sdk_wifi_station_set_config(&config); + } + + if(wifi_ap_enable) { + printf("try AP Mode: %s %s\n", wifi_ap_ssid, wifi_ap_password); +/* Read and validate paramenters. */ + int8_t wifi_ap_ssid_hidden = 0; + sysparam_get_int8("wifi_ap_ssid_hidden", &wifi_ap_ssid_hidden); + if(wifi_ap_ssid_hidden < 0 || wifi_ap_ssid_hidden > 1) { + wifi_ap_ssid_hidden = 1; + } + + int8_t wifi_ap_channel = 6; + sysparam_get_int8("wifi_ap_channel", &wifi_ap_channel); + +#if 0 + /* AU does not allow channels above 13, although 14 works. */ + if(wifi_ap_channel > 13) { + wifi_ap_channel = 13; + } + /* US does not allow channels above 11, although they work. */ + if (wifi_ap_channel > 11) { + wifi_ap_channel = 11; + } +#endif + if(wifi_ap_channel < 1 || wifi_ap_channel > 14) { + wifi_ap_channel = 6; + } + + int8_t wifi_ap_authmode = AUTH_WPA_WPA2_PSK; + sysparam_get_int8("wifi_ap_authmode", &wifi_ap_authmode); + if(wifi_ap_authmode != AUTH_OPEN && wifi_ap_authmode != AUTH_WPA_PSK && + wifi_ap_authmode != AUTH_WPA2_PSK && wifi_ap_authmode != AUTH_WPA_WPA2_PSK) { + wifi_ap_authmode = AUTH_WPA_WPA2_PSK; + } + + int8_t wifi_ap_max_conn = 3; + sysparam_get_int8("wifi_ap_max_conn", &wifi_ap_max_conn); + if(wifi_ap_max_conn < 1 || wifi_ap_max_conn > 8) { + wifi_ap_max_conn = 3; + } + + int32_t wifi_ap_beacon_interval = 100; + sysparam_get_int32("wifi_ap_beacon_interval", &wifi_ap_beacon_interval); + if(wifi_ap_beacon_interval < 0 || wifi_ap_beacon_interval > 1000) { + wifi_ap_beacon_interval = 100; + } + + /* Default AP IP address and netmask. */ + char *wifi_ap_ip_addr = nullptr; + sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + if(!wifi_ap_ip_addr) { + sysparam_set_string("wifi_ap_ip_addr", "172.16.0.1"); + sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + } + char *wifi_ap_netmask = nullptr; + sysparam_get_string("wifi_ap_netmask", &wifi_ap_netmask); + if(!wifi_ap_netmask) { + sysparam_set_string("wifi_ap_netmask", "255.255.0.0"); + sysparam_get_string("wifi_ap_netmask", &wifi_ap_netmask); + } + + if(strlen(wifi_ap_ip_addr) >= 7 && strlen(wifi_ap_netmask) >= 7) { + ip_info ap_ip; + ap_ip.ip.addr = ipaddr_addr(wifi_ap_ip_addr); + ap_ip.netmask.addr = ipaddr_addr(wifi_ap_netmask); + IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0); + sdk_wifi_set_ip_info(1, &ap_ip); + + sdk_softap_config ap_config; + strcpy((char *) ap_config.ssid, wifi_ap_ssid); + ap_config.ssid_len = strlen(wifi_ap_ssid); + strcpy((char *) ap_config.password, wifi_ap_password); + ap_config.channel = static_cast(wifi_ap_channel); + ap_config.authmode = static_cast(wifi_ap_authmode); + ap_config.ssid_hidden = static_cast(wifi_ap_ssid_hidden); + ap_config.max_connection = static_cast(wifi_ap_max_conn); + ap_config.beacon_interval = static_cast(wifi_ap_beacon_interval); + + sdk_wifi_softap_set_config(&ap_config); + + int8_t wifi_ap_dhcp_leases = 4; + sysparam_get_int8("wifi_ap_dhcp_leases", &wifi_ap_dhcp_leases); + + if(wifi_ap_dhcp_leases) { + ip4_addr_t first_client_ip; + first_client_ip.addr = ap_ip.ip.addr + htonl(1); + + int8_t wifi_ap_dns = 1; + sysparam_get_int8("wifi_ap_dns", &wifi_ap_dns); + if(wifi_ap_dns < 0 || wifi_ap_dns > 1) + wifi_ap_dns = 1; + + dhcpserver_start(&first_client_ip, wifi_ap_dhcp_leases); + dhcpserver_set_router(&ap_ip.ip); + if(wifi_ap_dns) { + dhcpserver_set_dns(&ap_ip.ip); + xTaskCreate(dns_task, "dns_task", 384, nullptr, 2, nullptr); + } + } + } + + free(wifi_ap_ip_addr); + free(wifi_ap_netmask); + } + + if(wifi_sta_ssid) free(wifi_sta_ssid); + if(wifi_sta_password) free(wifi_sta_password); + if(wifi_ap_ssid) free(wifi_ap_ssid); + if(wifi_ap_password) free(wifi_ap_password); + + while (1) { + //monitor connection here + vTaskDelay(5000); + } +} \ No newline at end of file diff --git a/firmware/wifi.h b/firmware/wifi.h index 97c5f85..58f957c 100644 --- a/firmware/wifi.h +++ b/firmware/wifi.h @@ -9,6 +9,8 @@ extern "C" { #endif +void wifi_task(void *pvParameters); + #ifdef __cplusplus } #endif