text/plain
•
6.69 KB
•
275 lines
#include <stdlib.h>
#include <string.h>
#include "../../src/config.h"
#include "../../src/moon.h"
#include "../../src/network.h"
#include "../../src/storage.h"
#include "esp_crt_bundle.h"
#include "esp_http_client.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
static const char* TAG = "NET";
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
#define DOWNLOAD_BUF_SIZE 4096
static EventGroupHandle_t wifi_event_group;
static bool wifi_stack_initialized = false;
static bool wifi_connected = false;
static void wifi_event_handler(void* arg,
esp_event_base_t event_base,
int32_t event_id,
void* event_data) {
(void)arg;
(void)event_data;
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void network_init(void) {
if (wifi_stack_initialized) {
return;
}
wifi_event_group = xEventGroupCreate();
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_sta();
wifi_init_config_t init_cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&init_cfg);
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler,
NULL);
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
wifi_event_handler, NULL);
esp_wifi_set_mode(WIFI_MODE_STA);
wifi_stack_initialized = true;
ESP_LOGI(TAG, "WiFi stack initialized");
}
static bool wifi_connect(void) {
config_t cfg;
if (!config_load(&cfg)) {
ESP_LOGI(TAG, "No WiFi config found");
return false;
}
// Try each configured network
for (int i = 0; i < cfg.wifi_count; i++) {
ESP_LOGI(TAG, "Trying SSID: %s", cfg.wifi[i].ssid);
wifi_config_t wifi_cfg = {0};
strncpy((char*)wifi_cfg.sta.ssid, cfg.wifi[i].ssid,
sizeof(wifi_cfg.sta.ssid) - 1);
strncpy((char*)wifi_cfg.sta.password, cfg.wifi[i].psk,
sizeof(wifi_cfg.sta.password) - 1);
xEventGroupClearBits(wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT);
esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg);
esp_wifi_start();
esp_wifi_connect();
EventBits_t bits = xEventGroupWaitBits(
wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE,
pdFALSE, pdMS_TO_TICKS(10000));
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "Connected to %s", cfg.wifi[i].ssid);
wifi_connected = true;
return true;
}
ESP_LOGI(TAG, "Failed to connect to %s", cfg.wifi[i].ssid);
esp_wifi_disconnect();
esp_wifi_stop();
}
ESP_LOGI(TAG, "Failed to connect to any WiFi network");
return false;
}
static void wifi_disconnect(void) {
if (!wifi_connected) {
return;
}
esp_wifi_disconnect();
esp_wifi_stop();
wifi_connected = false;
}
bool network_set_enabled(bool enabled) {
if (enabled) {
bool ok = wifi_connect();
wifi_enabled = ok;
return ok;
} else {
wifi_disconnect();
wifi_enabled = false;
return true;
}
}
typedef struct {
storage_file_t file;
bool ok;
} download_ctx_t;
static esp_err_t http_event_handler(esp_http_client_event_t* evt) {
download_ctx_t* ctx = (download_ctx_t*)evt->user_data;
if (evt->event_id == HTTP_EVENT_ON_DATA && ctx->file) {
size_t written = storage_write(ctx->file, evt->data, evt->data_len);
if (written != (size_t)evt->data_len) {
ctx->ok = false;
}
}
return ESP_OK;
}
bool network_download_file(const char* url, const char* destination_path) {
if (!url || !destination_path) {
return false;
}
ESP_LOGI(TAG, "Downloading %s -> %s", url, destination_path);
storage_file_t f = storage_open(destination_path, "w");
if (!f) {
return false;
}
download_ctx_t ctx = {.file = f, .ok = true};
esp_http_client_config_t config = {
.url = url,
.event_handler = http_event_handler,
.user_data = &ctx,
.timeout_ms = 30000,
.buffer_size = DOWNLOAD_BUF_SIZE,
.crt_bundle_attach = esp_crt_bundle_attach,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err = esp_http_client_perform(client);
int status = esp_http_client_get_status_code(client);
esp_http_client_cleanup(client);
storage_close(f);
if (err != ESP_OK || status != 200 || !ctx.ok) {
ESP_LOGI(TAG, "Download failed: err=%d status=%d", err, status);
storage_remove(destination_path);
return false;
}
return true;
}
bool network_is_connected(void) {
return wifi_connected;
}
int network_get_rssi(void) {
if (!wifi_connected) {
return 0;
}
wifi_ap_record_t ap_info;
if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
return ap_info.rssi;
}
return 0;
}
bool network_test_url(const char* url) {
if (!url || !wifi_connected) {
return false;
}
esp_http_client_config_t config = {
.url = url,
.timeout_ms = 10000,
.buffer_size = DOWNLOAD_BUF_SIZE,
.crt_bundle_attach = esp_crt_bundle_attach,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err = esp_http_client_perform(client);
int status = esp_http_client_get_status_code(client);
esp_http_client_cleanup(client);
return (err == ESP_OK && status == 200);
}
int network_scan(char ssids[][33], int max_results) {
if (!wifi_stack_initialized) {
ESP_LOGI(TAG, "Scan: stack not initialized");
return -1;
}
// Ensure clean state for scanning
esp_wifi_disconnect();
esp_wifi_stop();
esp_err_t err = esp_wifi_start();
if (err != ESP_OK) {
ESP_LOGI(TAG, "Scan: wifi_start: %s", esp_err_to_name(err));
return -2;
}
wifi_scan_config_t scan_cfg = {
.show_hidden = false,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time.active.min = 100,
.scan_time.active.max = 500,
};
err = esp_wifi_scan_start(&scan_cfg, true);
if (err != ESP_OK) {
ESP_LOGI(TAG, "Scan: scan_start failed: %s", esp_err_to_name(err));
return -3;
}
uint16_t ap_count = 0;
esp_wifi_scan_get_ap_num(&ap_count);
ESP_LOGI(TAG, "Scan: found %d APs", ap_count);
if (ap_count == 0) {
return 0;
}
uint16_t fetch = ap_count;
if (fetch > (uint16_t)max_results) {
fetch = (uint16_t)max_results;
}
wifi_ap_record_t* ap_list = malloc(fetch * sizeof(wifi_ap_record_t));
if (!ap_list) {
return -4;
}
esp_wifi_scan_get_ap_records(&fetch, ap_list);
for (int i = 0; i < fetch; i++) {
strncpy(ssids[i], (const char*)ap_list[i].ssid, 32);
ssids[i][32] = '\0';
ESP_LOGI(TAG, " AP[%d]: %s (rssi %d)", i, ssids[i], ap_list[i].rssi);
}
free(ap_list);
return (int)fetch;
}