mirror of
				https://github.com/thelsing/knx.git
				synced 2025-10-26 10:26:25 +01:00 
			
		
		
		
	Add native support for ESP IDF with example.
This commit is contained in:
		
						commit
						549b4df975
					
				
							
								
								
									
										34
									
								
								.github/workflows/esp-idf.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								.github/workflows/esp-idf.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| name: ESP-IDF | ||||
| 
 | ||||
| on: [push, pull_request] | ||||
| 
 | ||||
| concurrency: | ||||
|   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
| 
 | ||||
|   build: | ||||
|     name: "ESP-IDF ${{ matrix.idf_ver }}" | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 10 | ||||
| 
 | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         #idf_ver: ["v4.4.7", "v5.1.4", "v5.3.2"] | ||||
|         idf_ver: ["v5.4.1"] | ||||
|         idf_target: ["esp32"] | ||||
| 
 | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           path: ${{ github.workspace }}/app | ||||
| 
 | ||||
|       - name: Compile | ||||
|         uses: espressif/esp-idf-ci-action@v1 | ||||
|         with: | ||||
|           esp_idf_version: ${{ matrix.idf_ver }} | ||||
|           target: ${{ matrix.idf_target }} | ||||
|           path: app/examples/knx-demo-esp-idf | ||||
|           command: apt-get update && apt-get install -y python3-venv && idf.py build | ||||
| @ -1,6 +1,6 @@ | ||||
| # knx | ||||
| 
 | ||||
| This projects provides a knx-device stack for arduino (ESP8266, ESP32, SAMD21, RP2040, STM32), CC1310 and linux. (more are quite easy to add) | ||||
| This projects provides a knx-device stack for Arduino (ESP8266, ESP32, SAMD21, RP2040, STM32), CC1310, ESP IDF and Linux. (more are quite easy to add) | ||||
| It implements most of System-B specification and can be configured with ETS. | ||||
| The necessary knxprod-files can be generated with the [Kaenx-Creator](https://github.com/OpenKNX/Kaenx-Creator) tool. | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										14
									
								
								examples/knx-demo-esp-idf/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								examples/knx-demo-esp-idf/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| cmake_minimum_required(VERSION 3.16) | ||||
| include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||||
| 
 | ||||
| # require for knx components | ||||
| add_definitions( | ||||
|   -Wno-unknown-pragmas | ||||
|   -DMASK_VERSION=0x07B0 | ||||
|   -DKNX_NO_AUTOMATIC_GLOBAL_INSTANCE | ||||
|   -DKNX_FLASH_SIZE=4096 | ||||
|   #-DKNX_NO_PRINT | ||||
|   #-Wno-stringop-truncation | ||||
| ) | ||||
| 
 | ||||
| project(knx-demo-diy-idf) | ||||
							
								
								
									
										29
									
								
								examples/knx-demo-esp-idf/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/knx-demo-esp-idf/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| # KNX Demo DIY (ESP-IDF 5.x Native) | ||||
| 
 | ||||
| This is a native ESP-IDF 5.x example project for KNX, based on the Arduino `knx-demo-diy` example but using the new `Esp32IdfPlatform` for direct ESP-IDF support. | ||||
| 
 | ||||
| ## Features | ||||
| - Uses the native ESP-IDF APIs (no Arduino layer) | ||||
| - Demonstrates KNX stack integration on ESP32 | ||||
| - Based on the logic of the Arduino `knx-demo-diy.ino` example | ||||
| 
 | ||||
| ## How to Build | ||||
| 
 | ||||
| 1. Install [ESP-IDF 5.x](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/) | ||||
| 2. Open a terminal in this directory (`examples/knx-demo-esp-idf`) | ||||
| 3. Run: | ||||
|    ```sh | ||||
|    idf.py set-target esp32 | ||||
|    idf.py build | ||||
|    idf.py -p /dev/ttyUSB0 flash monitor | ||||
|    ``` | ||||
|    (Replace `/dev/ttyUSB0` with your ESP32 serial port) | ||||
| 
 | ||||
| ## Project Structure | ||||
| - `main.c` — Main application file (C++ code, but named .c for ESP-IDF compatibility) | ||||
| - `CMakeLists.txt` — ESP-IDF build configuration | ||||
| 
 | ||||
| ## Notes | ||||
| - This project uses the new `Esp32IdfPlatform` class for native ESP-IDF support. | ||||
| - You may need to adapt pin numbers and KNX configuration for your hardware. | ||||
| - The logic is adapted from the Arduino `knx-demo-diy.ino` example.  | ||||
							
								
								
									
										11
									
								
								examples/knx-demo-esp-idf/components/knx/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								examples/knx-demo-esp-idf/components/knx/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| # Define the directory containing your source files | ||||
| set(SOURCE_DIR "../../../../src") | ||||
| set(SOURCE_DIR_1 "../../../../src/knx") | ||||
| 
 | ||||
| # Use file(GLOB) to find all .cpp files in the 'src' directory | ||||
| file(GLOB SOURCE_FILES "${SOURCE_DIR}/*.cpp") | ||||
| file(GLOB SOURCE_FILES_1 "${SOURCE_DIR_1}/*.cpp") | ||||
| 
 | ||||
| idf_component_register(SRCS ${SOURCE_FILES} ${SOURCE_FILES_1} | ||||
|                     INCLUDE_DIRS "../../../../src" "../../../../src/knx" | ||||
|                     REQUIRES esp_netif driver esp_timer esp_wifi freertos nvs_flash esp_system)  | ||||
							
								
								
									
										12
									
								
								examples/knx-demo-esp-idf/main/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								examples/knx-demo-esp-idf/main/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| idf_component_register( | ||||
|     SRCS "main.cpp" | ||||
|     INCLUDE_DIRS "."         | ||||
|     REQUIRES | ||||
|         knx | ||||
|         esp_timer | ||||
|         nvs_flash | ||||
|         esp_wifi | ||||
|         esp_event | ||||
|         esp_netif | ||||
|         mdns | ||||
| ) | ||||
							
								
								
									
										2
									
								
								examples/knx-demo-esp-idf/main/idf_component.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								examples/knx-demo-esp-idf/main/idf_component.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| dependencies: | ||||
|   espressif/mdns: ^1.8.2 | ||||
							
								
								
									
										162
									
								
								examples/knx-demo-esp-idf/main/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								examples/knx-demo-esp-idf/main/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,162 @@ | ||||
| #include "esp32_idf_platform.h" | ||||
| #include "knx_facade.h" | ||||
| #include "knx/bau07B0.h" | ||||
| #include "knx/group_object.h" | ||||
| #include "esp_wifi.h" | ||||
| #include "nvs_flash.h" | ||||
| #include "esp_log.h" | ||||
| #include <esp_timer.h> | ||||
| #include <freertos/FreeRTOS.h> | ||||
| #include <freertos/task.h> | ||||
| #include <cstring> | ||||
| #include <stdlib.h> | ||||
| #include <limits.h> | ||||
| 
 | ||||
| #define WIFI_SSID      "your_ssid" | ||||
| #define WIFI_PASS      "your_password" | ||||
| #define MASK_VERSION   0x07B0 | ||||
| 
 | ||||
| static const char *TAG = "knx-demo"; | ||||
| 
 | ||||
| // --- KNX Group Object Shortcuts ---
 | ||||
| #define goCurrent knx.getGroupObject(1) | ||||
| #define goMax     knx.getGroupObject(2) | ||||
| #define goMin     knx.getGroupObject(3) | ||||
| #define goReset   knx.getGroupObject(4) | ||||
| 
 | ||||
| // --- Global Variables ---
 | ||||
| float currentValue = 0; | ||||
| float maxValue = 0; | ||||
| float minValue = RAND_MAX; | ||||
| int64_t lastsend = 0; | ||||
| 
 | ||||
| // --- KNX Stack Instance (migrated pattern) ---
 | ||||
| Esp32IdfPlatform knxPlatform(UART_NUM_1); // Use UART_NUM_1, change if needed
 | ||||
| Bau07B0 knxBau(knxPlatform); | ||||
| KnxFacade<Esp32IdfPlatform, Bau07B0> knx(knxBau); | ||||
| 
 | ||||
| // --- WiFi event handler ---
 | ||||
| static esp_netif_t* s_wifi_netif = nullptr; | ||||
| static void wifi_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) { | ||||
|         esp_wifi_connect(); | ||||
|         ESP_LOGI(TAG, "Retrying connection to the WiFi AP"); | ||||
|     } 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)); | ||||
|         if (s_wifi_netif) { | ||||
|             knxPlatform.setNetif(s_wifi_netif); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // --- Button ISR (simulate with a function call or GPIO interrupt in real use) ---
 | ||||
| void myButtonPressed() { | ||||
|     static int64_t lastpressed = 0; | ||||
|     int64_t now = esp_timer_get_time() / 1000; // ms
 | ||||
|     if (now - lastpressed > 200) { | ||||
|         knx.toggleProgMode(); | ||||
|         lastpressed = now; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // --- KNX Reset Callback ---
 | ||||
| void resetCallback(GroupObject& go) { | ||||
|     if (go.value()) { | ||||
|         maxValue = 0; | ||||
|         minValue = 10000; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // --- Simulate temperature measurement ---
 | ||||
| void measureTemp() { | ||||
|     int64_t now = esp_timer_get_time() / 1000; // ms
 | ||||
|     if ((now - lastsend) < 2000) | ||||
|         return; | ||||
| 
 | ||||
|     lastsend = now; | ||||
|     int r = rand(); | ||||
|     currentValue = (r * 1.0) / (RAND_MAX * 1.0); | ||||
|     currentValue *= 100 * 100; | ||||
| 
 | ||||
|     goCurrent.value(currentValue); | ||||
| 
 | ||||
|     if (currentValue > maxValue) { | ||||
|         maxValue = currentValue; | ||||
|         goMax.value(maxValue); | ||||
|     } | ||||
|     if (currentValue < minValue) { | ||||
|         minValue = currentValue; | ||||
|         goMin.value(minValue); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| extern "C" void app_main(void) { | ||||
|     // Initialize NVS
 | ||||
|     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); | ||||
| 
 | ||||
|     // Initialize TCP/IP and WiFi
 | ||||
|     ESP_ERROR_CHECK(esp_netif_init()); | ||||
|     ESP_ERROR_CHECK(esp_event_loop_create_default()); | ||||
|     s_wifi_netif = esp_netif_create_default_wifi_sta(); | ||||
| 
 | ||||
|     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); | ||||
|     ESP_ERROR_CHECK(esp_wifi_init(&cfg)); | ||||
|     ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL)); | ||||
|     ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL)); | ||||
| 
 | ||||
|     wifi_config_t wifi_config = {}; | ||||
|     strcpy((char*)wifi_config.sta.ssid, WIFI_SSID); | ||||
|     strcpy((char*)wifi_config.sta.password, WIFI_PASS); | ||||
| 
 | ||||
|     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 initialization finished."); | ||||
| 
 | ||||
|     // Set UART pins (example: RX=16, TX=17)
 | ||||
|     knxPlatform.knxUartPins(16, 17); | ||||
|     knxPlatform.setupUart(); | ||||
| 
 | ||||
|     // Set button ISR
 | ||||
|     knx.setButtonISRFunction(myButtonPressed); | ||||
| 
 | ||||
|     // Read KNX memory (address table, etc.)
 | ||||
|     knx.readMemory(); | ||||
| 
 | ||||
|     // Register group object callbacks and types if configured
 | ||||
|     if (knx.configured()) { | ||||
|         goReset.callback(resetCallback); | ||||
|         goReset.dataPointType(DPT_Trigger); | ||||
|         goCurrent.dataPointType(DPT_Value_Temp); | ||||
|         goMin.dataPointType(DPT_Value_Temp); | ||||
|         goMax.dataPointType(DPT_Value_Temp); | ||||
| 
 | ||||
|         ESP_LOGI(TAG, "Timeout: %d", knx.paramByte(0)); | ||||
|         ESP_LOGI(TAG, "Cyclic send: %d", knx.paramByte(1)); | ||||
|         ESP_LOGI(TAG, "Min/Max send: %d", knx.paramByte(2)); | ||||
|         ESP_LOGI(TAG, "Send on change: %d", knx.paramByte(3)); | ||||
|         ESP_LOGI(TAG, "Alignment: %d", knx.paramByte(4)); | ||||
|     } | ||||
| 
 | ||||
|     // Start KNX stack
 | ||||
|     knx.start(); | ||||
| 
 | ||||
|     // Main loop
 | ||||
|     while (1) { | ||||
|         knx.loop(); | ||||
|         if (knx.configured()) { | ||||
|             measureTemp(); | ||||
|         } | ||||
|         vTaskDelay(pdMS_TO_TICKS(10)); | ||||
|     } | ||||
| }  | ||||
| @ -1,3 +1,5 @@ | ||||
| #ifdef ARDUINO | ||||
| 
 | ||||
| #include "arduino_platform.h" | ||||
| #include "knx/bits.h" | ||||
| 
 | ||||
| @ -309,3 +311,5 @@ void println(void) | ||||
|     ArduinoPlatform::SerialDebug->println(); | ||||
| } | ||||
| #endif // KNX_NO_PRINT
 | ||||
| 
 | ||||
| #endif // ARDUINO
 | ||||
| @ -1,5 +1,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef ARDUINO | ||||
| 
 | ||||
| #include "knx/platform.h" | ||||
| 
 | ||||
| #include "Arduino.h" | ||||
| @ -42,3 +44,4 @@ class ArduinoPlatform : public Platform | ||||
|     protected: | ||||
|         HardwareSerial* _knxSerial; | ||||
| }; | ||||
| #endif // ARDUINO
 | ||||
							
								
								
									
										431
									
								
								src/esp32_idf_platform.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										431
									
								
								src/esp32_idf_platform.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,431 @@ | ||||
| #ifdef ESP_PLATFORM | ||||
| // esp32_idf_platform.cpp
 | ||||
| #include <esp_system.h> | ||||
| #include <esp_mac.h> | ||||
| #include "esp32_idf_platform.h" | ||||
| #include "esp_log.h" | ||||
| #include "knx/bits.h" | ||||
| #include "nvs.h" | ||||
| #include <esp_timer.h> | ||||
| 
 | ||||
| static const char* KTAG = "KNX_LIB"; | ||||
| 
 | ||||
| Esp32IdfPlatform::Esp32IdfPlatform(uart_port_t uart_num) | ||||
|     : _uart_num(uart_num) | ||||
| { | ||||
|     // Set the memory type to use our NVS-based EEPROM emulation
 | ||||
|     _memoryType = Eeprom; | ||||
| } | ||||
| 
 | ||||
| Esp32IdfPlatform::~Esp32IdfPlatform() | ||||
| { | ||||
|     if (_sock != -1) | ||||
|     { | ||||
|         closeMultiCast(); | ||||
|     } | ||||
|     if (_uart_installed) | ||||
|     { | ||||
|         closeUart(); | ||||
|     } | ||||
|     if (_eeprom_buffer) | ||||
|     { | ||||
|         free(_eeprom_buffer); | ||||
|     } | ||||
|     if (_nvs_handle) | ||||
|     { | ||||
|         nvs_close(_nvs_handle); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::knxUartPins(int8_t rxPin, int8_t txPin) | ||||
| { | ||||
|     _rxPin = rxPin; | ||||
|     _txPin = txPin; | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::setNetif(esp_netif_t* netif) | ||||
| { | ||||
|     _netif = netif; | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::fatalError() | ||||
| { | ||||
|     ESP_LOGE(KTAG, "FATAL ERROR. System halted."); | ||||
|     // Loop forever to halt the system
 | ||||
|     while (1) | ||||
|     { | ||||
|         vTaskDelay(pdMS_TO_TICKS(1000)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // ESP specific uart handling with pins
 | ||||
| void Esp32IdfPlatform::setupUart() | ||||
| { | ||||
|     if (_uart_installed) | ||||
|         return; | ||||
|     uart_config_t uart_config = { | ||||
|         .baud_rate = 19200, | ||||
|         .data_bits = UART_DATA_8_BITS, | ||||
|         .parity = UART_PARITY_EVEN, | ||||
|         .stop_bits = UART_STOP_BITS_1, | ||||
|         .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, | ||||
|         .source_clk = UART_SCLK_DEFAULT, | ||||
|     }; | ||||
|     ESP_ERROR_CHECK(uart_driver_install(_uart_num, 256 * 2, 0, 0, NULL, 0)); | ||||
|     ESP_ERROR_CHECK(uart_param_config(_uart_num, &uart_config)); | ||||
|     ESP_ERROR_CHECK(uart_set_pin(_uart_num, _txPin, _rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); | ||||
|     _uart_installed = true; | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::closeUart() | ||||
| { | ||||
|     if (!_uart_installed) | ||||
|         return; | ||||
|     uart_driver_delete(_uart_num); | ||||
|     _uart_installed = false; | ||||
| } | ||||
| 
 | ||||
| int Esp32IdfPlatform::uartAvailable() | ||||
| { | ||||
|     if (!_uart_installed) | ||||
|         return 0; | ||||
|     size_t length = 0; | ||||
|     ESP_ERROR_CHECK(uart_get_buffered_data_len(_uart_num, &length)); | ||||
|     return length; | ||||
| } | ||||
| 
 | ||||
| size_t Esp32IdfPlatform::writeUart(const uint8_t data) | ||||
| { | ||||
|     if (!_uart_installed) | ||||
|         return 0; | ||||
|     return uart_write_bytes(_uart_num, &data, 1); | ||||
| } | ||||
| 
 | ||||
| size_t Esp32IdfPlatform::writeUart(const uint8_t* buffer, size_t size) | ||||
| { | ||||
|     if (!_uart_installed) | ||||
|         return 0; | ||||
|     return uart_write_bytes(_uart_num, buffer, size); | ||||
| } | ||||
| 
 | ||||
| int Esp32IdfPlatform::readUart() | ||||
| { | ||||
|     if (!_uart_installed) | ||||
|         return -1; | ||||
|     uint8_t data; | ||||
|     if (uart_read_bytes(_uart_num, &data, 1, pdMS_TO_TICKS(20)) > 0) | ||||
|     { | ||||
|         return data; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| size_t Esp32IdfPlatform::readBytesUart(uint8_t* buffer, size_t length) | ||||
| { | ||||
|     if (!_uart_installed) | ||||
|         return 0; | ||||
|     return uart_read_bytes(_uart_num, buffer, length, pdMS_TO_TICKS(100)); | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::flushUart() | ||||
| { | ||||
|     if (!_uart_installed) | ||||
|         return; | ||||
|     ESP_ERROR_CHECK(uart_flush(_uart_num)); | ||||
| } | ||||
| 
 | ||||
| uint32_t Esp32IdfPlatform::currentIpAddress() | ||||
| { | ||||
|     if (!_netif) | ||||
|         return 0; | ||||
|     esp_netif_ip_info_t ip_info; | ||||
|     esp_netif_get_ip_info(_netif, &ip_info); | ||||
|     return ip_info.ip.addr; | ||||
| } | ||||
| 
 | ||||
| uint32_t Esp32IdfPlatform::currentSubnetMask() | ||||
| { | ||||
|     if (!_netif) | ||||
|         return 0; | ||||
|     esp_netif_ip_info_t ip_info; | ||||
|     esp_netif_get_ip_info(_netif, &ip_info); | ||||
|     return ip_info.netmask.addr; | ||||
| } | ||||
| 
 | ||||
| uint32_t Esp32IdfPlatform::currentDefaultGateway() | ||||
| { | ||||
|     if (!_netif) | ||||
|         return 0; | ||||
|     esp_netif_ip_info_t ip_info; | ||||
|     esp_netif_get_ip_info(_netif, &ip_info); | ||||
|     return ip_info.gw.addr; | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::macAddress(uint8_t* addr) | ||||
| { | ||||
|     if (!_netif) | ||||
|         return; | ||||
|     esp_netif_get_mac(_netif, addr); | ||||
| } | ||||
| 
 | ||||
| uint32_t Esp32IdfPlatform::uniqueSerialNumber() | ||||
| { | ||||
|     uint8_t mac[6]; | ||||
|     esp_efuse_mac_get_default(mac); | ||||
|     uint64_t chipid = 0; | ||||
|     for (int i = 0; i < 6; i++) | ||||
|     { | ||||
|         chipid |= ((uint64_t)mac[i] << (i * 8)); | ||||
|     } | ||||
|     uint32_t upperId = (chipid >> 32) & 0xFFFFFFFF; | ||||
|     uint32_t lowerId = (chipid & 0xFFFFFFFF); | ||||
|     return (upperId ^ lowerId); | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::restart() | ||||
| { | ||||
|     ESP_LOGI(KTAG, "Restarting system..."); | ||||
|     esp_restart(); | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::setupMultiCast(uint32_t addr, uint16_t port) | ||||
| { | ||||
|     _multicast_addr = addr; | ||||
|     _multicast_port = port; | ||||
| 
 | ||||
|     _sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); | ||||
|     if (_sock < 0) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "Failed to create socket. Errno: %d", errno); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     struct sockaddr_in saddr = {0}; | ||||
|     saddr.sin_family = AF_INET; | ||||
|     saddr.sin_port = htons(port); | ||||
|     saddr.sin_addr.s_addr = htonl(INADDR_ANY); | ||||
|     if (bind(_sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in)) < 0) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "Failed to bind socket. Errno: %d", errno); | ||||
|         close(_sock); | ||||
|         _sock = -1; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     struct ip_mreq imreq = {0}; | ||||
|     imreq.imr_interface.s_addr = IPADDR_ANY; | ||||
|     imreq.imr_multiaddr.s_addr = addr; | ||||
|     if (setsockopt(_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(struct ip_mreq)) < 0) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "Failed to join multicast group. Errno: %d", errno); | ||||
|         close(_sock); | ||||
|         _sock = -1; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     ESP_LOGI(KTAG, "Successfully joined multicast group on port %d", port); | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::closeMultiCast() | ||||
| { | ||||
|     if (_sock != -1) | ||||
|     { | ||||
|         close(_sock); | ||||
|         _sock = -1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool Esp32IdfPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) | ||||
| { | ||||
|     if (_sock < 0) | ||||
|         return false; | ||||
| 
 | ||||
|     struct sockaddr_in dest_addr = {}; | ||||
|     dest_addr.sin_family = AF_INET; | ||||
|     dest_addr.sin_port = htons(_multicast_port); | ||||
|     dest_addr.sin_addr.s_addr = _multicast_addr; | ||||
| 
 | ||||
|     int sent_len = sendto(_sock, buffer, len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); | ||||
|     if (sent_len < 0) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "sendBytesMultiCast failed. Errno: %d", errno); | ||||
|         return false; | ||||
|     } | ||||
|     return sent_len == len; | ||||
| } | ||||
| 
 | ||||
| int Esp32IdfPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) | ||||
| { | ||||
|     if (_sock < 0) | ||||
|         return 0; | ||||
| 
 | ||||
|     socklen_t socklen = sizeof(_remote_addr); | ||||
|     int len = recvfrom(_sock, buffer, maxLen, 0, (struct sockaddr*)&_remote_addr, &socklen); | ||||
| 
 | ||||
|     if (len <= 0) | ||||
|     { | ||||
|         return 0; // No data or error
 | ||||
|     } | ||||
| 
 | ||||
|     src_addr = _remote_addr.sin_addr.s_addr; | ||||
|     src_port = ntohs(_remote_addr.sin_port); | ||||
| 
 | ||||
|     return len; | ||||
| } | ||||
| 
 | ||||
| bool Esp32IdfPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) | ||||
| { | ||||
|     if (_sock < 0) | ||||
|         return false; | ||||
| 
 | ||||
|     struct sockaddr_in dest_addr; | ||||
|     dest_addr.sin_family = AF_INET; | ||||
| 
 | ||||
|     if (addr == 0) | ||||
|     { // If address is 0, use the address from the last received packet
 | ||||
|         dest_addr.sin_addr.s_addr = _remote_addr.sin_addr.s_addr; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         dest_addr.sin_addr.s_addr = addr; | ||||
|     } | ||||
| 
 | ||||
|     if (port == 0) | ||||
|     { // If port is 0, use the port from the last received packet
 | ||||
|         dest_addr.sin_port = _remote_addr.sin_port; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         dest_addr.sin_port = htons(port); | ||||
|     } | ||||
| 
 | ||||
|     if (sendto(_sock, buffer, len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "sendBytesUniCast failed. Errno: %d", errno); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| uint8_t* Esp32IdfPlatform::getEepromBuffer(uint32_t size) | ||||
| { | ||||
|     if (_eeprom_buffer && _eeprom_size == size) | ||||
|     { | ||||
|         return _eeprom_buffer; | ||||
|     } | ||||
| 
 | ||||
|     if (_eeprom_buffer) | ||||
|     { | ||||
|         free(_eeprom_buffer); | ||||
|         _eeprom_buffer = nullptr; | ||||
|     } | ||||
| 
 | ||||
|     _eeprom_size = size; | ||||
|     _eeprom_buffer = (uint8_t*)malloc(size); | ||||
|     if (!_eeprom_buffer) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "Failed to allocate EEPROM buffer"); | ||||
|         fatalError(); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     esp_err_t err = nvs_flash_init(); | ||||
|     if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) | ||||
|     { | ||||
|         ESP_ERROR_CHECK(nvs_flash_erase()); | ||||
|         err = nvs_flash_init(); | ||||
|     } | ||||
|     ESP_ERROR_CHECK(err); | ||||
| 
 | ||||
|     err = nvs_open(_nvs_namespace, NVS_READWRITE, &_nvs_handle); | ||||
|     if (err != ESP_OK) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "Error opening NVS handle: %s", esp_err_to_name(err)); | ||||
|         free(_eeprom_buffer); | ||||
|         _eeprom_buffer = nullptr; | ||||
|         fatalError(); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     size_t required_size = size; | ||||
|     err = nvs_get_blob(_nvs_handle, _nvs_key, _eeprom_buffer, &required_size); | ||||
|     if (err != ESP_OK || required_size != size) | ||||
|     { | ||||
|         if (err == ESP_ERR_NVS_NOT_FOUND) | ||||
|         { | ||||
|             ESP_LOGI(KTAG, "No previous EEPROM data found in NVS. Initializing fresh buffer."); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             ESP_LOGW(KTAG, "NVS get blob failed (%s) or size mismatch. Initializing fresh buffer.", esp_err_to_name(err)); | ||||
|         } | ||||
|         memset(_eeprom_buffer, 0xFF, size); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ESP_LOGI(KTAG, "Successfully loaded %d bytes from NVS into EEPROM buffer.", required_size); | ||||
|     } | ||||
| 
 | ||||
|     return _eeprom_buffer; | ||||
| } | ||||
| 
 | ||||
| void Esp32IdfPlatform::commitToEeprom() | ||||
| { | ||||
|     if (!_eeprom_buffer || !_nvs_handle) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "EEPROM not initialized, cannot commit."); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     esp_err_t err = nvs_set_blob(_nvs_handle, _nvs_key, _eeprom_buffer, _eeprom_size); | ||||
|     if (err != ESP_OK) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "Failed to set NVS blob: %s", esp_err_to_name(err)); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     err = nvs_commit(_nvs_handle); | ||||
|     if (err != ESP_OK) | ||||
|     { | ||||
|         ESP_LOGE(KTAG, "Failed to commit NVS: %s", esp_err_to_name(err)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ESP_LOGI(KTAG, "Committed %" PRIu32 " bytes to NVS.", _eeprom_size); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint32_t millis() | ||||
| { | ||||
|     // esp_timer_get_time() returns microseconds, so we divide by 1000 for milliseconds.
 | ||||
|     // Cast to uint32_t to match the Arduino function signature.
 | ||||
|     return (uint32_t)(esp_timer_get_time() / 1000); | ||||
| } | ||||
| 
 | ||||
| // Internal wrapper function to bridge Arduino-style ISR to ESP-IDF
 | ||||
| static void IRAM_ATTR isr_wrapper(void* arg) | ||||
| { | ||||
|     IsrFuncPtr fn = (IsrFuncPtr)arg; | ||||
|     fn();  // call the original ISR
 | ||||
| } | ||||
| 
 | ||||
| // Implement attachInterrupt arduino like in ESP IDF
 | ||||
| void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode) | ||||
| { | ||||
|     gpio_config_t io_conf = { | ||||
|         .pin_bit_mask = (1ULL << pin), | ||||
|         .mode = GPIO_MODE_INPUT, | ||||
|         .pull_up_en = GPIO_PULLUP_ENABLE, | ||||
|         .pull_down_en = GPIO_PULLDOWN_DISABLE, | ||||
|         .intr_type = (gpio_int_type_t)mode | ||||
|     }; | ||||
| 
 | ||||
|     ESP_ERROR_CHECK(gpio_config(&io_conf)); | ||||
| 
 | ||||
|     ESP_ERROR_CHECK(gpio_install_isr_service(0)); | ||||
|        // Add ISR using the wrapper and pass original function as argument
 | ||||
|     ESP_ERROR_CHECK(gpio_isr_handler_add((gpio_num_t)pin, isr_wrapper, (void*)callback)); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										85
									
								
								src/esp32_idf_platform.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/esp32_idf_platform.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| #ifdef ESP_PLATFORM | ||||
| // esp_idf_platform.h
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "driver/uart.h" | ||||
| #include "esp_netif.h" | ||||
| #include "esp_system.h" | ||||
| #include "lwip/sockets.h" | ||||
| #include "nvs_flash.h" | ||||
| #include "knx/platform.h"// Include the provided base class | ||||
| 
 | ||||
| class Esp32IdfPlatform : public Platform | ||||
| { | ||||
|   public: | ||||
|     Esp32IdfPlatform(uart_port_t uart_num = UART_NUM_1); | ||||
|     ~Esp32IdfPlatform(); | ||||
| 
 | ||||
|     // uart
 | ||||
|     void knxUartPins(int8_t rxPin, int8_t txPin); | ||||
| 
 | ||||
|     // Call this after WiFi/Ethernet has started and received an IP.
 | ||||
|     void setNetif(esp_netif_t* netif); | ||||
| 
 | ||||
|     // --- Overridden Virtual Functions ---
 | ||||
| 
 | ||||
|     // ip stuff
 | ||||
|     uint32_t currentIpAddress() override; | ||||
|     uint32_t currentSubnetMask() override; | ||||
|     uint32_t currentDefaultGateway() override; | ||||
|     void macAddress(uint8_t* addr) override; | ||||
| 
 | ||||
|     // unique serial number
 | ||||
|     uint32_t uniqueSerialNumber() override; | ||||
| 
 | ||||
|     // basic stuff (pure virtual in base)
 | ||||
|     void restart() override; | ||||
|     void fatalError() override; | ||||
| 
 | ||||
|     // multicast
 | ||||
|     void setupMultiCast(uint32_t addr, uint16_t port) override; | ||||
|     void closeMultiCast() override; | ||||
|     bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; | ||||
|     int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen, uint32_t& src_addr, uint16_t& src_port) override; | ||||
| 
 | ||||
|     // unicast
 | ||||
|     bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; | ||||
| 
 | ||||
|     // UART
 | ||||
|     void setupUart() override; | ||||
|     void closeUart() override; | ||||
|     int uartAvailable() override; | ||||
|     size_t writeUart(const uint8_t data) override; | ||||
|     size_t writeUart(const uint8_t* buffer, size_t size) override; | ||||
|     int readUart() override; | ||||
|     size_t readBytesUart(uint8_t* buffer, size_t length) override; | ||||
|     void flushUart() override; | ||||
| 
 | ||||
|     // Memory (EEPROM emulation via NVS)
 | ||||
|     // We override these two functions to provide the low-level storage mechanism.
 | ||||
|     // The base Platform class will use them when _memoryType is Eeprom.
 | ||||
|     uint8_t* getEepromBuffer(uint32_t size) override; | ||||
|     void commitToEeprom() override; | ||||
| 
 | ||||
|   private: | ||||
|     // Network
 | ||||
|     esp_netif_t* _netif = nullptr; | ||||
|     int _sock = -1; | ||||
|     struct sockaddr_in _remote_addr; | ||||
|     uint32_t _multicast_addr = 0; | ||||
|     uint16_t _multicast_port = 0; | ||||
| 
 | ||||
|     // UART
 | ||||
|     uart_port_t _uart_num; | ||||
|     int8_t _rxPin = -1; | ||||
|     int8_t _txPin = -1; | ||||
|     bool _uart_installed = false; | ||||
| 
 | ||||
|     // NVS (for EEPROM emulation)
 | ||||
|     nvs_handle_t _nvs_handle; | ||||
|     uint8_t* _eeprom_buffer = nullptr; | ||||
|     uint32_t _eeprom_size = 0; | ||||
|     const char* _nvs_namespace = "knx_eeprom"; | ||||
|     const char* _nvs_key = "data"; | ||||
| }; | ||||
| #endif | ||||
							
								
								
									
										184
									
								
								src/knx/bits.cpp
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								src/knx/bits.cpp
									
									
									
									
									
								
							| @ -176,3 +176,187 @@ uint16_t crc16Dnp(uint8_t* input, uint16_t length) | ||||
| 
 | ||||
|     return (~crc) & 0xffff; | ||||
| } | ||||
| 
 | ||||
| // Produce Arduino print and println in ESP IDF for ESP32 family using printf().
 | ||||
| #ifdef ESP_PLATFORM | ||||
|     // Helper function to print a number in binary format
 | ||||
|     static void print_binary(unsigned long long n) | ||||
|     { | ||||
|         if (n == 0) | ||||
|         { | ||||
|             printf("0"); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Buffer for the maximum possible bits in an unsigned long long
 | ||||
|         char binary_string[65]; | ||||
|         int i = 0; | ||||
|         while (n > 0) | ||||
|         { | ||||
|             binary_string[i++] = (n % 2) + '0'; | ||||
|             n /= 2; | ||||
|         } | ||||
|         binary_string[i] = '\0'; | ||||
| 
 | ||||
|         // Reverse the string to get the correct binary representation
 | ||||
|         for (int j = 0; j < i / 2; ++j) | ||||
|         { | ||||
|             char temp = binary_string[j]; | ||||
|             binary_string[j] = binary_string[i - j - 1]; | ||||
|             binary_string[i - j - 1] = temp; | ||||
|         } | ||||
|         printf("%s", binary_string); | ||||
|     } | ||||
| 
 | ||||
| // --- print function implementations ---
 | ||||
| 
 | ||||
| void print(const char str[]) { | ||||
|     printf("%s", str); | ||||
| } | ||||
| 
 | ||||
| void print(char c) { | ||||
|     printf("%c", c); | ||||
| } | ||||
| 
 | ||||
| void print(unsigned char b, int base) { | ||||
|     if (base == BIN) { | ||||
|         print_binary(b); | ||||
|     } else if (base == DEC) { | ||||
|         printf("%u", (unsigned int)b); | ||||
|     } else if (base == HEX) { | ||||
|         printf("%x", (unsigned int)b); | ||||
|     } else if (base == OCT) { | ||||
|         printf("%o", (unsigned int)b); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void print(int n, int base) { | ||||
|     if (base == BIN) { | ||||
|         print_binary(n); | ||||
|     } else if (base == DEC) { | ||||
|         printf("%d", n); | ||||
|     } else if (base == HEX) { | ||||
|         printf("%x", n); | ||||
|     } else if (base == OCT) { | ||||
|         printf("%o", n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void print(unsigned int n, int base) { | ||||
|     if (base == BIN) { | ||||
|         print_binary(n); | ||||
|     } else if (base == DEC) { | ||||
|         printf("%u", n); | ||||
|     } else if (base == HEX) { | ||||
|         printf("%x", n); | ||||
|     } else if (base == OCT) { | ||||
|         printf("%o", n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void print(long n, int base) { | ||||
|     if (base == BIN) { | ||||
|         print_binary(n); | ||||
|     } else if (base == DEC) { | ||||
|         printf("%ld", n); | ||||
|     } else if (base == HEX) { | ||||
|         printf("%lx", n); | ||||
|     } else if (base == OCT) { | ||||
|         printf("%lo", n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void print(unsigned long n, int base) { | ||||
|     if (base == BIN) { | ||||
|         print_binary(n); | ||||
|     } else if (base == DEC) { | ||||
|         printf("%lu", n); | ||||
|     } else if (base == HEX) { | ||||
|         printf("%lx", n); | ||||
|     } else if (base == OCT) { | ||||
|         printf("%lo", n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void print(long long n, int base) { | ||||
|     if (base == BIN) { | ||||
|         print_binary(n); | ||||
|     } else if (base == DEC) { | ||||
|         printf("%lld", n); | ||||
|     } else if (base == HEX) { | ||||
|         printf("%llx", n); | ||||
|     } else if (base == OCT) { | ||||
|         printf("%llo", n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void print(unsigned long long n, int base) { | ||||
|     if (base == BIN) { | ||||
|         print_binary(n); | ||||
|     } else if (base == DEC) { | ||||
|         printf("%llu", n); | ||||
|     } else if (base == HEX) { | ||||
|         printf("%llx", n); | ||||
|     } else if (base == OCT) { | ||||
|         printf("%llo", n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void print(double n) { | ||||
|     printf("%f", n); | ||||
| } | ||||
| 
 | ||||
| void println(void) { | ||||
|     printf("\n"); | ||||
| } | ||||
| 
 | ||||
| void println(const char c[]) { | ||||
|     print(c); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(char c) { | ||||
|     print(c); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(unsigned char b, int base) { | ||||
|     print(b, base); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(int num, int base) { | ||||
|     print(num, base); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(unsigned int num, int base) { | ||||
|     print(num, base); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(long num, int base) { | ||||
|     print(num, base); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(unsigned long num, int base) { | ||||
|     print(num, base); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(long long num, int base) { | ||||
|     print(num, base); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(unsigned long long num, int base) { | ||||
|     print(num, base); | ||||
|     println(); | ||||
| } | ||||
| 
 | ||||
| void println(double num) { | ||||
|     print(num); | ||||
|     println(); | ||||
| } | ||||
| #endif // ESP_PLATFORM
 | ||||
|  | ||||
| @ -33,6 +33,28 @@ | ||||
| #elif defined(ARDUINO_ARCH_ESP32) | ||||
|     #include <Arduino.h> | ||||
|     #include <esp_wifi.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|     #include <lwip/inet.h> | ||||
|     #include <driver/gpio.h> | ||||
|     // // Define Arduino-like macros if needed for compatibility
 | ||||
| 
 | ||||
|     #define lowByte(val) ((val)&255) | ||||
|     #define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255) | ||||
|     #define bitRead(val, bitno) (((val) >> (bitno)) & 1) | ||||
|     #define DEC 10 | ||||
|     #define HEX 16 | ||||
|     #define OCT  8 | ||||
|     #define BIN  2 | ||||
|     #define LOW  0 | ||||
|     #define HIGH 1 | ||||
|     #define CHANGE GPIO_INTR_ANYEDGE | ||||
|     #define FALLING GPIO_INTR_NEGEDGE | ||||
|     #define RISING GPIO_INTR_POSEDGE | ||||
|     // Implement or map Arduino-like functions if needed
 | ||||
|     uint32_t millis(); | ||||
|     typedef void (*IsrFuncPtr)(void); // Arduino-style
 | ||||
|     typedef void (*EspIsrFuncPtr)(void*); // ESP-IDF-style
 | ||||
|     void attachInterrupt(uint32_t pin, IsrFuncPtr callback, uint32_t mode); | ||||
| #else // Non-Arduino platforms
 | ||||
|     #define lowByte(val) ((val)&255) | ||||
|     #define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255) | ||||
|  | ||||
| @ -106,6 +106,10 @@ bool KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& dataty | ||||
|         if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10)) | ||||
|             return busValueToDateTime(payload, payload_length, datatype, value); | ||||
| 
 | ||||
|         // DPT 20.* - HVAC Control mode Unsigned 8 Bit Integer
 | ||||
|         if (datatype.mainGroup == 20 && !datatype.index) | ||||
|             return busValueToUnsigned8(payload, payload_length, datatype, value); | ||||
| 
 | ||||
|         // DPT 26.* - Scene Info
 | ||||
|         if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1) | ||||
|             return busValueToSceneInfo(payload, payload_length, datatype, value); | ||||
| @ -267,6 +271,10 @@ bool KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_le | ||||
|     if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10)) | ||||
|         return valueToBusValueDateTime(value, payload, payload_length, datatype); | ||||
| 
 | ||||
|     // DPT 20.* - HVAC Control mode Unsigned 8 Bit Integer
 | ||||
|     if (datatype.mainGroup == 20 && !datatype.index) | ||||
|         return valueToBusValueUnsigned8(value, payload, payload_length, datatype); | ||||
| 
 | ||||
|     // DPT 26.* - Scene Info
 | ||||
|     if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1) | ||||
|         return valueToBusValueSceneInfo(value, payload, payload_length, datatype); | ||||
|  | ||||
| @ -21,7 +21,7 @@ enum ComFlag : uint8_t | ||||
| class GroupObject; | ||||
| 
 | ||||
| #ifndef HAS_FUNCTIONAL | ||||
|     #if defined(__linux__) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_RP2040) | ||||
|     #if defined(__linux__) || defined(ARDUINO_ARCH_ESP32) || defined(ESP_PLATFORM) || defined(ARDUINO_ARCH_STM32) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_RP2040) | ||||
|         #define HAS_FUNCTIONAL    1 | ||||
|     #else | ||||
|         #define HAS_FUNCTIONAL   0 | ||||
|  | ||||
| @ -95,6 +95,18 @@ IRAM_ATTR void buttonEvent() | ||||
|         #error "Mask version not supported on ARDUINO_ARCH_ESP32" | ||||
|     #endif | ||||
| 
 | ||||
| #elif defined(ESP_PLATFORM) | ||||
|     // predefined global instance for TP or IP or TP/IP coupler
 | ||||
|     #if MASK_VERSION == 0x07B0 | ||||
|         KnxFacade<Esp32IdfPlatform, Bau07B0> knx(buttonEvent); | ||||
|     #elif MASK_VERSION == 0x57B0 | ||||
|         KnxFacade<Esp32IdfPlatform, Bau57B0> knx(buttonEvent); | ||||
|     #elif MASK_VERSION == 0x091A | ||||
|         KnxFacade<Esp32IdfPlatform, Bau091A> knx(buttonEvent); | ||||
|     #else | ||||
|         #error "Mask version not supported on ESP_IDF_ESP32" | ||||
|     #endif | ||||
| 
 | ||||
| #elif defined(ARDUINO_ARCH_STM32) | ||||
|     #if MASK_VERSION == 0x07B0 | ||||
|         KnxFacade<Stm32Platform, Bau07B0> knx(buttonEvent); | ||||
|  | ||||
| @ -32,6 +32,11 @@ | ||||
|     #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE | ||||
|         void buttonUp(); | ||||
|     #endif | ||||
| #elif defined(ESP_PLATFORM) | ||||
|     #include "esp32_idf_platform.h" | ||||
|     #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE | ||||
|         void buttonUp(); | ||||
|     #endif | ||||
| #elif defined(ARDUINO_ARCH_STM32) | ||||
|     #include "stm32_platform.h" | ||||
|     #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE | ||||
| @ -260,13 +265,27 @@ template <class P, class B> class KnxFacade : private SaveRestore | ||||
| 
 | ||||
|         void start() | ||||
|         { | ||||
| 
 | ||||
|             if (_ledPin >= 0) | ||||
|             { | ||||
| #if defined(ESP_PLATFORM) | ||||
|                 gpio_reset_pin((gpio_num_t)ledPin()); | ||||
|                 gpio_set_direction((gpio_num_t)ledPin(), GPIO_MODE_OUTPUT); | ||||
| #else | ||||
|                 pinMode(_ledPin, OUTPUT); | ||||
| #endif // ESP_PLATFORM
 | ||||
|             } | ||||
| 
 | ||||
|             progLedOff(); | ||||
| 
 | ||||
|             if(_buttonPin >= 0) | ||||
|             { | ||||
| #if defined(ESP_PLATFORM) | ||||
|                 if (_progButtonISRFuncPtr) | ||||
|                 { | ||||
|                     attachInterrupt(_buttonPin, _progButtonISRFuncPtr, CHANGE); | ||||
|                 } | ||||
| #else | ||||
|                 pinMode(_buttonPin, INPUT_PULLUP); | ||||
| 
 | ||||
|                 if (_progButtonISRFuncPtr) | ||||
| @ -276,8 +295,9 @@ template <class P, class B> class KnxFacade : private SaveRestore | ||||
|                     attachInterrupt(_buttonPin, _progButtonISRFuncPtr, (PinStatus)CHANGE); | ||||
| #else | ||||
|                     attachInterrupt(_buttonPin, _progButtonISRFuncPtr, CHANGE); | ||||
| #endif | ||||
| #endif // ARDUINO_API_VERSION
 | ||||
|                 } | ||||
| #endif // ESP_PLATFORM
 | ||||
|             } | ||||
| 
 | ||||
|             enabled(true); | ||||
| @ -456,7 +476,13 @@ template <class P, class B> class KnxFacade : private SaveRestore | ||||
|         void progLedOn() | ||||
|         { | ||||
|             if (_ledPin >= 0) | ||||
|             { | ||||
| #if defined(ESP_PLATFORM) | ||||
|                 gpio_set_level((gpio_num_t)ledPin(), _ledPinActiveOn); | ||||
| #else | ||||
|                 digitalWrite(_ledPin, _ledPinActiveOn); | ||||
| #endif // ESP_PLATFORM
 | ||||
|             } | ||||
| 
 | ||||
|             if (_progLedOffCallback != 0) | ||||
|                 _progLedOnCallback(); | ||||
| @ -465,7 +491,13 @@ template <class P, class B> class KnxFacade : private SaveRestore | ||||
|         void progLedOff() | ||||
|         { | ||||
|             if (_ledPin >= 0) | ||||
|             { | ||||
| #if defined(ESP_PLATFORM) | ||||
|                 gpio_set_level((gpio_num_t)ledPin(), 1 - _ledPinActiveOn); | ||||
| #else | ||||
|                 digitalWrite(_ledPin, HIGH - _ledPinActiveOn); | ||||
| #endif // ESP_PLATFORM
 | ||||
|             } | ||||
| 
 | ||||
|             if (_progLedOffCallback != 0) | ||||
|                 _progLedOffCallback(); | ||||
| @ -521,6 +553,17 @@ template <class P, class B> class KnxFacade : private SaveRestore | ||||
|         #else | ||||
|             #error "Mask version not supported on ARDUINO_ARCH_ESP32" | ||||
|         #endif | ||||
|     #elif defined(ESP_PLATFORM) | ||||
|         // predefined global instance for TP or IP or TP/IP coupler
 | ||||
|         #if MASK_VERSION == 0x07B0 | ||||
|             extern KnxFacade<Esp32IdfPlatform, Bau07B0> knx; | ||||
|         #elif MASK_VERSION == 0x57B0 | ||||
|             extern KnxFacade<Esp32IdfPlatform, Bau57B0> knx; | ||||
|         #elif MASK_VERSION == 0x091A | ||||
|             extern KnxFacade<Esp32IdfPlatform, Bau091A> knx; | ||||
|         #else | ||||
|             #error "Mask version not supported on ESP_PLATFORM" | ||||
|         #endif | ||||
|     #elif defined(ARDUINO_ARCH_STM32) | ||||
|         // predefined global instance for TP only
 | ||||
|         #if MASK_VERSION == 0x07B0 | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| #ifdef ARDUINO | ||||
| #pragma once | ||||
| 
 | ||||
| #include "arduino_platform.h" | ||||
| @ -153,3 +154,4 @@ class RP2040ArduinoPlatform : public ArduinoPlatform | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| #endif // ARDUINO
 | ||||
| @ -1,3 +1,4 @@ | ||||
| #ifdef ARDUINO | ||||
| #include "arduino_platform.h" | ||||
| 
 | ||||
| #include "Arduino.h" | ||||
| @ -53,3 +54,4 @@ class SamdPlatform : public ArduinoPlatform | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| #endif // ARDUINO
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user