aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/src/main.c')
-rw-r--r--firmware/src/main.c152
1 files changed, 86 insertions, 66 deletions
diff --git a/firmware/src/main.c b/firmware/src/main.c
index 3f186f8..9fa4c61 100644
--- a/firmware/src/main.c
+++ b/firmware/src/main.c
@@ -1,5 +1,7 @@
1#include "esp_event.h" 1#include "esp_event.h"
2#include "esp_log.h" 2#include "esp_log.h"
3#include "esp_netif.h"
4#include "esp_sntp.h"
3#include "esp_system.h" 5#include "esp_system.h"
4#include "esp_timer.h" 6#include "esp_timer.h"
5#include "nvs_flash.h" 7#include "nvs_flash.h"
@@ -8,21 +10,26 @@
8#include "wifi.h" 10#include "wifi.h"
9 11
10#include <stdio.h> 12#include <stdio.h>
13#include <time.h>
14
11static const char *TAG = "app"; 15static const char *TAG = "app";
16static EventGroupHandle_t wifi_event_group;
17#define WIFI_CONNECTED_BIT BIT0
12 18
13/** 19/**
14 * @brief Initialize NVS (Non-Volatile Storage) flash storage, handling full or 20* @brief Initialize NVS (Non-Volatile Storage) flash storage, handling full or
15 * incompatible pages. 21* incompatible pages.
16 * 22*
17 * This function checks the NVS flash storage to ensure that there is enough 23* This function checks the NVS flash storage to ensure that there is enough
18 * space and that the version of NVS is compatible. If the partition is full or 24* space and that the version of NVS is compatible. If the partition
19 * incompatible, it will erase the NVS partition and attempt initialization 25is full or
20 * again. 26* incompatible, it will erase the NVS partition and attempt initialization
21 * 27* again.
22 * @return esp_err_t 28*
23 * - ESP_OK: Initialization successful. 29* @return esp_err_t
24 * - Other error codes if initialization or erasure fails. 30* - ESP_OK: Initialization successful.
25 */ 31* - Other error codes if initialization or erasure fails.
32*/
26static esp_err_t nvs_flash_init_check(void) 33static esp_err_t nvs_flash_init_check(void)
27{ 34{
28 esp_err_t ret = nvs_flash_init(); 35 esp_err_t ret = nvs_flash_init();
@@ -31,13 +38,7 @@ static esp_err_t nvs_flash_init_check(void)
31 ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { 38 ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
32 ESP_LOGW(TAG, 39 ESP_LOGW(TAG,
33 "NVS partition is full or incompatible, erasing..."); 40 "NVS partition is full or incompatible, erasing...");
34 ret = nvs_flash_erase(); 41 ESP_ERROR_CHECK(nvs_flash_erase());
35
36 if (ret != ESP_OK) {
37 ESP_LOGE(TAG, "Failed to erase NVS partition (%s)",
38 esp_err_to_name(ret));
39 return ret;
40 }
41 ret = nvs_flash_init(); 42 ret = nvs_flash_init();
42 } 43 }
43 44
@@ -64,69 +65,88 @@ static esp_err_t nvs_flash_init_check(void)
64 * - ESP_OK: If initialization is successful. 65 * - ESP_OK: If initialization is successful.
65 * - Other error codes if initialization fails. 66 * - Other error codes if initialization fails.
66 */ 67 */
67static esp_err_t init_component(esp_err_t (*init_func)(void), 68static void wifi_event_handler(void *arg, esp_event_base_t event_base,
68 const char *component_name) 69 int32_t event_id, void *event_data)
69{ 70{
70 esp_err_t ret = init_func(); 71 if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
71 72 esp_wifi_connect();
72 if (ret != ESP_OK) { 73 } else if (event_base == WIFI_EVENT &&
73 ESP_LOGE(TAG, "Failed to initialize %s (%s)", component_name, 74 event_id == WIFI_EVENT_STA_DISCONNECTED) {
74 esp_err_to_name(ret)); 75 ESP_LOGW(TAG, "Wi-Fi disconnected, reconnecting...");
75 return ret; 76 esp_wifi_connect();
77 xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
78 } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
79 ESP_LOGI(TAG, "Wi-Fi connected and got IP!");
80 xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
76 } 81 }
77
78 return ESP_OK;
79} 82}
80 83
81/** 84/**
82 * @brief Initializes all the essential components for the application. 85 * @TODO missing doc
83 *
84 * This function initializes the NVS storage, network interface, and event loop
85 * in sequence. If any of these components fail to initialize, the function
86 * returns an error, and the application will stop early.
87 *
88 * @return esp_err_t
89 * - ESP_OK: If all components are successfully initialized.
90 * - ESP_FAIL: If any component fails to initialize.
91 */ 86 */
92esp_err_t init_app_components(void) 87static void obtain_time(void)
93{ 88{
94 if (init_component(nvs_flash_init_check, "NVS") != ESP_OK) { 89 ESP_LOGI(TAG, "Starting SNTP time sync...");
95 ESP_LOGE(TAG, "NVS initialization failed, aborting app start."); 90 sntp_setoperatingmode(SNTP_OPMODE_POLL);
96 return ESP_FAIL; 91 sntp_setservername(0, "pool.ntp.org");
92 sntp_init();
93
94 time_t now = 0;
95 struct tm timeinfo = {0};
96 int retry = 0;
97 const int retry_count = 10;
98
99 while (timeinfo.tm_year < (2022 - 1900) && ++retry < retry_count) {
100 ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)",
101 retry, retry_count);
102 vTaskDelay(pdMS_TO_TICKS(1000));
103 time(&now);
104 localtime_r(&now, &timeinfo);
97 } 105 }
98 106
99 if (init_component(esp_netif_init, "network interface") != ESP_OK) 107 if (timeinfo.tm_year >= (2022 - 1900)) {
100 return ESP_FAIL; 108 char buf[64];
101 109 strftime(buf, sizeof(buf), "%c", &timeinfo);
102 if (init_component(esp_event_loop_create_default, "event loop") != 110 ESP_LOGI(TAG, "System time synchronized: %s", buf);
103 ESP_OK) 111 } else {
104 return ESP_FAIL; 112 ESP_LOGW(TAG, "Failed to synchronize time.");
105 113 }
106 return ESP_OK;
107} 114}
108 115
109/** 116/**
110 * @brief Main entry point of the application. 117* @brief Main entry point of the application.
111 * 118*
112 * This function is responsible for initializing the core components of the 119* This function is responsible for initializing the core components
113 * application, including the NVS storage, network interface, and event loop. If 120of the
114 * any initialization step fails, the application will log the error and stop. 121* application, including the NVS storage, network interface, and event loop. If
115 * 122* any initialization step fails, the application will log the error
116 * After initialization, this function will configure the WiFi station and start 123and stop.
117 * the MQTT client. 124*
118 */ 125* After initialization, this function will configure the WiFi station and start
119 126* the MQTT client.
127*/
120void app_main(void) 128void app_main(void)
121{ 129{
122 if (init_app_components() != ESP_OK) { 130 ESP_ERROR_CHECK(nvs_flash_init_check());
123 ESP_LOGE(TAG, "App initialization failed, aborting."); 131 ESP_ERROR_CHECK(esp_netif_init());
124 return; 132 ESP_ERROR_CHECK(esp_event_loop_create_default());
125 } 133
134 wifi_event_group = xEventGroupCreate();
126 135
127 ESP_LOGI(TAG, "Initializing WiFi in station mode"); 136 ESP_LOGI(TAG, "Initializing WiFi (station mode)");
128 wifi_init_sta(); 137 wifi_init_sta();
129 138
130 ESP_LOGI(TAG, "Starting MQTT client"); 139 ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
140 &wifi_event_handler, NULL));
141 ESP_ERROR_CHECK(esp_event_handler_register(
142 IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL));
143
144 ESP_LOGI(TAG, "Waiting for Wi-Fi connection...");
145 xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE,
146 pdFALSE, portMAX_DELAY);
147
148 obtain_time();
149
150 ESP_LOGI(TAG, "Starting MQTT client...");
131 mqtt_app_start(); 151 mqtt_app_start();
132} 152}