diff --git a/main/maxxfan-controller.c b/main/maxxfan-controller.c index 7967975..a0198bc 100755 --- a/main/maxxfan-controller.c +++ b/main/maxxfan-controller.c @@ -1,26 +1,44 @@ #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" #include "driver/gpio.h" #include "driver/ledc.h" -#include "esp_log.h" -// Pin definitions -#define LED_PIN GPIO_NUM_13 // Onboard LED for status -#define MOTOR_R_EN GPIO_NUM_18 // BTS7960 R_EN pin -#define MOTOR_L_EN GPIO_NUM_19 // BTS7960 L_EN pin -#define PWM_R_PIN GPIO_NUM_21 // BTS7960 R_PWM pin -#define PWM_L_PIN GPIO_NUM_22 // BTS7960 L_PWM pin +// WiFi credentials - CHANGE THESE TO YOUR NETWORK +#define WIFI_SSID "YOUR_WIFI_NAME" +#define WIFI_PASS "YOUR_WIFI_PASSWORD" +#define WIFI_MAXIMUM_RETRY 5 -// PWM configuration -#define PWM_FREQUENCY 1000 // 1kHz PWM frequency -#define PWM_RESOLUTION LEDC_TIMER_8_BIT // 8-bit resolution (0-255) +// Pin definitions (same as before) +#define LED_PIN GPIO_NUM_13 +#define MOTOR_R_EN GPIO_NUM_18 +#define MOTOR_L_EN GPIO_NUM_19 +#define PWM_R_PIN GPIO_NUM_21 +#define PWM_L_PIN GPIO_NUM_22 + +// PWM configuration (same as before) +#define PWM_FREQUENCY 1000 +#define PWM_RESOLUTION LEDC_TIMER_8_BIT #define PWM_R_CHANNEL LEDC_CHANNEL_0 #define PWM_L_CHANNEL LEDC_CHANNEL_1 -static const char* TAG = "PWM_MOTOR"; +static const char* TAG = "WIFI_MOTOR"; -// Motor state +// WiFi event group +static EventGroupHandle_t s_wifi_event_group; +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +static int s_retry_num = 0; + +// Motor control (same as before) typedef enum { MOTOR_OFF, MOTOR_EXHAUST, @@ -28,13 +46,95 @@ typedef enum { } motor_mode_t; static motor_mode_t current_mode = MOTOR_OFF; -static int current_speed = 0; // 0-100% +static int current_speed = 0; + +// WiFi event handler +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < WIFI_MAXIMUM_RETRY) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + } + ESP_LOGI(TAG, "connect to the AP fail"); + } 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)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +void wifi_init_sta(void) +{ + s_wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + esp_event_handler_instance_t instance_any_id; + esp_event_handler_instance_t instance_got_ip; + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &event_handler, + NULL, + &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &event_handler, + NULL, + &instance_got_ip)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = WIFI_SSID, + .password = WIFI_PASS, + .threshold.authmode = WIFI_AUTH_WPA2_PSK, + .pmf_cfg = { + .capable = true, + .required = false + }, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s", WIFI_SSID); + } else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s", WIFI_SSID); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } +} void configure_gpio_pins(void) { ESP_LOGI(TAG, "Configuring GPIO pins..."); - // Configure enable pins as regular GPIO uint64_t pin_mask = (1ULL << LED_PIN) | (1ULL << MOTOR_R_EN) | (1ULL << MOTOR_L_EN); @@ -49,7 +149,6 @@ void configure_gpio_pins(void) gpio_config(&io_conf); - // Initialize enable pins to LOW gpio_set_level(LED_PIN, 0); gpio_set_level(MOTOR_R_EN, 0); gpio_set_level(MOTOR_L_EN, 0); @@ -61,7 +160,6 @@ void configure_pwm(void) { ESP_LOGI(TAG, "Configuring PWM..."); - // Configure PWM timer ledc_timer_config_t timer_conf = { .speed_mode = LEDC_LOW_SPEED_MODE, .timer_num = LEDC_TIMER_0, @@ -71,7 +169,6 @@ void configure_pwm(void) }; ledc_timer_config(&timer_conf); - // Configure PWM channel for R_PWM ledc_channel_config_t channel_conf = { .channel = PWM_R_CHANNEL, .duty = 0, @@ -82,13 +179,11 @@ void configure_pwm(void) }; ledc_channel_config(&channel_conf); - // Configure PWM channel for L_PWM channel_conf.channel = PWM_L_CHANNEL; channel_conf.gpio_num = PWM_L_PIN; ledc_channel_config(&channel_conf); - ESP_LOGI(TAG, "PWM configured - Frequency: %dHz, Resolution: %d-bit", - PWM_FREQUENCY, PWM_RESOLUTION); + ESP_LOGI(TAG, "PWM configured"); } void set_motor_speed(motor_mode_t mode, int speed_percent) @@ -99,60 +194,35 @@ void set_motor_speed(motor_mode_t mode, int speed_percent) current_mode = mode; current_speed = speed_percent; - // Convert percentage to PWM duty value (0-255 for 8-bit) uint32_t duty = (speed_percent * 255) / 100; if (mode == MOTOR_OFF || speed_percent == 0) { ESP_LOGI(TAG, "Motor OFF"); - - // Turn off LED gpio_set_level(LED_PIN, 0); - - // Disable both enables gpio_set_level(MOTOR_R_EN, 0); gpio_set_level(MOTOR_L_EN, 0); - - // Set both PWM to 0 ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_R_CHANNEL, 0); ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_L_CHANNEL, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_R_CHANNEL); ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_L_CHANNEL); } else if (mode == MOTOR_EXHAUST) { - ESP_LOGI(TAG, "Motor EXHAUST - Speed: %d%% (PWM duty: %d/255)", - speed_percent, duty); - - // Turn on LED + ESP_LOGI(TAG, "Motor EXHAUST - Speed: %d%%", speed_percent); gpio_set_level(LED_PIN, 1); - - // Enable R side, disable L side gpio_set_level(MOTOR_R_EN, 1); gpio_set_level(MOTOR_L_EN, 0); - - // Small delay for enables to settle vTaskDelay(pdMS_TO_TICKS(10)); - - // Set PWM: R side active, L side off ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_R_CHANNEL, duty); ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_L_CHANNEL, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_R_CHANNEL); ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_L_CHANNEL); } else if (mode == MOTOR_INTAKE) { - ESP_LOGI(TAG, "Motor INTAKE - Speed: %d%% (PWM duty: %d/255)", - speed_percent, duty); - - // Turn on LED + ESP_LOGI(TAG, "Motor INTAKE - Speed: %d%%", speed_percent); gpio_set_level(LED_PIN, 1); - - // Enable L side, disable R side gpio_set_level(MOTOR_R_EN, 0); gpio_set_level(MOTOR_L_EN, 1); - - // Small delay for enables to settle vTaskDelay(pdMS_TO_TICKS(10)); - - // Set PWM: L side active, R side off ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_R_CHANNEL, 0); ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_L_CHANNEL, duty); ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_R_CHANNEL); @@ -160,61 +230,58 @@ void set_motor_speed(motor_mode_t mode, int speed_percent) } } +// Simple demo task that runs once WiFi is connected +void motor_demo_task(void *pvParameters) +{ + ESP_LOGI(TAG, "Motor demo task started - waiting for WiFi..."); + + // Wait for WiFi connection + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "WiFi connected! Starting motor demo..."); + + while(1) { + ESP_LOGI(TAG, "=== WiFi Motor Demo Sequence ==="); + + // Short demo since we have WiFi now + set_motor_speed(MOTOR_EXHAUST, 50); + vTaskDelay(pdMS_TO_TICKS(3000)); + + set_motor_speed(MOTOR_INTAKE, 75); + vTaskDelay(pdMS_TO_TICKS(3000)); + + set_motor_speed(MOTOR_OFF, 0); + vTaskDelay(pdMS_TO_TICKS(5000)); + } + } +} + void app_main(void) { - ESP_LOGI(TAG, "Starting PWM motor control test!"); + ESP_LOGI(TAG, "Starting WiFi + Motor Control!"); + + // Initialize NVS (needed for WiFi) + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); // Configure hardware configure_gpio_pins(); configure_pwm(); - ESP_LOGI(TAG, "Starting motor speed test sequence..."); + ESP_LOGI(TAG, "Connecting to WiFi network: %s", WIFI_SSID); + wifi_init_sta(); - while(1) { - // Test sequence: demonstrate variable speed control - - ESP_LOGI(TAG, "\n=== EXHAUST MODE SPEED TEST ==="); - - // Exhaust: ramp up from 0 to 100% - for (int speed = 0; speed <= 100; speed += 25) { - set_motor_speed(MOTOR_EXHAUST, speed); - vTaskDelay(pdMS_TO_TICKS(2000)); // 2 seconds at each speed - } - - // Turn off - set_motor_speed(MOTOR_OFF, 0); - vTaskDelay(pdMS_TO_TICKS(2000)); - - ESP_LOGI(TAG, "\n=== INTAKE MODE SPEED TEST ==="); - - // Intake: ramp up from 0 to 100% - for (int speed = 0; speed <= 100; speed += 25) { - set_motor_speed(MOTOR_INTAKE, speed); - vTaskDelay(pdMS_TO_TICKS(2000)); // 2 seconds at each speed - } - - // Turn off - set_motor_speed(MOTOR_OFF, 0); - vTaskDelay(pdMS_TO_TICKS(2000)); - - ESP_LOGI(TAG, "\n=== SMOOTH SPEED CHANGES ==="); - - // Demonstrate smooth speed changes in exhaust mode - set_motor_speed(MOTOR_EXHAUST, 30); - vTaskDelay(pdMS_TO_TICKS(2000)); - - set_motor_speed(MOTOR_EXHAUST, 60); - vTaskDelay(pdMS_TO_TICKS(2000)); - - set_motor_speed(MOTOR_EXHAUST, 90); - vTaskDelay(pdMS_TO_TICKS(2000)); - - set_motor_speed(MOTOR_EXHAUST, 40); - vTaskDelay(pdMS_TO_TICKS(2000)); - - set_motor_speed(MOTOR_OFF, 0); - vTaskDelay(pdMS_TO_TICKS(3000)); - - ESP_LOGI(TAG, "\n=== Cycle Complete - Restarting ==="); - } + // Create motor demo task + xTaskCreate(motor_demo_task, "motor_demo", 4096, NULL, 5, NULL); + + ESP_LOGI(TAG, "Setup complete! Motor controllable via WiFi."); } \ No newline at end of file