/* * This program source code file is part of the KTag project. * * 🛡️ 🃞 * * Copyright © 2025 Joseph P. Kearney and the KTag developers. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * There should be a copy of the GNU Affero General Public License in the LICENSE * file in the root of this repository. If not, see . */ #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" #include "esp_wifi.h" #include "esp_mac.h" #include "esp_event.h" #include "esp_now.h" // #include "nvs_flash.h" static const char *TAG = "ESP-NOW"; // Broadcast address (all 0xFF sends to all devices) static uint8_t Broadcast_MAC[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // Structure for the data to send typedef struct { uint32_t counter; char message[32]; } broadcast_data_t; // ESP-NOW receive callback static void ESPNOW_Recv_CB(const esp_now_recv_info_t *recv_info, const uint8_t *data, int len) { if (recv_info == NULL || data == NULL || len <= 0) { KLOG_ERROR(TAG, "Receive callback error"); return; } // Log sender MAC address KLOG_INFO(TAG, "Received from: " MACSTR ", RSSI: %d", MAC2STR(recv_info->src_addr), recv_info->rx_ctrl->rssi); // Parse received data if (len == sizeof(broadcast_data_t)) { broadcast_data_t *recv_data = (broadcast_data_t *)data; KLOG_INFO(TAG, "Counter: %lu, Message: %s", recv_data->counter, recv_data->message); } else { KLOG_WARN(TAG, "Unexpected data length: %d", len); } } // ESP-NOW send callback static void ESPNOW_Send_CB(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) { if (tx_info == NULL) { KLOG_ERROR(TAG, "Send callback error: tx_info is NULL"); return; } if (status == ESP_NOW_SEND_SUCCESS) { KLOG_INFO(TAG, "Send success to " MACSTR, MAC2STR(tx_info->des_addr)); } else { KLOG_WARN(TAG, "Send failed to " MACSTR, MAC2STR(tx_info->des_addr)); } } static esp_err_t Initialize_ESPNOW(void) { esp_err_t ret = esp_now_init(); if (ret != ESP_OK) { KLOG_ERROR(TAG, "ESP-NOW init failed: %s", esp_err_to_name(ret)); return ret; } // Register send and receive callbacks esp_now_register_send_cb(ESPNOW_Send_CB); esp_now_register_recv_cb(ESPNOW_Recv_CB); // Add broadcast peer esp_now_peer_info_t peer_info = {}; memcpy(peer_info.peer_addr, Broadcast_MAC, ESP_NOW_ETH_ALEN); peer_info.channel = 0; // Use current channel peer_info.ifidx = WIFI_IF_STA; peer_info.encrypt = false; ret = esp_now_add_peer(&peer_info); if (ret != ESP_OK) { KLOG_ERROR(TAG, "Failed to add broadcast peer: %s", esp_err_to_name(ret)); return ret; } KLOG_INFO(TAG, "ESP-NOW initialized successfully"); return ESP_OK; } // FreeRTOS task for periodic broadcast static void ESPNOW_Task(void *pvParameters) { broadcast_data_t data = {0}; TickType_t last_wake = xTaskGetTickCount(); const TickType_t period = pdMS_TO_TICKS(2000); KLOG_INFO(TAG, "ESP-NOW task started"); while (1) { // Update data data.counter++; snprintf(data.message, sizeof(data.message), "Broadcast #%lu", data.counter); // Send broadcast esp_err_t ret = esp_now_send(Broadcast_MAC, (uint8_t *)&data, sizeof(data)); if (ret != ESP_OK) { KLOG_ERROR(TAG, "Send error: %s", esp_err_to_name(ret)); } // Wait for next period vTaskDelayUntil(&last_wake, period); } } static void Initialize_WiFi(void) { ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); KLOG_INFO(TAG, "WiFi initialized in station mode"); } void Initialize_ESP_NOW(void) { Initialize_WiFi(); // Initialize ESP-NOW if (Initialize_ESPNOW() != ESP_OK) { KLOG_ERROR(TAG, "ESP-NOW initialization failed"); return; } // Enable Long Range mode esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR); esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_LR); // Create broadcast task xTaskCreate(ESPNOW_Task, "ESP-NOW", 4096, NULL, 5, NULL); }