Files
snapclient/components/improv_wifi/wifi_provisioning.c
CarlosDerSeher a619587c03 Improv wifi (#85)
* - add wifi credential reset
  o press reset button (nRESET pin) 3 times
    but wait about 1s between button presses
    the button press counter is reset 5s after boot
* add wifi provisioning service through improv wifi (fix #75)

Signed-off-by: Karl Osterseher <karli_o@gmx.at>
2024-06-12 16:12:21 +02:00

250 lines
6.9 KiB
C

/*
* wifi_provisioning.c
*
* Created on: Apr 28, 2024
* Author: karl
*/
#include "wifi_provisioning.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/task.h"
#include "improv_wrapper.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[RD_BUF_SIZE];
size_t buffered_size;
// Waiting for UART event.
if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
// ESP_LOGI(TAG, "uart[%d] event:", UART_NUM_0);
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;
}
}
}
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));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(count));
// ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds =
// %u",
// *count, number);
scanResponse[0] = 0;
for (int i = 0; i < number; i++) {
char rssiStr[8] = {
0,
};
char cipherStr[8] = {
0,
};
uint16_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;
}
}
// ESP_LOGI(TAG, "APs \t\t%s", scanResponse);
}
bool improv_wifi_connect(const char *ssid, const char *password) {
uint8_t count = 0;
wifi_ap_record_t apRec;
esp_err_t err;
while ((err = esp_wifi_sta_get_ap_info(&apRec)) != ESP_ERR_WIFI_NOT_CONNECT) {
esp_wifi_disconnect();
vTaskDelay(pdMS_TO_TICKS(100));
}
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_connect();
while (esp_wifi_sta_get_ap_info(&apRec) != ESP_OK) {
vTaskDelay(pdMS_TO_TICKS(500));
if (count > 20) {
esp_wifi_disconnect();
return false;
}
count++;
}
return true;
}
bool improv_wifi_is_connected(void) {
wifi_ap_record_t apRec;
if (esp_wifi_sta_get_ap_info(&apRec) == ESP_OK) {
// printf("connected\n");
return true;
}
// printf("NOT connected\n");
return false;
}
void improv_wifi_get_local_ip(uint8_t *address) {
esp_netif_ip_info_t ip_info;
// TODO: find a better way to do this
do {
esp_netif_get_ip_info(get_current_netif(), &ip_info);
vTaskDelay(pdMS_TO_TICKS(200));
} while (ip_info.ip.addr == 0);
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}:";
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();
}