Files
snapclient/components/improv_wifi/wifi_provisioning.c
2025-02-21 23:58:23 +01:00

263 lines
7.0 KiB
C

/*
* wifi_provisioning.c
*
* Created on: Apr 28, 2024
* Author: karl
*/
#include <stdlib.h>
#include <string.h>
#include "driver/uart.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/projdefs.h"
#include "freertos/task.h"
#include "improv_wrapper.h"
#include "network_interface.h"
#include "wifi_interface.h"
#define TAG "IMPROV"
#define RD_BUF_SIZE (UART_FIFO_LEN)
#define PATTERN_CHR_NUM (3)
static TaskHandle_t t_improv_task = NULL;
static const int uart_buffer_size = 2 * RD_BUF_SIZE;
static QueueHandle_t uart0_queue;
void uart_event_handler(void) {
uart_event_t event;
uint8_t *dtmp;
// Waiting for UART event.
if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
dtmp = (uint8_t *)calloc(1, event.size);
if (!dtmp) {
ESP_LOGE(TAG, "no free memory for uart receive. Dropping data...");
uint8_t drop;
while (event.size--) {
uart_read_bytes(UART_NUM_0, &drop, event.size, portMAX_DELAY);
}
return;
}
// ESP_LOGI(TAG, "uart[%d] event: %d, size %d", UART_NUM_0, event.type,
// event.size);
switch (event.type) {
// Event of UART receving data
/*We'd better handler data event fast, there would be much more data
events than other types of events. If we take too much time on data event,
the queue might be full.*/
case UART_DATA:
// ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
uart_read_bytes(UART_NUM_0, dtmp, event.size, portMAX_DELAY);
// ESP_LOGI(TAG, "[DATA EVT]:");
improv_wifi_handle_serial(dtmp, event.size);
break;
// Event of HW FIFO overflow detected
case UART_FIFO_OVF:
// ESP_LOGI(TAG, "hw fifo overflow");
// If fifo overflow happened, you should consider adding flow control
// for your application. The ISR has already reset the rx FIFO, As an
// example, we directly flush the rx buffer here in order to read more
// data.
uart_flush_input(UART_NUM_0);
xQueueReset(uart0_queue);
break;
// Event of UART ring buffer full
case UART_BUFFER_FULL:
// ESP_LOGI(TAG, "ring buffer full");
// If buffer full happened, you should consider increasing your buffer
// size As an example, we directly flush the rx buffer here in order to
// read more data.
uart_flush_input(UART_NUM_0);
xQueueReset(uart0_queue);
break;
// Others
default:
// ESP_LOGI(TAG, "uart event type: %d", event.type);
break;
}
free(dtmp);
}
}
static void improv_task(void *pvParameters) {
while (1) {
uart_event_handler();
}
}
void uart_write(const unsigned char *txData, int length) {
uart_write_bytes(UART_NUM_0, txData, length);
}
void improv_wifi_scan(unsigned char *scanResponse, int bufLen,
uint16_t *count) {
uint16_t number = 16;
wifi_ap_record_t ap_info[16];
memset(ap_info, 0, sizeof(ap_info));
if (esp_wifi_scan_start(NULL, true) == ESP_ERR_WIFI_STATE) {
wifi_ap_record_t ap_info_tmp;
do {
esp_wifi_disconnect();
vTaskDelay(pdMS_TO_TICKS(500));
} while (esp_wifi_sta_get_ap_info(&ap_info_tmp) !=
ESP_ERR_WIFI_NOT_CONNECT);
esp_wifi_scan_start(NULL, true);
}
// ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
*count = 0;
scanResponse[0] = 0;
for (int i = 0; i < number; i++) {
char rssiStr[8] = {
0,
};
char cipherStr[8] = {
0,
};
int16_t neededLen;
itoa(ap_info[i].rssi, rssiStr, 10);
if (ap_info[i].authmode != WIFI_AUTH_OPEN) {
strcat(cipherStr, "YES");
} else {
strcat(cipherStr, "NO");
}
neededLen = strlen((const char *)ap_info[i].ssid) + strlen(rssiStr) +
strlen(cipherStr) + 3;
if ((bufLen - neededLen) > 0) {
strcat((char *)scanResponse, (char *)ap_info[i].ssid);
strcat((char *)scanResponse, (char *)",");
strcat((char *)scanResponse, (char *)rssiStr);
strcat((char *)scanResponse, (char *)",");
strcat((char *)scanResponse, (char *)cipherStr);
strcat((char *)scanResponse, (char *)"\n");
bufLen -= neededLen;
(*count)++;
}
}
// ESP_LOGI(TAG, "APs \n%s", scanResponse);
}
bool improv_wifi_connect(const char *ssid, const char *password) {
uint8_t count = 0;
esp_netif_ip_info_t ip;
wifi_config_t wifi_config;
ESP_ERROR_CHECK(esp_wifi_get_config(WIFI_IF_STA, &wifi_config));
strcpy((char *)wifi_config.sta.ssid, ssid);
strcpy((char *)wifi_config.sta.password, password);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
esp_wifi_disconnect();
while (wifi_get_ip(&ip) == true) {
vTaskDelay(pdMS_TO_TICKS(100));
}
esp_wifi_connect();
while (wifi_get_ip(&ip) == false) {
vTaskDelay(pdMS_TO_TICKS(500));
if (count > 20) {
esp_wifi_disconnect();
return false;
}
count++;
}
return true;
}
/**
*/
bool improv_wifi_is_connected(void) {
bool ret = network_if_get_ip(NULL);
return ret;
}
/**
*/
void improv_wifi_get_local_ip(uint8_t *address) {
esp_netif_ip_info_t ip_info;
if (network_if_get_ip(&ip_info) == false) {
ESP_LOGE(TAG, "%s: no valid IP available", __func__);
return;
}
address[0] = ip_info.ip.addr >> 0;
address[1] = ip_info.ip.addr >> 8;
address[2] = ip_info.ip.addr >> 16;
address[3] = ip_info.ip.addr >> 24;
ESP_LOGI(TAG, "%d.%d.%d.%d", address[0], address[1], address[2], address[3]);
}
/**
*/
void improv_init(void) {
uint8_t webPortStr[6] = {0};
uint16_t webPort = CONFIG_WEB_PORT;
uint8_t urlStr[26] = "http://{LOCAL_IPV4}:";
ESP_LOGI(TAG, "start IPROV WiFi provisioning service");
utoa(webPort, (char *)webPortStr, 10);
strcat((char *)urlStr, (char *)webPortStr);
improv_wifi_create();
improv_wifi_serialWrite(uart_write);
improv_wifi_set_device_info(CF_ESP32, "esp32_snapclient", "0.0.3",
"snapclient", (const char *)urlStr);
improv_wifi_setCustomConnectWiFi(improv_wifi_connect);
improv_wifi_setCustomScanWiFi(improv_wifi_scan);
improv_wifi_setCustomIsConnected(improv_wifi_is_connected);
improv_wifi_setCustomGetLocalIpCallback(improv_wifi_get_local_ip);
// Set UART pins(TX: IO4, RX: IO5, RTS: IO18, CTS: IO19)
// ESP_ERROR_CHECK(uart_set_pin(UART_NUM_0, 1, 3, -1, -1));
// Install UART driver using an event queue here
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_0, uart_buffer_size,
uart_buffer_size, 10, &uart0_queue, 0));
xTaskCreatePinnedToCore(&improv_task, "improv", 4 * 1024, NULL, 4,
&t_improv_task, tskNO_AFFINITY);
}
void improv_deinit(void) {
if (t_improv_task) {
vTaskDelete(t_improv_task);
uart_driver_delete(UART_NUM_0);
t_improv_task = NULL;
}
improv_wifi_destroy();
ESP_ERROR_CHECK(uart_driver_delete(UART_NUM_0));
}