Files
gateway/components/gateway_controller/include/gateway_controller.hpp
T
Tony 639fdd860e feat(gateway): implement reconciliation mechanism and command prioritization
- Introduced a reconciliation job structure to manage the reconciliation process for gateway channels.
- Added methods to schedule and run reconciliation steps, including group, scene, and settings reconciliation.
- Implemented a locking mechanism to ensure thread safety during reconciliation operations.
- Enhanced command handling in GatewayRuntime to classify commands by priority (control, normal, maintenance).
- Updated command enqueueing and processing to respect command priorities, ensuring maintenance commands are handled appropriately.
- Added configuration options for enabling/disabling cache functionality in GatewayRuntime.
- Improved logging to include cache status during runtime initialization.

Co-authored-by: Copilot <copilot@github.com>
2026-05-02 03:04:06 +08:00

173 lines
6.2 KiB
C++

#pragma once
#include <array>
#include <atomic>
#include <cstdint>
#include <functional>
#include <map>
#include <string>
#include <string_view>
#include <vector>
#include "gateway_cache.hpp"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
namespace gateway {
class DaliDomainService;
struct DaliRawFrame;
class GatewayRuntime;
struct GatewayControllerConfig {
uint32_t task_stack_size{6144};
UBaseType_t task_priority{5};
int color_temperature_min{2000};
int color_temperature_max{6500};
bool setup_supported{true};
bool ble_supported{false};
bool wifi_supported{true};
bool ip_router_supported{true};
bool internal_scene_supported{true};
bool internal_group_supported{true};
};
struct GatewayChannelSnapshot {
uint8_t channel_index{0};
uint8_t gateway_id{0};
std::string name;
std::string phy;
uint8_t scene_mask_low{0};
uint8_t scene_mask_high{0};
uint8_t group_mask_low{0};
uint8_t group_mask_high{0};
bool allocating{false};
int last_alloc_addr{0};
};
struct GatewayControllerSnapshot {
bool setup_mode{false};
bool wireless_setup_mode{false};
bool ble_enabled{false};
bool wifi_enabled{false};
bool ip_router_enabled{false};
bool internal_scene_supported{false};
bool internal_group_supported{false};
std::vector<GatewayChannelSnapshot> channels;
};
class GatewayController {
public:
using NotificationSink = std::function<void(const std::vector<uint8_t>& frame)>;
using BleStateSink = std::function<void(bool enabled)>;
using WifiStateSink = std::function<void(uint8_t mode)>;
using GatewayNameSink = std::function<void(uint8_t gateway_id)>;
GatewayController(GatewayRuntime& runtime, DaliDomainService& dali_domain,
GatewayCache& cache,
GatewayControllerConfig config = {});
~GatewayController();
esp_err_t start();
bool enqueueCommandFrame(const std::vector<uint8_t>& frame);
void addNotificationSink(NotificationSink sink);
void addBleStateSink(BleStateSink sink);
void addWifiStateSink(WifiStateSink sink);
void addGatewayNameSink(GatewayNameSink sink);
bool setupMode() const;
bool wirelessSetupMode() const;
void setWirelessSetupMode(bool enabled);
bool bleEnabled() const;
bool wifiEnabled() const;
bool ipRouterEnabled() const;
GatewayControllerSnapshot snapshot();
private:
struct ReconciliationJob {
enum class Phase : uint8_t {
kReloadFlags = 0,
kGroups = 1,
kScenes = 2,
kSettings = 3,
};
GatewayCacheChannelFlags flags{};
Phase phase{Phase::kReloadFlags};
uint8_t short_address{0};
uint8_t scene_id{0};
};
static void TaskEntry(void* arg);
void taskLoop();
void dispatchCommand(const std::vector<uint8_t>& command);
void scheduleReconciliation(uint8_t gateway_id);
bool hasPendingReconciliation() const;
bool runMaintenanceStep();
bool runReconciliationStep(uint8_t gateway_id, ReconciliationJob& job);
void reconcileGroupStep(uint8_t gateway_id, uint8_t short_address);
void reconcileSceneStep(uint8_t gateway_id, uint8_t short_address, uint8_t scene_id);
void reconcileSettingsStep(uint8_t gateway_id, uint8_t short_address);
bool hasGateway(uint8_t gateway_id) const;
std::vector<uint8_t> gatewayIds() const;
std::string gatewayName(uint8_t gateway_id) const;
void refreshRuntimeGatewayNames();
void publishPayload(uint8_t gateway_id, const std::vector<uint8_t>& payload);
void publishFrame(const std::vector<uint8_t>& frame);
void handleDaliRawFrame(const DaliRawFrame& frame);
uint8_t resolveInternalGroupRawAddress(uint8_t gateway_id, uint8_t raw_addr);
static uint8_t normalizeGroupTargetType(uint8_t target_type);
static uint8_t normalizeGroupTargetValue(uint8_t target_type, uint8_t target_value);
static uint8_t internalGroupRawTargetAddress(uint8_t target_type, uint8_t target_value,
uint8_t raw_addr);
static int internalGroupDecTargetAddress(uint8_t target_type, uint8_t target_value);
static int shortAddressFromRaw(uint8_t raw_addr);
static int reverseInRange(int value, int min_value, int max_value);
bool setSceneEnabled(uint8_t gateway_id, uint8_t scene_id, bool enabled);
bool setSceneDetail(uint8_t gateway_id, uint8_t scene_id, uint8_t brightness,
uint8_t color_mode, uint8_t data1, uint8_t data2, uint8_t data3);
bool setSceneName(uint8_t gateway_id, uint8_t scene_id, std::string_view name);
bool deleteScene(uint8_t gateway_id, uint8_t scene_id);
std::pair<uint8_t, uint8_t> sceneMask(uint8_t gateway_id);
bool executeScene(uint8_t gateway_id, int short_address, uint8_t scene_id);
bool setGroupEnabled(uint8_t gateway_id, uint8_t group_id, bool enabled);
bool setGroupDetail(uint8_t gateway_id, uint8_t group_id, uint8_t target_type,
uint8_t target_value);
bool setGroupName(uint8_t gateway_id, uint8_t group_id, std::string_view name);
bool deleteGroup(uint8_t gateway_id, uint8_t group_id);
std::pair<uint8_t, uint8_t> groupMask(uint8_t gateway_id);
bool executeGroup(uint8_t gateway_id, uint8_t group_id);
void handleGatewayNameCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
void handleGatewayIdentityCommand(uint8_t gateway_id, uint8_t op);
void handleAllocationCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
void handleInternalSceneCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
void handleInternalGroupCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
GatewayRuntime& runtime_;
DaliDomainService& dali_domain_;
GatewayCache& cache_;
GatewayControllerConfig config_;
TaskHandle_t task_handle_{nullptr};
SemaphoreHandle_t maintenance_lock_{nullptr};
std::vector<NotificationSink> notification_sinks_;
std::vector<BleStateSink> ble_state_sinks_;
std::vector<WifiStateSink> wifi_state_sinks_;
std::vector<GatewayNameSink> gateway_name_sinks_;
std::map<uint8_t, ReconciliationJob> reconciliation_jobs_;
std::atomic<int> maintenance_activity_gateway_{-1};
bool setup_mode_{false};
bool wireless_setup_mode_{false};
bool ble_enabled_{false};
bool wifi_enabled_{false};
bool ip_router_enabled_{true};
};
} // namespace gateway