MySensors Library & Examples  2.3.2-62-ge298769
ESPNOWHelper.h
1 #pragma once
2 
3 #ifndef ESP32
4 #error "ESP32 constant is not defined."
5 #endif
6 
7 // ESP includes
8 #include <stdlib.h>
9 #include <time.h>
10 #include <string.h>
11 #include <assert.h>
12 #include "freertos/FreeRTOS.h"
13 #include "freertos/semphr.h"
14 #include "freertos/timers.h"
15 #include "nvs_flash.h"
16 #include "esp_event_loop.h"
17 #include "tcpip_adapter.h"
18 #include "esp_wifi.h"
19 #include "esp_log.h"
20 #include "esp_system.h"
21 #include "esp_now.h"
22 #include "rom/ets_sys.h"
23 #include "rom/crc.h"
24 #include "esp_wifi_types.h"
25 
26 static const char *TAG = "espnow";
27 
28 /* ESPNOW can work in both station and softap mode.
29  It is configured in menuconfig. */
30 #if CONFIG_STATION_MODE
31 #define ESPNOW_WIFI_MODE WIFI_MODE_STA
32 #define ESPNOW_WIFI_IF ESP_IF_WIFI_STA
33 #else
34 #define ESPNOW_WIFI_MODE WIFI_MODE_AP
35 #define ESPNOW_WIFI_IF ESP_IF_WIFI_AP
36 #endif
37 
38 #define ESPNOW_MAX_PACKET 250
39 #define ESPNOW_QUEUE_SIZE 6
40 
41 static uint8_t espnow_broadcast_mac[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
42 #define IS_BROADCAST_ADDR(addr) (memcmp(addr, espnow_broadcast_mac, ESP_NOW_ETH_ALEN) == 0)
43 
44 typedef struct {
45  uint8_t mac_addr[ESP_NOW_ETH_ALEN];
46  esp_now_send_status_t status;
48 
49 typedef struct {
50  uint8_t mac_addr[ESP_NOW_ETH_ALEN];
51  uint8_t *data;
52  int data_len;
54 
55 enum {
56  ESPNOW_DATA_BROADCAST,
57  ESPNOW_DATA_UNICAST,
58  ESPNOW_DATA_MAX,
59 };
60 
61 static uint8_t last_mac[ESP_NOW_ETH_ALEN];
62 static TaskHandle_t pjon_task_h = NULL;
63 static xQueueHandle espnow_recv_queue = NULL;
64 
65 static void espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status)
66 {
67  // The only thing we do in the send callback is unblock the
68  // other thread which blocks after posting data to the MAC
69  xTaskNotifyGive(pjon_task_h);
70  if(mac_addr == NULL) {
71  ESP_LOGE(TAG, "Send cb arg error");
72  }
73  return;
74 };
75 
76 static void espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int len)
77 {
78  espnow_packet_t packet;
79  if(mac_addr == NULL || data == NULL || len <= 0) {
80  ESP_LOGE(TAG, "Receive cb arg error");
81  return;
82  }
83  memcpy(packet.mac_addr, mac_addr, ESP_NOW_ETH_ALEN);
84  packet.data = (uint8_t *)malloc(len);
85  if(packet.data == NULL) {
86  ESP_LOGE(TAG, "Malloc receive data fail");
87  return;
88  }
89  memcpy(packet.data, data, len);
90  packet.data_len = len;
91  // Post to the queue, but don't wait
92  if(xQueueSend(espnow_recv_queue, &packet, 0) != pdTRUE) {
93  ESP_LOGW(TAG, "Send receive queue fail");
94  free(packet.data);
95  }
96 };
97 
98 class ENHelper
99 {
100  uint8_t _magic_header[4];
101  uint8_t _channel = 14;
102  uint8_t _esp_pmk[16];
103 
104 public:
105  void add_node_mac(uint8_t mac_addr[ESP_NOW_ETH_ALEN])
106  {
107  ESP_ERROR_CHECK(add_peer(mac_addr));
108  };
109 
110  esp_err_t add_peer(uint8_t mac_addr[ESP_NOW_ETH_ALEN])
111  {
112  if(esp_now_is_peer_exist(mac_addr)) {
113  return ESP_OK;
114  }
115  /* Add broadcast peer information to peer list. */
116  esp_now_peer_info_t *peer =
117  (esp_now_peer_info_t *)malloc(sizeof(esp_now_peer_info_t));
118  if(peer == NULL) {
119  ESP_LOGE(TAG, "Malloc peer information fail");
120  vSemaphoreDelete(espnow_recv_queue);
121  esp_now_deinit();
122  return ESP_FAIL;
123  }
124  memset(peer, 0, sizeof(esp_now_peer_info_t));
125  peer->channel = _channel;
126  peer->ifidx = ESPNOW_WIFI_IF;
127  if(IS_BROADCAST_ADDR(mac_addr)) {
128  peer->encrypt = false;
129  }
130  // else {
131  // peer->encrypt = true;
132  // memcpy(peer->lmk, _esp_pmk, 16);
133  // }
134  memcpy(peer->peer_addr, mac_addr, ESP_NOW_ETH_ALEN);
135  ESP_ERROR_CHECK(esp_now_add_peer(peer));
136  free(peer);
137  return ESP_OK;
138  };
139 
140  bool begin(uint8_t channel, uint8_t *espnow_pmk)
141  {
142  esp_err_t ret = nvs_flash_init();
143  if(
144  ret == ESP_ERR_NVS_NO_FREE_PAGES // ||
145  // ret == ESP_ERR_NVS_NEW_VERSION_FOUND
146  // error: ESP_ERR_NVS_NEW_VERSION_FOUND was not declared in this scope
147  ) {
148  ESP_ERROR_CHECK(nvs_flash_erase());
149  ret = nvs_flash_init();
150  }
151  ESP_ERROR_CHECK(ret);
152  pjon_task_h = xTaskGetCurrentTaskHandle();
153  _channel = channel;
154  memcpy(_esp_pmk, espnow_pmk, 16);
155  if(espnow_recv_queue != NULL) {
156  return ESP_FAIL;
157  }
158  espnow_recv_queue =
159  xQueueCreate(ESPNOW_QUEUE_SIZE, sizeof(espnow_packet_t));
160  if(espnow_recv_queue == NULL) {
161  ESP_LOGE(TAG, "Create mutex fail");
162  return ESP_FAIL;
163  }
164  tcpip_adapter_init();
165  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
166  ESP_ERROR_CHECK(esp_wifi_init(&cfg));
167  ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country));
168  ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
169  ESP_ERROR_CHECK(esp_wifi_set_mode(ESPNOW_WIFI_MODE));
170  /* These two steps are required BEFORE the channel can be set
171  As per the documentation from Espressif:
172  docs.espressif.com/projects/esp-idf/en/latest/api-reference/network/
173  esp_wifi.html#_CPPv420esp_wifi_set_channel7uint8_t18wifi_second_chan_t */
174  ESP_ERROR_CHECK(esp_wifi_start());
175  ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
176  ESP_ERROR_CHECK(esp_wifi_set_channel(_channel, WIFI_SECOND_CHAN_NONE));
177  // Initialize ESPNOW and register sending & receiving callback function
178  ESP_ERROR_CHECK(esp_now_init());
179  ESP_ERROR_CHECK(esp_now_register_send_cb(espnow_send_cb));
180  ESP_ERROR_CHECK(esp_now_register_recv_cb(espnow_recv_cb));
181  // Set primary master key
182  ESP_ERROR_CHECK(esp_now_set_pmk(_esp_pmk));
183  // Add broadcast peer information to peer list
184  add_peer(espnow_broadcast_mac);
185  return true;
186  };
187 
188  uint16_t receive_frame(uint8_t *data, uint16_t max_length)
189  {
190  // see if there's any received data waiting
191  espnow_packet_t packet;
192  if(xQueueReceive(espnow_recv_queue, &packet, 0) == pdTRUE) {
193  if(packet.data_len >= 4) {
194  uint8_t len = packet.data_len - 4;
195  if(
196  (packet.data[0] ^ len) != _magic_header[0] ||
197  (packet.data[1] ^ len) != _magic_header[1] ||
198  (packet.data[packet.data_len - 2] ^ len) != _magic_header[2] ||
199  (packet.data[packet.data_len - 1] ^ len) != _magic_header[3]
200  ) {
201  ESP_LOGE(TAG, "magic mismatch");
202  free(packet.data);
203  return PJON_FAIL;
204  }
205  if(len > max_length) {
206  free(packet.data);
207  ESP_LOGE(TAG, "buffer overflow - %d bytes but max is %d", len, max_length);
208  return PJON_FAIL;
209  }
210  memcpy(data, packet.data + 2, len);
211  free(packet.data);
212  // Update last mac received from
213  memcpy(last_mac, packet.mac_addr, ESP_NOW_ETH_ALEN);
214  return len;
215  } else {
216  ESP_LOGE(TAG, "packet < 4 received");
217  free(packet.data);
218  return PJON_FAIL; // No data waiting
219  }
220  }
221  return PJON_FAIL;
222  };
223 
224  void send_frame(
225  uint8_t *data,
226  uint16_t length,
227  uint8_t dest_mac[ESP_NOW_ETH_ALEN]
228  )
229  {
230  uint8_t packet[ESPNOW_MAX_PACKET];
231  if(length + 4 > ESPNOW_MAX_PACKET) {
232  ESP_LOGE(TAG, "Packet send error - too long :%d", length + 4);
233  return;
234  }
235  uint8_t len = length;
236  packet[0] = _magic_header[0] ^ len;
237  packet[1] = _magic_header[1] ^ len;
238  memcpy(packet + 2, data, len);
239  packet[len + 2] = _magic_header[2] ^ len;
240  packet[len + 3] = _magic_header[3] ^ len;
241  if(esp_now_send(dest_mac, packet, len + 4) != ESP_OK) {
242  ESP_LOGE(TAG, "Send error");
243  } else { // Wait for notification that the data has been received by the MAC
244  ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
245  }
246  };
247 
248  void send_response(uint8_t response)
249  {
250  send_frame(&response, 1, last_mac);
251  };
252 
253  void send_frame(uint8_t *data, uint16_t length)
254  {
255  // Broadcast
256  send_frame(data, length, espnow_broadcast_mac);
257  };
258 
259  void set_magic_header(uint8_t *magic_header)
260  {
261  memcpy(_magic_header, magic_header, 4);
262  };
263 
264  void get_sender(uint8_t *ip)
265  {
266  memcpy(ip, last_mac, ESP_NOW_ETH_ALEN);
267  };
268 };
data
char data[MAX_PAYLOAD_SIZE+1]
Buffer for raw payload data.
Definition: MyMessage.h:654
espnow_event_send_cb_t
Definition: ESPNOWHelper.h:44
espnow_packet_t
Definition: ESPNOWHelper.h:49
ENHelper
Definition: ESPNOWHelper.h:98