]> granicus.if.org Git - esp-idf/commitdiff
Add an example to show how to use ESPNOW
authorXiaXiaotian <xiaxiaotian@espressif.com>
Wed, 13 Sep 2017 12:38:04 +0000 (20:38 +0800)
committerXiaXiaotian <xiaxiaotian@espressif.com>
Fri, 22 Sep 2017 07:52:45 +0000 (15:52 +0800)
examples/wifi/README.md
examples/wifi/espnow/Makefile [new file with mode: 0644]
examples/wifi/espnow/README.md [new file with mode: 0644]
examples/wifi/espnow/main/Kconfig.projbuild [new file with mode: 0644]
examples/wifi/espnow/main/component.mk [new file with mode: 0644]
examples/wifi/espnow/main/espnow_example.h [new file with mode: 0644]
examples/wifi/espnow/main/espnow_example_main.c [new file with mode: 0644]

index 21578e9d4e842b3e910cb5a87ecec015f0f2c364..ba9f2e0fa2bfbcdfad555d72cb36988b0eabda7c 100644 (file)
@@ -20,6 +20,12 @@ shows how to use wps(Wifi Protected Setup).
 \r
 See the [README.md](./wps/README.md) file in the project [wps](./wps/).\r
 \r
+## espnow\r
+\r
+shows how to use espnow.\r
+\r
+See the [README.md](./espnow/README.md) file in the project [espnow](./espnow/).\r
+\r
 # More\r
 \r
 See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples.\r
diff --git a/examples/wifi/espnow/Makefile b/examples/wifi/espnow/Makefile
new file mode 100644 (file)
index 0000000..a98a511
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := espnow_example
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/wifi/espnow/README.md b/examples/wifi/espnow/README.md
new file mode 100644 (file)
index 0000000..595d51d
--- /dev/null
@@ -0,0 +1,30 @@
+# ESPNOW Example
+
+This example shows how to use ESPNOW of wifi. Example does the following steps:
+
+1. Start WiFi.
+
+2. Initialize ESPNOW.
+
+3. Register ESPNOW sending or receiving callback function.
+
+4. Add ESPNOW peer information.
+
+5. Send and receive ESPNOW data. 
+
+In order to get the MAC address of the other device, firstly send broadcast ESPNOW data to each other with 'state' set as 0. When receiving 
+broadcast ESPNOW data with 'state' as 0, add the device from which the data comes to the peer list. Then start sending broadcast ESPNOW 
+data with 'state' set as 1. When receiving broadcast ESPNOW data with 'state' as 1, compare the local magic number with that in the data. 
+If the local one is bigger than that one, stop sending broadcast ESPNOW data and start sending unicast ESPNOW data. If receive unicast 
+ESPNOW data, also stop sending broadcast ESPNOW data. That is what happens in this example. It shows how to send/receive broadcast/unicast 
+ESPNOW data. In practice, if the MAC address of the other device is known, it's not required to send/receive broadcast ESPNOW data first, 
+just add the device to the peer list and send/receive unicast ESPNOW data.
+
+There are a lot of "extras" on top of ESPNOW data, such as type, state, sequence number, CRC and magic in this example. These "extras" are 
+not required to use ESPNOW. They are only used to make this example to run correctly. However, it is recommended that users add some "extras" 
+to make ESPNOW data more safe and more reliable.
+
+*Note:* The two devices can be set as either station or softap or station+softap mode. If the receiving device is in station mode only
+and it connects to an AP, modem sleep should be disabled.
+
+More info in the code [espnow_example_main.c](./main/espnow_example_main.c).
diff --git a/examples/wifi/espnow/main/Kconfig.projbuild b/examples/wifi/espnow/main/Kconfig.projbuild
new file mode 100644 (file)
index 0000000..be6b6ff
--- /dev/null
@@ -0,0 +1,55 @@
+menu "Example Configuration"
+
+choice WIFI_MODE
+    prompt "WiFi mode"
+    default STATION_MODE
+    help
+        WiFi mode(station or softap).
+    
+config STATION_MODE
+    bool "Station"
+config SOFTAP_MODE
+    bool "Softap"
+endchoice
+      
+config ESPNOW_PMK
+    string "ESPNOW primary master key"
+    default "pmk1234567890123"
+    help
+        ESPNOW primary master for the example to use. The length of ESPNOW primary master must be 16 bytes.
+
+config ESPNOW_LMK
+    string "ESPNOW local master key"
+    default "lmk1234567890123"
+    help
+        ESPNOW local master for the example to use. The length of ESPNOW local master must be 16 bytes.
+        
+config ESPNOW_CHANNEL
+    int "Channel"
+    default 1
+    range 1 13
+    help
+        The channel on which sending and receiving ESPNOW data.
+
+config ESPNOW_SEND_COUNT
+    int "Send count"
+    default 100
+    range 1 65535
+    help
+        Total count of unicast ESPNOW data to be sent.
+        
+config ESPNOW_SEND_DELAY
+    int "Send delay"
+    default 1000
+    range 0 65535
+    help
+        Delay between sending two ESPNOW data, unit: ms.
+        
+config ESPNOW_SEND_LEN
+    int "Send len"
+    range 10 250
+    default 200
+    help
+        Length of ESPNOW data to be sent, unit: byte.
+
+endmenu
diff --git a/examples/wifi/espnow/main/component.mk b/examples/wifi/espnow/main/component.mk
new file mode 100644 (file)
index 0000000..7d7b29b
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
+
+
diff --git a/examples/wifi/espnow/main/espnow_example.h b/examples/wifi/espnow/main/espnow_example.h
new file mode 100644 (file)
index 0000000..b53e403
--- /dev/null
@@ -0,0 +1,82 @@
+/* ESPNOW Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef ESPNOW_EXAMPLE_H
+#define ESPNOW_EXAMPLE_H
+
+/* ESPNOW can work in both station and softap mode. It is configured in menuconfig. */
+#if CONFIG_STATION_MODE
+#define ESPNOW_WIFI_MODE WIFI_MODE_STA
+#define ESPNOW_WIFI_IF   ESP_IF_WIFI_STA
+#else
+#define ESPNOW_WIFI_MODE WIFI_MODE_AP
+#define ESPNOW_WIFI_IF   ESP_IF_WIFI_AP
+#endif
+
+#define ESPNOW_QUEUE_SIZE           6
+
+#define IS_BROADCAST_ADDR(addr) (memcmp(addr, example_broadcast_mac, ESP_NOW_ETH_ALEN) == 0)
+
+typedef enum {
+    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;
+
+/* When ESPNOW sending or receiving callback function is called, post event to ESPNOW task. */
+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,
+};
+
+/* 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 payload[0];                   //Real payload of ESPNOW data.
+} __attribute__((packed)) example_espnow_data_t;
+
+/* Parameters of sending ESPNOW data. */
+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
diff --git a/examples/wifi/espnow/main/espnow_example_main.c b/examples/wifi/espnow/main/espnow_example_main.c
new file mode 100644 (file)
index 0000000..68e56ff
--- /dev/null
@@ -0,0 +1,386 @@
+/* ESPNOW Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+/*
+   This example shows how to use ESPNOW.
+   Prepare two device, one for sending ESPNOW data and another for receiving
+   ESPNOW data.
+*/
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <assert.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/timers.h"
+#include "nvs_flash.h"
+#include "esp_event_loop.h"
+#include "tcpip_adapter.h"
+#include "esp_wifi.h"
+#include "esp_log.h"
+#include "esp_system.h"
+#include "esp_now.h"
+#include "rom/ets_sys.h"
+#include "rom/crc.h"
+#include "espnow_example.h"
+
+static const char *TAG = "espnow_example";
+
+static xQueueHandle example_espnow_queue;
+
+static uint8_t example_broadcast_mac[ESP_NOW_ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static uint16_t s_example_espnow_seq[EXAMPLE_ESPNOW_DATA_MAX] = { 0, 0 };
+
+static void example_espnow_deinit(example_espnow_send_param_t *send_param);
+
+static esp_err_t example_event_handler(void *ctx, system_event_t *event)
+{
+    switch(event->event_id) {
+    case SYSTEM_EVENT_STA_START:
+        ESP_LOGI(TAG, "WiFi started");
+        break;
+    default:
+        break;
+    }
+    return ESP_OK;
+}
+
+/* WiFi should start before using ESPNOW */
+static void example_wifi_init(void)
+{
+    tcpip_adapter_init();
+    ESP_ERROR_CHECK( esp_event_loop_init(example_event_handler, NULL) );
+    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());
+
+    /* In order to simplify example, channel is set after WiFi started.
+     * This is not necessary in real application if the two devices have
+     * been already on the same channel.
+     */
+    ESP_ERROR_CHECK( esp_wifi_set_channel(CONFIG_ESPNOW_CHANNEL, 0) );
+}
+
+/* ESPNOW sending or receiving callback function is called in WiFi task.
+ * Users should not do lengthy operations from this task. Instead, post
+ * necessary data to a queue and handle it from a lower priority task. */
+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(example_espnow_queue, &evt, portMAX_DELAY) != pdTRUE) {
+        ESP_LOGW(TAG, "Send send queue fail");
+    }
+}
+
+static void example_espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int len)
+{
+    example_espnow_event_t evt;
+    example_espnow_event_recv_cb_t *recv_cb = &evt.info.recv_cb;
+
+    if (mac_addr == NULL || data == NULL || len <= 0) {
+        ESP_LOGE(TAG, "Receive cb arg error");
+        return;
+    }
+
+    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(example_espnow_queue, &evt, portMAX_DELAY) != pdTRUE) {
+        ESP_LOGW(TAG, "Send receive queue fail");
+        free(recv_cb->data);
+    }
+}
+
+/* Parse received ESPNOW data. */
+int example_espnow_data_parse(uint8_t *data, uint16_t data_len, uint8_t *state, uint16_t *seq, int *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 = crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len);
+
+    if (crc_cal == crc) {
+        return buf->type;
+    }
+
+    return -1;
+}
+
+/* Prepare ESPNOW data to be sent. */
+void example_espnow_data_prepare(example_espnow_send_param_t *send_param)
+{
+    example_espnow_data_t *buf = (example_espnow_data_t *)send_param->buffer;
+    int i = 0;
+
+    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;
+    for (i = 0; i < send_param->len - sizeof(example_espnow_data_t); i++) {
+        buf->payload[i] = (uint8_t)esp_random();
+    }
+    buf->crc = crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len);
+}
+
+static void example_espnow_task(void *pvParameter)
+{
+    example_espnow_event_t evt;
+    uint8_t recv_state = 0;
+    uint16_t recv_seq = 0;
+    int recv_magic = 0;
+    bool is_broadcast = false;
+    int ret;
+
+    vTaskDelay(5000 / portTICK_RATE_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(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_RATE_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;
+
+    example_espnow_queue = xQueueCreate(ESPNOW_QUEUE_SIZE, sizeof(example_espnow_event_t));
+    if (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) );
+
+    /* 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(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, 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));
+    memset(send_param, 0, sizeof(example_espnow_send_param_t));
+    if (send_param == NULL) {
+        ESP_LOGE(TAG, "Malloc send parameter fail");
+        vSemaphoreDelete(example_espnow_queue);
+        esp_now_deinit();
+        return ESP_FAIL;
+    }
+    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(example_espnow_queue);
+        esp_now_deinit();
+        return ESP_FAIL;
+    }
+    memcpy(send_param->dest_mac, 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;
+}
+
+static void example_espnow_deinit(example_espnow_send_param_t *send_param)
+{
+    free(send_param->buffer);
+    free(send_param);
+    vSemaphoreDelete(example_espnow_queue);
+    esp_now_deinit();
+}
+
+void app_main()
+{
+    // Initialize NVS
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+        ESP_ERROR_CHECK( nvs_flash_erase() );
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( ret );
+
+    example_wifi_init();
+    example_espnow_init();
+}