diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8c0ff5f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "." + PRIV_REQUIRES esp_netif esp_eth esp_wifi nvs_flash esp_driver_gpio + INCLUDE_DIRS "." +) diff --git a/idf_component.yml b/idf_component.yml new file mode 100644 index 0000000..1076a80 --- /dev/null +++ b/idf_component.yml @@ -0,0 +1,7 @@ +## IDF Component Manager Manifest File +dependencies: + ## Required IDF version + idf: + version: '>=6.0.0' + espressif/ethernet_init: ^1.3.0 +# espressif/lan87xx: '*' \ No newline at end of file diff --git a/network.c b/network.c new file mode 100644 index 0000000..1859a21 --- /dev/null +++ b/network.c @@ -0,0 +1,120 @@ +#include "network.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ESP_EVENT_DEFINE_BASE(SNTP_EVENT); + +static const char *TAG = "network"; + +void time_sync_notification_cb(struct timeval *tv) { // NOLINT, it cant + ESP_LOGI(TAG, "time synced, unix time is %llu", tv->tv_sec); + esp_event_post(SNTP_EVENT, SNTP_EVENT_SYNCED, nullptr, 0, portMAX_DELAY); +} + + +// logs IP, starts sntp +static void on_get_ip(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + const ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + ESP_LOGI(TAG, "ip getto: " IPSTR, IP2STR(&event->ip_info.ip)); + sntp_set_time_sync_notification_cb(time_sync_notification_cb); + sntp_set_sync_interval(SNTP_TIME_SYNC_INTERVAL_MINUTES * 60 * 1000); + esp_sntp_setservername(0, SNTP_SERVER); + setenv("TZ", POSIX_TIMEZONE_STRING, true); + tzset(); + esp_sntp_init(); +} + +// we sometimes call this by hand to init scanning +static void on_wifi_disconnect(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + ESP_LOGI(TAG, "Wi-Fi disconnected, scanning for networks..."); + const wifi_scan_config_t scan_cfg = {.show_hidden = true}; + esp_wifi_scan_start(&scan_cfg, false); +} + +// when scanning done, match against known networks and try to connect to it +static void on_scan_done(void *nets, esp_event_base_t event_base, int32_t event_id, void *event_data) { + const struct wifi_networks_t *known_networks = (struct wifi_networks_t *)nets; + uint16_t ap_count = 0; + esp_wifi_scan_get_ap_num(&ap_count); + + wifi_ap_record_t *ap_list = malloc(ap_count * sizeof(wifi_ap_record_t)); + esp_wifi_scan_get_ap_records(&ap_count, ap_list); + + int best_match = -1; + int best_rssi = INT_MIN; + + for (int i = 0; i < ap_count; i++) { + for (int k = 0; k < known_networks->num_nets; k++) { + if (strcmp((char *)ap_list[i].ssid, + known_networks->nets[k].ssid) == 0) { + if (ap_list[i].rssi > best_rssi) { + best_rssi = (uint8_t)ap_list[i].rssi; + best_match = k; + } + } + } + } + free(ap_list); + + if (best_match < 0) { + ESP_LOGW(TAG, "no known networks found"); + on_wifi_disconnect(nullptr, WIFI_EVENT, WIFI_EVENT_SCAN_DONE, nullptr); + return; + } + + wifi_config_t wifi_cfg = {}; + strncpy((char *)wifi_cfg.sta.ssid, known_networks->nets[best_match].ssid, sizeof(known_networks->nets[0].ssid) - 1); + strncpy((char *)wifi_cfg.sta.password, known_networks->nets[best_match].password, sizeof(known_networks->nets[0].password) - 1); + wifi_cfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; + + esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg); + esp_wifi_connect(); +} + +void init_ethernet(const char *hostname) { + ESP_ERROR_CHECK(esp_netif_init()); + + uint8_t eth_port_cnt = 0; + esp_eth_handle_t *eth_handles; + + // allow ethernet oscillator + ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT)); + ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_16, 1)); + + // install eth chip driver + ESP_ERROR_CHECK(ethernet_init_all(ð_handles, ð_port_cnt)); + + const esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); + esp_netif_t *eth_netif = esp_netif_new(&cfg); + esp_netif_set_hostname(eth_netif, hostname); + + ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0]))); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_get_ip, nullptr)); + ESP_ERROR_CHECK(esp_eth_start(eth_handles[0])); +} + +void init_wifi(const struct wifi_networks_t *nets, const char *hostname) { + nvs_flash_init(); + esp_netif_init(); + esp_netif_t *netif = esp_netif_create_default_wifi_sta(); + esp_netif_set_hostname(netif, hostname); + + // create and register event handlers + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, on_scan_done, (void *)nets); + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect, nullptr); + esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_get_ip, nullptr); + + const wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + esp_wifi_init(&cfg); + esp_wifi_set_mode(WIFI_MODE_STA); + esp_wifi_start(); + on_wifi_disconnect(nullptr, WIFI_EVENT, WIFI_EVENT_SCAN_DONE, nullptr); +} diff --git a/network.h b/network.h new file mode 100644 index 0000000..1c3ea5c --- /dev/null +++ b/network.h @@ -0,0 +1,30 @@ +#ifndef NETWORK_H +#define NETWORK_H + +#include + +#define POSIX_TIMEZONE_STRING "CET-1CEST,M3.5.0,M10.5.0/3" +#define SNTP_TIME_SYNC_INTERVAL_MINUTES (6 * 60) // 6 hours +#define SNTP_SERVER "pool.ntp.org" + +ESP_EVENT_DECLARE_BASE(SNTP_EVENT); + +enum sntp_event_t { + SNTP_EVENT_UNKNOWN = 0, + SNTP_EVENT_SYNCED, +}; + +struct wifi_network_t { + const char ssid[32]; + const char password[32]; +}; + +struct wifi_networks_t { + uint8_t num_nets; + struct wifi_network_t nets[]; +}; + +void init_wifi(const struct wifi_networks_t *nets, const char *hostname); +void init_ethernet(const char *hostname); + +#endif