| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- /* 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_random.h"
- #include "esp_event.h"
- #include "esp_netif.h"
- #include "esp_wifi.h"
- #include "esp_log.h"
- #include "esp_mac.h"
- #include "esp_now.h"
- #include "esp_crc.h"
- #include "espnow_example.h"
- #define ESPNOW_MAXDELAY 512
- static const char *TAG = "espnow_example";
- 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[EXAMPLE_ESPNOW_DATA_MAX] = { 0, 0 };
- static void example_espnow_deinit(example_espnow_send_param_t *send_param);
- /* WiFi should start before using ESPNOW */
- static void example_wifi_init(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(ESPNOW_WIFI_MODE) );
- ESP_ERROR_CHECK( esp_wifi_start());
- #if CONFIG_ESPNOW_ENABLE_LONG_RANGE
- ESP_ERROR_CHECK( esp_wifi_set_protocol(ESPNOW_WIFI_IF, WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N|WIFI_PROTOCOL_LR) );
- #endif
- }
- /* 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(s_example_espnow_queue, &evt, ESPNOW_MAXDELAY) != 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(s_example_espnow_queue, &evt, ESPNOW_MAXDELAY) != 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 = esp_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;
- 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;
- /* Fill all remaining bytes after the data with random values */
- esp_fill_random(buf->payload, send_param->len - sizeof(example_espnow_data_t));
- buf->crc = esp_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_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_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE
- ESP_ERROR_CHECK( esp_now_set_wake_window(65535) );
- #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;
- }
- 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 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 );
- example_wifi_init();
- example_espnow_init();
- }
|