500 lines
18 KiB
C
500 lines
18 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/event_groups.h"
|
|
#include "freertos/task.h"
|
|
|
|
#include "esp_wifi.h"
|
|
#include "esp_sleep.h"
|
|
#include "esp_now.h"
|
|
#include "esp_log.h"
|
|
|
|
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
|
|
#include "esp_mac.h"
|
|
#include "esp_random.h"
|
|
#else
|
|
#include "esp_system.h"
|
|
#endif
|
|
|
|
#include "esp_event_base.h"
|
|
|
|
#include "espnow.h"
|
|
#include "espnow_ctrl.h"
|
|
#include "espnow_mem.h"
|
|
#include "espnow_storage.h"
|
|
#include "espnow_utils.h"
|
|
|
|
#define ESPNOW_BIND_LIST_MAX_SIZE 32
|
|
|
|
extern wifi_country_t g_self_country;
|
|
typedef struct {
|
|
int8_t rssi;
|
|
uint32_t timestamp;
|
|
espnow_ctrl_bind_cb_t cb;
|
|
espnow_ctrl_data_cb_t data_cb;
|
|
espnow_ctrl_data_raw_cb_t data_raw_cb;
|
|
size_t size;
|
|
espnow_ctrl_bind_info_t data[ESPNOW_BIND_LIST_MAX_SIZE];
|
|
} espnow_bindlist_t;
|
|
|
|
static const char *TAG = "espnow_ctrl";
|
|
static espnow_bindlist_t g_bindlist = {0};
|
|
|
|
#ifdef CONFIG_ESPNOW_ALL_SECURITY
|
|
#define CONFIG_ESPNOW_CONTROL_SECURITY 1
|
|
#else
|
|
#ifndef CONFIG_ESPNOW_CONTROL_SECURITY
|
|
#define CONFIG_ESPNOW_CONTROL_SECURITY 0
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_SENDING
|
|
#define ESPNOW_CHANNEL_KEY "ch_key"
|
|
#define RESEND_SCAN_COUNT_MAX (sizeof(scan_channel_sequence) * 2)
|
|
|
|
#ifndef CONFIG_ESPNOW_VERSION
|
|
#define ESPNOW_VERSION 2
|
|
#else
|
|
#define ESPNOW_VERSION CONFIG_ESPNOW_VERSION
|
|
#endif
|
|
|
|
static SemaphoreHandle_t g_bind_sem = NULL;
|
|
|
|
typedef struct {
|
|
uint8_t type : 4;
|
|
uint8_t version : 2;
|
|
uint8_t : 2;
|
|
uint8_t size;
|
|
espnow_frame_head_t frame_head;
|
|
uint8_t dest_addr[6];
|
|
uint8_t src_addr[6];
|
|
uint8_t payload[0];
|
|
} __attribute__((packed)) espnow_forward_data_t;
|
|
#else
|
|
static const espnow_frame_head_t g_initiator_frame = {
|
|
.retransmit_count = 0,
|
|
.broadcast = true,
|
|
.channel = ESPNOW_CHANNEL_CURRENT,
|
|
.forward_ttl = 0,
|
|
.forward_rssi = -25,
|
|
.security = CONFIG_ESPNOW_CONTROL_SECURITY,
|
|
};
|
|
#endif
|
|
|
|
static bool espnow_ctrl_responder_is_bindlist(const uint8_t *mac, espnow_attribute_t initiator_attribute)
|
|
{
|
|
for (int i = 0; i < g_bindlist.size; ++i) {
|
|
if (!memcmp(g_bindlist.data[i].mac, mac, 6)
|
|
&& g_bindlist.data[i].initiator_attribute == initiator_attribute) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_responder_get_bindlist(espnow_ctrl_bind_info_t *list, size_t *size)
|
|
{
|
|
if (!list) {
|
|
*size = g_bindlist.size;
|
|
} else {
|
|
*size = MIN(g_bindlist.size, *size);
|
|
memcpy(list, g_bindlist.data, sizeof(espnow_ctrl_bind_info_t) * (*size));
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_responder_set_bindlist(const espnow_ctrl_bind_info_t *info)
|
|
{
|
|
if (!espnow_ctrl_responder_is_bindlist(info->mac, info->initiator_attribute)) {
|
|
memcpy(g_bindlist.data + g_bindlist.size, info, sizeof(espnow_ctrl_bind_info_t));
|
|
g_bindlist.size++;
|
|
espnow_storage_set("bindlist", &g_bindlist, sizeof(g_bindlist));
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_responder_remove_bindlist(const espnow_ctrl_bind_info_t *info)
|
|
{
|
|
for (int i = 0; i < g_bindlist.size; ++i) {
|
|
if (!memcmp(g_bindlist.data + i, info, sizeof(espnow_ctrl_bind_info_t))) {
|
|
g_bindlist.size--;
|
|
|
|
if (g_bindlist.size > 0) {
|
|
g_bindlist.data[g_bindlist.size].initiator_attribute = info->initiator_attribute;
|
|
memcpy(g_bindlist.data[g_bindlist.size].mac, info->mac, 6);
|
|
}
|
|
|
|
espnow_storage_set("bindlist", &g_bindlist, sizeof(g_bindlist));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_FORWARD
|
|
static esp_err_t espnow_ctrl_responder_forward(uint8_t type, uint8_t *src_addr, const void *data, size_t size, wifi_pkt_rx_ctrl_t *rx_ctrl)
|
|
{
|
|
uint8_t primary = 0;
|
|
wifi_second_chan_t second = 0;
|
|
int retransmit_count = 0;
|
|
espnow_ctrl_data_t *ctrl_data = (espnow_ctrl_data_t *)data;
|
|
espnow_forward_data_t *espnow_data = ESP_MALLOC(sizeof(espnow_forward_data_t) + size);
|
|
|
|
espnow_data->type = type;
|
|
espnow_data->version = ESPNOW_VERSION;
|
|
espnow_data->size = size;
|
|
memcpy(&espnow_data->frame_head, &ctrl_data->frame_head, sizeof(espnow_frame_head_t));
|
|
memcpy(espnow_data->dest_addr, ESPNOW_ADDR_BROADCAST, 6);
|
|
memcpy(espnow_data->src_addr, src_addr, 6);
|
|
memcpy(espnow_data->payload, data, size);
|
|
|
|
esp_wifi_get_channel(&primary, &second);
|
|
while (retransmit_count < g_self_country.nchan) {
|
|
esp_wifi_set_channel(g_self_country.schan + retransmit_count, WIFI_SECOND_CHAN_NONE);
|
|
esp_now_send(ESPNOW_ADDR_BROADCAST, (uint8_t *)espnow_data, espnow_data->size + sizeof(espnow_forward_data_t));
|
|
retransmit_count++;
|
|
}
|
|
esp_wifi_set_channel(primary, second);
|
|
|
|
return ESP_OK;
|
|
}
|
|
#endif
|
|
|
|
static esp_err_t espnow_ctrl_responder_bind_process(uint8_t *src_addr, void *data,
|
|
size_t size, wifi_pkt_rx_ctrl_t *rx_ctrl)
|
|
{
|
|
ESP_PARAM_CHECK(src_addr);
|
|
ESP_PARAM_CHECK(data);
|
|
ESP_PARAM_CHECK(size);
|
|
ESP_PARAM_CHECK(rx_ctrl);
|
|
|
|
espnow_ctrl_data_t *ctrl_data = (espnow_ctrl_data_t *)data;
|
|
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_SENDING
|
|
if (ctrl_data->frame_head.ack) {
|
|
espnow_send(ESPNOW_DATA_TYPE_ACK, ESPNOW_ADDR_BROADCAST, &ctrl_data->frame_head, sizeof(ctrl_data->frame_head), &ctrl_data->frame_head, pdMS_TO_TICKS(100));
|
|
}
|
|
#endif
|
|
|
|
if (ctrl_data->responder_value_b) {
|
|
ESP_LOGI(TAG, "bind, esp_log_timestamp: %d, timestamp: %d, rssi: %d, rssi: %d",
|
|
esp_log_timestamp(), g_bindlist.timestamp, rx_ctrl->rssi, g_bindlist.rssi);
|
|
|
|
bool bind_cb_flag = false;
|
|
|
|
if (g_bindlist.cb) {
|
|
bind_cb_flag = g_bindlist.cb(ctrl_data->initiator_attribute, src_addr, rx_ctrl->rssi);
|
|
} else {
|
|
bind_cb_flag = true;
|
|
}
|
|
|
|
if (bind_cb_flag && esp_log_timestamp() < g_bindlist.timestamp && rx_ctrl->rssi > g_bindlist.rssi) {
|
|
ESP_LOGI("control_func", "addr: "MACSTR", initiator_type: %d, initiator_value: %d",
|
|
MAC2STR(src_addr), ctrl_data->initiator_attribute >> 8, ctrl_data->initiator_attribute & 0xff);
|
|
|
|
if (!espnow_ctrl_responder_is_bindlist(src_addr, ctrl_data->initiator_attribute)) {
|
|
g_bindlist.data[g_bindlist.size].initiator_attribute = ctrl_data->initiator_attribute;
|
|
memcpy(g_bindlist.data[g_bindlist.size].mac, src_addr, 6);
|
|
|
|
esp_event_post(ESP_EVENT_ESPNOW, ESP_EVENT_ESPNOW_CTRL_BIND,
|
|
g_bindlist.data + g_bindlist.size, sizeof(espnow_ctrl_bind_info_t), 0);
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_SENDING
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
#endif
|
|
g_bindlist.size++;
|
|
espnow_storage_set("bindlist", &g_bindlist, sizeof(g_bindlist));
|
|
}
|
|
}
|
|
} else {
|
|
for (int i = 0; i < g_bindlist.size; ++i) {
|
|
if (!memcmp(g_bindlist.data[i].mac, src_addr, 6)
|
|
&& g_bindlist.data[i].initiator_attribute == ctrl_data->initiator_attribute) {
|
|
esp_event_post(ESP_EVENT_ESPNOW, ESP_EVENT_ESPNOW_CTRL_UNBIND,
|
|
g_bindlist.data + i, sizeof(espnow_ctrl_bind_info_t), 0);
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_SENDING
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
#endif
|
|
|
|
g_bindlist.size--;
|
|
|
|
for (int j = i; j < g_bindlist.size; j++) {
|
|
g_bindlist.data[j].initiator_attribute = g_bindlist.data[j + 1].initiator_attribute;
|
|
memcpy(g_bindlist.data[j].mac, g_bindlist.data[j + 1].mac, 6);
|
|
}
|
|
g_bindlist.data[g_bindlist.size].initiator_attribute = 0;
|
|
memset(g_bindlist.data[g_bindlist.size].mac, 0, 6);
|
|
|
|
espnow_storage_set("bindlist", &g_bindlist, sizeof(g_bindlist));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_FORWARD
|
|
espnow_ctrl_responder_forward(ESPNOW_DATA_TYPE_CONTROL_BIND, src_addr, data, size, rx_ctrl);
|
|
#endif
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_responder_bind(uint32_t wait_ms, int8_t rssi, espnow_ctrl_bind_cb_t cb)
|
|
{
|
|
espnow_storage_get("bindlist", &g_bindlist, sizeof(g_bindlist));
|
|
|
|
g_bindlist.cb = cb;
|
|
g_bindlist.timestamp = esp_log_timestamp() + wait_ms;
|
|
g_bindlist.rssi = rssi;
|
|
|
|
espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_CONTROL_BIND, true, espnow_ctrl_responder_bind_process);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t espnow_ctrl_responder_data_process(uint8_t *src_addr, void *data,
|
|
size_t size, wifi_pkt_rx_ctrl_t *rx_ctrl)
|
|
{
|
|
ESP_PARAM_CHECK(src_addr);
|
|
ESP_PARAM_CHECK(data);
|
|
ESP_PARAM_CHECK(size);
|
|
ESP_PARAM_CHECK(rx_ctrl);
|
|
|
|
espnow_ctrl_data_t *ctrl_data = (espnow_ctrl_data_t *)data;
|
|
ESP_LOGD(TAG, "src_addr: "MACSTR", espnow_ctrl_responder_recv, value: s1 = %d, s2 = %d, lx = %d, ly = %d, rx = %d, ry = %d",
|
|
MAC2STR(src_addr), ctrl_data->responder_value_i, ctrl_data->status_value_i, ctrl_data->left_x_value_i,
|
|
ctrl_data->left_y_value_i, ctrl_data->right_x_value_i, ctrl_data->right_y_value_i,
|
|
ctrl_data->channel_one_value_i, ctrl_data->channel_two_value_i);
|
|
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_SENDING
|
|
if (ctrl_data->frame_head.ack) {
|
|
espnow_send(ESPNOW_DATA_TYPE_ACK, ESPNOW_ADDR_BROADCAST, &ctrl_data->frame_head, sizeof(ctrl_data->frame_head), &ctrl_data->frame_head, pdMS_TO_TICKS(100));
|
|
}
|
|
#endif
|
|
|
|
if (espnow_ctrl_responder_is_bindlist(src_addr, ctrl_data->initiator_attribute)) {
|
|
if (g_bindlist.data_cb) {
|
|
g_bindlist.data_cb(ctrl_data->initiator_attribute, ctrl_data->responder_attribute, ctrl_data->responder_value_i,
|
|
ctrl_data->status_value_i,
|
|
ctrl_data->left_x_value_i, ctrl_data->left_y_value_i,
|
|
ctrl_data->right_x_value_i, ctrl_data->right_y_value_i,
|
|
ctrl_data->channel_one_value_i, ctrl_data->channel_two_value_i);
|
|
}
|
|
|
|
if (g_bindlist.data_raw_cb) {
|
|
g_bindlist.data_raw_cb(src_addr, ctrl_data, rx_ctrl);
|
|
}
|
|
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_FORWARD
|
|
espnow_ctrl_responder_forward(ESPNOW_DATA_TYPE_CONTROL_DATA, src_addr, data, size, rx_ctrl);
|
|
#endif
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_responder_data(espnow_ctrl_data_cb_t cb)
|
|
{
|
|
g_bindlist.data_cb = cb;
|
|
espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_CONTROL_DATA, 1, espnow_ctrl_responder_data_process);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
#ifdef CONFIG_ESPNOW_CONTROL_AUTO_CHANNEL_SENDING
|
|
static esp_err_t espnow_ctrl_initiator_ack(uint8_t *src_addr, void *data,
|
|
size_t size, wifi_pkt_rx_ctrl_t *rx_ctrl)
|
|
{
|
|
espnow_frame_head_t *frame_head = (espnow_frame_head_t *)data;
|
|
|
|
uint8_t channel = frame_head ? frame_head->channel : 1;
|
|
|
|
ESP_LOGI(TAG, "src_addr: "MACSTR", %s, channel: %d", MAC2STR(src_addr), __func__, channel);
|
|
|
|
espnow_storage_set(ESPNOW_CHANNEL_KEY, &channel, sizeof(channel));
|
|
|
|
if (g_bind_sem) {
|
|
xSemaphoreGive(g_bind_sem);
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t espnow_ctrl_initiator_handle(espnow_data_type_t type, espnow_attribute_t initiator_attribute, espnow_attribute_t responder_attribute, uint32_t responder_value)
|
|
{
|
|
esp_err_t ret = ESP_OK;
|
|
|
|
g_bind_sem = xSemaphoreCreateBinary();
|
|
if (!g_bind_sem) {
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
BaseType_t bind_sem_ret = pdFAIL;
|
|
int retransmit_count = 0;
|
|
uint8_t channel = 1;
|
|
espnow_storage_get(ESPNOW_CHANNEL_KEY, &channel, sizeof(channel));
|
|
espnow_ctrl_data_t data = {
|
|
.frame_head = {
|
|
.broadcast = true,
|
|
.forward_ttl = CONFIG_ESPNOW_CONTROL_FORWARD_TTL,
|
|
.forward_rssi = CONFIG_ESPNOW_CONTROL_FORWARD_RSSI,
|
|
.magic = esp_random(),
|
|
.ack = true,
|
|
.channel = channel,
|
|
.security = CONFIG_ESPNOW_CONTROL_SECURITY,
|
|
},
|
|
.initiator_attribute = initiator_attribute,
|
|
.responder_attribute = responder_attribute,
|
|
.responder_value_i = responder_value
|
|
};
|
|
espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_ACK, true, espnow_ctrl_initiator_ack);
|
|
|
|
do {
|
|
espnow_send(type, ESPNOW_ADDR_BROADCAST, &data, sizeof(espnow_ctrl_data_t), &data.frame_head, portMAX_DELAY);
|
|
bind_sem_ret = xSemaphoreTake(g_bind_sem, pdMS_TO_TICKS(CONFIG_ESPNOW_CONTROL_WAIT_ACK_DURATION));
|
|
|
|
if (bind_sem_ret == pdPASS) {
|
|
break;
|
|
}
|
|
#ifdef CONFIG_ESPNOW_LIGHT_SLEEP
|
|
esp_sleep_enable_timer_wakeup(CONFIG_ESPNOW_LIGHT_SLEEP_DURATION * 1000);
|
|
esp_light_sleep_start();
|
|
#endif
|
|
} while (retransmit_count ++ < CONFIG_ESPNOW_CONTROL_RETRANSMISSION_TIMES);
|
|
|
|
if (bind_sem_ret != pdPASS) {
|
|
for (int i = 0; i < g_self_country.nchan; i++) {
|
|
if (g_self_country.schan + i == channel) {
|
|
continue;
|
|
}
|
|
data.frame_head.channel = g_self_country.schan + i;
|
|
retransmit_count = 0;
|
|
do {
|
|
espnow_send(type, ESPNOW_ADDR_BROADCAST, &data, sizeof(espnow_ctrl_data_t), &data.frame_head, portMAX_DELAY);
|
|
bind_sem_ret = xSemaphoreTake(g_bind_sem, pdMS_TO_TICKS(CONFIG_ESPNOW_CONTROL_WAIT_ACK_DURATION));
|
|
if (bind_sem_ret == pdPASS) {
|
|
ret = ESP_OK;
|
|
break;
|
|
} else {
|
|
ret = ESP_FAIL;
|
|
}
|
|
#ifdef CONFIG_ESPNOW_LIGHT_SLEEP
|
|
if (retransmit_count < CONFIG_ESPNOW_CONTROL_RETRANSMISSION_TIMES || (i < g_self_country.nchan - 1 &&
|
|
// !(Second last channel, however last channel is the saved channel)
|
|
!(i == g_self_country.nchan - 2 && g_self_country.schan + i + 1 == channel))) {
|
|
esp_sleep_enable_timer_wakeup(CONFIG_ESPNOW_LIGHT_SLEEP_DURATION * 1000);
|
|
esp_light_sleep_start();
|
|
}
|
|
#endif
|
|
} while (retransmit_count ++ < CONFIG_ESPNOW_CONTROL_RETRANSMISSION_TIMES);
|
|
if (ret == ESP_OK) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
vSemaphoreDelete(g_bind_sem);
|
|
g_bind_sem = NULL;
|
|
|
|
ESP_ERROR_RETURN(ret != ESP_OK, ret, "espnow_broadcast, ret: %d", ret);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_initiator_bind(espnow_attribute_t initiator_attribute, bool enable)
|
|
{
|
|
return espnow_ctrl_initiator_handle(ESPNOW_DATA_TYPE_CONTROL_BIND, initiator_attribute, ESPNOW_ATTRIBUTE_BASE, enable);
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_initiator_send(espnow_attribute_t initiator_attribute,
|
|
espnow_attribute_t responder_attribute,
|
|
uint32_t responder_value)
|
|
{
|
|
return espnow_ctrl_initiator_handle(ESPNOW_DATA_TYPE_CONTROL_DATA, initiator_attribute, responder_attribute, responder_value);
|
|
}
|
|
#else
|
|
esp_err_t espnow_ctrl_initiator_bind(espnow_attribute_t initiator_attribute, bool enable)
|
|
{
|
|
esp_err_t ret = ESP_OK;
|
|
espnow_ctrl_data_t data = {
|
|
.initiator_attribute = initiator_attribute,
|
|
.responder_value_i = enable,
|
|
};
|
|
|
|
espnow_frame_head_t frame_head = {0};
|
|
memcpy(&frame_head, &g_initiator_frame, sizeof(espnow_frame_head_t));
|
|
frame_head.forward_ttl = 0;
|
|
|
|
ret = espnow_send(ESPNOW_DATA_TYPE_CONTROL_BIND, ESPNOW_ADDR_BROADCAST, &data,
|
|
sizeof(espnow_ctrl_data_t), &frame_head, portMAX_DELAY);
|
|
ESP_ERROR_RETURN(ret != ESP_OK, ret, "espnow_send");
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_initiator_send(espnow_attribute_t initiator_attribute,
|
|
espnow_attribute_t responder_attribute,
|
|
uint32_t responder_value,
|
|
int status,
|
|
int lx_value,
|
|
int ly_value,
|
|
int rx_value,
|
|
int ry_value,
|
|
int channel_one_value,
|
|
int channel_two_value)
|
|
{
|
|
esp_err_t ret = ESP_OK;
|
|
espnow_ctrl_data_t data = {
|
|
.initiator_attribute = initiator_attribute,
|
|
.responder_attribute = responder_attribute,
|
|
.responder_value_i = responder_value,
|
|
.status_value_i = status,
|
|
.left_x_value_i = lx_value,
|
|
.left_y_value_i = ly_value,
|
|
.right_x_value_i = rx_value,
|
|
.right_y_value_i = ry_value,
|
|
.channel_one_value_i = channel_one_value,
|
|
.channel_two_value_i = channel_two_value,
|
|
};
|
|
|
|
ret = espnow_send(ESPNOW_DATA_TYPE_CONTROL_DATA, ESPNOW_ADDR_BROADCAST, &data,
|
|
sizeof(espnow_ctrl_data_t), &g_initiator_frame, pdMS_TO_TICKS(1000));
|
|
ESP_ERROR_RETURN(ret != ESP_OK, ret, "espnow_broadcast, ret: %d", ret);
|
|
|
|
return ESP_OK;
|
|
}
|
|
#endif
|
|
|
|
esp_err_t espnow_ctrl_send(const espnow_addr_t dest_addr, const espnow_ctrl_data_t *data, const espnow_frame_head_t *frame_head, TickType_t wait_ticks)
|
|
{
|
|
ESP_PARAM_CHECK(dest_addr);
|
|
ESP_PARAM_CHECK(data);
|
|
ESP_PARAM_CHECK(frame_head);
|
|
|
|
uint8_t size = (!data->responder_value_s_flag && data->responder_value_s_size) ? data->responder_value_s_size : 0;
|
|
|
|
esp_err_t ret = espnow_send(ESPNOW_DATA_TYPE_CONTROL_DATA, ESPNOW_ADDR_BROADCAST, data,
|
|
sizeof(espnow_ctrl_data_t) + size, frame_head, wait_ticks);
|
|
ESP_ERROR_RETURN(ret != ESP_OK, ret, "espnow_broadcast, ret: %d", ret);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t espnow_ctrl_recv(espnow_ctrl_data_raw_cb_t cb)
|
|
{
|
|
g_bindlist.data_raw_cb = cb;
|
|
espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_CONTROL_DATA, 1, espnow_ctrl_responder_data_process);
|
|
|
|
return ESP_OK;
|
|
}
|