2025-11-28 18:26:32 -06:00
|
|
|
#include <driver/gptimer.h>
|
2025-12-31 15:44:48 -06:00
|
|
|
#include "servo.hpp"
|
2025-11-28 18:26:32 -06:00
|
|
|
#include "defines.h"
|
|
|
|
|
#include "nvs_flash.h"
|
|
|
|
|
#include "NimBLEDevice.h"
|
|
|
|
|
#include "WiFi.hpp"
|
2025-11-29 16:24:56 -06:00
|
|
|
#include "setup.hpp"
|
2025-12-23 17:21:44 -06:00
|
|
|
#include "socketIO.hpp"
|
2025-12-28 12:46:09 -06:00
|
|
|
#include "encoder.hpp"
|
2025-12-28 20:52:11 -06:00
|
|
|
#include "calibration.hpp"
|
|
|
|
|
|
2026-01-03 22:59:36 -06:00
|
|
|
// Global synchronization primitives
|
|
|
|
|
EventGroupHandle_t g_system_events = NULL;
|
|
|
|
|
QueueHandle_t g_servo_command_queue = NULL;
|
|
|
|
|
QueueHandle_t g_encoder_event_queue = NULL;
|
|
|
|
|
SemaphoreHandle_t g_calibration_mutex = NULL;
|
|
|
|
|
|
2025-12-28 20:52:11 -06:00
|
|
|
// Global encoder instances
|
2025-12-31 17:23:44 -06:00
|
|
|
Encoder* topEnc = new Encoder(ENCODER_PIN_A, ENCODER_PIN_B);
|
|
|
|
|
Encoder* bottomEnc = new Encoder(InputEnc_PIN_A, InputEnc_PIN_B);
|
|
|
|
|
|
2026-01-03 22:59:36 -06:00
|
|
|
void mainTask(void* arg) {
|
|
|
|
|
EventBits_t bits;
|
2025-12-28 15:31:20 -06:00
|
|
|
|
2026-01-03 22:59:36 -06:00
|
|
|
printf("Main task started - event-driven mode\n");
|
2025-12-23 17:21:44 -06:00
|
|
|
|
2025-11-28 18:26:32 -06:00
|
|
|
while (1) {
|
2026-01-03 22:59:36 -06:00
|
|
|
// Block waiting for ANY event (no polling!)
|
|
|
|
|
bits = xEventGroupWaitBits(
|
|
|
|
|
g_system_events,
|
|
|
|
|
EVENT_SOCKETIO_DISCONNECTED | EVENT_CLEAR_CALIB | EVENT_SAVE_POSITION,
|
|
|
|
|
pdTRUE, // Clear bits on exit
|
|
|
|
|
pdFALSE, // Wait for ANY bit (not all)
|
|
|
|
|
portMAX_DELAY // Block forever - no polling!
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (bits & EVENT_SOCKETIO_DISCONNECTED) {
|
2025-12-24 18:39:21 -06:00
|
|
|
if (!connected) {
|
|
|
|
|
printf("Disconnected! Beginning setup loop.\n");
|
|
|
|
|
stopSocketIO();
|
|
|
|
|
setupLoop();
|
|
|
|
|
}
|
2026-01-03 22:59:36 -06:00
|
|
|
else {
|
|
|
|
|
printf("Reconnected!\n");
|
|
|
|
|
}
|
2025-12-24 18:39:21 -06:00
|
|
|
}
|
2026-01-03 22:59:36 -06:00
|
|
|
|
|
|
|
|
if (bits & EVENT_CLEAR_CALIB) {
|
|
|
|
|
xSemaphoreTake(g_calibration_mutex, portMAX_DELAY);
|
2026-01-04 11:43:23 -06:00
|
|
|
Calibration::clearCalibrated();
|
2026-01-03 22:59:36 -06:00
|
|
|
xSemaphoreGive(g_calibration_mutex);
|
2025-12-31 15:44:48 -06:00
|
|
|
emitCalibStatus(false);
|
|
|
|
|
}
|
2026-01-03 22:59:36 -06:00
|
|
|
|
|
|
|
|
if (bits & EVENT_SAVE_POSITION) {
|
2025-12-31 15:44:48 -06:00
|
|
|
servoSavePos();
|
|
|
|
|
|
|
|
|
|
// Send position update to server
|
2026-01-04 11:43:23 -06:00
|
|
|
uint8_t currentAppPos = Calibration::convertToAppPos(topEnc->getCount());
|
2025-12-31 15:44:48 -06:00
|
|
|
emitPosHit(currentAppPos);
|
|
|
|
|
|
|
|
|
|
printf("Sent pos_hit: position %d\n", currentAppPos);
|
2025-12-28 20:52:11 -06:00
|
|
|
}
|
2025-11-28 18:26:32 -06:00
|
|
|
}
|
2025-12-28 12:46:09 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void encoderTest() {
|
2025-12-28 15:31:20 -06:00
|
|
|
// Create encoder instance
|
|
|
|
|
Encoder encoder(ENCODER_PIN_A, ENCODER_PIN_B);
|
|
|
|
|
encoder.init();
|
2025-12-28 12:46:09 -06:00
|
|
|
|
2025-12-28 15:31:20 -06:00
|
|
|
int32_t prevCount = encoder.getCount();
|
2025-12-28 12:46:09 -06:00
|
|
|
|
|
|
|
|
while (1) {
|
2025-12-28 15:31:20 -06:00
|
|
|
int32_t currentCount = encoder.getCount();
|
|
|
|
|
if (currentCount != prevCount) {
|
|
|
|
|
prevCount = currentCount;
|
2025-12-28 12:46:09 -06:00
|
|
|
printf("Encoder Pos: %d\n", prevCount);
|
|
|
|
|
}
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" void app_main() {
|
2026-01-03 22:59:36 -06:00
|
|
|
// Initialize NVS first
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
// Create synchronization primitives
|
|
|
|
|
g_system_events = xEventGroupCreate();
|
|
|
|
|
g_servo_command_queue = xQueueCreate(10, sizeof(servo_cmd_msg_t));
|
|
|
|
|
g_encoder_event_queue = xQueueCreate(50, sizeof(encoder_event_t));
|
|
|
|
|
g_calibration_mutex = xSemaphoreCreateMutex();
|
|
|
|
|
|
|
|
|
|
if (g_system_events == NULL || g_servo_command_queue == NULL ||
|
|
|
|
|
g_encoder_event_queue == NULL || g_calibration_mutex == NULL) {
|
|
|
|
|
printf("ERROR: Failed to create synchronization primitives\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize hardware
|
2026-01-04 11:43:23 -06:00
|
|
|
WiFi::init();
|
|
|
|
|
Calibration::init();
|
2026-01-03 22:59:36 -06:00
|
|
|
|
|
|
|
|
// Initialize encoders
|
|
|
|
|
topEnc->init();
|
|
|
|
|
bottomEnc->init();
|
|
|
|
|
servoInit();
|
|
|
|
|
|
|
|
|
|
// Create servo control task (highest priority - real-time)
|
|
|
|
|
xTaskCreate(servoControlTask, "servo_ctrl", 4096, NULL, SERVO_TASK_PRIORITY, NULL);
|
|
|
|
|
|
|
|
|
|
// Create main task (lower priority)
|
|
|
|
|
xTaskCreate(mainTask, "main", 4096, NULL, MAIN_TASK_PRIORITY, NULL);
|
|
|
|
|
|
|
|
|
|
// Run setup loop (this will handle WiFi/SocketIO connection)
|
|
|
|
|
setupLoop();
|
|
|
|
|
|
|
|
|
|
// app_main returns, but tasks continue running
|
|
|
|
|
printf("app_main complete - tasks running\n");
|
2025-11-28 18:26:32 -06:00
|
|
|
}
|