Compare commits

...
8 Commits
Author SHA1 Message Date
skruecken 669f1c255d FIXED render test mermaid in readme 2024-12-27 15:07:37 +01:00
skruecken 95881426f4 Render Graph in README Test 2024-12-27 15:06:22 +01:00
skruecken c4ae453af7 Added UART and PingPong function 2024-11-26 22:03:48 +01:00
skruecken e618b2510a Added espnow_handler.c to CMakeList 2024-10-04 16:12:57 +02:00
skruecken 44cd594d96 Refactored in multiple files.
- isMaster variable should not be set like this but now it is working
- TODO: Rework it in a modular way!
- shared.h is not very pretty but works that way
- There should be a universal logger with the tag
2024-10-04 16:11:16 +02:00
skruecken b6fbe05312 Added Switch Case on recive site for payload pagination 2024-10-04 14:38:07 +02:00
skruecken 7f1369f1cf Added Pagianation for Sending Payload
- Cut of 1 Byte for Pagination
- Now we can send 256 Datapackages without chaning any logic from
  sending and receiving
- We have 250 Bytes from ESP NOW
- We use 10 Byte for Meta Data, 1 for Pagination
- We have 239 Bytes for Real Payload
2024-10-04 14:26:00 +02:00
skruecken 6d383e43b4 Some Cleanup removed the example prefix from functions and structs 2024-10-04 13:11:54 +02:00
7 changed files with 582 additions and 441 deletions
+10
View File
@@ -30,3 +30,13 @@ Below is short explanation of remaining files in the project folder.
``` ```
Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system. Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system.
They are not used or needed when building with CMake and idf.py. They are not used or needed when building with CMake and idf.py.
# Example Render Test
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
+2 -2
View File
@@ -1,3 +1,3 @@
idf_component_register(SRCS "main.c" idf_component_register(SRCS "main.c" "espnow_handler.c"
INCLUDE_DIRS "." INCLUDE_DIRS "."
) )
+414
View File
@@ -0,0 +1,414 @@
#include "FreeRTOSConfig.h"
#include "driver/gpio.h"
#include "esp_crc.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "esp_netif.h"
#include "esp_now.h"
#include "esp_random.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "hal/gpio_types.h"
#include "nvs_flash.h"
#include "portmacro.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "espnow_handler.h"
#define ESPNOW_WIFI_MODE WIFI_MODE_AP
#define ESPNOW_WIFI_IF ESP_IF_WIFI_AP
#define ESPNOW_MAXDELAY 512
// default CONFIG values from menuconfig
#define CONFIG_ESPNOW_CHANNEL 1
#define CONFIG_ESPNOW_PMK "pmk1234567890123"
#define CONFIG_ESPNOW_SEND_COUNT 100
#define CONFIG_ESPNOW_SEND_DELAY 1000
#define CONFIG_ESPNOW_SEND_LEN 250
#define CONFIG_ESPNOW_LMK "lmk1234567890123"
static QueueHandle_t s_espnow_queue;
static uint8_t s_broadcast_mac[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF};
static uint16_t s_espnow_seq[2] = {0, 0};
void setIsMaster(bool status) { isMaster = status; }
void wifi_init(void) {
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
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(ESPNOW_WIFI_MODE));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(
esp_wifi_set_channel(CONFIG_ESPNOW_CHANNEL, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_wifi_set_protocol(
ESPNOW_WIFI_IF, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G |
WIFI_PROTOCOL_11N | WIFI_PROTOCOL_LR));
}
void espnow_deinit(espnow_send_param_t *send_param) {
free(send_param->buffer);
free(send_param);
vSemaphoreDelete(s_espnow_queue);
esp_now_deinit();
}
void espnow_data_prepare(espnow_send_param_t *send_param) {
espnow_data_t *buf = (espnow_data_t *)send_param->buffer;
ESP_LOGI(tag, "Example_Data_SIZE: %u, send_param_len: %d\n",
sizeof(espnow_data_t), send_param->len);
assert(send_param->len >= sizeof(espnow_data_t));
buf->type = IS_BROADCAST_ADDR(send_param->dest_mac)
? EXAMPLE_ESPNOW_DATA_BROADCAST
: EXAMPLE_ESPNOW_DATA_UNICAST;
buf->state = send_param->state;
buf->seq_num = 0; // s_espnow_seq[buf->type]++;
buf->crc = 0;
buf->magic = send_param->magic;
buf->unionPage = UNION_PING_PONG;
buf->realPayload.pingPongData.startCounter = xTaskGetTickCount();
buf->crc = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len);
}
void espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) {
espnow_event_t evt;
espnow_event_send_cb_t *send_cb = &evt.info.send_cb;
if (mac_addr == NULL) {
ESP_LOGE(tag, "Send cb arg error");
return;
}
evt.id = EXAMPLE_ESPNOW_SEND_CB;
memcpy(send_cb->mac_addr, mac_addr, ESP_NOW_ETH_ALEN);
send_cb->status = status;
if (xQueueSend(s_espnow_queue, &evt, ESPNOW_MAXDELAY) != pdTRUE) {
ESP_LOGW(tag, "Send send queue fail");
}
}
void espnow_recv_cb(const esp_now_recv_info_t *recv_info, const uint8_t *data,
int len) {
espnow_event_t evt;
espnow_event_recv_cb_t *recv_cb = &evt.info.recv_cb;
uint8_t *mac_addr = recv_info->src_addr;
uint8_t *des_addr = recv_info->des_addr;
if (mac_addr == NULL || data == NULL || len <= 0) {
ESP_LOGE(tag, "Receive cb arg error");
return;
}
if (IS_BROADCAST_ADDR(des_addr)) {
/* If added a peer with encryption before, the receive packets may be
* encrypted as peer-to-peer message or unencrypted over the broadcast
* channel. Users can check the destination address to distinguish it.
*/
ESP_LOGD(tag, "Receive broadcast ESPNOW data");
} else {
ESP_LOGD(tag, "Receive unicast ESPNOW data");
}
evt.id = EXAMPLE_ESPNOW_RECV_CB;
memcpy(recv_cb->mac_addr, mac_addr, ESP_NOW_ETH_ALEN);
recv_cb->data = malloc(len);
if (recv_cb->data == NULL) {
ESP_LOGE(tag, "Malloc receive data fail");
return;
}
memcpy(recv_cb->data, data, len);
recv_cb->data_len = len;
if (xQueueSend(s_espnow_queue, &evt, ESPNOW_MAXDELAY) != pdTRUE) {
ESP_LOGW(tag, "Send receive queue fail");
free(recv_cb->data);
}
}
int espnow_data_parse(uint8_t *data, uint16_t data_len, uint8_t *state,
uint16_t *seq, uint32_t *magic,
espnow_event_recv_cb_t *recv_cb) {
espnow_data_t *buf = (espnow_data_t *)data;
uint16_t crc, crc_cal = 0;
if (data_len < sizeof(espnow_data_t)) {
ESP_LOGE(tag, "Receive ESPNOW data too short, len:%d", data_len);
return -1;
}
*state = buf->state;
*seq = buf->seq_num;
*magic = buf->magic;
crc = buf->crc;
buf->crc = 0;
crc_cal = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len);
switch (buf->unionPage) {
case UNION_STATUS:
if (buf->realPayload.status.isMaster) {
ESP_LOGI(tag, "Recived Data from Master");
} else {
ESP_LOGI(tag, "Recived Data from Slave");
}
break;
case UNION_SENSORDATA:
ESP_LOGI(tag, "Yeah Daten %d", buf->realPayload.sensorData.dataPoint);
break;
case UNION_PING_PONG:
if (isMaster) {
uint endCounter = xTaskGetTickCount();
uint diffCounter =
endCounter - buf->realPayload.pingPongData.startCounter;
ESP_LOGI(tag, "Start: %d, End: %d, Diff: %d, Ping: %d",
buf->realPayload.pingPongData.startCounter, endCounter,
diffCounter, diffCounter / configTICK_RATE_HZ);
} else {
ESP_LOGI(tag, "Got Ping request sending back startCounter %d",
buf->realPayload.pingPongData.startCounter);
if (esp_now_send(recv_cb->mac_addr, recv_cb->data, recv_cb->data_len) !=
ESP_OK) {
ESP_LOGE(tag, "Send error PingPong");
}
// todo send back data
}
break;
case UNION_TEST:
ESP_LOGI(tag, "Unit Testing!!!");
break;
}
if (crc_cal == crc) {
return buf->type;
}
return -1;
}
esp_err_t espnow_init(void) {
espnow_send_param_t *send_param;
s_espnow_queue = xQueueCreate(ESPNOW_QUEUE_SIZE, sizeof(espnow_event_t));
if (s_espnow_queue == NULL) {
ESP_LOGE(tag, "Create mutex fail");
return ESP_FAIL;
}
/* Initialize ESPNOW and register sending and receiving callback function. */
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_send_cb(espnow_send_cb));
ESP_ERROR_CHECK(esp_now_register_recv_cb(espnow_recv_cb));
#if CONFIG_ESPNOW_ENABLE_POWER_SAVE
ESP_ERROR_CHECK(esp_now_set_wake_window(CONFIG_ESPNOW_WAKE_WINDOW));
ESP_ERROR_CHECK(esp_wifi_connectionless_module_set_wake_interval(
CONFIG_ESPNOW_WAKE_INTERVAL));
#endif
/* Set primary master key. */
ESP_ERROR_CHECK(esp_now_set_pmk((uint8_t *)CONFIG_ESPNOW_PMK));
/* Add broadcast peer information to peer list. */
esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));
if (peer == NULL) {
ESP_LOGE(tag, "Malloc peer information fail");
vSemaphoreDelete(s_espnow_queue);
esp_now_deinit();
return ESP_FAIL;
}
memset(peer, 0, sizeof(esp_now_peer_info_t));
peer->channel = CONFIG_ESPNOW_CHANNEL;
peer->ifidx = ESPNOW_WIFI_IF;
peer->encrypt = false;
memcpy(peer->peer_addr, s_broadcast_mac, ESP_NOW_ETH_ALEN);
ESP_ERROR_CHECK(esp_now_add_peer(peer));
free(peer);
/* Initialize sending parameters. */
send_param = malloc(sizeof(espnow_send_param_t));
if (send_param == NULL) {
ESP_LOGE(tag, "Malloc send parameter fail");
vSemaphoreDelete(s_espnow_queue);
esp_now_deinit();
return ESP_FAIL;
}
memset(send_param, 0, sizeof(espnow_send_param_t));
send_param->unicast = false;
send_param->broadcast = true;
send_param->state = 0;
send_param->magic = esp_random();
send_param->count = CONFIG_ESPNOW_SEND_COUNT;
send_param->delay = CONFIG_ESPNOW_SEND_DELAY;
send_param->len = CONFIG_ESPNOW_SEND_LEN;
send_param->buffer = malloc(CONFIG_ESPNOW_SEND_LEN);
if (send_param->buffer == NULL) {
ESP_LOGE(tag, "Malloc send buffer fail");
free(send_param);
vSemaphoreDelete(s_espnow_queue);
esp_now_deinit();
return ESP_FAIL;
}
memcpy(send_param->dest_mac, s_broadcast_mac, ESP_NOW_ETH_ALEN);
espnow_data_prepare(send_param);
xTaskCreate(espnow_task, "espnow_task", 2048, send_param, 4, NULL);
return ESP_OK;
}
void espnow_task(void *pvParameter) {
espnow_event_t evt;
uint8_t recv_state = 0;
uint16_t recv_seq = 0;
uint32_t recv_magic = 0;
bool is_broadcast = false;
int ret;
vTaskDelay(5000 / portTICK_PERIOD_MS);
ESP_LOGI(tag, "Start sending broadcast data");
/* Start sending broadcast ESPNOW data. */
espnow_send_param_t *send_param = (espnow_send_param_t *)pvParameter;
if (esp_now_send(send_param->dest_mac, send_param->buffer, send_param->len) !=
ESP_OK) {
ESP_LOGE(tag, "Send error");
espnow_deinit(send_param);
vTaskDelete(NULL);
}
while (xQueueReceive(s_espnow_queue, &evt, portMAX_DELAY) == pdTRUE) {
switch (evt.id) {
case EXAMPLE_ESPNOW_SEND_CB: {
espnow_event_send_cb_t *send_cb = &evt.info.send_cb;
is_broadcast = IS_BROADCAST_ADDR(send_cb->mac_addr);
ESP_LOGD(tag, "Send data to " MACSTR ", status1: %d",
MAC2STR(send_cb->mac_addr), send_cb->status);
if (is_broadcast && (send_param->broadcast == false)) {
break;
}
if (!is_broadcast) {
send_param->count--;
if (send_param->count == 0) {
ESP_LOGI(tag, "Send done");
espnow_deinit(send_param);
vTaskDelete(NULL);
}
}
/* Delay a while before sending the next data. */
if (send_param->delay > 0) {
vTaskDelay(send_param->delay / portTICK_PERIOD_MS);
}
ESP_LOGI(tag, "send data to " MACSTR "", MAC2STR(send_cb->mac_addr));
memcpy(send_param->dest_mac, send_cb->mac_addr, ESP_NOW_ETH_ALEN);
espnow_data_prepare(send_param);
/* Send the next data after the previous data is sent. */
if (esp_now_send(send_param->dest_mac, send_param->buffer,
send_param->len) != ESP_OK) {
ESP_LOGE(tag, "Send error");
espnow_deinit(send_param);
vTaskDelete(NULL);
}
break;
}
case EXAMPLE_ESPNOW_RECV_CB: {
espnow_event_recv_cb_t *recv_cb = &evt.info.recv_cb;
ret = espnow_data_parse(recv_cb->data, recv_cb->data_len, &recv_state,
&recv_seq, &recv_magic, recv_cb);
free(recv_cb->data);
if (ret == EXAMPLE_ESPNOW_DATA_BROADCAST) {
ESP_LOGI(tag, "Receive %dth broadcast data from: " MACSTR ", len: %d",
recv_seq, MAC2STR(recv_cb->mac_addr), recv_cb->data_len);
/* If MAC address does not exist in peer list, add it to peer list. */
if (esp_now_is_peer_exist(recv_cb->mac_addr) == false) {
esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));
if (peer == NULL) {
ESP_LOGE(tag, "Malloc peer information fail");
espnow_deinit(send_param);
vTaskDelete(NULL);
}
memset(peer, 0, sizeof(esp_now_peer_info_t));
peer->channel = CONFIG_ESPNOW_CHANNEL;
peer->ifidx = ESPNOW_WIFI_IF;
peer->encrypt = true;
memcpy(peer->lmk, CONFIG_ESPNOW_LMK, ESP_NOW_KEY_LEN);
memcpy(peer->peer_addr, recv_cb->mac_addr, ESP_NOW_ETH_ALEN);
ESP_ERROR_CHECK(esp_now_add_peer(peer));
free(peer);
}
/* Indicates that the device has received broadcast ESPNOW data. */
if (send_param->state == 0) {
send_param->state = 1;
}
/* If receive broadcast ESPNOW data which indicates that the other
* device has received broadcast ESPNOW data and the local magic number
* is bigger than that in the received broadcast ESPNOW data, stop
* sending broadcast ESPNOW data and start sending unicast ESPNOW data.
*/
if (recv_state == 1) {
/* The device which has the bigger magic number sends ESPNOW data, the
* other one receives ESPNOW data.
*/
if (send_param->unicast == false && send_param->magic >= recv_magic) {
ESP_LOGI(tag, "Start sending unicast data");
ESP_LOGI(tag, "send data to " MACSTR "",
MAC2STR(recv_cb->mac_addr));
/* Start sending unicast ESPNOW data. */
memcpy(send_param->dest_mac, recv_cb->mac_addr, ESP_NOW_ETH_ALEN);
espnow_data_prepare(send_param);
if (esp_now_send(send_param->dest_mac, send_param->buffer,
send_param->len) != ESP_OK) {
ESP_LOGE(tag, "Send error");
espnow_deinit(send_param);
vTaskDelete(NULL);
} else {
send_param->broadcast = false;
send_param->unicast = true;
}
}
}
} else if (ret == EXAMPLE_ESPNOW_DATA_UNICAST) {
ESP_LOGI(tag, "Receive %dth unicast data from: " MACSTR ", len: %d",
recv_seq, MAC2STR(recv_cb->mac_addr), recv_cb->data_len);
/* If receive unicast ESPNOW data, also stop sending broadcast ESPNOW
* data. */
send_param->broadcast = false;
} else {
ESP_LOGI(tag, "Receive error data from: " MACSTR "",
MAC2STR(recv_cb->mac_addr));
}
break;
}
default:
ESP_LOGE(tag, "Callback type error: %d", evt.id);
break;
}
}
}
+119
View File
@@ -0,0 +1,119 @@
#ifndef ESPNOW_HANDLER_H
#define ESPNOW_HANDLER_H
#include "shared.h"
#include <stdint.h>
#include <sys/types.h>
static bool isMaster;
#define MAX_PAYLOAD_SIZE 250
#define ESPNOW_QUEUE_SIZE 6
#define IS_BROADCAST_ADDR(addr) \
(memcmp(addr, s_broadcast_mac, ESP_NOW_ETH_ALEN) == 0)
typedef enum {
EXAMPLE_ESPNOW_SEND_CB,
EXAMPLE_ESPNOW_RECV_CB,
} espnow_event_id_t;
typedef struct {
uint8_t mac_addr[ESP_NOW_ETH_ALEN];
esp_now_send_status_t status;
} espnow_event_send_cb_t;
typedef struct {
uint8_t mac_addr[ESP_NOW_ETH_ALEN];
uint8_t *data;
int data_len;
} espnow_event_recv_cb_t;
typedef union {
espnow_event_send_cb_t send_cb;
espnow_event_recv_cb_t recv_cb;
} espnow_event_info_t;
typedef struct {
espnow_event_id_t id;
espnow_event_info_t info;
} espnow_event_t;
enum {
EXAMPLE_ESPNOW_DATA_BROADCAST,
EXAMPLE_ESPNOW_DATA_UNICAST,
EXAMPLE_ESPNOW_DATA_MAX,
};
enum {
UNION_STATUS,
UNION_SENSORDATA,
UNION_PING_PONG,
UNION_TEST,
};
typedef struct {
bool isMaster;
} __attribute__((packed)) payloadStatus;
typedef struct {
uint8_t dataPoint;
} __attribute__((packed)) payloadSensorData;
typedef struct {
uint startCounter;
} __attribute__((packed)) payloadPingPong;
typedef struct {
uint testNumber;
} __attribute__((packed)) payloadTesting;
union realPayload {
payloadStatus status;
payloadSensorData sensorData;
payloadPingPong pingPongData;
payloadTesting testingData;
};
/* User defined field of ESPNOW data in this example. */
typedef struct {
uint8_t type; // Broadcast or unicast ESPNOW data.
uint8_t state; // Indicate that if has received broadcast ESPNOW data or not.
uint16_t seq_num; // Sequence number of ESPNOW data.
uint16_t crc; // CRC16 value of ESPNOW data.
uint32_t magic; // Magic number which is used to determine which device to
// send unicast ESPNOW data.
uint8_t unionPage;
union realPayload realPayload; // Real payload of ESPNOW data.
} __attribute__((packed)) espnow_data_t;
static_assert(sizeof(espnow_data_t) <= MAX_PAYLOAD_SIZE,
"payloadData struct is too big to be sent in one part, keep it "
"under 250 Bytes!");
typedef struct {
bool unicast; // Send unicast ESPNOW data.
bool broadcast; // Send broadcast ESPNOW data.
uint8_t state; // Indicate that if has received broadcast ESPNOW data or not.
uint32_t magic; // Magic number which is used to determine which device to
// send unicast ESPNOW data.
uint16_t count; // Total count of unicast ESPNOW data to be sent.
uint16_t delay; // Delay between sending two ESPNOW data, unit: ms.
int len; // Length of ESPNOW data to be sent, unit: byte.
uint8_t *buffer; // Buffer pointing to ESPNOW data.
uint8_t dest_mac[ESP_NOW_ETH_ALEN]; // MAC address of destination device.
} espnow_send_param_t;
void wifi_init(void);
void espnow_deinit(espnow_send_param_t *send_param);
void espnow_data_prepare(espnow_send_param_t *send_param);
void espnow_send_cb(const uint8_t *mac_addr,
esp_now_send_status_t status);
void espnow_recv_cb(const esp_now_recv_info_t *recv_info,
const uint8_t *data, int len);
int espnow_data_parse(uint8_t *data, uint16_t data_len, uint8_t *state,
uint16_t *seq, uint32_t *magic, espnow_event_recv_cb_t* recv_cb);
esp_err_t espnow_init(void);
void espnow_task(void *pvParameter);
void setIsMaster(bool status);
#endif
+29 -371
View File
@@ -1,4 +1,5 @@
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_crc.h" #include "esp_crc.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
@@ -10,383 +11,20 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "hal/gpio_types.h" #include "hal/gpio_types.h"
#include "hal/uart_types.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "portmacro.h" #include "portmacro.h"
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "espnow_handler.h"
#include "main.h" #include "main.h"
#define ESPNOW_WIFI_MODE WIFI_MODE_AP #define BUF_SIZE (1024)
#define ESPNOW_WIFI_IF ESP_IF_WIFI_AP #define TXD_PIN (GPIO_NUM_17)
#define ESPNOW_MAXDELAY 512 #define RXD_PIN (GPIO_NUM_16)
// default CONFIG values from menuconfig
#define CONFIG_ESPNOW_CHANNEL 1
#define CONFIG_ESPNOW_PMK "pmk1234567890123"
#define CONFIG_ESPNOW_SEND_COUNT 100
#define CONFIG_ESPNOW_SEND_DELAY 1000
#define CONFIG_ESPNOW_SEND_LEN 250
#define CONFIG_ESPNOW_LMK "lmk1234567890123"
const char *tag = "Exam";
static QueueHandle_t s_example_espnow_queue;
static uint8_t s_example_broadcast_mac[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF};
static uint16_t s_example_espnow_seq[2] = {0, 0};
static void example_espnow_deinit(example_espnow_send_param_t *send_param);
void wifi_init(void) {
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
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(ESPNOW_WIFI_MODE));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(
esp_wifi_set_channel(CONFIG_ESPNOW_CHANNEL, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_wifi_set_protocol(
ESPNOW_WIFI_IF, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G |
WIFI_PROTOCOL_11N | WIFI_PROTOCOL_LR));
}
static void example_espnow_deinit(example_espnow_send_param_t *send_param) {
free(send_param->buffer);
free(send_param);
vSemaphoreDelete(s_example_espnow_queue);
esp_now_deinit();
}
void example_espnow_data_prepare(example_espnow_send_param_t *send_param) {
example_espnow_data_t *buf = (example_espnow_data_t *)send_param->buffer;
ESP_LOGI(tag, "Example_Data_SIZE: %u, send_param_len: %d\n", sizeof(example_espnow_data_t), send_param->len);
assert(send_param->len >= sizeof(example_espnow_data_t));
buf->type = IS_BROADCAST_ADDR(send_param->dest_mac)
? EXAMPLE_ESPNOW_DATA_BROADCAST
: EXAMPLE_ESPNOW_DATA_UNICAST;
buf->state = send_param->state;
buf->seq_num = s_example_espnow_seq[buf->type]++;
buf->crc = 0;
buf->magic = send_param->magic;
buf->payload.isMaster = isMaster;
/* Fill all remaining bytes after the data with random values */
/* esp_fill_random(buf->payload,
send_param->len - sizeof(example_espnow_data_t)); */ // wieso sollte ich das mit random daten füllen
buf->crc = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len);
}
static void example_espnow_send_cb(const uint8_t *mac_addr,
esp_now_send_status_t status) {
example_espnow_event_t evt;
example_espnow_event_send_cb_t *send_cb = &evt.info.send_cb;
if (mac_addr == NULL) {
ESP_LOGE(tag, "Send cb arg error");
return;
}
evt.id = EXAMPLE_ESPNOW_SEND_CB;
memcpy(send_cb->mac_addr, mac_addr, ESP_NOW_ETH_ALEN);
send_cb->status = status;
if (xQueueSend(s_example_espnow_queue, &evt, ESPNOW_MAXDELAY) != pdTRUE) {
ESP_LOGW(tag, "Send send queue fail");
}
}
static void example_espnow_recv_cb(const esp_now_recv_info_t *recv_info,
const uint8_t *data, int len) {
example_espnow_event_t evt;
example_espnow_event_recv_cb_t *recv_cb = &evt.info.recv_cb;
uint8_t *mac_addr = recv_info->src_addr;
uint8_t *des_addr = recv_info->des_addr;
if (mac_addr == NULL || data == NULL || len <= 0) {
ESP_LOGE(tag, "Receive cb arg error");
return;
}
if (IS_BROADCAST_ADDR(des_addr)) {
/* If added a peer with encryption before, the receive packets may be
* encrypted as peer-to-peer message or unencrypted over the broadcast
* channel. Users can check the destination address to distinguish it.
*/
ESP_LOGD(tag, "Receive broadcast ESPNOW data");
} else {
ESP_LOGD(tag, "Receive unicast ESPNOW data");
}
evt.id = EXAMPLE_ESPNOW_RECV_CB;
memcpy(recv_cb->mac_addr, mac_addr, ESP_NOW_ETH_ALEN);
recv_cb->data = malloc(len);
if (recv_cb->data == NULL) {
ESP_LOGE(tag, "Malloc receive data fail");
return;
}
memcpy(recv_cb->data, data, len);
recv_cb->data_len = len;
if (xQueueSend(s_example_espnow_queue, &evt, ESPNOW_MAXDELAY) != pdTRUE) {
ESP_LOGW(tag, "Send receive queue fail");
free(recv_cb->data);
}
}
int example_espnow_data_parse(uint8_t *data, uint16_t data_len, uint8_t *state,
uint16_t *seq, uint32_t *magic) {
example_espnow_data_t *buf = (example_espnow_data_t *)data;
uint16_t crc, crc_cal = 0;
if (data_len < sizeof(example_espnow_data_t)) {
ESP_LOGE(tag, "Receive ESPNOW data too short, len:%d", data_len);
return -1;
}
*state = buf->state;
*seq = buf->seq_num;
*magic = buf->magic;
crc = buf->crc;
buf->crc = 0;
crc_cal = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len);
if(buf->payload.isMaster) {
ESP_LOGE(tag, "Recived Data from Master");
} else {
ESP_LOGE(tag, "Recived Data from Slave");
}
if (crc_cal == crc) {
return buf->type;
}
return -1;
}
static void example_espnow_task(void *pvParameter) {
example_espnow_event_t evt;
uint8_t recv_state = 0;
uint16_t recv_seq = 0;
uint32_t recv_magic = 0;
bool is_broadcast = false;
int ret;
vTaskDelay(5000 / portTICK_PERIOD_MS);
ESP_LOGI(tag, "Start sending broadcast data");
/* Start sending broadcast ESPNOW data. */
example_espnow_send_param_t *send_param =
(example_espnow_send_param_t *)pvParameter;
if (esp_now_send(send_param->dest_mac, send_param->buffer, send_param->len) !=
ESP_OK) {
ESP_LOGE(tag, "Send error");
example_espnow_deinit(send_param);
vTaskDelete(NULL);
}
while (xQueueReceive(s_example_espnow_queue, &evt, portMAX_DELAY) == pdTRUE) {
switch (evt.id) {
case EXAMPLE_ESPNOW_SEND_CB: {
example_espnow_event_send_cb_t *send_cb = &evt.info.send_cb;
is_broadcast = IS_BROADCAST_ADDR(send_cb->mac_addr);
ESP_LOGD(tag, "Send data to " MACSTR ", status1: %d",
MAC2STR(send_cb->mac_addr), send_cb->status);
if (is_broadcast && (send_param->broadcast == false)) {
break;
}
if (!is_broadcast) {
send_param->count--;
if (send_param->count == 0) {
ESP_LOGI(tag, "Send done");
example_espnow_deinit(send_param);
vTaskDelete(NULL);
}
}
/* Delay a while before sending the next data. */
if (send_param->delay > 0) {
vTaskDelay(send_param->delay / portTICK_PERIOD_MS);
}
ESP_LOGI(tag, "send data to " MACSTR "", MAC2STR(send_cb->mac_addr));
memcpy(send_param->dest_mac, send_cb->mac_addr, ESP_NOW_ETH_ALEN);
example_espnow_data_prepare(send_param);
/* Send the next data after the previous data is sent. */
if (esp_now_send(send_param->dest_mac, send_param->buffer,
send_param->len) != ESP_OK) {
ESP_LOGE(tag, "Send error");
example_espnow_deinit(send_param);
vTaskDelete(NULL);
}
break;
}
case EXAMPLE_ESPNOW_RECV_CB: {
example_espnow_event_recv_cb_t *recv_cb = &evt.info.recv_cb;
ret = example_espnow_data_parse(recv_cb->data, recv_cb->data_len,
&recv_state, &recv_seq, &recv_magic);
free(recv_cb->data);
if (ret == EXAMPLE_ESPNOW_DATA_BROADCAST) {
ESP_LOGI(tag, "Receive %dth broadcast data from: " MACSTR ", len: %d",
recv_seq, MAC2STR(recv_cb->mac_addr), recv_cb->data_len);
/* If MAC address does not exist in peer list, add it to peer list. */
if (esp_now_is_peer_exist(recv_cb->mac_addr) == false) {
esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));
if (peer == NULL) {
ESP_LOGE(tag, "Malloc peer information fail");
example_espnow_deinit(send_param);
vTaskDelete(NULL);
}
memset(peer, 0, sizeof(esp_now_peer_info_t));
peer->channel = CONFIG_ESPNOW_CHANNEL;
peer->ifidx = ESPNOW_WIFI_IF;
peer->encrypt = true;
memcpy(peer->lmk, CONFIG_ESPNOW_LMK, ESP_NOW_KEY_LEN);
memcpy(peer->peer_addr, recv_cb->mac_addr, ESP_NOW_ETH_ALEN);
ESP_ERROR_CHECK(esp_now_add_peer(peer));
free(peer);
}
/* Indicates that the device has received broadcast ESPNOW data. */
if (send_param->state == 0) {
send_param->state = 1;
}
/* If receive broadcast ESPNOW data which indicates that the other
* device has received broadcast ESPNOW data and the local magic number
* is bigger than that in the received broadcast ESPNOW data, stop
* sending broadcast ESPNOW data and start sending unicast ESPNOW data.
*/
if (recv_state == 1) {
/* The device which has the bigger magic number sends ESPNOW data, the
* other one receives ESPNOW data.
*/
if (send_param->unicast == false && send_param->magic >= recv_magic) {
ESP_LOGI(tag, "Start sending unicast data");
ESP_LOGI(tag, "send data to " MACSTR "",
MAC2STR(recv_cb->mac_addr));
/* Start sending unicast ESPNOW data. */
memcpy(send_param->dest_mac, recv_cb->mac_addr, ESP_NOW_ETH_ALEN);
example_espnow_data_prepare(send_param);
if (esp_now_send(send_param->dest_mac, send_param->buffer,
send_param->len) != ESP_OK) {
ESP_LOGE(tag, "Send error");
example_espnow_deinit(send_param);
vTaskDelete(NULL);
} else {
send_param->broadcast = false;
send_param->unicast = true;
}
}
}
} else if (ret == EXAMPLE_ESPNOW_DATA_UNICAST) {
ESP_LOGI(tag, "Receive %dth unicast data from: " MACSTR ", len: %d",
recv_seq, MAC2STR(recv_cb->mac_addr), recv_cb->data_len);
/* If receive unicast ESPNOW data, also stop sending broadcast ESPNOW
* data. */
send_param->broadcast = false;
} else {
ESP_LOGI(tag, "Receive error data from: " MACSTR "",
MAC2STR(recv_cb->mac_addr));
}
break;
}
default:
ESP_LOGE(tag, "Callback type error: %d", evt.id);
break;
}
}
}
static esp_err_t example_espnow_init(void) {
example_espnow_send_param_t *send_param;
s_example_espnow_queue =
xQueueCreate(ESPNOW_QUEUE_SIZE, sizeof(example_espnow_event_t));
if (s_example_espnow_queue == NULL) {
ESP_LOGE(tag, "Create mutex fail");
return ESP_FAIL;
}
/* Initialize ESPNOW and register sending and receiving callback function. */
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_send_cb(example_espnow_send_cb));
ESP_ERROR_CHECK(esp_now_register_recv_cb(example_espnow_recv_cb));
#if CONFIG_ESPNOW_ENABLE_POWER_SAVE
ESP_ERROR_CHECK(esp_now_set_wake_window(CONFIG_ESPNOW_WAKE_WINDOW));
ESP_ERROR_CHECK(esp_wifi_connectionless_module_set_wake_interval(
CONFIG_ESPNOW_WAKE_INTERVAL));
#endif
/* Set primary master key. */
ESP_ERROR_CHECK(esp_now_set_pmk((uint8_t *)CONFIG_ESPNOW_PMK));
/* Add broadcast peer information to peer list. */
esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));
if (peer == NULL) {
ESP_LOGE(tag, "Malloc peer information fail");
vSemaphoreDelete(s_example_espnow_queue);
esp_now_deinit();
return ESP_FAIL;
}
memset(peer, 0, sizeof(esp_now_peer_info_t));
peer->channel = CONFIG_ESPNOW_CHANNEL;
peer->ifidx = ESPNOW_WIFI_IF;
peer->encrypt = false;
memcpy(peer->peer_addr, s_example_broadcast_mac, ESP_NOW_ETH_ALEN);
ESP_ERROR_CHECK(esp_now_add_peer(peer));
free(peer);
/* Initialize sending parameters. */
send_param = malloc(sizeof(example_espnow_send_param_t));
if (send_param == NULL) {
ESP_LOGE(tag, "Malloc send parameter fail");
vSemaphoreDelete(s_example_espnow_queue);
esp_now_deinit();
return ESP_FAIL;
}
memset(send_param, 0, sizeof(example_espnow_send_param_t));
send_param->unicast = false;
send_param->broadcast = true;
send_param->state = 0;
send_param->magic = esp_random();
send_param->count = CONFIG_ESPNOW_SEND_COUNT;
send_param->delay = CONFIG_ESPNOW_SEND_DELAY;
send_param->len = CONFIG_ESPNOW_SEND_LEN;
send_param->buffer = malloc(CONFIG_ESPNOW_SEND_LEN);
if (send_param->buffer == NULL) {
ESP_LOGE(tag, "Malloc send buffer fail");
free(send_param);
vSemaphoreDelete(s_example_espnow_queue);
esp_now_deinit();
return ESP_FAIL;
}
memcpy(send_param->dest_mac, s_example_broadcast_mac, ESP_NOW_ETH_ALEN);
example_espnow_data_prepare(send_param);
xTaskCreate(example_espnow_task, "example_espnow_task", 2048, send_param, 4,
NULL);
return ESP_OK;
}
void app_main(void) { void app_main(void) {
// Master Slave Detection, default pin is pull up so ground it and check state // Master Slave Detection, default pin is pull up so ground it and check state
@@ -395,12 +33,32 @@ void app_main(void) {
int checkMaster = gpio_get_level(Master_SlavePin); int checkMaster = gpio_get_level(Master_SlavePin);
if (checkMaster == 0) { if (checkMaster == 0) {
isMaster = true; isMaster = true;
setIsMaster(true);
} }
uart_config_t uart_config = {.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE};
uart_driver_install(UART_NUM_2, BUF_SIZE * 2, 0, 0, NULL, 0);
uart_param_config(UART_NUM_2, &uart_config);
uart_set_pin(UART_NUM_2, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE,
UART_PIN_NO_CHANGE);
char *test_str = "Ok\n";
/*while (1) {*/
/* uart_write_bytes(UART_NUM_2, (const char *)test_str, strlen(test_str));*/
/* ESP_LOGI(tag, "Sending UART\n");*/
/* vTaskDelay(100 / portTICK_PERIOD_MS);*/
/*}*/
ESP_LOGI(tag, "ESP MASTER State %d\n", isMaster); ESP_LOGI(tag, "ESP MASTER State %d\n", isMaster);
vTaskDelay(500/portTICK_PERIOD_MS); vTaskDelay(500 / portTICK_PERIOD_MS);
wifi_init(); wifi_init();
example_espnow_init(); espnow_init();
} }
+2 -68
View File
@@ -1,76 +1,10 @@
#ifndef MAIN_H #ifndef MAIN_H
#define MAIN_H #define MAIN_H
#define Master_SlavePin 23 #include "shared.h"
#define MAX_PAYLOAD_SIZE 250
#define ESPNOW_QUEUE_SIZE 6
#define IS_BROADCAST_ADDR(addr) \
(memcmp(addr, s_example_broadcast_mac, ESP_NOW_ETH_ALEN) == 0)
static bool isMaster; static bool isMaster;
typedef enum { #define Master_SlavePin 23
EXAMPLE_ESPNOW_SEND_CB,
EXAMPLE_ESPNOW_RECV_CB,
} example_espnow_event_id_t;
typedef struct {
uint8_t mac_addr[ESP_NOW_ETH_ALEN];
esp_now_send_status_t status;
} example_espnow_event_send_cb_t;
typedef struct {
uint8_t mac_addr[ESP_NOW_ETH_ALEN];
uint8_t *data;
int data_len;
} example_espnow_event_recv_cb_t;
typedef union {
example_espnow_event_send_cb_t send_cb;
example_espnow_event_recv_cb_t recv_cb;
} example_espnow_event_info_t;
typedef struct {
example_espnow_event_id_t id;
example_espnow_event_info_t info;
} example_espnow_event_t;
enum {
EXAMPLE_ESPNOW_DATA_BROADCAST,
EXAMPLE_ESPNOW_DATA_UNICAST,
EXAMPLE_ESPNOW_DATA_MAX,
};
typedef struct {
bool isMaster;
} __attribute__((packed)) payloadData;
static_assert(sizeof(payloadData) <= MAX_PAYLOAD_SIZE, "payloadData struct is too big to be sent in one part, keep it under 250 Bytes!");
/* User defined field of ESPNOW data in this example. */
typedef struct {
uint8_t type; // Broadcast or unicast ESPNOW data.
uint8_t state; // Indicate that if has received broadcast ESPNOW data or not.
uint16_t seq_num; // Sequence number of ESPNOW data.
uint16_t crc; // CRC16 value of ESPNOW data.
uint32_t magic; // Magic number which is used to determine which device to
// send unicast ESPNOW data.
payloadData payload; // Real payload of ESPNOW data.
} __attribute__((packed)) example_espnow_data_t;
typedef struct {
bool unicast; // Send unicast ESPNOW data.
bool broadcast; // Send broadcast ESPNOW data.
uint8_t state; // Indicate that if has received broadcast ESPNOW data or not.
uint32_t magic; // Magic number which is used to determine which device to
// send unicast ESPNOW data.
uint16_t count; // Total count of unicast ESPNOW data to be sent.
uint16_t delay; // Delay between sending two ESPNOW data, unit: ms.
int len; // Length of ESPNOW data to be sent, unit: byte.
uint8_t *buffer; // Buffer pointing to ESPNOW data.
uint8_t dest_mac[ESP_NOW_ETH_ALEN]; // MAC address of destination device.
} example_espnow_send_param_t;
#endif #endif
+6
View File
@@ -0,0 +1,6 @@
#ifndef SHARED_H
#define SHARED_H
static char *tag = "Alox";
#endif