70367f53ca
- Created CMakeLists.txt for the OpenKNX IDF component, ensuring dependencies on OpenKNX and TPUart submodules. - Implemented Arduino compatibility header for basic functions like millis, delay, pinMode, and digitalRead. - Developed EspIdfPlatform class for network interface management and multicast communication. - Added EtsMemoryLoader for loading ETS memory snapshots and managing associations. - Introduced TpuartUartInterface for UART communication with methods for reading, writing, and managing callbacks. - Implemented arduino_compat.cpp for Arduino-like functionality on ESP-IDF. - Created source files for platform and memory loader implementations. - Updated submodules for knx, knx_dali_gw, and tpuart. Signed-off-by: Tony <tonylu@tony-cloud.com>
208 lines
7.0 KiB
C++
208 lines
7.0 KiB
C++
#pragma once
|
|
|
|
#include "bridge.hpp"
|
|
#include "model_value.hpp"
|
|
|
|
#include "esp_err.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "lwip/sockets.h"
|
|
|
|
#include <atomic>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace gateway {
|
|
|
|
constexpr uint16_t kGatewayKnxDefaultUdpPort = 3671;
|
|
constexpr const char* kGatewayKnxDefaultMulticastAddress = "224.0.23.12";
|
|
constexpr uint32_t kGatewayKnxDefaultTpBaudrate = 19200;
|
|
|
|
struct GatewayKnxTpUartConfig {
|
|
int uart_port{1};
|
|
int tx_pin{-1};
|
|
int rx_pin{-1};
|
|
uint32_t baudrate{kGatewayKnxDefaultTpBaudrate};
|
|
size_t rx_buffer_size{1024};
|
|
size_t tx_buffer_size{1024};
|
|
uint32_t read_timeout_ms{20};
|
|
};
|
|
|
|
enum class GatewayKnxMappingMode : uint8_t {
|
|
kFormula = 0,
|
|
kGwReg1Direct = 1,
|
|
kManual = 2,
|
|
kEtsDatabase = 3,
|
|
};
|
|
|
|
struct GatewayKnxEtsAssociation {
|
|
uint16_t group_address{0};
|
|
uint16_t group_object_number{0};
|
|
};
|
|
|
|
struct GatewayKnxConfig {
|
|
bool dali_router_enabled{true};
|
|
bool ip_router_enabled{false};
|
|
bool tunnel_enabled{true};
|
|
bool multicast_enabled{true};
|
|
bool ets_database_enabled{true};
|
|
GatewayKnxMappingMode mapping_mode{GatewayKnxMappingMode::kFormula};
|
|
uint8_t main_group{0};
|
|
uint16_t udp_port{kGatewayKnxDefaultUdpPort};
|
|
std::string multicast_address{kGatewayKnxDefaultMulticastAddress};
|
|
uint16_t individual_address{0x1101};
|
|
std::vector<GatewayKnxEtsAssociation> ets_associations;
|
|
GatewayKnxTpUartConfig tp_uart;
|
|
};
|
|
|
|
enum class GatewayKnxDaliDataType : uint8_t {
|
|
kUnknown = 0,
|
|
kSwitch = 1,
|
|
kBrightness = 2,
|
|
kColorTemperature = 3,
|
|
kRgb = 4,
|
|
};
|
|
|
|
enum class GatewayKnxDaliTargetKind : uint8_t {
|
|
kNone = 0,
|
|
kBroadcast = 1,
|
|
kShortAddress = 2,
|
|
kGroup = 3,
|
|
};
|
|
|
|
struct GatewayKnxDaliTarget {
|
|
GatewayKnxDaliTargetKind kind{GatewayKnxDaliTargetKind::kNone};
|
|
int address{-1};
|
|
};
|
|
|
|
struct GatewayKnxDaliBinding {
|
|
uint16_t group_address{0};
|
|
uint8_t main_group{0};
|
|
uint8_t middle_group{0};
|
|
uint8_t sub_group{0};
|
|
GatewayKnxMappingMode mapping_mode{GatewayKnxMappingMode::kFormula};
|
|
int group_object_number{-1};
|
|
int channel_index{-1};
|
|
std::string address;
|
|
std::string name;
|
|
std::string object_role;
|
|
std::string datapoint_type;
|
|
GatewayKnxDaliDataType data_type{GatewayKnxDaliDataType::kUnknown};
|
|
GatewayKnxDaliTarget target;
|
|
};
|
|
|
|
std::optional<GatewayKnxConfig> GatewayKnxConfigFromValue(const DaliValue* value);
|
|
DaliValue GatewayKnxConfigToValue(const GatewayKnxConfig& config);
|
|
|
|
const char* GatewayKnxMappingModeToString(GatewayKnxMappingMode mode);
|
|
GatewayKnxMappingMode GatewayKnxMappingModeFromString(const std::string& value);
|
|
const char* GatewayKnxDataTypeToString(GatewayKnxDaliDataType data_type);
|
|
const char* GatewayKnxTargetKindToString(GatewayKnxDaliTargetKind kind);
|
|
std::optional<GatewayKnxDaliDataType> GatewayKnxDaliDataTypeForMiddleGroup(
|
|
uint8_t middle_group);
|
|
std::optional<GatewayKnxDaliTarget> GatewayKnxDaliTargetForSubgroup(uint8_t sub_group);
|
|
uint16_t GatewayKnxGroupAddress(uint8_t main_group, uint8_t middle_group,
|
|
uint8_t sub_group);
|
|
std::string GatewayKnxGroupAddressString(uint16_t group_address);
|
|
|
|
class GatewayKnxBridge {
|
|
public:
|
|
explicit GatewayKnxBridge(DaliBridgeEngine& engine);
|
|
|
|
void setConfig(const GatewayKnxConfig& config);
|
|
const GatewayKnxConfig& config() const;
|
|
size_t etsBindingCount() const;
|
|
|
|
std::vector<GatewayKnxDaliBinding> describeDaliBindings() const;
|
|
DaliBridgeResult handleCemiFrame(const uint8_t* data, size_t len);
|
|
DaliBridgeResult handleGroupWrite(uint16_t group_address, const uint8_t* data,
|
|
size_t len);
|
|
|
|
private:
|
|
DaliBridgeResult executeForDecodedWrite(uint16_t group_address,
|
|
GatewayKnxDaliDataType data_type,
|
|
GatewayKnxDaliTarget target,
|
|
const uint8_t* data, size_t len);
|
|
DaliBridgeResult executeEtsBindings(uint16_t group_address,
|
|
const std::vector<GatewayKnxDaliBinding>& bindings,
|
|
const uint8_t* data, size_t len);
|
|
void rebuildEtsBindings();
|
|
|
|
DaliBridgeEngine& engine_;
|
|
GatewayKnxConfig config_;
|
|
std::map<uint16_t, std::vector<GatewayKnxDaliBinding>> ets_bindings_by_group_address_;
|
|
};
|
|
|
|
class GatewayKnxTpIpRouter {
|
|
public:
|
|
using CemiFrameHandler = std::function<DaliBridgeResult(const uint8_t* data, size_t len)>;
|
|
|
|
GatewayKnxTpIpRouter(GatewayKnxBridge& bridge, CemiFrameHandler handler);
|
|
~GatewayKnxTpIpRouter();
|
|
|
|
void setConfig(const GatewayKnxConfig& config);
|
|
const GatewayKnxConfig& config() const;
|
|
|
|
esp_err_t start(uint32_t task_stack_size, UBaseType_t task_priority);
|
|
esp_err_t stop();
|
|
bool started() const;
|
|
const std::string& lastError() const;
|
|
|
|
private:
|
|
static void TaskEntry(void* arg);
|
|
|
|
void taskLoop();
|
|
void finishTask();
|
|
void closeSockets();
|
|
bool configureSocket();
|
|
bool configureTpUart();
|
|
bool initializeTpUart();
|
|
void handleUdpDatagram(const uint8_t* data, size_t len, const ::sockaddr_in& remote);
|
|
void handleRoutingIndication(const uint8_t* body, size_t len);
|
|
void handleTunnellingRequest(const uint8_t* body, size_t len, const ::sockaddr_in& remote);
|
|
void handleConnectRequest(const uint8_t* body, size_t len, const ::sockaddr_in& remote);
|
|
void handleConnectionStateRequest(const uint8_t* body, size_t len,
|
|
const ::sockaddr_in& remote);
|
|
void handleDisconnectRequest(const uint8_t* body, size_t len, const ::sockaddr_in& remote);
|
|
void sendTunnellingAck(uint8_t channel_id, uint8_t sequence, uint8_t status,
|
|
const ::sockaddr_in& remote);
|
|
void sendTunnelIndication(const uint8_t* data, size_t len);
|
|
void sendConnectionStateResponse(uint8_t channel_id, uint8_t status,
|
|
const ::sockaddr_in& remote);
|
|
void sendDisconnectResponse(uint8_t channel_id, uint8_t status,
|
|
const ::sockaddr_in& remote);
|
|
void sendConnectResponse(uint8_t channel_id, uint8_t status,
|
|
const ::sockaddr_in& remote);
|
|
void sendRoutingIndication(const uint8_t* data, size_t len);
|
|
void pollTpUart();
|
|
void handleTpUartControlByte(uint8_t byte);
|
|
void handleTpTelegram(const uint8_t* data, size_t len);
|
|
void forwardCemiToTp(const uint8_t* data, size_t len);
|
|
|
|
GatewayKnxBridge& bridge_;
|
|
CemiFrameHandler handler_;
|
|
GatewayKnxConfig config_;
|
|
TaskHandle_t task_handle_{nullptr};
|
|
std::atomic_bool stop_requested_{false};
|
|
std::atomic_bool started_{false};
|
|
int udp_sock_{-1};
|
|
int tp_uart_port_{-1};
|
|
uint8_t tunnel_channel_id_{1};
|
|
uint8_t expected_tunnel_sequence_{0};
|
|
uint8_t tunnel_send_sequence_{0};
|
|
bool tunnel_connected_{false};
|
|
::sockaddr_in tunnel_remote_{};
|
|
std::vector<uint8_t> tp_rx_frame_;
|
|
std::vector<uint8_t> tp_last_sent_telegram_;
|
|
TickType_t tp_uart_last_byte_tick_{0};
|
|
bool tp_uart_extended_frame_{false};
|
|
bool tp_uart_online_{false};
|
|
std::string last_error_;
|
|
};
|
|
|
|
} // namespace gateway
|