mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 10:53:17 +00:00
Wi-Fi improvements (#77)
Refactoring, new features and stability improvements.
This commit is contained in:
parent
8086cd5d82
commit
8b6463d060
@ -9,3 +9,16 @@ uint32_t tt_hash_string_djb2(const char* str) {
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint32_t tt_hash_bytes_djb2(const void* data, size_t length) {
|
||||
uint32_t hash = 5381;
|
||||
uint8_t* data_bytes = (uint8_t*)data;
|
||||
uint8_t c = *data_bytes++;
|
||||
size_t index = 0;
|
||||
while (index < length) {
|
||||
hash = ((hash << 5) + hash) + (uint32_t)c; // hash * 33 + c
|
||||
c = *data_bytes++;
|
||||
index++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -7,13 +8,19 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is quicker than the m-string.h hashing, as the latter
|
||||
* operates on raw memory blocks and thus a strlen() call is required first.
|
||||
* Implementation of DJB2 hashing algorithm.
|
||||
* @param[in] str the string to calculate the hash for
|
||||
* @return the hash
|
||||
*/
|
||||
uint32_t tt_hash_string_djb2(const char* str);
|
||||
|
||||
/**
|
||||
* Implementation of DJB2 hashing algorithm.
|
||||
* @param[in] data the bytes to calculate the hash for
|
||||
* @return the hash
|
||||
*/
|
||||
uint32_t tt_hash_bytes_djb2(const void* data, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -120,17 +120,19 @@ static void get_key(uint8_t key[32]) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void tt_secure_get_iv_from_string(const char* input, uint8_t iv[16]) {
|
||||
void tt_secure_get_iv_from_data(const void* data, size_t data_length, uint8_t iv[16]) {
|
||||
memset((void*)iv, 0, 16);
|
||||
char c = *input++;
|
||||
int index = 0;
|
||||
while (c) {
|
||||
iv[index] = c;
|
||||
index++;
|
||||
c = *input++;
|
||||
uint8_t* data_bytes = (uint8_t*)data;
|
||||
for (int i = 0; i < data_length; ++i) {
|
||||
size_t safe_index = i % 16;
|
||||
iv[safe_index] %= data_bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
void tt_secure_get_iv_from_string(const char* input, uint8_t iv[16]) {
|
||||
tt_secure_get_iv_from_data((const void*)input, strlen(input), iv);
|
||||
}
|
||||
|
||||
static int tt_aes256_crypt_cbc(
|
||||
const uint8_t key[32],
|
||||
int mode,
|
||||
|
||||
@ -26,7 +26,15 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Fills the IV with zeros and then copies up to 16 characters of the string into the IV.
|
||||
* @brief Fills the IV with zeros and then creates an IV based on the input data.
|
||||
* @param data input data
|
||||
* @param data_length input data length
|
||||
* @param iv output IV
|
||||
*/
|
||||
void tt_secure_get_iv_from_data(const void* data, size_t data_length, uint8_t iv[16]);
|
||||
|
||||
/**
|
||||
* @brief Fills the IV with zeros and then creates an IV based on the input data.
|
||||
* @param input input text
|
||||
* @param iv output IV
|
||||
*/
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#ifdef ESP_TARGET
|
||||
|
||||
#include "esp_partitions.h"
|
||||
#include "services/wifi/wifi_credentials.h"
|
||||
#include "services/wifi/wifi_settings.h"
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
@ -34,7 +34,7 @@ void tt_esp_init() {
|
||||
|
||||
tt_esp_network_init();
|
||||
|
||||
tt_wifi_credentials_init();
|
||||
tt_wifi_settings_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -7,6 +7,7 @@ extern "C" {
|
||||
#include "pubsub.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "wifi_globals.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_wifi.h"
|
||||
@ -65,7 +66,7 @@ typedef struct {
|
||||
} WifiEvent;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ssid[33];
|
||||
uint8_t ssid[TT_WIFI_SSID_LIMIT + 1];
|
||||
int8_t rssi;
|
||||
wifi_auth_mode_t auth_mode;
|
||||
} WifiApRecord;
|
||||
@ -112,7 +113,7 @@ void wifi_set_enabled(bool enabled);
|
||||
* @param ssid
|
||||
* @param password
|
||||
*/
|
||||
void wifi_connect(const char* ssid, const char _Nullable password[64]);
|
||||
void wifi_connect(const char* ssid, _Nullable const char* password);
|
||||
|
||||
/**
|
||||
* @brief Disconnect from the access point. Doesn't have any effect when not connected.
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TT_WIFI_CREDENTIALS_PASSWORD_LIMIT 64 // Should be equal to wifi_sta_config_t.password
|
||||
// TODO: Move to config file
|
||||
#define TT_WIFI_CREDENTIALS_LIMIT 16
|
||||
|
||||
void tt_wifi_credentials_init();
|
||||
|
||||
bool tt_wifi_credentials_contains(const char* ssid);
|
||||
|
||||
bool tt_wifi_credentials_get(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]);
|
||||
|
||||
bool tt_wifi_credentials_set(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]);
|
||||
|
||||
bool tt_wifi_credentials_remove(const char* ssid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,235 +0,0 @@
|
||||
#ifdef ESP_TARGET
|
||||
|
||||
#include "wifi_credentials.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "log.h"
|
||||
#include "hash.h"
|
||||
#include "check.h"
|
||||
#include "mutex.h"
|
||||
#include "secure.h"
|
||||
|
||||
#define TAG "wifi_credentials"
|
||||
#define TT_NVS_NAMESPACE "tt_wifi_cred" // limited by NVS_KEY_NAME_MAX_SIZE
|
||||
#define TT_NVS_PARTITION "nvs"
|
||||
|
||||
static void hash_reset_all();
|
||||
|
||||
// region Hash
|
||||
|
||||
static Mutex* hash_mutex = NULL;
|
||||
static int8_t hash_index = -1;
|
||||
static uint32_t hashes[TT_WIFI_CREDENTIALS_LIMIT] = { 0 };
|
||||
|
||||
static void hash_init() {
|
||||
tt_assert(hash_mutex == NULL);
|
||||
hash_mutex = tt_mutex_alloc(MutexTypeNormal);
|
||||
hash_reset_all();
|
||||
}
|
||||
|
||||
static void tt_hash_mutex_lock() {
|
||||
tt_assert(tt_mutex_acquire(hash_mutex, 100) == TtStatusOk);
|
||||
}
|
||||
|
||||
static void tt_hash_mutex_unlock() {
|
||||
tt_assert(tt_mutex_release(hash_mutex) == TtStatusOk);
|
||||
}
|
||||
|
||||
static int hash_find_value(uint32_t hash) {
|
||||
tt_hash_mutex_lock();
|
||||
for (int i = 0; i < hash_index; ++i) {
|
||||
if (hashes[i] == hash) {
|
||||
tt_hash_mutex_unlock();
|
||||
return i;
|
||||
}
|
||||
}
|
||||
tt_hash_mutex_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool hash_contains_value(uint32_t value) {
|
||||
return hash_find_value(value) != -1;
|
||||
}
|
||||
|
||||
static void hash_add(const char* ssid) {
|
||||
uint32_t hash = tt_hash_string_djb2(ssid);
|
||||
if (!hash_contains_value(hash)) {
|
||||
tt_hash_mutex_lock();
|
||||
tt_check((hash_index + 1) < TT_WIFI_CREDENTIALS_LIMIT, "exceeding wifi credentials list size");
|
||||
hash_index++;
|
||||
hashes[hash_index] = hash;
|
||||
tt_hash_mutex_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
static void hash_reset_all() {
|
||||
hash_index = -1;
|
||||
}
|
||||
|
||||
// endregion Hash
|
||||
|
||||
// region Wi-Fi Credentials - static
|
||||
|
||||
static esp_err_t tt_wifi_credentials_nvs_open(nvs_handle_t* handle, nvs_open_mode_t mode) {
|
||||
return nvs_open(TT_NVS_NAMESPACE, NVS_READWRITE, handle);
|
||||
}
|
||||
|
||||
static void tt_wifi_credentials_nvs_close(nvs_handle_t handle) {
|
||||
nvs_close(handle);
|
||||
}
|
||||
|
||||
static bool tt_wifi_credentials_contains_in_flash(const char* ssid) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READONLY);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
hash_reset_all();
|
||||
|
||||
nvs_iterator_t iterator;
|
||||
result = nvs_entry_find(TT_NVS_PARTITION, TT_NVS_NAMESPACE, NVS_TYPE_BLOB, &iterator);
|
||||
bool contains_ssid = false;
|
||||
while (result == ESP_OK) {
|
||||
nvs_entry_info_t info;
|
||||
nvs_entry_info(iterator, &info); // Can omit error check if parameters are guaranteed to be non-NULL
|
||||
if (strcmp(info.key, ssid) == 0) {
|
||||
contains_ssid = true;
|
||||
break;
|
||||
}
|
||||
result = nvs_entry_next(&iterator);
|
||||
}
|
||||
|
||||
nvs_release_iterator(iterator);
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
|
||||
return contains_ssid;
|
||||
}
|
||||
|
||||
// endregion Wi-Fi Credentials - static
|
||||
|
||||
// region Wi-Fi Credentials - public
|
||||
|
||||
bool tt_wifi_credentials_contains(const char* ssid) {
|
||||
uint32_t hash = tt_hash_string_djb2(ssid);
|
||||
if (hash_contains_value(hash)) {
|
||||
return tt_wifi_credentials_contains_in_flash(ssid);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void tt_wifi_credentials_init() {
|
||||
TT_LOG_I(TAG, "init started");
|
||||
hash_init();
|
||||
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle for init: %s", esp_err_to_name(result));
|
||||
return;
|
||||
}
|
||||
|
||||
nvs_iterator_t iterator;
|
||||
result = nvs_entry_find(TT_NVS_PARTITION, TT_NVS_NAMESPACE, NVS_TYPE_BLOB, &iterator);
|
||||
while (result == ESP_OK) {
|
||||
nvs_entry_info_t info;
|
||||
nvs_entry_info(iterator, &info); // Can omit error check if parameters are guaranteed to be non-NULL
|
||||
hash_add(info.key);
|
||||
result = nvs_entry_next(&iterator);
|
||||
}
|
||||
nvs_release_iterator(iterator);
|
||||
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
TT_LOG_I(TAG, "init finished");
|
||||
}
|
||||
|
||||
bool tt_wifi_credentials_get(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READONLY);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
char password_encrypted[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT];
|
||||
size_t length = TT_WIFI_CREDENTIALS_PASSWORD_LIMIT;
|
||||
result = nvs_get_blob(handle, ssid, password_encrypted, &length);
|
||||
|
||||
uint8_t iv[16];
|
||||
tt_secure_get_iv_from_string(ssid, iv);
|
||||
int decrypt_result = tt_secure_decrypt(
|
||||
iv,
|
||||
(uint8_t*)password_encrypted,
|
||||
(uint8_t*)password,
|
||||
TT_WIFI_CREDENTIALS_PASSWORD_LIMIT
|
||||
);
|
||||
|
||||
if (decrypt_result != 0) {
|
||||
result = ESP_FAIL;
|
||||
TT_LOG_E(TAG, "Failed to decrypt credentials for \"%s\": %d", ssid, decrypt_result);
|
||||
}
|
||||
|
||||
if (result != ESP_OK && result != ESP_ERR_NVS_NOT_FOUND) {
|
||||
TT_LOG_E(TAG, "Failed to get credentials for \"%s\": %s", ssid, esp_err_to_name(result));
|
||||
}
|
||||
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
return result == ESP_OK;
|
||||
}
|
||||
|
||||
bool tt_wifi_credentials_set(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
char password_encrypted[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT];
|
||||
uint8_t iv[16];
|
||||
tt_secure_get_iv_from_string(ssid, iv);
|
||||
int encrypt_result = tt_secure_encrypt(
|
||||
iv,
|
||||
(uint8_t*)password,
|
||||
(uint8_t*)password_encrypted,
|
||||
TT_WIFI_CREDENTIALS_PASSWORD_LIMIT
|
||||
);
|
||||
|
||||
if (encrypt_result != 0) {
|
||||
result = ESP_FAIL;
|
||||
TT_LOG_E(TAG, "Failed to encrypt credentials for \"%s\": %d", ssid, encrypt_result);
|
||||
}
|
||||
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_set_blob(handle, ssid, password_encrypted, TT_WIFI_CREDENTIALS_PASSWORD_LIMIT);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to get credentials for \"%s\": %s", ssid, esp_err_to_name(result));
|
||||
}
|
||||
}
|
||||
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
return result == ESP_OK;
|
||||
}
|
||||
|
||||
bool tt_wifi_credentials_remove(const char* ssid) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle to store \"%s\": %s", ssid, esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = nvs_erase_key(handle, ssid);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to erase credentials for \"%s\": %s", ssid, esp_err_to_name(result));
|
||||
}
|
||||
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
return result == ESP_OK;
|
||||
}
|
||||
|
||||
// end region Wi-Fi Credentials - public
|
||||
|
||||
#endif // ESP_TARGET
|
||||
@ -1,30 +0,0 @@
|
||||
#ifndef ESP_TARGET
|
||||
|
||||
#include "wifi_credentials.h"
|
||||
#include "log.h"
|
||||
|
||||
#define TAG "wifi_credentials_mock"
|
||||
|
||||
static void hash_reset_all();
|
||||
|
||||
bool tt_wifi_credentials_contains(const char* ssid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void tt_wifi_credentials_init() {
|
||||
TT_LOG_I(TAG, "init");
|
||||
}
|
||||
|
||||
bool tt_wifi_credentials_get(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tt_wifi_credentials_set(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tt_wifi_credentials_remove(const char* ssid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // ESP_TARGET
|
||||
@ -11,10 +11,10 @@
|
||||
#include "mutex.h"
|
||||
#include "pubsub.h"
|
||||
#include "service.h"
|
||||
#include "wifi_settings.h"
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#define TAG "wifi"
|
||||
#define WIFI_SCAN_RECORD_LIMIT 16 // default, can be overridden
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
@ -50,8 +50,8 @@ typedef enum {
|
||||
} WifiMessageType;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ssid[32];
|
||||
uint8_t password[64];
|
||||
uint8_t ssid[TT_WIFI_SSID_LIMIT];
|
||||
uint8_t password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT];
|
||||
} WifiConnectMessage;
|
||||
|
||||
typedef struct {
|
||||
@ -83,7 +83,7 @@ static Wifi* wifi_alloc() {
|
||||
instance->scan_active = false;
|
||||
instance->scan_list = NULL;
|
||||
instance->scan_list_count = 0;
|
||||
instance->scan_list_limit = WIFI_SCAN_RECORD_LIMIT;
|
||||
instance->scan_list_limit = TT_WIFI_SCAN_RECORD_LIMIT;
|
||||
instance->event_handler_any_id = NULL;
|
||||
instance->event_handler_got_ip = NULL;
|
||||
instance->event_group = xEventGroupCreate();
|
||||
@ -109,52 +109,67 @@ PubSub* wifi_get_pubsub() {
|
||||
}
|
||||
|
||||
WifiRadioState wifi_get_radio_state() {
|
||||
return wifi_singleton->radio_state;
|
||||
tt_assert(wifi_singleton);
|
||||
wifi_lock(wifi_singleton);
|
||||
WifiRadioState state = wifi_singleton->radio_state;
|
||||
wifi_unlock(wifi_singleton);
|
||||
return state;
|
||||
}
|
||||
|
||||
void wifi_scan() {
|
||||
tt_assert(wifi_singleton);
|
||||
wifi_lock(wifi_singleton);
|
||||
WifiMessage message = {.type = WifiMessageTypeScan};
|
||||
// No need to lock for queue
|
||||
tt_message_queue_put(wifi_singleton->queue, &message, 100 / portTICK_PERIOD_MS);
|
||||
wifi_unlock(wifi_singleton);
|
||||
}
|
||||
|
||||
bool wifi_is_scanning() {
|
||||
tt_assert(wifi_singleton);
|
||||
return wifi_singleton->scan_active;
|
||||
wifi_lock(wifi_singleton);
|
||||
bool is_scanning = wifi_singleton->scan_active;
|
||||
wifi_unlock(wifi_singleton);
|
||||
return is_scanning;
|
||||
}
|
||||
|
||||
void wifi_connect(const char* ssid, const char _Nullable password[64]) {
|
||||
void wifi_connect(const char* ssid, _Nullable const char* password) {
|
||||
tt_assert(wifi_singleton);
|
||||
tt_check(strlen(ssid) <= 32);
|
||||
WifiMessage message = {.type = WifiMessageTypeConnect};
|
||||
memcpy(message.connect_message.ssid, ssid, 32);
|
||||
wifi_lock(wifi_singleton);
|
||||
memcpy(message.connect_message.ssid, ssid, TT_WIFI_SSID_LIMIT);
|
||||
if (password != NULL) {
|
||||
memcpy(message.connect_message.password, password, 64);
|
||||
memcpy(message.connect_message.password, password, TT_WIFI_CREDENTIALS_PASSWORD_LIMIT);
|
||||
} else {
|
||||
message.connect_message.password[0] = 0;
|
||||
}
|
||||
tt_message_queue_put(wifi_singleton->queue, &message, 100 / portTICK_PERIOD_MS);
|
||||
wifi_unlock(wifi_singleton);
|
||||
}
|
||||
|
||||
void wifi_disconnect() {
|
||||
tt_assert(wifi_singleton);
|
||||
WifiMessage message = {.type = WifiMessageTypeDisconnect};
|
||||
wifi_lock(wifi_singleton);
|
||||
tt_message_queue_put(wifi_singleton->queue, &message, 100 / portTICK_PERIOD_MS);
|
||||
wifi_unlock(wifi_singleton);
|
||||
}
|
||||
|
||||
void wifi_set_scan_records(uint16_t records) {
|
||||
tt_assert(wifi_singleton);
|
||||
wifi_lock(wifi_singleton);
|
||||
if (records != wifi_singleton->scan_list_limit) {
|
||||
wifi_scan_list_free_safely(wifi_singleton);
|
||||
wifi_singleton->scan_list_limit = records;
|
||||
}
|
||||
wifi_unlock(wifi_singleton);
|
||||
}
|
||||
|
||||
void wifi_get_scan_results(WifiApRecord records[], uint16_t limit, uint16_t* result_count) {
|
||||
tt_check(wifi_singleton);
|
||||
tt_check(result_count);
|
||||
|
||||
wifi_lock(wifi_singleton);
|
||||
if (wifi_singleton->scan_list_count == 0) {
|
||||
*result_count = 0;
|
||||
} else {
|
||||
@ -170,9 +185,12 @@ void wifi_get_scan_results(WifiApRecord records[], uint16_t limit, uint16_t* res
|
||||
// so it effectively became the list count:
|
||||
*result_count = i;
|
||||
}
|
||||
wifi_unlock(wifi_singleton);
|
||||
}
|
||||
|
||||
void wifi_set_enabled(bool enabled) {
|
||||
tt_check(wifi_singleton);
|
||||
wifi_lock(wifi_singleton);
|
||||
if (enabled) {
|
||||
WifiMessage message = {.type = WifiMessageTypeRadioOn};
|
||||
// No need to lock for queue
|
||||
@ -182,14 +200,19 @@ void wifi_set_enabled(bool enabled) {
|
||||
// No need to lock for queue
|
||||
tt_message_queue_put(wifi_singleton->queue, &message, 100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
wifi_unlock(wifi_singleton);
|
||||
}
|
||||
|
||||
bool wifi_is_connection_secure() {
|
||||
tt_check(wifi_singleton);
|
||||
return wifi_singleton->secure_connection;
|
||||
wifi_lock(wifi_singleton);
|
||||
bool is_secure = wifi_singleton->secure_connection;
|
||||
wifi_unlock(wifi_singleton);
|
||||
return is_secure;
|
||||
}
|
||||
|
||||
int wifi_get_rssi() {
|
||||
tt_check(wifi_singleton);
|
||||
static int rssi = 0;
|
||||
if (esp_wifi_sta_get_rssi(&rssi) == ESP_OK) {
|
||||
return rssi;
|
||||
@ -201,16 +224,15 @@ int wifi_get_rssi() {
|
||||
// endregion Public functions
|
||||
|
||||
static void wifi_lock(Wifi* wifi) {
|
||||
tt_crash("this fails for now"); // TODO: Fix
|
||||
tt_assert(wifi);
|
||||
tt_assert(wifi->mutex);
|
||||
tt_check(xSemaphoreTakeRecursive(wifi->mutex, portMAX_DELAY) == pdPASS);
|
||||
tt_mutex_acquire(wifi->mutex, tt_ms_to_ticks(100));
|
||||
}
|
||||
|
||||
static void wifi_unlock(Wifi* wifi) {
|
||||
tt_assert(wifi);
|
||||
tt_assert(wifi->mutex);
|
||||
tt_check(xSemaphoreGiveRecursive(wifi->mutex) == pdPASS);
|
||||
tt_mutex_release(wifi->mutex);
|
||||
}
|
||||
|
||||
static void wifi_scan_list_alloc(Wifi* wifi) {
|
||||
@ -243,7 +265,42 @@ static void wifi_publish_event_simple(Wifi* wifi, WifiEventType type) {
|
||||
tt_pubsub_publish(wifi->pubsub, &turning_on_event);
|
||||
}
|
||||
|
||||
static void wifi_copy_scan_list(Wifi* wifi) {
|
||||
// Create scan list if it does not exist
|
||||
wifi_scan_list_alloc_safely(wifi);
|
||||
wifi->scan_list_count = 0;
|
||||
uint16_t record_count = wifi->scan_list_limit;
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&record_count, wifi->scan_list));
|
||||
uint16_t safe_record_count = TT_MIN(wifi->scan_list_limit, record_count);
|
||||
wifi->scan_list_count = safe_record_count;
|
||||
TT_LOG_I(TAG, "Scanned %u APs. Showing %u:", record_count, safe_record_count);
|
||||
for (uint16_t i = 0; i < safe_record_count; i++) {
|
||||
wifi_ap_record_t* record = &wifi->scan_list[i];
|
||||
TT_LOG_I(TAG, " - SSID %s (RSSI %d, channel %d)", record->ssid, record->rssi, record->primary);
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_auto_connect(Wifi* wifi) {
|
||||
for (int i = 0; i < wifi->scan_list_count; ++i) {
|
||||
const char* ssid = (const char*)wifi->scan_list[i].ssid;
|
||||
if (tt_wifi_settings_contains(ssid)) {
|
||||
static_assert(sizeof(wifi->scan_list[i].ssid) == (TT_WIFI_SSID_LIMIT + 1), "SSID size mismatch");
|
||||
WifiApSettings ap_settings;
|
||||
if (tt_wifi_settings_load(ssid, &ap_settings)) {
|
||||
if (ap_settings.auto_connect) {
|
||||
wifi_connect(ssid, ap_settings.secret);
|
||||
}
|
||||
} else {
|
||||
TT_LOG_E(TAG, "Failed to load credentials for ssid %s", ssid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void event_handler(TT_UNUSED void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
||||
wifi_lock(wifi_singleton);
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
TT_LOG_I(TAG, "event_handler: sta start");
|
||||
if (wifi_singleton->radio_state == WIFI_RADIO_CONNECTION_PENDING) {
|
||||
@ -258,7 +315,37 @@ static void event_handler(TT_UNUSED void* arg, esp_event_base_t event_base, int3
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
|
||||
TT_LOG_I(TAG, "event_handler: got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
xEventGroupSetBits(wifi_singleton->event_group, WIFI_CONNECTED_BIT);
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
|
||||
wifi_event_sta_scan_done_t* event = (wifi_event_sta_scan_done_t*)event_data;
|
||||
TT_LOG_I(TAG, "event_handler: wifi scanning done (scan id %u)", event->scan_id);
|
||||
bool copied_list;
|
||||
if (
|
||||
wifi_singleton->radio_state == WIFI_RADIO_ON ||
|
||||
wifi_singleton->radio_state == WIFI_RADIO_CONNECTION_ACTIVE ||
|
||||
wifi_singleton->radio_state == WIFI_RADIO_CONNECTION_PENDING
|
||||
) {
|
||||
wifi_copy_scan_list(wifi_singleton);
|
||||
copied_list = true;
|
||||
} else {
|
||||
copied_list = false;
|
||||
}
|
||||
|
||||
if (
|
||||
wifi_singleton->radio_state != WIFI_RADIO_OFF &&
|
||||
wifi_singleton->radio_state != WIFI_RADIO_OFF_PENDING
|
||||
) {
|
||||
esp_wifi_scan_stop();
|
||||
}
|
||||
|
||||
wifi_publish_event_simple(wifi_singleton, WifiEventTypeScanFinished);
|
||||
wifi_singleton->scan_active = false;
|
||||
TT_LOG_I(TAG, "Finished scan");
|
||||
|
||||
if (copied_list) {
|
||||
wifi_auto_connect(wifi_singleton);
|
||||
}
|
||||
}
|
||||
wifi_unlock(wifi_singleton);
|
||||
}
|
||||
|
||||
static void wifi_enable(Wifi* wifi) {
|
||||
@ -353,6 +440,7 @@ static void wifi_disable(Wifi* wifi) {
|
||||
}
|
||||
|
||||
TT_LOG_I(TAG, "Disabling");
|
||||
xEventGroupClearBits(wifi_singleton->event_group, WIFI_FAIL_BIT | WIFI_CONNECTED_BIT);
|
||||
wifi->radio_state = WIFI_RADIO_OFF_PENDING;
|
||||
wifi_publish_event_simple(wifi, WifiEventTypeRadioStateOffPending);
|
||||
|
||||
@ -401,35 +489,22 @@ static void wifi_disable(Wifi* wifi) {
|
||||
|
||||
static void wifi_scan_internal(Wifi* wifi) {
|
||||
WifiRadioState state = wifi->radio_state;
|
||||
if (state != WIFI_RADIO_ON && state != WIFI_RADIO_CONNECTION_ACTIVE) {
|
||||
if (state != WIFI_RADIO_ON && state != WIFI_RADIO_CONNECTION_ACTIVE && state != WIFI_RADIO_CONNECTION_PENDING) {
|
||||
TT_LOG_W(TAG, "Scan unavailable: wifi not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
TT_LOG_I(TAG, "Starting scan");
|
||||
wifi->scan_active = true;
|
||||
wifi_publish_event_simple(wifi, WifiEventTypeScanStarted);
|
||||
|
||||
// Create scan list if it does not exist
|
||||
wifi_scan_list_alloc_safely(wifi);
|
||||
wifi->scan_list_count = 0;
|
||||
|
||||
esp_wifi_scan_start(NULL, true);
|
||||
uint16_t record_count = wifi->scan_list_limit;
|
||||
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&record_count, wifi->scan_list));
|
||||
uint16_t safe_record_count = TT_MIN(wifi->scan_list_limit, record_count);
|
||||
wifi->scan_list_count = safe_record_count;
|
||||
TT_LOG_I(TAG, "Scanned %u APs. Showing %u:", record_count, safe_record_count);
|
||||
for (uint16_t i = 0; i < safe_record_count; i++) {
|
||||
wifi_ap_record_t* record = &wifi->scan_list[i];
|
||||
TT_LOG_I(TAG, " - SSID %s (RSSI %d, channel %d)", record->ssid, record->rssi, record->primary);
|
||||
if (!wifi->scan_active) {
|
||||
if (esp_wifi_scan_start(NULL, false) == ESP_OK) {
|
||||
TT_LOG_I(TAG, "Starting scan");
|
||||
wifi->scan_active = true;
|
||||
wifi_publish_event_simple(wifi, WifiEventTypeScanStarted);
|
||||
} else {
|
||||
TT_LOG_I(TAG, "Can't start scan");
|
||||
}
|
||||
} else {
|
||||
TT_LOG_W(TAG, "Scan already pending");
|
||||
}
|
||||
|
||||
esp_wifi_scan_stop();
|
||||
|
||||
wifi_publish_event_simple(wifi, WifiEventTypeScanFinished);
|
||||
wifi->scan_active = false;
|
||||
TT_LOG_I(TAG, "Finished scan");
|
||||
}
|
||||
|
||||
static void wifi_connect_internal(Wifi* wifi, WifiConnectMessage* connect_message) {
|
||||
@ -452,8 +527,10 @@ static void wifi_connect_internal(Wifi* wifi, WifiConnectMessage* connect_messag
|
||||
.sae_h2e_identifier = {0},
|
||||
},
|
||||
};
|
||||
memcpy(wifi_config.sta.ssid, connect_message->ssid, 32);
|
||||
memcpy(wifi_config.sta.password, connect_message->password, 64);
|
||||
|
||||
static_assert(sizeof(wifi_config.sta.ssid) == sizeof(connect_message->ssid), "SSID size mismatch");
|
||||
memcpy(wifi_config.sta.ssid, connect_message->ssid, sizeof(wifi_config.sta.ssid));
|
||||
memcpy(wifi_config.sta.password, connect_message->password, sizeof(wifi_config.sta.password));
|
||||
|
||||
wifi->secure_connection = (wifi_config.sta.password[0] != 0x00);
|
||||
|
||||
@ -558,28 +635,51 @@ _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) {
|
||||
Wifi* wifi = wifi_singleton;
|
||||
MessageQueue* queue = wifi->queue;
|
||||
|
||||
if (TT_WIFI_AUTO_ENABLE) {
|
||||
wifi_enable(wifi);
|
||||
wifi_scan_internal(wifi);
|
||||
}
|
||||
|
||||
WifiMessage message;
|
||||
while (true) {
|
||||
if (tt_message_queue_get(queue, &message, 1000 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||
if (tt_message_queue_get(queue, &message, 5000 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||
TT_LOG_I(TAG, "Processing message of type %d", message.type);
|
||||
switch (message.type) {
|
||||
case WifiMessageTypeRadioOn:
|
||||
wifi_lock(wifi);
|
||||
wifi_enable(wifi);
|
||||
wifi_unlock(wifi);
|
||||
break;
|
||||
case WifiMessageTypeRadioOff:
|
||||
wifi_lock(wifi);
|
||||
wifi_disable(wifi);
|
||||
wifi_unlock(wifi);
|
||||
break;
|
||||
case WifiMessageTypeScan:
|
||||
wifi_lock(wifi);
|
||||
wifi_scan_internal(wifi);
|
||||
wifi_unlock(wifi);
|
||||
break;
|
||||
case WifiMessageTypeConnect:
|
||||
wifi_lock(wifi);
|
||||
wifi_connect_internal(wifi, &message.connect_message);
|
||||
wifi_unlock(wifi);
|
||||
break;
|
||||
case WifiMessageTypeDisconnect:
|
||||
wifi_lock(wifi);
|
||||
wifi_disconnect_internal_but_keep_active(wifi);
|
||||
wifi_unlock(wifi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Automatic scanning is done so we can automatically connect to access points
|
||||
wifi_lock(wifi);
|
||||
bool should_start_scan = wifi->radio_state == WIFI_RADIO_ON && !wifi->scan_active;
|
||||
wifi_unlock(wifi);
|
||||
if (should_start_scan) {
|
||||
wifi_scan_internal(wifi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
17
tactility-headless/src/services/wifi/wifi_globals.h
Normal file
17
tactility-headless/src/services/wifi/wifi_globals.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TT_WIFI_AUTO_CONNECT true // Default setting for new Wi-Fi entries
|
||||
#define TT_WIFI_AUTO_ENABLE false
|
||||
|
||||
#define TT_WIFI_SCAN_RECORD_LIMIT 16 // default, can be overridden
|
||||
|
||||
#define TT_WIFI_SSID_LIMIT 32 // 32 characters/octets, according to IEEE 802.11-2020 spec
|
||||
#define TT_WIFI_CREDENTIALS_PASSWORD_LIMIT 64 // 64 characters/octets, according to IEEE 802.11-2020 spec
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -12,7 +12,6 @@
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#define TAG "wifi"
|
||||
#define WIFI_SCAN_RECORD_LIMIT 16 // default, can be overridden
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
@ -77,7 +76,7 @@ bool wifi_is_scanning() {
|
||||
return wifi_singleton->scan_active;
|
||||
}
|
||||
|
||||
void wifi_connect(const char* ssid, const char _Nullable password[64]) {
|
||||
void wifi_connect(const char* ssid, _Nullable const char* password) {
|
||||
tt_assert(wifi_singleton);
|
||||
tt_check(strlen(ssid) <= 32);
|
||||
// TODO: implement
|
||||
|
||||
34
tactility-headless/src/services/wifi/wifi_settings.h
Normal file
34
tactility-headless/src/services/wifi/wifi_settings.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "wifi_globals.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This struct is stored as-is into NVS flash.
|
||||
*
|
||||
* The SSID and secret are increased by 1 byte to facilitate string null termination.
|
||||
* This makes it easier to use the char array as a string in various places.
|
||||
*/
|
||||
typedef struct {
|
||||
char ssid[TT_WIFI_SSID_LIMIT + 1];
|
||||
char secret[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT + 1];
|
||||
bool auto_connect;
|
||||
} WifiApSettings;
|
||||
|
||||
void tt_wifi_settings_init();
|
||||
|
||||
bool tt_wifi_settings_contains(const char* ssid);
|
||||
|
||||
bool tt_wifi_settings_load(const char* ssid, WifiApSettings* settings);
|
||||
|
||||
bool tt_wifi_settings_save(const WifiApSettings* settings);
|
||||
|
||||
bool tt_wifi_settings_remove(const char* ssid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
147
tactility-headless/src/services/wifi/wifi_settings_esp.c
Normal file
147
tactility-headless/src/services/wifi/wifi_settings_esp.c
Normal file
@ -0,0 +1,147 @@
|
||||
#ifdef ESP_TARGET
|
||||
|
||||
#include "wifi_globals.h"
|
||||
#include "wifi_settings.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "log.h"
|
||||
#include "hash.h"
|
||||
#include "check.h"
|
||||
#include "secure.h"
|
||||
|
||||
#define TAG "wifi_settings"
|
||||
#define TT_NVS_NAMESPACE "wifi_settings" // limited by NVS_KEY_NAME_MAX_SIZE
|
||||
|
||||
// region Wi-Fi Credentials - static
|
||||
|
||||
static esp_err_t tt_wifi_credentials_nvs_open(nvs_handle_t* handle, nvs_open_mode_t mode) {
|
||||
return nvs_open(TT_NVS_NAMESPACE, NVS_READWRITE, handle);
|
||||
}
|
||||
|
||||
static void tt_wifi_credentials_nvs_close(nvs_handle_t handle) {
|
||||
nvs_close(handle);
|
||||
}
|
||||
|
||||
// endregion Wi-Fi Credentials - static
|
||||
|
||||
// region Wi-Fi Credentials - public
|
||||
|
||||
bool tt_wifi_settings_contains(const char* ssid) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READONLY);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool key_exists = nvs_find_key(handle, ssid, NULL) == ESP_OK;
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
|
||||
return key_exists;
|
||||
}
|
||||
|
||||
void tt_wifi_settings_init() {
|
||||
TT_LOG_I(TAG, "init");
|
||||
static_assert(strlen(TT_NVS_NAMESPACE) <= NVS_KEY_NAME_MAX_SIZE, "Namespace name too long");
|
||||
}
|
||||
|
||||
bool tt_wifi_settings_load(const char* ssid, WifiApSettings* settings) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READONLY);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
WifiApSettings encrypted_settings;
|
||||
size_t length = sizeof(WifiApSettings);
|
||||
result = nvs_get_blob(handle, ssid, &encrypted_settings, &length);
|
||||
|
||||
uint8_t iv[16];
|
||||
tt_secure_get_iv_from_string(ssid, iv);
|
||||
int decrypt_result = tt_secure_decrypt(
|
||||
iv,
|
||||
(uint8_t*)encrypted_settings.secret,
|
||||
(uint8_t*)settings->secret,
|
||||
TT_WIFI_CREDENTIALS_PASSWORD_LIMIT
|
||||
);
|
||||
// Manually ensure null termination, because encryption must be a multiple of 16 bytes
|
||||
encrypted_settings.secret[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT] = 0;
|
||||
|
||||
if (decrypt_result != 0) {
|
||||
result = ESP_FAIL;
|
||||
TT_LOG_E(TAG, "Failed to decrypt credentials for \"%s\": %d", ssid, decrypt_result);
|
||||
}
|
||||
|
||||
if (result != ESP_OK && result != ESP_ERR_NVS_NOT_FOUND) {
|
||||
TT_LOG_E(TAG, "Failed to get credentials for \"%s\": %s", ssid, esp_err_to_name(result));
|
||||
}
|
||||
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
|
||||
settings->auto_connect = encrypted_settings.auto_connect;
|
||||
strcpy((char*)settings->ssid, encrypted_settings.ssid);
|
||||
|
||||
return result == ESP_OK;
|
||||
}
|
||||
|
||||
bool tt_wifi_settings_save(const WifiApSettings* settings) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
WifiApSettings encrypted_settings = {
|
||||
.auto_connect = settings->auto_connect,
|
||||
};
|
||||
strcpy((char*)encrypted_settings.ssid, settings->ssid);
|
||||
// We only decrypt multiples of 16, so we have to ensure the last byte is set to 0
|
||||
encrypted_settings.secret[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT] = 0;
|
||||
|
||||
uint8_t iv[16];
|
||||
tt_secure_get_iv_from_data(settings->ssid, strlen(settings->ssid), iv);
|
||||
int encrypt_result = tt_secure_encrypt(
|
||||
iv,
|
||||
(uint8_t*)settings->secret,
|
||||
(uint8_t*)encrypted_settings.secret,
|
||||
TT_WIFI_CREDENTIALS_PASSWORD_LIMIT
|
||||
);
|
||||
|
||||
if (encrypt_result != 0) {
|
||||
result = ESP_FAIL;
|
||||
TT_LOG_E(TAG, "Failed to encrypt credentials \"%s\": %d", settings->ssid, encrypt_result);
|
||||
}
|
||||
|
||||
if (result == ESP_OK) {
|
||||
result = nvs_set_blob(handle, settings->ssid, &encrypted_settings, sizeof(WifiApSettings));
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to get credentials for \"%s\": %s", settings->ssid, esp_err_to_name(result));
|
||||
}
|
||||
}
|
||||
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
return result == ESP_OK;
|
||||
}
|
||||
|
||||
bool tt_wifi_settings_remove(const char* ssid) {
|
||||
nvs_handle_t handle;
|
||||
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open NVS handle to store \"%s\": %s", ssid, esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = nvs_erase_key(handle, ssid);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to erase credentials for \"%s\": %s", ssid, esp_err_to_name(result));
|
||||
}
|
||||
|
||||
tt_wifi_credentials_nvs_close(handle);
|
||||
return result == ESP_OK;
|
||||
}
|
||||
|
||||
// end region Wi-Fi Credentials - public
|
||||
|
||||
#endif // ESP_TARGET
|
||||
28
tactility-headless/src/services/wifi/wifi_settings_mock.c
Normal file
28
tactility-headless/src/services/wifi/wifi_settings_mock.c
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef ESP_TARGET
|
||||
|
||||
#include "wifi_settings.h"
|
||||
#include "log.h"
|
||||
|
||||
#define TAG "wifi_settings_mock"
|
||||
|
||||
bool tt_wifi_settings_contains(const char* ssid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void tt_wifi_settings_init() {
|
||||
TT_LOG_I(TAG, "init");
|
||||
}
|
||||
|
||||
bool tt_wifi_settings_load(const char* ssid, WifiApSettings* settings) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tt_wifi_settings_save(const WifiApSettings* settings) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tt_wifi_settings_remove(const char* ssid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // ESP_TARGET
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef void (*OnConnectSsid)(const char* ssid, const char password[64], void* context);
|
||||
typedef void (*OnConnectSsid)(const char ssid[TT_WIFI_SSID_LIMIT], const char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT], void* context);
|
||||
|
||||
typedef struct {
|
||||
OnConnectSsid on_connect_ssid;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include "log.h"
|
||||
#include "lvgl.h"
|
||||
#include "services/gui/gui.h"
|
||||
#include "services/wifi/wifi_credentials.h"
|
||||
#include "services/wifi/wifi_settings.h"
|
||||
#include "ui/spacer.h"
|
||||
#include "ui/style.h"
|
||||
#include "ui/toolbar.h"
|
||||
@ -19,23 +19,37 @@ static void on_connect(lv_event_t* event) {
|
||||
const char* ssid = lv_textarea_get_text(view->ssid_textarea);
|
||||
const char* password = lv_textarea_get_text(view->password_textarea);
|
||||
|
||||
if (strlen(password) > 63) {
|
||||
size_t password_len = strlen(password);
|
||||
if (password_len > TT_WIFI_CREDENTIALS_PASSWORD_LIMIT) {
|
||||
// TODO: UI feedback
|
||||
TT_LOG_E(TAG, "Password too long");
|
||||
return;
|
||||
}
|
||||
char password_buffer[64];
|
||||
strcpy(password_buffer, password);
|
||||
|
||||
size_t ssid_len = strlen(ssid);
|
||||
if (ssid_len > TT_WIFI_SSID_LIMIT) {
|
||||
// TODO: UI feedback
|
||||
TT_LOG_E(TAG, "SSID too long");
|
||||
return;
|
||||
}
|
||||
|
||||
WifiApSettings settings;
|
||||
strcpy((char*)settings.secret, password);
|
||||
strcpy((char*)settings.ssid, ssid);
|
||||
settings.auto_connect = TT_WIFI_AUTO_CONNECT; // No UI yet, so use global setting:w
|
||||
|
||||
|
||||
WifiConnectBindings* bindings = &wifi->bindings;
|
||||
bindings->on_connect_ssid(
|
||||
ssid,
|
||||
password_buffer,
|
||||
settings.ssid,
|
||||
settings.secret,
|
||||
bindings->on_connect_ssid_context
|
||||
);
|
||||
|
||||
if (lv_obj_get_state(view->remember_switch) == LV_STATE_CHECKED) {
|
||||
tt_wifi_credentials_set(ssid, password_buffer);
|
||||
if (!tt_wifi_settings_save(&settings)) {
|
||||
TT_LOG_E(TAG, "Failed to store credentials");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
#include "app.h"
|
||||
#include "apps/wifi_connect/wifi_connect_bundle.h"
|
||||
#include "services/loader/loader.h"
|
||||
#include "services/wifi/wifi_settings.h"
|
||||
#include "tactility_core.h"
|
||||
#include "ui/lvgl_sync.h"
|
||||
#include "wifi_manage_state_updating.h"
|
||||
#include "wifi_manage_view.h"
|
||||
#include "services/wifi/wifi_credentials.h"
|
||||
|
||||
#define TAG "wifi_manage"
|
||||
|
||||
@ -15,10 +15,10 @@
|
||||
static void wifi_manage_event_callback(const void* message, void* context);
|
||||
|
||||
static void on_connect(const char* ssid) {
|
||||
char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT];
|
||||
if (tt_wifi_credentials_get(ssid, password)) {
|
||||
WifiApSettings settings;
|
||||
if (tt_wifi_settings_load(ssid, &settings)) {
|
||||
TT_LOG_I(TAG, "Connecting with known credentials");
|
||||
wifi_connect(ssid, password);
|
||||
wifi_connect(ssid, settings.secret);
|
||||
} else {
|
||||
TT_LOG_I(TAG, "Starting connection dialog");
|
||||
Bundle bundle = tt_bundle_alloc();
|
||||
@ -39,8 +39,7 @@ static void on_wifi_toggled(bool enabled) {
|
||||
static WifiManage* wifi_manage_alloc() {
|
||||
WifiManage* wifi = malloc(sizeof(WifiManage));
|
||||
|
||||
PubSub* wifi_pubsub = wifi_get_pubsub();
|
||||
wifi->wifi_subscription = tt_pubsub_subscribe(wifi_pubsub, &wifi_manage_event_callback, wifi);
|
||||
wifi->wifi_subscription = NULL;
|
||||
wifi->mutex = tt_mutex_alloc(MutexTypeNormal);
|
||||
wifi->state = (WifiManageState) {
|
||||
.scanning = wifi_is_scanning(),
|
||||
@ -57,8 +56,6 @@ static WifiManage* wifi_manage_alloc() {
|
||||
}
|
||||
|
||||
static void wifi_manage_free(WifiManage* wifi) {
|
||||
PubSub* wifi_pubsub = wifi_get_pubsub();
|
||||
tt_pubsub_unsubscribe(wifi_pubsub, wifi->wifi_subscription);
|
||||
tt_mutex_free(wifi->mutex);
|
||||
|
||||
free(wifi);
|
||||
@ -116,6 +113,9 @@ static void wifi_manage_event_callback(const void* message, void* context) {
|
||||
static void app_show(App app, lv_obj_t* parent) {
|
||||
WifiManage* wifi = (WifiManage*)tt_app_get_data(app);
|
||||
|
||||
PubSub* wifi_pubsub = wifi_get_pubsub();
|
||||
wifi->wifi_subscription = tt_pubsub_subscribe(wifi_pubsub, &wifi_manage_event_callback, wifi);
|
||||
|
||||
// State update (it has its own locking)
|
||||
wifi_manage_state_set_radio_state(wifi, wifi_get_radio_state());
|
||||
wifi_manage_state_set_scanning(wifi, wifi_is_scanning());
|
||||
@ -130,7 +130,10 @@ static void app_show(App app, lv_obj_t* parent) {
|
||||
wifi_manage_unlock(wifi);
|
||||
|
||||
WifiRadioState radio_state = wifi_get_radio_state();
|
||||
if (radio_state == WIFI_RADIO_ON && !wifi_is_scanning()) {
|
||||
bool can_scan = radio_state == WIFI_RADIO_ON ||
|
||||
radio_state == WIFI_RADIO_CONNECTION_PENDING ||
|
||||
radio_state == WIFI_RADIO_CONNECTION_ACTIVE;
|
||||
if (can_scan && !wifi_is_scanning()) {
|
||||
wifi_scan();
|
||||
}
|
||||
}
|
||||
@ -138,6 +141,9 @@ static void app_show(App app, lv_obj_t* parent) {
|
||||
static void app_hide(App app) {
|
||||
WifiManage* wifi = (WifiManage*)tt_app_get_data(app);
|
||||
wifi_manage_lock(wifi);
|
||||
PubSub* wifi_pubsub = wifi_get_pubsub();
|
||||
tt_pubsub_unsubscribe(wifi_pubsub, wifi->wifi_subscription);
|
||||
wifi->wifi_subscription = NULL;
|
||||
wifi->view_enabled = false;
|
||||
wifi_manage_unlock(wifi);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user