refactoring codebase

This commit is contained in:
2026-07-06 23:11:34 +07:00
parent 77997736f1
commit 9c522fb95c
8 changed files with 469 additions and 170 deletions

View File

@@ -0,0 +1,180 @@
#include "mqtt_handler.h"
#include "config.h"
#include "motor.h"
#include <WiFi.h>
#include <PubSubClient.h>
// --- ГЛОБАЛЬНЫЕ ОБЪЕКТЫ (Static внутри cpp) ---
static WiFiClient espClient;
static PubSubClient client(espClient);
// --- ПЕРЕМЕННЫЕ ДЛЯ ОТСЛЕЖИВАНИЯ ИЗМЕНЕНИЙ ТЕЛЕМЕТРИИ ---
static unsigned long last_feedback_time = 0;
static int last_pub_rpm = -1;
static unsigned long last_pub_sps = -1;
static unsigned long last_pub_steps = -1;
static int last_pub_driver_state = -1; // -1: unknown, 0: off, 1: on
static int last_pub_is_run = -1; // -1: unknown, 0: stop, 1: run
// --- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ---
static void setup_wifi() {
Serial.print("Connecting to WiFi");
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
vTaskDelay(pdMS_TO_TICKS(500));
Serial.print(".");
}
Serial.println("\nWiFi Connected");
}
static void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS)) {
Serial.println("connected");
// Сбрасываем кэш телеметрии, чтобы при переподключении
// сразу отправить актуальное состояние, даже если оно не менялось
last_pub_rpm = -1;
last_pub_sps = -1;
last_pub_steps = -1;
last_pub_driver_state = -1;
last_pub_is_run = -1;
// Подписка на топики управления
client.subscribe("motor/control/command");
client.subscribe("motor/control/driver");
client.subscribe("motor/control/step_per_sec");
client.subscribe("motor/control/rpm");
client.subscribe("motor/control/totalsteps/reset");
} else {
Serial.printf("failed, rc=%d, retry in 5s\n", client.state());
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
}
static void callback(char* topic, byte* payload, unsigned int length) {
// Безопасное преобразование payload в строку
char msg[length + 1];
memcpy(msg, payload, length);
msg[length] = '\0';
Serial.printf("MQTT Received [%s]: %s\n", topic, msg);
if (strcmp(topic, "motor/control/command") == 0) {
if (strcmp(msg, "start") == 0) {
// Если была команда stop (RPM 0), запускаем на дефолтной скорости или последней целевой
// Здесь для простоты запускаем на 60 RPM, если текущая скорость близка к 0
if (getCurrentRPM() < 5) {
setTargetRPM(60);
} else {
// Если мотор уже крутится, можно просто возобновить рампу к текущей цели,
// но setTargetRPM и так это делает.
setTargetRPM(getCurrentRPM());
}
} else if (strcmp(msg, "stop") == 0) {
setTargetRPM(0);
}
}
else if (strcmp(topic, "motor/control/rpm") == 0) {
setTargetRPM(atoi(msg));
}
else if (strcmp(topic, "motor/control/step_per_sec") == 0) {
unsigned long sps = strtoul(msg, NULL, 10);
unsigned long total_steps_per_rev = (unsigned long)STEPS_PER_REVOLUTION * MICROSTEP_FACTOR;
if (sps > 0) {
int calc_rpm = (sps * 60) / total_steps_per_rev;
setTargetRPM(calc_rpm);
}
}
else if (strcmp(topic, "motor/control/driver") == 0) {
// TMC2209: LOW = Enabled, HIGH = Disabled
bool enable = (strcmp(msg, "turnon") == 0);
digitalWrite(EN_PIN, enable ? LOW : HIGH);
}
else if (strcmp(topic, "motor/control/totalsteps/reset") == 0) {
resetSteps();
// Принудительно публикуем 0 сразу, не дожидаясь цикла телеметрии
if (client.connected()) {
client.publish("motor/feedback/totalsteps", "0");
}
last_pub_steps = 0;
}
}
static void publishTelemetry() {
unsigned long now = millis();
// Проверяем каждые 200 мс
if (now - last_feedback_time >= 200) {
// 1. RPM
int current_rpm = getCurrentRPM();
if (current_rpm != last_pub_rpm) {
client.publish("motor/feedback/rpm", String(current_rpm).c_str());
last_pub_rpm = current_rpm;
}
// 2. Steps Per Second (SPS)
unsigned long interval_us = getStepIntervalUs();
unsigned long current_sps = 0;
if (interval_us > 0 && interval_us < 100000) {
current_sps = 1000000UL / interval_us;
}
if (current_sps != last_pub_sps) {
client.publish("motor/feedback/step_per_seconds", String(current_sps).c_str());
last_pub_sps = current_sps;
}
// 3. Total Steps
unsigned long current_steps = getMotorSteps();
if (current_steps != last_pub_steps) {
client.publish("motor/feedback/totalsteps", String(current_steps).c_str());
last_pub_steps = current_steps;
}
// 4. Driver State (EN_PIN)
// LOW = On, HIGH = Off
int current_driver_state = (digitalRead(EN_PIN) == LOW) ? 1 : 0;
if (current_driver_state != last_pub_driver_state) {
client.publish("motor/feedback/driver", current_driver_state ? "on" : "off");
last_pub_driver_state = current_driver_state;
}
// 5. Is Running
int current_is_run = isMotorRunning() ? 1 : 0;
if (current_is_run != last_pub_is_run) {
client.publish("motor/feedback/is_run", current_is_run ? "true" : "false");
last_pub_is_run = current_is_run;
}
last_feedback_time = now;
}
}
// --- ОСНОВНАЯ ЗАДАЧА FREE RTOS ---
void mqttTask(void *parameter) {
// Инициализация WiFi и MQTT клиента
setup_wifi();
client.setServer(MQTT_SERVER, MQTT_PORT);
client.setCallback(callback);
for (;;) {
// Поддержание соединения
if (!client.connected()) {
reconnect();
}
// Обработка входящих сообщений
client.loop();
// Отправка телеметрии
publishTelemetry();
// Yield для других задач
vTaskDelay(pdMS_TO_TICKS(10));
}
}