EnigmaIOT  0.9.8
Secure sensor and gateway platform based on ESP8266 and ESP32
espnow_hal.cpp
Go to the documentation of this file.
1 
9 #include "espnow_hal.h"
10 extern "C" {
11 #ifdef ESP8266
12 #include <espnow.h>
13 #elif defined ESP32
14 #include <esp_now.h>
15 #include <esp_wifi.h>
16 #endif
17 }
18 
19 
21 
23 
25  if (esp_now_init ()) {
26  ESP.restart ();
27  delay (1);
28  }
29  if (peerType == COMM_NODE) {
30 #ifdef ESP8266
31  esp_now_set_self_role (ESP_NOW_ROLE_CONTROLLER);
32  esp_now_add_peer (gateway, ESP_NOW_ROLE_SLAVE, channel, NULL, 0);
33 #elif defined ESP32
34  // esp_now_peer_info_t networkGw;
35  // memcpy (networkGw.peer_addr, gateway, COMMS_HAL_ADDR_LEN);
36  // networkGw.channel = channel;
37  // networkGw.ifidx = WIFI_IF_STA;
38  // networkGw.encrypt = false;
39  //esp_err_t result = esp_now_add_peer (&networkGw);
40  //DEBUG_INFO ("Gateway peer Added in channel %d. Result = %s", channel, esp_err_to_name (result));
41  DEBUG_DBG ("WIFI channel is %d", WiFi.channel ());
42 #endif
43  }
44 #ifdef ESP8266
45  else {
46  esp_now_set_self_role (ESP_NOW_ROLE_SLAVE);
47  }
48 #endif
49 
50  esp_now_register_recv_cb (reinterpret_cast<esp_now_recv_cb_t>(rx_cb));
51  esp_now_register_send_cb (reinterpret_cast<esp_now_send_cb_t>(tx_cb));
52 
53 #ifdef ESP32
54  xTaskCreateUniversal (runHandle, "espnow_loop", 2048, NULL, 1, &espnowLoopTask, CONFIG_ARDUINO_RUNNING_CORE);
55 #else
56  os_timer_setfn (&espnowLoopTask, runHandle, NULL);
57  os_timer_arm (&espnowLoopTask, 20, true);
58  // timer1_attachInterrupt (runHandle);
59  // timer1_enable (TIM_DIV16, TIM_EDGE, TIM_LOOP);
60  // timer1_write (25000); //5000 us
61 #endif
62 }
63 
64 void ICACHE_FLASH_ATTR Espnow_halClass::rx_cb (uint8_t* mac_addr, uint8_t* data, uint8_t len) {
65  if (Espnow_hal.dataRcvd) {
66  Espnow_hal.dataRcvd (mac_addr, data, len);
67  }
68 }
69 
70 void ICACHE_FLASH_ATTR Espnow_halClass::tx_cb (uint8_t* mac_addr, uint8_t status) {
71  Espnow_hal.readyToSend = true;
72  DEBUG_DBG ("Ready to send: true");
73  if (Espnow_hal.sentResult) {
74  Espnow_hal.sentResult (mac_addr, status);
75  }
76 }
77 
78 void Espnow_halClass::begin (uint8_t* gateway, uint8_t channel, peerType_t peerType) {
79  _ownPeerType = peerType;
80  _peerType = peerType;
81  DEBUG_INFO ("Starting ESP-NOW as %s", _peerType == COMM_GATEWAY ? "gateway" : "node");
82  if (peerType == COMM_NODE) {
83  DEBUG_DBG ("Gateway address is " MACSTR, MAC2STR (gateway));
84  memcpy (this->gateway, gateway, COMMS_HAL_ADDR_LEN);
85  this->channel = channel;
86  }
87  initComms (peerType);
88  if (_ownPeerType == COMM_NODE) {
90  }
91 }
92 
93 bool Espnow_halClass::addPeer (const uint8_t* da) {
94 #ifdef ESP32
95  esp_now_peer_info_t peer;
96  memcpy (peer.peer_addr, da, COMMS_HAL_ADDR_LEN);
97  uint8_t ch;
98  wifi_second_chan_t secondCh;
99  esp_wifi_get_channel (&ch, &secondCh);
100  peer.channel = ch;
101  if (_ownPeerType == COMM_NODE) {
102  peer.ifidx = WIFI_IF_STA;
103  } else {
104  peer.ifidx = WIFI_IF_AP;
105  }
106  peer.encrypt = false;
107  esp_err_t error = esp_now_add_peer (&peer);
108  DEBUG_DBG ("Peer %s added on channel %u. Result 0x%X %s", mac2str (da), ch, error, esp_err_to_name (error));
109  return error == ESP_OK;
110 #else
111  return true;
112 #endif
113 }
114 
116  DEBUG_INFO ("-------------> ESP-NOW STOP");
117  esp_now_unregister_recv_cb ();
118  esp_now_unregister_send_cb ();
119  esp_now_deinit ();
120 }
121 
122 int32_t Espnow_halClass::send (uint8_t* da, uint8_t* data, int len) {
123  comms_queue_item_t message;
124 
125  if (!da || !data || !len) {
126  DEBUG_WARN ("Parameters error");
127  return -1;
128  }
129 
130  if (len > MAX_MESSAGE_LENGTH) {
131  DEBUG_WARN ("Length error");
132  return -1;
133  }
134 
135  if (out_queue.size () >= COMMS_QUEUE_SIZE) {
136  out_queue.pop ();
137  }
138 
139  memcpy (message.dstAddress, da, ENIGMAIOT_ADDR_LEN);
140  message.payload_len = len;
141  memcpy (message.payload, data, len);
142 
143  if (out_queue.push (&message)) {
144  DEBUG_DBG ("%d Comms messages queued. Type: 0x%02X Len: %d", out_queue.size (), data[0], len);
145  return 0;
146  } else {
147  DEBUG_WARN ("Error queuing Comms message 0x%02X to %s", data[0], mac2str (da));
148  return -1;
149  }
150 }
151 
153  if (out_queue.size ()) {
154  DEBUG_DBG ("Comms message got from queue");
155  return out_queue.front ();
156  }
157  return nullptr;
158 }
159 
161  if (out_queue.size ()) {
162  comms_queue_item_t* message;
163 
164  message = out_queue.front ();
165  if (message) {
166  message->payload_len = 0;
167  }
168  out_queue.pop ();
169  DEBUG_DBG ("Comms message pop. Queue size %d", out_queue.size ());
170  }
171 }
172 
174  int32_t error;
175 
176  if (!message) {
177  return -1;
178  }
179  if (!(message->payload_len) || (message->payload_len > MAX_MESSAGE_LENGTH)) {
180  return -1;
181  }
182 
183  DEBUG_DBG ("ESP-NOW message to %s", mac2str(message->dstAddress));
184 #ifdef ESP32
185  //if (_ownPeerType == COMM_GATEWAY) {
186  addPeer (message->dstAddress);
187  DEBUG_DBG ("Peer added");
188  //}
189 #endif
190 
191  error = esp_now_send (message->dstAddress, message->payload, message->payload_len);
192  DEBUG_DBG ("Ready to send: false");
193  readyToSend = false;
194 #ifdef ESP32
195  DEBUG_DBG ("esp now send result = %s", esp_err_to_name(error));
196  //if (_ownPeerType == COMM_GATEWAY) {
197  error = esp_now_del_peer (message->dstAddress); // TODO: test
198  DEBUG_DBG ("Peer deleted. Result %s", esp_err_to_name(error));
199  //}
200 #endif
201  return error;
202 }
203 
205  this->dataRcvd = dataRcvd;
206 }
207 
209  this->sentResult = sentResult;
210 }
211 
213  if (readyToSend) {
214  //DEBUG_WARN ("Process queue: Elements: %d", out_queue.size ());
215  if (!out_queue.empty ()) {
216  comms_queue_item_t* message;
217  message = getCommsQueue ();
218  if (message) {
219  if (!sendEspNowMessage (message)) {
220  DEBUG_DBG ("Message to %s sent. Type: 0x%02X. Len: %u", mac2str (message->dstAddress), (message->payload)[0], message->payload_len);
221  } else {
222  DEBUG_WARN ("Error sendign message to %s. Type: 0x%02X. Len: %u", mac2str (message->dstAddress), (message->payload)[0], message->payload_len);
223  }
224  popCommsQueue ();
225  }
226  }
227  }
228 }
229 
230 void Espnow_halClass::runHandle (void* param) {
231 #ifdef ESP32
232  for (;;) {
233 #endif
234  Espnow_hal.handle ();
235 #ifdef ESP32
236  vTaskDelay (1 / portTICK_PERIOD_MS);
237  }
238 #endif
239 }
Espnow_halClass::out_queue
EnigmaIOTRingBuffer< comms_queue_item_t > out_queue
Definition: espnow_hal.h:38
peerType_t
peerType_t
Peer role on communication.
Definition: Comms_hal.h:23
comms_queue_item_t
Definition: Comms_hal.h:28
ENIGMAIOT_ADDR_LEN
static const size_t ENIGMAIOT_ADDR_LEN
Address size. Mac address = 6 bytes.
Definition: EnigmaIoTconfigAdvanced.h:23
Espnow_halClass::addPeer
bool addPeer(const uint8_t *da)
Adds a peer to esp-now peer list.
Definition: espnow_hal.cpp:93
MAX_MESSAGE_LENGTH
static const uint8_t MAX_MESSAGE_LENGTH
Maximum payload size on ESP-NOW.
Definition: EnigmaIoTconfigAdvanced.h:21
EnigmaIOTRingBuffer::size
int size()
Returns actual number of elements that buffer holds.
Definition: EnigmaIOTRingBuffer.h:54
Espnow_halClass
Definition for ESP-NOW hardware abstraction layer.
Definition: espnow_hal.h:31
Espnow_halClass::readyToSend
bool readyToSend
Definition: espnow_hal.h:39
EnigmaIOTRingBuffer::push
bool push(Telement *item)
Adds a new item to buffer, deleting older element if it is full.
Definition: EnigmaIOTRingBuffer.h:73
Espnow_halClass::handle
void handle() override
Sends next message in the queue.
Definition: espnow_hal.cpp:212
Espnow_halClass::begin
void begin(uint8_t *gateway, uint8_t channel=0, peerType_t peerType=COMM_NODE) override
Setup communication environment and establish the connection from node to gateway.
Definition: espnow_hal.cpp:78
Espnow_halClass::tx_cb
static void ICACHE_FLASH_ATTR tx_cb(uint8_t *mac_addr, uint8_t status)
Function that gets sending status.
Definition: espnow_hal.cpp:70
EnigmaIOTRingBuffer::empty
bool empty()
Checks if buffer is empty.
Definition: EnigmaIOTRingBuffer.h:66
EnigmaIOTRingBuffer::pop
bool pop()
Deletes older item from buffer, if buffer is not empty.
Definition: EnigmaIOTRingBuffer.h:106
Espnow_halClass::rx_cb
static void ICACHE_FLASH_ATTR rx_cb(uint8_t *mac_addr, uint8_t *data, uint8_t len)
Function that processes incoming messages and passes them to upper layer.
Definition: espnow_hal.cpp:64
Espnow_halClass::getCommsQueue
comms_queue_item_t * getCommsQueue()
Definition: espnow_hal.cpp:152
comms_queue_item_t::dstAddress
uint8_t dstAddress[ENIGMAIOT_ADDR_LEN]
Definition: Comms_hal.h:29
Espnow_halClass::send
int32_t send(uint8_t *da, uint8_t *data, int len) override
Sends data to the other peer.
Definition: espnow_hal.cpp:122
Comms_halClass::sentResult
comms_hal_sent_data sentResult
Pointer to a function to be called to notify last sending status.
Definition: Comms_hal.h:51
EnigmaIOTRingBuffer::front
Telement * front()
Gets a pointer to older item in buffer, if buffer is not empty.
Definition: EnigmaIOTRingBuffer.h:125
comms_queue_item_t::payload_len
size_t payload_len
Definition: Comms_hal.h:31
Espnow_halClass::espnowLoopTask
ETSTimer espnowLoopTask
Definition: espnow_hal.h:43
COMM_NODE
@ COMM_NODE
Definition: Comms_hal.h:24
COMMS_QUEUE_SIZE
static const uint8_t COMMS_QUEUE_SIZE
Definition: EnigmaIoTconfigAdvanced.h:28
Espnow_halClass::initComms
void initComms(peerType_t peerType) override
Communication subsistem initialization.
Definition: espnow_hal.cpp:24
Espnow_halClass::onDataSent
void onDataSent(comms_hal_sent_data dataRcvd) override
Attach a callback function to be run after sending a message to receive its status.
Definition: espnow_hal.cpp:208
BROADCAST_ADDRESS
static const uint8_t BROADCAST_ADDRESS[]
Broadcast address.
Definition: EnigmaIoTconfigAdvanced.h:26
comms_hal_rcvd_data
void(* comms_hal_rcvd_data)(uint8_t *address, uint8_t *data, uint8_t len)
Definition: Comms_hal.h:35
MACSTR
#define MACSTR
Definition: helperFunctions.cpp:83
Espnow_halClass::onDataRcvd
void onDataRcvd(comms_hal_rcvd_data dataRcvd) override
Attach a callback function to be run on every received message.
Definition: espnow_hal.cpp:204
COMM_GATEWAY
@ COMM_GATEWAY
Definition: Comms_hal.h:25
Comms_halClass::dataRcvd
comms_hal_rcvd_data dataRcvd
Pointer to a function to be called on every received message.
Definition: Comms_hal.h:50
data
@ data
Definition: GwOutput_generic.h:23
Comms_halClass::_ownPeerType
peerType_t _ownPeerType
Stores peer type, node or gateway.
Definition: Comms_hal.h:52
Espnow_hal
Espnow_halClass Espnow_hal
Singleton instance of ESP-NOW class.
Definition: espnow_hal.cpp:20
Espnow_halClass::sendEspNowMessage
int32_t sendEspNowMessage(comms_queue_item_t *message)
Definition: espnow_hal.cpp:173
mac2str
char * mac2str(const uint8_t *mac, char *extBuffer)
Debug helper function that generates a string that represent a MAC address.
Definition: helperFunctions.cpp:85
Espnow_halClass::runHandle
static void runHandle(void *param)
Static function that calls handle inside task.
Definition: espnow_hal.cpp:230
_peerType
peerType_t _peerType
Definition: espnow_hal.cpp:22
comms_hal_sent_data
void(* comms_hal_sent_data)(uint8_t *address, uint8_t status)
Definition: Comms_hal.h:36
espnow_hal.h
ESP-NOW communication system abstraction layer. To be used on ESP8266 or ESP32 platforms.
Espnow_halClass::stop
void stop() override
Terminates communication and closes all connectrions.
Definition: espnow_hal.cpp:115
Espnow_halClass::popCommsQueue
void popCommsQueue()
Definition: espnow_hal.cpp:160
Comms_halClass::gateway
uint8_t gateway[COMMS_HAL_ADDR_LEN]
Gateway address.
Definition: Comms_hal.h:47
Comms_halClass::channel
uint8_t channel
Comms channel to be used.
Definition: Comms_hal.h:48
status
@ status
Definition: GwOutput_generic.h:25
Espnow_halClass::COMMS_HAL_ADDR_LEN
static const uint8_t COMMS_HAL_ADDR_LEN
Address length for ESP-NOW. Correspond to mac address.
Definition: espnow_hal.h:34
comms_queue_item_t::payload
uint8_t payload[MAX_MESSAGE_LENGTH]
Definition: Comms_hal.h:30