EnigmaIOT  0.9.3
Secure sensor and gateway platform based on ESP8266 and ESP32
EnigmaIOTGateway.cpp
Go to the documentation of this file.
1 
9 #include "EnigmaIOTGateway.h"
10 #include <FS.h>
11 #include "libb64/cdecode.h"
12 #include <ArduinoJson.h>
13 #ifdef ESP8266
14 #include <Updater.h>
15 #elif defined ESP32
16 #include <SPIFFS.h>
17 #include <Update.h>
18 #include <esp_wifi.h>
19 #endif
20 
21 #include "cryptModule.h"
22 #include "helperFunctions.h"
23 #include <cstddef>
24 #include <cstdint>
25 #include <regex>
26 
27 const char CONFIG_FILE[] = "/config.json";
28 
29 bool shouldSave = false;
30 bool OTAongoing = false;
31 time_t lastOTAmsg = 0;
32 
33 
35  DEBUG_INFO ("Configuration saving activated");
36  shouldSave = true;
37 }
38 
40  return (shouldSave);
41 }
42 
43 void EnigmaIOTGatewayClass::setTxLed (uint8_t led, time_t onTime) {
44  this->txled = led;
45  txLedOnTime = onTime;
46  pinMode (txled, OUTPUT);
47  digitalWrite (txled, LED_OFF);
48 }
49 
50 void EnigmaIOTGatewayClass::setRxLed (uint8_t led, time_t onTime) {
51  this->rxled = led;
52  rxLedOnTime = onTime;
53  pinMode (rxled, OUTPUT);
54  digitalWrite (rxled, LED_OFF);
55 }
56 
57 const void* memstr (const void* str, size_t str_size,
58  const char* target, size_t target_size) {
59  const uint8_t* pointer = (const uint8_t*)str;
60  for (size_t i = 0; i != str_size - target_size; ++i) {
61  if (!memcmp (pointer + i, target, target_size)) {
62  return pointer + i;
63  }
64  }
65 
66  return NULL;
67 }
68 
69 bool buildGetVersion (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
70  DEBUG_DBG ("Build 'Get Version' message from: %s", printHexBuffer (inputData, inputLen));
71  if (dataLen < 1) {
72  return false;
73  }
74  data[0] = (uint8_t)control_message_type::VERSION;
75  dataLen = 1;
76  return true;
77 }
78 
79 bool buildGetSleep (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
80  DEBUG_VERBOSE ("Build 'Get Sleep' message from: %s", printHexBuffer (inputData, inputLen));
81  if (dataLen < 1) {
82  return false;
83  }
85  dataLen = 1;
86  return true;
87 }
88 
89 bool buildSetIdentify (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
90  DEBUG_VERBOSE ("Build 'Set Identify' message from: %s", printHexBuffer (inputData, inputLen));
91  if (dataLen < 1) {
92  return false;
93  }
95  dataLen = 1;
96  return true;
97 }
98 
99 bool buildGetRSSI (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
100  DEBUG_VERBOSE ("Build 'Get RSSI' message from: %s", printHexBuffer (inputData, inputLen));
101  if (dataLen < 1) {
102  return false;
103  }
104  data[0] = (uint8_t)control_message_type::RSSI_GET;
105  dataLen = 1;
106  return true;
107 }
108 
109 bool buildGetName (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
110  DEBUG_VERBOSE ("Build 'Get Node Name and Address' message from: %s", printHexBuffer (inputData, inputLen));
111  if (dataLen < 1) {
112  return false;
113  }
114  data[0] = (uint8_t)control_message_type::NAME_GET;
115  dataLen = 1;
116  return true;
117 }
118 
119 bool buildSetName (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
120  DEBUG_VERBOSE ("Build 'Set Node Name' message from: %s", printHexBuffer (inputData, inputLen));
121  if (dataLen < NODE_NAME_LENGTH + 1) {
122  DEBUG_ERROR ("Not enough space to build message");
123  return false;
124  }
125  if (inputLen < 2 || inputLen > NODE_NAME_LENGTH) {
126  DEBUG_ERROR ("Name too short");
127  return false;
128  }
129  data[0] = (uint8_t)control_message_type::NAME_SET;
130  memcpy (data + 1, inputData, inputLen);
131  dataLen = 1 + inputLen;
132  return true;
133 }
134 
135 bool buildSetResetConfig (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
136  DEBUG_VERBOSE ("Build 'Reset Config' message from: %s", printHexBuffer (inputData, inputLen));
137  if (dataLen < 1) {
138  return false;
139  }
140  data[0] = (uint8_t)control_message_type::RESET;
141  dataLen = 1;
142  return true;
143 }
144 
145 int getNextNumber (char*& data, size_t& len/*, char* &position*/) {
146  char strNum[10];
147  int number;
148  char* tempData = data;
149  size_t tempLen = len;
150 
151  for (int i = 0; i < 10; i++) {
152  //DEBUG_DBG ("Processing char: %c", tempData[i]);
153  if (tempData[i] != ',') {
154  if (tempData[i] >= '0' && tempData[i] <= '9') {
155  strNum[i] = tempData[i];
156  } else {
157  DEBUG_ERROR ("OTA message format error. Message number not found");
158  number = -1;
159  }
160  if (i == 9) {
161  DEBUG_ERROR ("OTA message format error, separator not found");
162  number = -2;
163  }
164  } else {
165  if (i == 0) {
166  DEBUG_ERROR ("OTA message format error, cannot find a number");
167  number = -3;
168  }
169  strNum[i] = '\0';
170  //DEBUG_DBG ("Increment pointer by %d", i);
171  tempData += i;
172  tempLen -= i;
173  break;
174  }
175  }
176  if (tempData[0] == ',' && tempLen > 0) {
177  tempData++;
178  tempLen--;
179  } else {
180  DEBUG_WARN ("OTA message format warning. separator not found");
181  }
182  number = atoi (strNum);
183  data = tempData;
184  len = tempLen;
185  DEBUG_DBG ("Extracted number %d", number);
186  DEBUG_DBG ("Resulting data %s", data);
187  //DEBUG_WARN ("Resulting length %d", len);
188  return number;
189 }
190 
191 bool isHexChar (char c) {
192  //DEBUG_DBG ("Is Hex Char %c", c);
193  return (
194  (c >= '0' && c <= '9')
195  || (c >= 'a' && c <= 'f')
196  //|| c >= 'A' && c <= 'F'
197  );
198 }
199 
200 bool buildOtaMsg (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
201  char* payload;
202  size_t payloadLen;
203  int number;
204  uint8_t* tempData = data;
205 
206  DEBUG_VERBOSE ("Build 'OTA' message from: %s", inputData);
207 
208  payload = (char*)inputData;
209  payloadLen = inputLen;
210 
211  // Get message number
212  number = getNextNumber (payload, payloadLen);
213  if (number < 0) {
214  return false;
215  }
216  uint16_t msgIdx = number;
217 
218  tempData[0] = (uint8_t)control_message_type::OTA;
219  tempData++;
220  memcpy (tempData, &msgIdx, sizeof (uint16_t));
221  size_t decodedLen = sizeof (uint8_t) + sizeof (uint16_t);
222  tempData += sizeof (uint16_t);
223 
224  DEBUG_WARN ("OTA message number %u", msgIdx);
225  //DEBUG_INFO ("Payload len = %u", payloadLen);
226  //DEBUG_INFO ("Payload data: %s", payload);
227 
228  if (msgIdx > 0) {
229  decodedLen += base64_decode_chars (payload, payloadLen, (char*)(data + 1 + sizeof (uint16_t)));
230  lastOTAmsg = millis ();
231  } else {
232  OTAongoing = true;
233  lastOTAmsg = millis ();
234 
235  if (inputLen < 39) {
236  DEBUG_ERROR ("OTA message format error. Message #0 too short to be a MD5 string");
237  return false;
238  }
239 
240  // Get firmware size
241  number = getNextNumber (payload, payloadLen);
242  if (number < 0) {
243  return false;
244  }
245  uint32_t fileSize = number;
246 
247  memcpy (tempData, &fileSize, sizeof (uint32_t));
248  tempData += sizeof (uint32_t);
249  decodedLen += sizeof (uint32_t);
250 
251 
252  // Get number of chunks
253  number = getNextNumber (payload, payloadLen);
254  if (number < 0) {
255  return false;
256  }
257  uint16_t msgNum = number;
258 
259  memcpy (tempData, &msgNum, sizeof (uint16_t));
260  tempData += sizeof (uint16_t);
261  decodedLen += sizeof (uint16_t);
262 
263  DEBUG_WARN ("Number of OTA chunks %u", msgNum);
264  DEBUG_WARN ("OTA length = %u bytes", fileSize);
265  //DEBUG_INFO ("Payload data: %s", payload);
266 
267  if (payloadLen < 32) {
268  DEBUG_ERROR ("OTA message format error. MD5 is too short: %d", payloadLen);
269  return false;
270  }
271 
272  for (size_t i = 0; i < 32; i++) {
273  if (!isHexChar (payload[i])) {
274  DEBUG_ERROR ("OTA message format error. MD5 string has no valid format");
275  return false;
276  }
277  *tempData = (uint8_t)payload[i];
278  tempData++;
279  decodedLen++;
280  }
281 
282  DEBUG_VERBOSE ("Payload data: %s", printHexBuffer (data, decodedLen));
283  }
284 
285  if ((decodedLen) > MAX_MESSAGE_LENGTH) {
286  DEBUG_ERROR ("OTA message too long. %u bytes.", decodedLen);
287  return false;
288  }
289  dataLen = decodedLen;
290  DEBUG_VERBOSE ("Payload has %u bytes of data: %s", dataLen, printHexBuffer (data, dataLen));
291  return true;
292 }
293 
294 bool buildSetSleep (uint8_t* data, size_t& dataLen, const uint8_t* inputData, size_t inputLen) {
295  DEBUG_VERBOSE ("Build 'Set Sleep' message from: %s", printHexBuffer (inputData, inputLen));
296  if (dataLen < 5) {
297  DEBUG_ERROR ("Not enough space to build message");
298  return false;
299  }
300 
301  if (inputLen <= 1) {
302  DEBUG_ERROR ("Set sleep time value is empty");
303  return false;
304  }
305 
306  for (unsigned int i = 0; i < (inputLen - 1); i++) { // Check if all digits are number
307  if (inputData[i] < 30 || inputData[i] > '9') {
308  DEBUG_ERROR ("Set sleep time value is not a number on position %d: %d", i, inputData[i]);
309  return false;
310  }
311  }
312  if (inputData[inputLen - 1] != 0) { // Array should end with \0
313  DEBUG_ERROR ("Set sleep time value does not end with \\0");
314  return false;
315  }
316 
317  uint32_t sleepTime = atoi ((char*)inputData);
318 
320  memcpy (data + 1, &sleepTime, sizeof (uint32_t));
321  dataLen = 5;
322  return true;
323 }
324 
325 bool EnigmaIOTGatewayClass::sendDownstream (uint8_t* mac, const uint8_t* data, size_t len, control_message_type_t controlData, gatewayPayloadEncoding_t encoding, char* nodeName) {
326  Node* node;
327  if (nodeName) {
328  node = nodelist.getNodeFromName (nodeName);
329  if (node) {
330  uint8_t* addr = node->getMacAddress ();
331  DEBUG_DBG ("Message to node %s with address " MACSTR, nodeName, MAC2STR (addr));
332  }
333  //DEBUG_WARN ("Message to node %s with address %s", nodeName, mac2str (node->getMacAddress (), addrStr));
334  } else {
335  node = nodelist.getNodeFromMAC (mac);
336  }
337 
338  uint8_t downstreamData[MAX_MESSAGE_LENGTH];
339 
340  if (len == 0 && (controlData == USERDATA_GET || controlData == USERDATA_SET))
341  return false;
342 
343  DEBUG_VERBOSE ("Downstream: %s", printHexBuffer (data, len));
344  DEBUG_DBG ("Downstream message type 0x%02X", controlData);
345 
346  size_t dataLen = MAX_MESSAGE_LENGTH;
347 
348  switch (controlData) {
350  if (!buildGetVersion (downstreamData, dataLen, data, len)) {
351  DEBUG_ERROR ("Error building get Version message");
352  return false;
353  }
354  DEBUG_VERBOSE ("Get Version. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
355  break;
357  if (!buildGetSleep (downstreamData, dataLen, data, len)) {
358  DEBUG_ERROR ("Error building get Sleep message");
359  return false;
360  }
361  DEBUG_VERBOSE ("Get Sleep. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
362  break;
364  if (!buildSetSleep (downstreamData, dataLen, data, len)) {
365  DEBUG_ERROR ("Error building set Sleep message");
366  return false;
367  }
368  DEBUG_VERBOSE ("Set Sleep. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
369  break;
371  if (!buildOtaMsg (downstreamData, dataLen, data, len)) {
372  DEBUG_ERROR ("Error building OTA message");
373  return false;
374  }
375  DEBUG_VERBOSE ("OTA message. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
376  break;
378  if (!buildSetIdentify (downstreamData, dataLen, data, len)) {
379  DEBUG_ERROR ("Error building Identify message");
380  return false;
381  }
382  DEBUG_VERBOSE ("Identify message. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
383  break;
385  if (!buildSetResetConfig (downstreamData, dataLen, data, len)) {
386  DEBUG_ERROR ("Error building Reset message");
387  return false;
388  }
389  DEBUG_VERBOSE ("Reset Config message. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
390  break;
392  if (!buildGetRSSI (downstreamData, dataLen, data, len)) {
393  DEBUG_ERROR ("Error building get RSSI message");
394  return false;
395  }
396  DEBUG_VERBOSE ("Get RSSI message. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
397  break;
399  if (!buildGetName (downstreamData, dataLen, data, len)) {
400  DEBUG_ERROR ("Error building get name message");
401  return false;
402  }
403  DEBUG_VERBOSE ("Get name message. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
404  break;
406  if (!buildSetName (downstreamData, dataLen, data, len)) {
407  DEBUG_ERROR ("Error building set name message");
408  return false;
409  }
410  DEBUG_VERBOSE ("Set name message. Len: %d Data %s", dataLen, printHexBuffer (downstreamData, dataLen));
411  break;
413  DEBUG_INFO ("Data message GET");
414  break;
416  DEBUG_INFO ("Data message SET");
417  break;
418  default:
419  return false;
420  }
421 
422 
423  DEBUG_INFO ("Send downstream");
424 
425  if (node) {
426  if (controlData != control_message_type::USERDATA_GET && controlData != control_message_type::USERDATA_SET)
427  return downstreamDataMessage (node, downstreamData, dataLen, controlData);
428  else if (controlData == control_message_type::OTA) {
429  if (node->getSleepy ()) {
430  DEBUG_ERROR ("Node must be in non sleepy mode to receive OTA messages");
431  return false;
432  } else
433  return downstreamDataMessage (node, data, len, controlData);
434  } else
435  return downstreamDataMessage (node, data, len, controlData, encoding);
436  } else {
437  char addr[ENIGMAIOT_ADDR_LEN * 3];
438  DEBUG_ERROR ("Downlink destination %s not found", nodeName ? nodeName : mac2str (mac, addr));
439  return false;
440  }
441 }
442 
444  server = new AsyncWebServer (80);
445  dns = new DNSServer ();
446  wifiManager = new AsyncWiFiManager (server, dns);
447 
448  char networkKey[33] = "";
449  //char networkName[NETWORK_NAME_LENGTH] = "";
450  char channel[4];
451  //String (gwConfig.channel).toCharArray (channel, 4);
452  snprintf (channel, 4, "%u", gwConfig.channel);
453 
454  //AsyncWiFiManager wifiManager (&server, &dns);
455  AsyncWiFiManagerParameter netNameParam ("netname", "Network Name", gwConfig.networkName, (int)NETWORK_NAME_LENGTH - 1, "required type=\"text\" pattern=\"^[^/\\\\]+$\" maxlength=20");
456  AsyncWiFiManagerParameter netKeyParam ("netkey", "NetworkKey", networkKey, 33, "required type=\"password\" minlength=\"8\" maxlength=\"32\"");
457  AsyncWiFiManagerParameter channelParam ("channel", "WiFi Channel", channel, 4, "required type=\"number\" min=\"0\" max=\"13\" step=\"1\"");
458 
459  wifiManager->setCustomHeadElement ("<style>input:invalid {border: 2px dashed red;input:valid{border: 2px solid black;}</style>");
460  wifiManager->addParameter (&netKeyParam);
461  wifiManager->addParameter (&channelParam);
462  wifiManager->addParameter (&netNameParam);
463  wifiManager->addParameter (new AsyncWiFiManagerParameter ("<br>"));
464 
467  }
468 
469  wifiManager->setDebugOutput (true);
470 #if CONNECT_TO_WIFI_AP != 1
471  wifiManager->setBreakAfterConfig (true);
472 #endif // CONNECT_TO_WIFI_AP
473  wifiManager->setTryConnectDuringConfigPortal (false);
474  wifiManager->setSaveConfigCallback (doSave);
475  wifiManager->setConfigPortalTimeout (150);
476 
477 #if CONNECT_TO_WIFI_AP == 1
478  boolean result = wifiManager->autoConnect ("EnigmaIoTGateway", NULL, 3, 2000);
479 #else
480  boolean result = wifiManager->startConfigPortal ("EnigmaIoTGateway", NULL);
481  result = true; // Force true if this should not connect to a WiFi
482 #endif // CONNECT_TO_WIFI_AP
483 
484  DEBUG_INFO ("==== Config Portal result ====");
485  DEBUG_INFO ("Network Name: %s", netNameParam.getValue ());
486  DEBUG_INFO ("Network Key: %s", netKeyParam.getValue ());
487  DEBUG_INFO ("Channel: %s", channelParam.getValue ());
488  DEBUG_INFO ("Status: %s", result ? "true" : "false");
489  DEBUG_INFO ("Save config: %s", shouldSave ? "yes" : "no");
490  if (result) {
491  if (shouldSave) {
492  bool regexResult;
493 
494  std::regex networkNameRegex ("^[^/\\\\]+$");
495  regexResult = std::regex_match (netNameParam.getValue (), networkNameRegex);
496  if (regexResult) {
497  strncpy (this->gwConfig.networkName, netNameParam.getValue (), NETWORK_NAME_LENGTH - 1);
498  DEBUG_DBG ("Network name: %s", gwConfig.networkName);
499  } else {
500  DEBUG_WARN ("Network name parameter error");
501  result = false;
502  }
503 
504  std::regex netKeyRegex ("^.{8,32}$");
505  regexResult = std::regex_match (netKeyParam.getValue (), netKeyRegex);
506  if (regexResult) {
507  uint8_t keySize = netKeyParam.getValueLength ();
508  if (keySize > KEY_LENGTH)
509  keySize = KEY_LENGTH;
510  const char* netKey = netKeyParam.getValue ();
511  if (netKey && (netKey[0] != '\0')) {// If password is empty, keep the old one
512  memset (this->gwConfig.networkKey, 0, KEY_LENGTH);
513  memcpy (this->gwConfig.networkKey, netKey, keySize);
514  memcpy (this->plainNetKey, netKey, keySize);
516  DEBUG_DBG ("Raw network Key: %s", printHexBuffer (this->gwConfig.networkKey, KEY_LENGTH));
517  } else {
518  DEBUG_INFO ("Network key password field empty. Keeping the old one");
519  }
520  } else {
521  DEBUG_WARN ("Network key parameter error");
522  result = false;
523  }
524 
525  std::regex channelRegex ("^([0-9]|[0-1][0-3])$");
526  regexResult = std::regex_match (channelParam.getValue (), channelRegex);
527  if (regexResult) {
528  this->gwConfig.channel = atoi (channelParam.getValue ());
529  DEBUG_DBG ("WiFi ESP-NOW channel: %d", this->gwConfig.channel);
530  } else {
531  DEBUG_WARN ("Network name parameter error");
532  result = false;
533  }
534  } else {
535  DEBUG_DBG ("Configuration does not need to be saved");
536  }
537  } else {
538  DEBUG_ERROR ("WiFi connection unsuccessful. Restarting");
539  ESP.restart ();
540  }
541 
542  if (notifyWiFiManagerExit) {
543  notifyWiFiManagerExit (result);
544  }
545 
546  delete (server);
547  delete (dns);
548  delete (wifiManager);
549 
550  return result;
551 }
552 
554  //SPIFFS.remove (CONFIG_FILE); // Only for testing
555  bool json_correct = false;
556 
557  if (SPIFFS.exists (CONFIG_FILE)) {
558 
559  DEBUG_DBG ("Opening %s file", CONFIG_FILE);
560  File configFile = SPIFFS.open (CONFIG_FILE, "r");
561  if (configFile) {
562  size_t size = configFile.size ();
563  DEBUG_DBG ("%s opened. %u bytes", CONFIG_FILE, size);
564 
565  const size_t capacity = JSON_OBJECT_SIZE (3) + 150;
566  DynamicJsonDocument doc (capacity);
567 
568  DeserializationError error = deserializeJson (doc, configFile);
569  if (error) {
570  DEBUG_ERROR ("Failed to parse file");
571  } else {
572  DEBUG_DBG ("JSON file parsed");
573  }
574 
575  if (doc.containsKey ("channel") && doc.containsKey ("networkKey")
576  && doc.containsKey ("networkName")) {
577  json_correct = true;
578  }
579 
580  gwConfig.channel = doc["channel"].as<int> ();
581  strncpy ((char*)gwConfig.networkKey, doc["networkKey"] | "", sizeof (gwConfig.networkKey));
582  strncpy (gwConfig.networkName, doc["networkName"] | "", sizeof (gwConfig.networkName));
583 
584  configFile.close ();
585  if (json_correct) {
586  DEBUG_VERBOSE ("Gateway configuration successfuly read");
587  }
588  DEBUG_DBG ("==== EnigmaIOT Gateway Configuration ====");
589  DEBUG_DBG ("Network name: %s", gwConfig.networkName);
590  DEBUG_DBG ("WiFi channel: %u", gwConfig.channel);
591  DEBUG_VERBOSE ("Network key: %s", gwConfig.networkKey);
592  strncpy (plainNetKey, (char*)gwConfig.networkKey, KEY_LENGTH);
594  DEBUG_VERBOSE ("Raw Network key: %s", printHexBuffer (gwConfig.networkKey, KEY_LENGTH));
595 
596 #if DEBUG_LEVEL >= DBG
597  char* output;
598  size_t json_len = measureJsonPretty (doc)+1;
599  output = (char*)malloc (json_len);
600  serializeJsonPretty (doc, output, json_len);
601 
602  DEBUG_DBG ("JSON file %s", output);
603  free (output);
604 #endif
605 
606  } else {
607  DEBUG_WARN ("Error opening %s", CONFIG_FILE);
608  }
609  } else {
610  DEBUG_WARN ("%s do not exist", CONFIG_FILE);
611  //SPIFFS.format (); // Testing only
612  //WiFi.begin ("0", "0"); // Delete WiFi credentials
613  //DEBUG_WARN ("Dummy STA config loaded");
614  //return false;
615  }
616 
617  if (!json_correct) {
618  WiFi.begin ("0", "0"); // Delete WiFi credentials
619  DEBUG_WARN ("Dummy STA config loaded");
620  }
621  return json_correct;
622 }
623 
625  File configFile = SPIFFS.open (CONFIG_FILE, "w");
626  if (!configFile) {
627  DEBUG_WARN ("failed to open config file %s for writing", CONFIG_FILE);
628  return false;
629  }
630 
631  const size_t capacity = JSON_OBJECT_SIZE (3) + 150;
632  DynamicJsonDocument doc (capacity);
633 
634  doc["channel"] = gwConfig.channel;
635  doc["networkKey"] = plainNetKey;
636  doc["networkName"] = gwConfig.networkName;
637 
638  if (serializeJson (doc, configFile) == 0) {
639  DEBUG_ERROR ("Failed to write to file");
640  configFile.close ();
641  //SPIFFS.remove (CONFIG_FILE); // Testing only
642  return false;
643  }
644 
645 #if DEBUG_LEVEL >= DBG
646  char* output;
647  size_t json_len = measureJsonPretty (doc) + 1;
648  output = (char*)malloc (json_len);
649  serializeJsonPretty (doc, output, json_len);
650 
651  DEBUG_DBG ("\n%s", output);
652 
653  free (output);
654 #endif
655 
656  configFile.flush ();
657  size_t size = configFile.size ();
658 
659  configFile.close ();
660 
661  //memset (networkKey, 0, KEY_LENGTH);
662 
663  DEBUG_DBG ("Gateway configuration saved to flash. %u bytes", size);
664  return true;
665 }
666 
667 void EnigmaIOTGatewayClass::begin (Comms_halClass* comm, uint8_t* networkKey, bool useDataCounter) {
669  this->comm = comm;
670  this->useCounter = useDataCounter;
671 
672  if (networkKey) {
673  memcpy (this->gwConfig.networkKey, networkKey, KEY_LENGTH);
674  strncpy (plainNetKey, (char*)networkKey, KEY_LENGTH);
676  } else {
677  if (!SPIFFS.begin ()) {
678  DEBUG_ERROR ("Error mounting flash");
679  SPIFFS.format ();
680  DEBUG_ERROR ("Formatted");
681  ESP.restart ();
682  return;
683  }
684  if (!loadFlashData ()) { // Load from flash
685  if (configWiFiManager ()) {
686  if (shouldSave) {
687  DEBUG_DBG ("Got configuration. Storing");
688  if (saveFlashData ()) {
689  DEBUG_DBG ("Network Key stored on flash");
690  } else {
691  DEBUG_ERROR ("Error saving data on flash");
692  }
693  ESP.restart ();
694  } else {
695  DEBUG_INFO ("Configuration has not to be saved");
696  }
697  } else {
698  DEBUG_ERROR ("Configuration error. Restarting");
699  ESP.restart ();
700  }
701  } else {
702  DEBUG_INFO ("Configuration loaded from flash");
703  }
704 
707  comm->onDataRcvd (rx_cb);
708  comm->onDataSent (tx_cb);
709  }
710 }
711 
712 bool EnigmaIOTGatewayClass::addInputMsgQueue (const uint8_t* addr, const uint8_t* msg, size_t len) {
713  msg_queue_item_t message;
714 
715  message.len = len;
716  memcpy (message.data, msg, len);
717  memcpy (message.addr, addr, ENIGMAIOT_ADDR_LEN);
718 
719 #ifdef ESP32
720  portENTER_CRITICAL (&myMutex);
721 #else
722  noInterrupts ();
723 #endif
724  input_queue->push (&message);
725  char macstr[ENIGMAIOT_ADDR_LEN * 3];
726  DEBUG_DBG ("Message 0x%02X added from %s. Size: %d", message.data[0], mac2str (message.addr, macstr), input_queue->size ());
727 #ifdef ESP32
728  portEXIT_CRITICAL (&myMutex);
729 #else
730  interrupts ();
731 #endif
732  return true;
733 }
734 
736 
737  msg_queue_item_t* message;
738 #ifdef esp32
739  portENTER_CRITICAL (&myMutex);
740 #else
741  noInterrupts ();
742 #endif
743  message = input_queue->front ();
744  if (message) {
745  DEBUG_DBG ("EnigmaIOT message got from queue. Size: %d", input_queue->size ());
746  memcpy (buffer->data, message->data, message->len);
747  memcpy (buffer->addr, message->addr, ENIGMAIOT_ADDR_LEN);
748  buffer->len = message->len;
749  popInputMsgQueue ();
750  }
751 #ifdef esp32
752  portEXIT_CRITICAL (&myMutex);
753 #else
754  interrupts ();
755 #endif
756  if (message) {
757  return buffer;
758  } else {
759  return NULL;
760  }
761 }
762 
764  if (input_queue->pop ()) {
765  DEBUG_DBG ("EnigmaIOT message pop. Size %d", input_queue->size ());
766  }
767 }
768 
769 void EnigmaIOTGatewayClass::rx_cb (uint8_t* mac_addr, uint8_t* data, uint8_t len) {
770 
771  EnigmaIOTGateway.addInputMsgQueue (mac_addr, data, len);
772 }
773 
774 void EnigmaIOTGatewayClass::tx_cb (uint8_t* mac_addr, uint8_t status) {
775  EnigmaIOTGateway.getStatus (mac_addr, status);
776 }
777 
778 void EnigmaIOTGatewayClass::getStatus (uint8_t* mac_addr, uint8_t status) {
779  char buffer[ENIGMAIOT_ADDR_LEN * 3];
780 #ifdef ESP8266
781  DEBUG_VERBOSE ("SENDStatus %s. Peer %s", status == 0 ? "OK" : "ERROR", mac2str (mac_addr, buffer));
782 #elif defined ESP32
783  DEBUG_VERBOSE ("SENDStatus %d. Peer %s", status, mac2str (mac_addr, buffer));
784 #endif
785 }
786 
788 //#ifdef ESP8266
789  static unsigned long rxOntime;
790  static unsigned long txOntime;
791 
792  if (flashRx) {
793  DEBUG_DBG ("EnigmaIOTGatewayClass::flashrx");
794 
795  if (rxled == txled) {
796  flashTx = true;
797  } else {
798  rxOntime = millis ();
799  digitalWrite (rxled, LED_ON);
800  }
801  flashRx = false;
802  }
803 
804  if (rxled != txled) {
805  if ( millis () - rxOntime > rxLedOnTime) {
806  digitalWrite (rxled, LED_OFF);
807  }
808  }
809 
810  if (flashTx) {
811  txOntime = millis ();
812  digitalWrite (txled, LED_ON);
813  flashTx = false;
814  }
815 
816  if ( millis () - txOntime > txLedOnTime) {
817  digitalWrite (txled, LED_OFF);
818  }
819 //#endif
820 
821  // Clean up dead nodes
822  for (int i = 0; i < NUM_NODES; i++) {
824  if (node->isRegistered () && millis () - node->getLastMessageTime () > MAX_NODE_INACTIVITY) {
825  // TODO. Trigger node expired event
826  node->reset ();
827  }
828  }
829 
830  if (OTAongoing) {
831  time_t currentTime = millis ();
832  if ((currentTime - lastOTAmsg) > OTA_GW_TIMEOUT) {
833  OTAongoing = false;
834  DEBUG_WARN ("OTA ongoing = false");
835  DEBUG_WARN ("millis() = %u, lastOTAmsg = %u, diff = %d", currentTime, lastOTAmsg, currentTime - lastOTAmsg);
836  }
837  }
838 
839  // Check input EnigmaIOT message queue
840 
841  if (!input_queue->empty ()) {
842  msg_queue_item_t* message;
843 
844  message = getInputMsgQueue (&tempBuffer);
845 
846  if (message) {
847  DEBUG_DBG ("EnigmaIOT input message from queue. MsgType: 0x%02X", message->data[0]);
848  manageMessage (message->addr, message->data, message->len);
849  }
850  }
851 }
852 
853 void EnigmaIOTGatewayClass::manageMessage (const uint8_t* mac, uint8_t* buf, uint8_t count) {
854  Node* node;
855 
856  DEBUG_INFO ("Reveived message. Origin MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
857  DEBUG_VERBOSE ("Received data: %s", printHexBuffer (buf, count));
858 
859  if (count <= 1) {
860  DEBUG_WARN ("Empty message");
861  return;
862  }
863 
864  node = nodelist.getNewNode (mac);
865 
866  flashRx = true;
867 
868  int espNowError = 0; // May I remove this??
869 
870  switch (buf[0]) {
871  case CLIENT_HELLO:
872  // TODO: Do no accept new Client Hello if registration is on process on any node?? Possible DoS Attack??
873  // May cause undesired behaviour in case a node registration message is lost
874  DEBUG_INFO (" <------- CLIENT HELLO");
875  //if (!OTAongoing) {
876  if (espNowError == 0) {
877  if (processClientHello (mac, buf, count, node)) {
878  if (serverHello (myPublicKey, node)) {
879  DEBUG_INFO ("Server Hello sent");
880  node->setStatus (REGISTERED);
881  node->setKeyValidFrom (millis ());
882  node->setLastMessageCounter (0);
883  node->setLastMessageTime ();
884  if (notifyNewNode) {
885  notifyNewNode (node->getMacAddress (), node->getNodeId (), NULL);
886  }
887 #if DEBUG_LEVEL >= INFO
889 #endif
890  } else {
891  node->reset ();
892  DEBUG_INFO ("Error sending Server Hello");
893  }
894 
895  } else {
896  // Ignore message in case of error
897  //invalidateKey (node, WRONG_CLIENT_HELLO);
898  node->reset ();
899  DEBUG_ERROR ("Error processing client hello");
900  }
901  } else {
902  DEBUG_ERROR ("Error adding peer %d", espNowError);
903  }
904  //} else {
905  // DEBUG_WARN ("OTA ongoing. Registration ignored");
906  //}
907  break;
908  case CONTROL_DATA:
909  DEBUG_INFO (" <------- CONTROL MESSAGE");
910  if (node->getStatus () == REGISTERED) {
911  if (processControlMessage (mac, buf, count, node)) {
912  DEBUG_INFO ("Control message OK");
913  if (millis () - node->getKeyValidFrom () > MAX_KEY_VALIDITY) {
915  }
916  } else {
919  }
920  DEBUG_WARN ("Control message not OK");
921  }
922  } else {
924  }
925  break;
926  case SENSOR_DATA:
928  bool encrypted;
929  if (buf[0] == SENSOR_DATA) {
930  DEBUG_INFO (" <------- ENCRYPTED DATA");
931  encrypted = true;
932  } else {
933  DEBUG_INFO (" <------- UNENCRYPTED DATA");
934  encrypted = false;
935  }
936  //if (!OTAongoing) {
937  if (node->getStatus () == REGISTERED) {
938  float packetsHour = (float)1 / ((millis () - node->getLastMessageTime ()) / (float)3600000);
939  node->updatePacketsRate (packetsHour);
940  if (processDataMessage (mac, buf, count, node, encrypted)) {
941  node->setLastMessageTime ();
942  DEBUG_INFO ("Data OK");
943  DEBUG_VERBOSE ("Key valid from %lu ms", millis () - node->getKeyValidFrom ());
944  if (millis () - node->getKeyValidFrom () > MAX_KEY_VALIDITY) {
946  }
947  } else {
950  }
951  DEBUG_WARN ("Data not OK");
952  }
953  } else {
955  node->reset ();
956  }
957  //} else {
958  // DEBUG_WARN ("Data ignored. OTA ongoing");
959  //}
960  break;
961  case CLOCK_REQUEST:
962  DEBUG_INFO (" <------- CLOCK REQUEST");
963  if (node->getStatus () == REGISTERED) {
964  if (processClockRequest (mac, buf, count, node)) {
965  DEBUG_INFO ("Clock request OK");
966  if (millis () - node->getKeyValidFrom () > MAX_KEY_VALIDITY) {
968  }
969  } else {
971  DEBUG_WARN ("Clock request not OK");
972  }
973 
974  } else {
976  }
977  break;
978  case NODE_NAME_SET:
979  DEBUG_INFO (" <------- NODE NAME REQUEST");
980  if (node->getStatus () == REGISTERED) {
981  if (processNodeNameSet (mac, buf, count, node)) {
982  DEBUG_INFO ("Node name for node %d set to %s", node->getNodeId (), node->getNodeName ());
983  if (notifyNewNode) {
984  notifyNewNode (node->getMacAddress (), node->getNodeId (), node->getNodeName ());
985  }
986  } else {
987  DEBUG_WARN ("Error setting node name for node %d", node->getNodeId ());
988  }
989  }
990  break;
991  default:
992  DEBUG_WARN ("Received unknown EnigmaIOT message 0x%02X");
993  }
994 }
995 
997  /*
998  * ---------------------------------------------------
999  *| msgType (1) | IV (12) | Result code (1) | tag (16) |
1000  * ---------------------------------------------------
1001  */
1002  struct __attribute__ ((packed, aligned (1))) {
1003  uint8_t msgType;
1004  uint8_t iv[IV_LENGTH];
1005  int8_t errorCode;
1006  uint8_t tag[TAG_LENGTH];
1007  } nodeNameSetResponse_msg;
1008 
1009  const unsigned int NNSRMSG_LEN = sizeof (nodeNameSetResponse_msg);
1010 
1011  nodeNameSetResponse_msg.msgType = NODE_NAME_RESULT;
1012 
1013  DEBUG_DBG ("Set node name Response. Error code: %d", error);
1014 
1015  CryptModule::random (nodeNameSetResponse_msg.iv, IV_LENGTH);
1016 
1017  DEBUG_VERBOSE ("IV: %s", printHexBuffer (nodeNameSetResponse_msg.iv, IV_LENGTH));
1018 
1019  nodeNameSetResponse_msg.errorCode = error;
1020 
1021  const uint8_t addDataLen = 1 + IV_LENGTH;
1022  uint8_t aad[AAD_LENGTH + addDataLen];
1023 
1024  memcpy (aad, (uint8_t*)&nodeNameSetResponse_msg, addDataLen); // Copy message upto iv
1025 
1026  // Copy 8 last bytes from node key
1027  memcpy (aad + addDataLen, node->getEncriptionKey () + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1028 
1029  if (!CryptModule::encryptBuffer ((uint8_t*)&(nodeNameSetResponse_msg.errorCode), sizeof (int8_t), // Encrypt error code only, 1 byte
1030  nodeNameSetResponse_msg.iv, IV_LENGTH,
1031  node->getEncriptionKey (), KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1032  aad, sizeof (aad), nodeNameSetResponse_msg.tag, TAG_LENGTH)) {
1033  DEBUG_ERROR ("Error during encryption");
1034  return false;
1035  }
1036 
1037  DEBUG_VERBOSE ("Encrypted set node name response message: %s", printHexBuffer ((uint8_t*)&nodeNameSetResponse_msg, NNSRMSG_LEN));
1038 
1039  DEBUG_INFO (" -------> SEND SET NODE NAME RESPONSE");
1040  uint8_t* addr = node->getMacAddress ();
1041  char addrStr[ENIGMAIOT_ADDR_LEN * 3];
1042  if (comm->send (addr, (uint8_t*)&nodeNameSetResponse_msg, NNSRMSG_LEN) == 0) {
1043  DEBUG_INFO ("Set Node Name Response message sent to %s", mac2str(addr,addrStr));
1044  return true;
1045  } else {
1047  DEBUG_ERROR ("Error sending Set Node Name Response message to %s", mac2str (addr, addrStr));
1048  return false;
1049  }
1050 }
1051 
1052 bool EnigmaIOTGatewayClass::processNodeNameSet (const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t* buf, size_t count, Node* node) {
1053  /*
1054  * ----------------------------------------------------------------------
1055  *| msgType (1) | IV (12) | NodeID (2) | Node name (up to 32) | tag (16) |
1056  * ----------------------------------------------------------------------
1057  */
1058  int8_t error = 0;
1059 
1060  char nodeName[NODE_NAME_LENGTH];
1061  memset ((void*)nodeName, 0, NODE_NAME_LENGTH);
1062 
1063  uint8_t iv_idx = 1;
1064  uint8_t nodeId_idx = iv_idx + IV_LENGTH;
1065  uint8_t nodeName_idx = nodeId_idx + sizeof (int16_t);
1066  uint8_t tag_idx = count - TAG_LENGTH;
1067 
1068  const uint8_t addDataLen = 1 + IV_LENGTH;
1069  uint8_t aad[AAD_LENGTH + addDataLen];
1070 
1071  memcpy (aad, buf, addDataLen); // Copy message upto iv
1072  // Copy 8 last bytes from NetworkKey
1073  memcpy (aad + addDataLen, node->getEncriptionKey () + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1074 
1075  uint8_t packetLen = count - TAG_LENGTH;
1076 
1077  if (!CryptModule::decryptBuffer (buf + nodeId_idx, packetLen - 1 - IV_LENGTH, // Decrypt from nodeId
1078  buf + iv_idx, IV_LENGTH,
1079  node->getEncriptionKey (), KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1080  aad, sizeof (aad), buf + tag_idx, TAG_LENGTH)) {
1081  DEBUG_ERROR ("Error during decryption");
1082  error = -4; // Message error
1083  }
1084 
1085  if (!error) {
1086  DEBUG_VERBOSE ("Decripted node name set message: %s", printHexBuffer (buf, count - TAG_LENGTH));
1087 
1088  size_t nodeNameLen = tag_idx - nodeName_idx;
1089 
1090  DEBUG_DBG ("Node name length: %d bytes\n", nodeNameLen);
1091 
1092  if (nodeNameLen >= NODE_NAME_LENGTH) {
1093  nodeNameLen = NODE_NAME_LENGTH - 1;
1094  }
1095 
1096  memcpy ((void*)nodeName, (void*)(buf + nodeName_idx), nodeNameLen);
1097 
1098  error = nodelist.checkNodeName (nodeName, mac);
1099  }
1100 
1101  nodeNameSetRespose (node, error);
1102 
1103  if (error) {
1104  return false;
1105  } else {
1106  node->setNodeName (nodeName);
1107  DEBUG_INFO ("Node name set to %s", node->getNodeName ());
1108  return true;
1109  }
1110 }
1111 
1112 bool EnigmaIOTGatewayClass::processControlMessage (const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t* buf, size_t count, Node* node) {
1113  /*
1114  * ----------------------------------------------------------------------------------------
1115  *| msgType (1) | IV (12) | length (2) | NodeId (2) | Counter (2) | Data (....) | Tag (16) |
1116  * ----------------------------------------------------------------------------------------
1117  */
1118 
1119  uint8_t iv_idx = 1;
1120  uint8_t length_idx = iv_idx + IV_LENGTH;
1121  uint8_t nodeId_idx = length_idx + sizeof (int16_t);
1122  uint8_t counter_idx = nodeId_idx + sizeof (int16_t);
1123  uint8_t data_idx = counter_idx + sizeof (int16_t);
1124  uint8_t tag_idx = count - TAG_LENGTH;
1125 
1126  const uint8_t addDataLen = 1 + IV_LENGTH;
1127  uint8_t aad[AAD_LENGTH + addDataLen];
1128 
1129  memcpy (aad, buf, addDataLen); // Copy message upto iv
1130 
1131  // Copy 8 last bytes from NetworkKey
1132  memcpy (aad + addDataLen, node->getEncriptionKey () + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1133 
1134  uint8_t packetLen = count - TAG_LENGTH;
1135 
1136  if (!CryptModule::decryptBuffer (buf + length_idx, packetLen - 1 - IV_LENGTH, // Decrypt from nodeId
1137  buf + iv_idx, IV_LENGTH,
1138  node->getEncriptionKey (), KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1139  aad, sizeof (aad), buf + tag_idx, TAG_LENGTH)) {
1140  DEBUG_ERROR ("Error during decryption");
1141  return false;
1142  }
1143 
1144  DEBUG_VERBOSE ("Decripted control message: %s", printHexBuffer (buf, count - TAG_LENGTH));
1145 
1146  // Check if command informs about a sleepy mode change
1147  const uint8_t* payload = buf + data_idx;
1148  if (payload[0] == control_message_type::SLEEP_ANS && (tag_idx - data_idx) >= 5) {
1149  uint32_t sleepTime;
1150  DEBUG_DBG ("Check if sleepy mode has changed for node");
1151  memcpy (&sleepTime, payload + 1, sizeof (uint32_t));
1152  if (sleepTime > 0) {
1153  DEBUG_DBG ("Set node to sleepy mode");
1154  node->setSleepy (true);
1155  } else {
1156  DEBUG_DBG ("Set node to non sleepy mode");
1157  node->setSleepy (false);
1158  }
1159  }
1160 
1161  DEBUG_DBG ("Payload length: %d bytes\n", tag_idx - data_idx);
1162 
1163  char* nodeName = node->getNodeName ();
1164 
1165  if (notifyData) {
1166  notifyData (const_cast<uint8_t*>(mac), buf + data_idx, tag_idx - data_idx, 0, true, ENIGMAIOT, nodeName ? nodeName : NULL);
1167  }
1168 
1169  return true;
1170 }
1171 
1172 bool EnigmaIOTGatewayClass::processUnencryptedDataMessage (const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t* buf, size_t count, Node* node) {
1173  /*
1174  * ------------------------------------------------------------------------
1175  *| msgType (1) | NodeId (2) | Counter (2) | PayloadType (1) | Data (....) |
1176  * ------------------------------------------------------------------------
1177  */
1178 
1179  uint8_t nodeId_idx = 1;
1180  uint8_t counter_idx = nodeId_idx + sizeof (int16_t);
1181  uint8_t payloadType_idx = counter_idx + sizeof (int16_t);
1182  uint8_t data_idx = payloadType_idx + sizeof (int8_t);
1183 
1184  uint16_t counter;
1185  size_t lostMessages = 0;
1186 
1187  uint8_t packetLen = count;
1188 
1189  DEBUG_VERBOSE ("Unencrypted data message: %s", printHexBuffer (buf, count));
1190 
1191  node->packetNumber++;
1192 
1193  memcpy (&counter, &buf[counter_idx], sizeof (uint16_t));
1194  if (useCounter) {
1195  if (counter > node->getLastMessageCounter ()) {
1196  lostMessages = counter - node->getLastMessageCounter () - 1;
1197  node->packetErrors += lostMessages;
1198  node->setLastMessageCounter (counter);
1199  } else {
1200  DEBUG_WARN ("Data counter error %d : %d", counter, node->getLastMessageCounter ());
1201  return false;
1202  }
1203  }
1204 
1205  char* nodeName = node->getNodeName ();
1206 
1207  if (notifyData) {
1208  notifyData (const_cast<uint8_t*>(mac), &(buf[data_idx]), count - data_idx, lostMessages, false, RAW, nodeName ? nodeName : NULL);
1209  }
1210 
1211  if (node->getSleepy ()) {
1212  if (node->qMessagePending) {
1213  DEBUG_INFO (" -------> DOWNLINK QUEUED DATA");
1214  flashTx = true;
1215  node->qMessagePending = false;
1216  return comm->send (node->getMacAddress (), node->queuedMessage, node->qMessageLength) == 0;
1217  }
1218  }
1219 
1220  return true;
1221 
1222 }
1223 
1224 
1225 bool EnigmaIOTGatewayClass::processDataMessage (const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t* buf, size_t count, Node* node, bool encrypted) {
1226  /*
1227  * ----------------------------------------------------------------------------------------
1228  *| msgType (1) | IV (12) | length (2) | NodeId (2) | Counter (2) | Data (....) | Tag (16) |
1229  * ----------------------------------------------------------------------------------------
1230  */
1231 
1232  if (!encrypted) {
1233  return processUnencryptedDataMessage (mac, buf, count, node);
1234  }
1235 
1236  uint8_t iv_idx = 1;
1237  uint8_t length_idx = iv_idx + IV_LENGTH;
1238  uint8_t nodeId_idx = length_idx + sizeof (int16_t);
1239  uint8_t counter_idx = nodeId_idx + sizeof (int16_t);
1240  uint8_t encoding_idx = counter_idx + sizeof (int16_t);
1241  uint8_t data_idx = encoding_idx + sizeof (int8_t);
1242  uint8_t tag_idx = count - TAG_LENGTH;
1243 
1244  uint16_t counter;
1245  size_t lostMessages = 0;
1246 
1247  const uint8_t addDataLen = 1 + IV_LENGTH;
1248  uint8_t aad[AAD_LENGTH + addDataLen];
1249 
1250  memcpy (aad, buf, addDataLen); // Copy message upto iv
1251 
1252  // Copy 8 last bytes from NetworkKey
1253  memcpy (aad + addDataLen, node->getEncriptionKey () + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1254 
1255  uint8_t packetLen = count - TAG_LENGTH;
1256 
1257  if (!CryptModule::decryptBuffer (buf + length_idx, packetLen - 1 - IV_LENGTH, // Decrypt from nodeId
1258  buf + iv_idx, IV_LENGTH,
1259  node->getEncriptionKey (), KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1260  aad, sizeof (aad), buf + tag_idx, TAG_LENGTH)) {
1261  DEBUG_ERROR ("Error during decryption");
1262  return false;
1263  }
1264  DEBUG_VERBOSE ("Decrypted data message: %s", printHexBuffer (buf, count - TAG_LENGTH));
1265  DEBUG_DBG ("Data payload encoding: 0x%02X", buf[encoding_idx]);
1266  node->packetNumber++;
1267 
1268  memcpy (&counter, &(buf[counter_idx]), sizeof (uint16_t));
1269  if (useCounter) {
1270  if (counter > node->getLastMessageCounter ()) {
1271  lostMessages = counter - node->getLastMessageCounter () - 1;
1272  node->packetErrors += lostMessages;
1273  node->setLastMessageCounter (counter);
1274  } else {
1275  return false;
1276  }
1277  }
1278 
1279  char* nodeName = node->getNodeName ();
1280 
1281  if (notifyData) {
1282  //DEBUG_WARN ("Notify data %d", input_queue->size());
1283  notifyData (const_cast<uint8_t*>(mac), &(buf[data_idx]), tag_idx - data_idx, lostMessages, false, (gatewayPayloadEncoding_t)(buf[encoding_idx]), nodeName ? nodeName : NULL);
1284  }
1285 
1286  if (node->getSleepy ()) {
1287  if (node->qMessagePending) {
1288  DEBUG_INFO (" -------> DOWNLINK QUEUED DATA");
1289  flashTx = true;
1290  node->qMessagePending = false;
1291  return comm->send (node->getMacAddress (), node->queuedMessage, node->qMessageLength) == 0;
1292  }
1293  }
1294 
1295  return true;
1296 
1297 }
1298 
1299 double EnigmaIOTGatewayClass::getPER (uint8_t* address) {
1300  Node* node = nodelist.getNewNode (address);
1301 
1302  if (node->packetNumber > 0) {
1303  node->per = (double)node->packetErrors / (double)node->packetNumber;
1304  }
1305 
1306  return node->per;
1307 }
1308 
1309 uint32_t EnigmaIOTGatewayClass::getTotalPackets (uint8_t* address) {
1310  Node* node = nodelist.getNewNode (address);
1311 
1312  return node->packetNumber + getErrorPackets (address);
1313 }
1314 
1315 uint32_t EnigmaIOTGatewayClass::getErrorPackets (uint8_t* address) {
1316  Node* node = nodelist.getNewNode (address);
1317 
1318  return node->packetErrors;
1319 }
1320 
1321 double EnigmaIOTGatewayClass::getPacketsHour (uint8_t* address) {
1322  Node* node = nodelist.getNewNode (address);
1323 
1324  return node->packetsHour;
1325 }
1326 
1327 
1328 bool EnigmaIOTGatewayClass::downstreamDataMessage (Node* node, const uint8_t* data, size_t len, control_message_type_t controlData, gatewayPayloadEncoding_t encoding) {
1329  /*
1330  * ---------------------------------------------------------------------------
1331  *| msgType (1) | IV (12) | length (2) | NodeId (2) | Data (....) | Tag (16) |
1332  * ---------------------------------------------------------------------------
1333  */
1334 
1335  uint8_t buffer[MAX_MESSAGE_LENGTH];
1336  uint16_t packet_length;
1337 
1338  if (!node->isRegistered ()) {
1339  DEBUG_VERBOSE ("Error sending downstream. Node is not registered");
1340  return false;
1341  }
1342 
1343  uint16_t nodeId = node->getNodeId ();
1344 
1345  uint8_t iv_idx = 1;
1346  uint8_t length_idx = iv_idx + IV_LENGTH;
1347  uint8_t nodeId_idx = length_idx + sizeof (int16_t);
1348  uint8_t data_idx;
1349  uint8_t encoding_idx; // Only for user data
1350  if (controlData == USERDATA_GET || controlData == USERDATA_SET) {
1351  encoding_idx = nodeId_idx + sizeof (int16_t);
1352  data_idx = encoding_idx + sizeof (int8_t);
1353  buffer[encoding_idx] = encoding;
1354  packet_length = 1 + IV_LENGTH + sizeof (int16_t) + sizeof (int16_t) + 1 + len;
1355  } else {
1356  data_idx = nodeId_idx + sizeof (int16_t);
1357  packet_length = 1 + IV_LENGTH + sizeof (int16_t) + sizeof (int16_t) + len;
1358  }
1359  uint8_t tag_idx = data_idx + len;
1360 
1361  if (!data) {
1362  DEBUG_ERROR ("Downlink message buffer empty");
1363  return false;
1364  }
1365  if (len > MAX_MESSAGE_LENGTH - 25) {
1366  DEBUG_ERROR ("Downlink message too long: %d bytes", len);
1367  return false;
1368  }
1369 
1370  if (controlData == control_message_type::USERDATA_GET) {
1371  buffer[0] = (uint8_t)DOWNSTREAM_DATA_GET;
1372  } else if (controlData == control_message_type::USERDATA_SET) {
1373  buffer[0] = (uint8_t)DOWNSTREAM_DATA_SET;
1374  } else {
1375  buffer[0] = (uint8_t)DOWNSTREAM_CTRL_DATA;
1376  }
1377 
1378  CryptModule::random (buffer + iv_idx, IV_LENGTH);
1379 
1380  DEBUG_VERBOSE ("IV: %s", printHexBuffer (buffer + iv_idx, IV_LENGTH));
1381 
1382  memcpy (buffer + nodeId_idx, &nodeId, sizeof (uint16_t));
1383 
1384  //if (useCounter) {
1385  // counter = node.getLastMessageCounter () + 1;
1386  // node.setLastMessageCounter (counter);
1387  // rtcmem_data.lastMessageCounter = counter;
1388  //}
1389  //else {
1390  // counter = Crypto.random ();
1391  //}
1392 
1393  //memcpy (counter_p, &counter, sizeof (uint16_t));
1394 
1395  memcpy (buffer + data_idx, data, len);
1396  DEBUG_VERBOSE ("Data: %s", printHexBuffer (buffer + data_idx, len));
1397 
1398  memcpy (buffer + length_idx, &packet_length, sizeof (uint16_t));
1399 
1400  DEBUG_VERBOSE ("Downlink message: %s", printHexBuffer (buffer, packet_length));
1401  DEBUG_VERBOSE ("Message length: %d bytes", packet_length);
1402 
1403  //uint8_t* crypt_buf = buffer + length_idx;
1404 
1405  //size_t cryptLen = packet_length - length_idx;
1406 
1407  const uint8_t addDataLen = 1 + IV_LENGTH;
1408  uint8_t aad[AAD_LENGTH + addDataLen];
1409 
1410  memcpy (aad, buffer, addDataLen); // Copy message upto iv
1411 
1412  // Copy 8 last bytes from Node Key
1413  memcpy (aad + addDataLen, node->getEncriptionKey () + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1414 
1415  if (!CryptModule::encryptBuffer (buffer + length_idx, packet_length - addDataLen, // Encrypt from length
1416  buffer + iv_idx, IV_LENGTH,
1417  node->getEncriptionKey (), KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of node key
1418  aad, sizeof (aad), buffer + tag_idx, TAG_LENGTH)) {
1419  DEBUG_ERROR ("Error during encryption");
1420  return false;
1421  }
1422 
1423  DEBUG_VERBOSE ("Encrypted downlink message: %s", printHexBuffer (buffer, packet_length + TAG_LENGTH));
1424 
1425  if (node->getSleepy ()) { // Queue message if node may be sleeping
1426  if (controlData != control_message_type::OTA) {
1427  DEBUG_VERBOSE ("Node is sleepy. Queing message");
1428  memcpy (node->queuedMessage, buffer, packet_length + TAG_LENGTH);
1429  //node->queuedMessage = buffer;
1430  node->qMessageLength = packet_length + TAG_LENGTH;
1431  node->qMessagePending = true;
1432  return true;
1433  } else {
1434  DEBUG_ERROR ("OTA is only possible with non sleepy nodes. Configure it accordingly first");
1435  return false;
1436  }
1437  } else {
1438  DEBUG_INFO (" -------> DOWNLINK DATA");
1439  flashTx = true;
1440  return comm->send (node->getMacAddress (), buffer, packet_length + TAG_LENGTH) == 0;
1441  }
1442 }
1443 
1445  /*
1446  * --------------------------
1447  *| msgType (1) | reason (1) |
1448  * --------------------------
1449  */
1450 
1451  struct __attribute__ ((packed, aligned (1))) {
1452  uint8_t msgType;
1453  uint8_t reason;
1454  } invalidateKey_msg;
1455 
1456 #define IKMSG_LEN sizeof(invalidateKey_msg)
1457 
1458  invalidateKey_msg.msgType = INVALIDATE_KEY; // Server hello message
1459 
1460  invalidateKey_msg.reason = reason;
1461 
1462  DEBUG_VERBOSE ("Invalidate Key message: %s", printHexBuffer ((uint8_t*)&invalidateKey_msg, IKMSG_LEN));
1463  DEBUG_INFO (" -------> INVALIDATE_KEY");
1465  uint8_t* mac = node->getMacAddress ();
1466  notifyNodeDisconnection (mac, reason);
1467  }
1468  return comm->send (node->getMacAddress (), (uint8_t*)&invalidateKey_msg, IKMSG_LEN) == 0;
1469 }
1470 
1471 bool EnigmaIOTGatewayClass::processClientHello (const uint8_t mac[ENIGMAIOT_ADDR_LEN], const uint8_t* buf, size_t count, Node* node) {
1472  /*
1473  * -------------------------------------------------------
1474  *| msgType (1) | random (12) | DH Kmaster (32) | Tag (16) |
1475  * -------------------------------------------------------
1476  */
1477 
1478  bool sleepyNode;
1479 
1480  struct __attribute__ ((packed, aligned (1))) {
1481  uint8_t msgType;
1482  uint8_t iv[IV_LENGTH];
1483  uint8_t publicKey[KEY_LENGTH];
1484  uint32_t random;
1485  uint8_t tag[TAG_LENGTH];
1486  } clientHello_msg;
1487 
1488 #define CHMSG_LEN sizeof(clientHello_msg)
1489 
1490  if (count < CHMSG_LEN) {
1491  DEBUG_WARN ("Message too short");
1492  return false;
1493  }
1494 
1495  memcpy (&clientHello_msg, buf, count);
1496 
1497  const uint8_t addDataLen = CHMSG_LEN - TAG_LENGTH - sizeof (uint32_t) - KEY_LENGTH;
1498  uint8_t aad[AAD_LENGTH + addDataLen];
1499 
1500  memcpy (aad, (uint8_t*)&clientHello_msg, addDataLen); // Copy message upto iv
1501 
1502  // Copy 8 last bytes from NetworkKey
1503  memcpy (aad + addDataLen, gwConfig.networkKey + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1504 
1505  if (!CryptModule::decryptBuffer (clientHello_msg.publicKey, KEY_LENGTH + sizeof (uint32_t),
1506  clientHello_msg.iv, IV_LENGTH,
1507  gwConfig.networkKey, KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1508  aad, sizeof (aad), clientHello_msg.tag, TAG_LENGTH)) {
1509  DEBUG_ERROR ("Error during decryption");
1510  return false;
1511  }
1512 
1513  DEBUG_VERBOSE ("Decrypted Client Hello message: %s", printHexBuffer ((uint8_t*)&clientHello_msg, CHMSG_LEN - TAG_LENGTH));
1514 
1515  node->setEncryptionKey (clientHello_msg.publicKey);
1516 
1517  Crypto.getDH1 ();
1518  memcpy (myPublicKey, Crypto.getPubDHKey (), KEY_LENGTH);
1519 
1520  if (Crypto.getDH2 (node->getEncriptionKey ())) {
1521  CryptModule::getSHA256 (node->getEncriptionKey (), KEY_LENGTH);
1522 
1523  node->setKeyValid (true);
1524  node->setStatus (INIT);
1525  DEBUG_DBG ("Node key: %s", printHexBuffer (node->getEncriptionKey (), KEY_LENGTH));
1526  } else {
1528  char macstr[ENIGMAIOT_ADDR_LEN * 3];
1529  mac2str ((uint8_t*)mac, macstr);
1530  DEBUG_ERROR ("DH2 error with %s", macstr);
1531  return false;
1532  }
1533 
1534  sleepyNode = (clientHello_msg.random & 0x00000001U) == 1;
1535  node->setInitAsSleepy (sleepyNode);
1536  node->setSleepy (sleepyNode);
1537 
1538  DEBUG_VERBOSE ("This is a %s node", sleepyNode ? "sleepy" : "always awaken");
1539 
1540  return true;
1541 }
1542 
1543 bool EnigmaIOTGatewayClass::processClockRequest (const uint8_t mac[ENIGMAIOT_ADDR_LEN], const uint8_t* buf, size_t count, Node* node) {
1544  struct timeval tv;
1545  struct timezone tz;
1546 
1547  struct __attribute__ ((packed, aligned (1))) {
1548  uint8_t msgType;
1549  uint8_t iv[IV_LENGTH];
1550  int64_t t1;
1551  uint8_t tag[TAG_LENGTH];
1552  } clockRequest_msg;
1553 
1554 #define CRMSG_LEN sizeof(clockRequest_msg)
1555 
1556  if (count < CRMSG_LEN) {
1557  DEBUG_WARN ("Message too short");
1558  return false;
1559  }
1560 
1561  CryptModule::random (clockRequest_msg.iv, IV_LENGTH);
1562 
1563  DEBUG_VERBOSE ("IV: %s", printHexBuffer (clockRequest_msg.iv, IV_LENGTH));
1564 
1565  memcpy (&clockRequest_msg, buf, count);
1566 
1567  const uint8_t addDataLen = 1 + IV_LENGTH;
1568  uint8_t aad[AAD_LENGTH + addDataLen];
1569 
1570  memcpy (aad, buf, addDataLen); // Copy message upto iv
1571 
1572  // Copy 8 last bytes from NetworkKey
1573  memcpy (aad + addDataLen, node->getEncriptionKey () + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1574 
1575  uint8_t packetLen = count - TAG_LENGTH;
1576 
1577  if (!CryptModule::decryptBuffer ((uint8_t*)&(clockRequest_msg.t1), sizeof (clock_t), // Decrypt from t2, 8 bytes
1578  clockRequest_msg.iv, IV_LENGTH,
1579  node->getEncriptionKey (), KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1580  aad, sizeof (aad), clockRequest_msg.tag, TAG_LENGTH)) {
1581  DEBUG_ERROR ("Error during decryption");
1582  return false;
1583  }
1584 
1585  DEBUG_VERBOSE ("Decripted Clock Request message: %s", printHexBuffer ((uint8_t*)&clockRequest_msg, packetLen));
1586 
1587  node->t1 = clockRequest_msg.t1;
1588 
1589  // Get current time. If Gateway is synchronized to NTP server it sends real world time.
1590  gettimeofday (&tv, &tz);
1591  int64_t time_ms = tv.tv_sec;
1592  time_ms *= 1000;
1593  time_ms += tv.tv_usec / 1000;
1594  node->t2 = time_ms;
1595 
1596  DEBUG_DBG ("T1: %llu", node->t1);
1597  DEBUG_DBG ("T2: %llu", node->t2);
1598  DEBUG_VERBOSE ("Clock Request message: %s", printHexBuffer ((uint8_t*)&clockRequest_msg, CRMSG_LEN - TAG_LENGTH));
1599 
1600  return clockResponse (node);
1601 }
1602 
1604  struct timeval tv;
1605  struct timezone tz;
1606 
1607  struct __attribute__ ((packed, aligned (1))) {
1608  uint8_t msgType;
1609  uint8_t iv[IV_LENGTH];
1610  int64_t t2;
1611  int64_t t3;
1612  uint8_t tag[TAG_LENGTH];
1613  } clockResponse_msg;
1614 
1615  const unsigned int CRSMSG_LEN = sizeof (clockResponse_msg);
1616 
1617  clockResponse_msg.msgType = CLOCK_RESPONSE;
1618 
1619  memcpy (&(clockResponse_msg.t2), &(node->t2), sizeof (int64_t));
1620 
1621  // Get current time. If Gateway is synchronized to NTP server it sends real world time.
1622  gettimeofday (&tv, &tz);
1623  int64_t time_ms = tv.tv_sec;
1624  time_ms *= 1000;
1625  time_ms += tv.tv_usec / 1000;
1626  node->t3 = time_ms;
1627 
1628  memcpy (&(clockResponse_msg.t3), &(node->t3), sizeof (int64_t));
1629 
1630  DEBUG_VERBOSE ("Clock Response message: %s", printHexBuffer ((uint8_t*)&clockResponse_msg, CRSMSG_LEN - TAG_LENGTH));
1631 
1632 #ifdef DEBUG_ESP_PORT
1633  char mac[ENIGMAIOT_ADDR_LEN * 3];
1634  mac2str (node->getMacAddress (), mac);
1635 #endif
1636  DEBUG_DBG ("T1: %llu", node->t1);
1637  DEBUG_DBG ("T2: %llu", node->t2);
1638  DEBUG_DBG ("T3: %llu", node->t3);
1639 
1640  const uint8_t addDataLen = 1 + IV_LENGTH;
1641  uint8_t aad[AAD_LENGTH + addDataLen];
1642 
1643  memcpy (aad, (uint8_t*)&clockResponse_msg, addDataLen); // Copy message upto iv
1644 
1645  // Copy 8 last bytes from NetworkKey
1646  memcpy (aad + addDataLen, node->getEncriptionKey () + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1647 
1648  if (!CryptModule::encryptBuffer ((uint8_t*)&(clockResponse_msg.t2), sizeof (int64_t) << 1, // Encrypt only from t2, 16 bytes
1649  clockResponse_msg.iv, IV_LENGTH,
1650  node->getEncriptionKey (), KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1651  aad, sizeof (aad), clockResponse_msg.tag, TAG_LENGTH)) {
1652  DEBUG_ERROR ("Error during encryption");
1653  return false;
1654  }
1655 
1656  DEBUG_VERBOSE ("Encrypted Clock Response message: %s", printHexBuffer ((uint8_t*)&clockResponse_msg, CRSMSG_LEN));
1657 
1658  DEBUG_INFO (" -------> CLOCK RESPONSE");
1659  if (comm->send (node->getMacAddress (), (uint8_t*)&clockResponse_msg, CRSMSG_LEN) == 0) {
1660  DEBUG_INFO ("Clock Response message sent to %s", mac);
1661  return true;
1662  } else {
1664  DEBUG_ERROR ("Error sending Clock Response message to %s", mac);
1665  return false;
1666  }
1667 }
1668 
1669 bool EnigmaIOTGatewayClass::serverHello (const uint8_t* key, Node* node) {
1670  /*
1671  * ------------------------------------------------------
1672  *| msgType (1) | random (12) | DH Kslave (32) | Tag (16) |
1673  * ------------------------------------------------------
1674  */
1675 
1676  struct __attribute__ ((packed, aligned (1))) {
1677  uint8_t msgType;
1678  uint8_t iv[IV_LENGTH];
1679  uint8_t publicKey[KEY_LENGTH];
1680  uint16_t nodeId;
1681  uint32_t random;
1682  uint8_t tag[TAG_LENGTH];
1683  } serverHello_msg;
1684 
1685 #define SHMSG_LEN sizeof(serverHello_msg)
1686 
1687  uint32_t random;
1688 
1689  if (!key) {
1690  DEBUG_ERROR ("NULL key");
1691  return false;
1692  }
1693 
1694  serverHello_msg.msgType = SERVER_HELLO; // Server hello message
1695 
1696  CryptModule::random (serverHello_msg.iv, IV_LENGTH);
1697 
1698  DEBUG_VERBOSE ("IV: %s", printHexBuffer (serverHello_msg.iv, IV_LENGTH));
1699 
1700  for (int i = 0; i < KEY_LENGTH; i++) {
1701  serverHello_msg.publicKey[i] = key[i];
1702  }
1703 
1704  uint16_t nodeId = node->getNodeId ();
1705  memcpy (&(serverHello_msg.nodeId), &nodeId, sizeof (uint16_t));
1706 
1707  random = Crypto.random ();
1708  memcpy (&(serverHello_msg.random), &random, RANDOM_LENGTH);
1709 
1710  DEBUG_VERBOSE ("Server Hello message: %s", printHexBuffer ((uint8_t*)&serverHello_msg, SHMSG_LEN - TAG_LENGTH));
1711 
1712  const uint8_t addDataLen = SHMSG_LEN - TAG_LENGTH - sizeof (uint32_t) - sizeof (uint16_t) - KEY_LENGTH;
1713  uint8_t aad[AAD_LENGTH + addDataLen];
1714 
1715  memcpy (aad, (uint8_t*)&serverHello_msg, addDataLen); // Copy message upto iv
1716 
1717  // Copy 8 last bytes from NetworkKey
1718  memcpy (aad + addDataLen, gwConfig.networkKey + KEY_LENGTH - AAD_LENGTH, AAD_LENGTH);
1719 
1720  if (!CryptModule::encryptBuffer (serverHello_msg.publicKey, KEY_LENGTH + sizeof (uint16_t) + sizeof (uint32_t), // Encrypt from public key
1721  serverHello_msg.iv, IV_LENGTH,
1722  gwConfig.networkKey, KEY_LENGTH - AAD_LENGTH, // Use first 24 bytes of network key
1723  aad, sizeof (aad), serverHello_msg.tag, TAG_LENGTH)) {
1724  DEBUG_ERROR ("Error during encryption");
1725  return false;
1726  }
1727 
1728  DEBUG_VERBOSE ("Encrypted Server Hello message: %s", printHexBuffer ((uint8_t*)&serverHello_msg, SHMSG_LEN));
1729 
1730  flashTx = true;
1731 
1732 #ifdef DEBUG_ESP_PORT
1733  char mac[ENIGMAIOT_ADDR_LEN * 3];
1734  mac2str (node->getMacAddress (), mac);
1735 #endif
1736  DEBUG_INFO (" -------> SERVER_HELLO");
1737  if (comm->send (node->getMacAddress (), (uint8_t*)&serverHello_msg, SHMSG_LEN) == 0) {
1738  DEBUG_INFO ("Server Hello message sent to %s", mac);
1739  return true;
1740  } else {
1742  DEBUG_ERROR ("Error sending Server Hello message to %s", mac);
1743  return false;
1744  }
1745 }
1746 
1748 
Comms_halClass::onDataRcvd
virtual void onDataRcvd(comms_hal_rcvd_data dataRcvd)=0
Attach a callback function to be run on every received message.
EnigmaIOTGatewayClass::flashRx
volatile bool flashRx
true if Rx LED should flash
Definition: EnigmaIOTGateway.h:208
CryptModule::decryptBuffer
static bool decryptBuffer(const uint8_t *data, size_t length, const uint8_t *iv, uint8_t ivlen, const uint8_t *key, uint8_t keylen, const uint8_t *aad, uint8_t aadLen, const uint8_t *tag, uint8_t tagLen)
Decrypts a buffer using a shared key.
Definition: cryptModule.cpp:52
CLOCK_RESPONSE
@ CLOCK_RESPONSE
Definition: EnigmaIOTGateway.h:42
EnigmaIOTGatewayClass::invalidateKey
bool invalidateKey(Node *node, gwInvalidateReason_t reason)
Creates an InvalidateKey message and sned it. This trigger a new key agreement to start on related no...
Definition: EnigmaIOTGateway.cpp:1444
CryptModule::getPubDHKey
uint8_t * getPubDHKey()
Gets own public key used on Diffie Hellman algorithm.
Definition: cryptModule.h:133
OTAongoing
bool OTAongoing
Definition: EnigmaIOTGateway.cpp:30
EnigmaIOTGatewayClass::useCounter
bool useCounter
true if counter is used to check data messages order
Definition: EnigmaIOTGateway.h:219
IDENTIFY
@ IDENTIFY
Definition: NodeList.h:47
CHMSG_LEN
#define CHMSG_LEN
buildSetName
bool buildSetName(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:119
buildSetResetConfig
bool buildSetResetConfig(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:135
EnigmaIOTGatewayClass::myPublicKey
uint8_t myPublicKey[KEY_LENGTH]
Temporary public key store used during key agreement.
Definition: EnigmaIOTGateway.h:206
EnigmaIOTGatewayClass::addInputMsgQueue
bool addInputMsgQueue(const uint8_t *addr, const uint8_t *msg, size_t len)
Add message to input queue.
Definition: EnigmaIOTGateway.cpp:712
CryptModule::getDH1
void getDH1()
Starts first stage of Diffie Hellman key agreement algorithm.
Definition: cryptModule.cpp:141
SLEEP_SET
@ SLEEP_SET
Definition: NodeList.h:45
EnigmaIOTGatewayClass::rxLedOnTime
unsigned long rxLedOnTime
Flash duration for Rx LED.
Definition: EnigmaIOTGateway.h:215
NodeList::getNodeFromName
Node * getNodeFromName(const char *name)
Gets node that correspond with given node name.
Definition: NodeList.cpp:148
EnigmaIOTRingBuffer< msg_queue_item_t >
USERDATA_SET
@ USERDATA_SET
Definition: NodeList.h:58
Comms_halClass::onDataSent
virtual void onDataSent(comms_hal_sent_data dataRcvd)=0
Attach a callback function to be run after sending a message to receive its status.
cryptModule.h
Crypto library that implements EnigmaIoT encryption, decryption and key agreement fuctions.
NODE_NAME_SET
@ NODE_NAME_SET
Definition: EnigmaIOTGateway.h:43
EnigmaIOTGatewayClass
Main gateway class. Manages communication with nodes and sends data to upper layer.
Definition: EnigmaIOTGateway.h:204
NodeList::printToSerial
void printToSerial(Stream *port)
Dumps node list data to a Stream object.
Definition: NodeList.cpp:290
memstr
const void * memstr(const void *str, size_t str_size, const char *target, size_t target_size)
Definition: EnigmaIOTGateway.cpp:57
MAX_NODE_INACTIVITY
static const unsigned int MAX_NODE_INACTIVITY
After this time (in ms) a node is marked as gone.
Definition: EnigmaIoTconfig.h:24
EnigmaIOTGatewayClass::processControlMessage
bool processControlMessage(const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t *buf, size_t count, Node *node)
Processes control message from node.
Definition: EnigmaIOTGateway.cpp:1112
CRMSG_LEN
#define CRMSG_LEN
Comms_halClass::begin
virtual void begin(uint8_t *gateway, uint8_t channel, peerType_t peerType=COMM_NODE)=0
Setup communication environment and establish the connection from node to gateway.
buildOtaMsg
bool buildOtaMsg(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:200
EnigmaIOTRingBuffer::size
int size()
Returns actual number of elements that buffer holds.
Definition: EnigmaIOTGateway.h:126
initWiFi
void initWiFi(uint8_t channel, const char *networkName, const char *networkKey, uint8_t role)
Initalizes WiFi interfaces on ESP8266 or ESP32.
Definition: helperFunctions.cpp:31
EnigmaIOTGatewayClass::tempBuffer
msg_queue_item_t tempBuffer
Temporary storage for input message got from buffer.
Definition: EnigmaIOTGateway.h:226
EnigmaIOTRingBuffer::push
bool push(Telement *item)
Adds a new item to buffer, deleting older element if it is full.
Definition: EnigmaIOTGateway.h:145
EnigmaIOTGatewayClass::manageMessage
void manageMessage(const uint8_t *mac, uint8_t *buf, uint8_t count)
Process every received message.
Definition: EnigmaIOTGateway.cpp:853
EnigmaIOTGatewayClass::comm
Comms_halClass * comm
Instance of physical communication layer.
Definition: EnigmaIOTGateway.h:211
EnigmaIOTGatewayClass::rx_cb
static void rx_cb(uint8_t *mac_addr, uint8_t *data, uint8_t len)
Function that will be called anytime this gateway receives a message.
Definition: EnigmaIOTGateway.cpp:769
NodeList::getNewNode
Node * getNewNode(const uint8_t *mac)
Finds a node that correspond with given address of creates a new one if it does not exist.
Definition: NodeList.cpp:275
EnigmaIOTGatewayClass::txled
int8_t txled
I/O pin to connect a led that flashes when gateway transmits data.
Definition: EnigmaIOTGateway.h:212
OTA_GW_TIMEOUT
static const int OTA_GW_TIMEOUT
OTA mode timeout. In OTA mode all data messages are ignored.
Definition: EnigmaIoTconfig.h:25
EnigmaIOTGatewayClass::configWiFiManager
bool configWiFiManager()
Starts configuration AP and web server and gets settings from it.
Definition: EnigmaIOTGateway.cpp:443
EnigmaIOTGatewayClass::processDataMessage
bool processDataMessage(const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t *buf, size_t count, Node *node, bool encrypted=true)
Processes data message from node.
Definition: EnigmaIOTGateway.cpp:1225
CryptModule::encryptBuffer
static bool encryptBuffer(const uint8_t *data, size_t length, const uint8_t *iv, uint8_t ivlen, const uint8_t *key, uint8_t keylen, const uint8_t *aad, uint8_t aadLen, const uint8_t *tag, uint8_t tagLen)
Decrypts a buffer using a shared key.
Definition: cryptModule.cpp:86
EnigmaIOTGatewayClass::server
AsyncWebServer * server
WebServer that holds configuration portal.
Definition: EnigmaIOTGateway.h:230
Crypto
CryptModule Crypto
Singleton Crypto class instance.
Definition: cryptModule.cpp:167
gateway_config_t::networkKey
uint8_t networkKey[KEY_LENGTH]
Definition: EnigmaIOTGateway.h:90
buildSetSleep
bool buildSetSleep(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:294
NodeList::getNodeFromMAC
Node * getNodeFromMAC(const uint8_t *mac)
Gets node that correspond with given address.
Definition: NodeList.cpp:133
EnigmaIOTGatewayClass::notifyData
onGwDataRx_t notifyData
Callback function that will be invoked when data is received fron a node.
Definition: EnigmaIOTGateway.h:216
RAW
@ RAW
Definition: EnigmaIOTGateway.h:51
EnigmaIOTGatewayClass::input_queue
EnigmaIOTRingBuffer< msg_queue_item_t > * input_queue
Input messages buffer. It acts as a FIFO queue.
Definition: EnigmaIOTGateway.h:228
ENIGMAIOT_ADDR_LEN
static const size_t ENIGMAIOT_ADDR_LEN
Address size. Mac address = 6 bytes.
Definition: EnigmaIoTconfig.h:14
LED_ON
#define LED_ON
Definition: enigmaiot_led_flasher.ino:39
NODE_NAME_LENGTH
static const uint8_t NODE_NAME_LENGTH
Maximum number of characters of node name.
Definition: EnigmaIoTconfig.h:19
OTA
@ OTA
Definition: NodeList.h:55
buildGetSleep
bool buildGetSleep(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:79
ENIGMAIOT
@ ENIGMAIOT
Definition: EnigmaIOTGateway.h:58
RESET
@ RESET
Definition: NodeList.h:48
DOWNSTREAM_DATA_GET
@ DOWNSTREAM_DATA_GET
Definition: EnigmaIOTGateway.h:38
printHexBuffer
char * printHexBuffer(const uint8_t *buffer, uint16_t len)
Debug helper function that generates a string that represent a buffer hexadecimal values.
Definition: helperFunctions.cpp:17
buildSetIdentify
bool buildSetIdentify(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:89
EnigmaIOTGatewayClass::setRxLed
void setRxLed(uint8_t led, time_t onTime=FLASH_LED_TIME)
Sets a LED to be flashed every time a message is received.
Definition: EnigmaIOTGateway.cpp:50
EnigmaIOTGatewayClass::notifyWiFiManagerExit
onWiFiManagerExit_t notifyWiFiManagerExit
Function called when configuration portal exits.
Definition: EnigmaIOTGateway.h:233
DOWNSTREAM_DATA_SET
@ DOWNSTREAM_DATA_SET
Definition: EnigmaIOTGateway.h:37
EnigmaIOTGatewayClass::handle
void handle()
This method should be called periodically for instance inside loop() function. It is used for interna...
Definition: EnigmaIOTGateway.cpp:787
IV_LENGTH
const uint8_t IV_LENGTH
Initalization vector length used by selected crypto algorythm.
Definition: EnigmaIoTconfig.h:59
RSSI_GET
@ RSSI_GET
Definition: NodeList.h:50
NodeList::unregisterNode
bool unregisterNode(uint16_t nodeId)
Frees up a node and marks it as available.
Definition: NodeList.cpp:220
DEBUG_ESP_PORT
#define DEBUG_ESP_PORT
Stream to output debug info. It will normally be Serial
Definition: EnigmaIoTconfig.h:65
msg_queue_item_t::addr
uint8_t addr[ENIGMAIOT_ADDR_LEN]
Definition: EnigmaIOTGateway.h:95
INIT
@ INIT
Definition: NodeList.h:25
DOWNSTREAM_CTRL_DATA
@ DOWNSTREAM_CTRL_DATA
Definition: EnigmaIOTGateway.h:40
EnigmaIOTGatewayClass::notifyNodeDisconnection
onNodeDisconnected_t notifyNodeDisconnection
Callback function that will be invoked when a node gets disconnected.
Definition: EnigmaIOTGateway.h:218
EnigmaIOTGatewayClass::processUnencryptedDataMessage
bool processUnencryptedDataMessage(const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t *buf, size_t count, Node *node)
Processes unencrypted data message from node.
Definition: EnigmaIOTGateway.cpp:1172
EnigmaIOTRingBuffer::empty
bool empty()
Checks if buffer is empty.
Definition: EnigmaIOTGateway.h:138
EnigmaIOTGatewayClass::clockResponse
bool clockResponse(Node *node)
Returns timestaps needed so that node can calculate time difference.
Definition: EnigmaIOTGateway.cpp:1603
CryptModule::getSHA256
static uint8_t * getSHA256(uint8_t *buffer, uint8_t length)
Generates a SHA256 hash from input.
Definition: cryptModule.cpp:20
EnigmaIOTGatewayClass::setTxLed
void setTxLed(uint8_t led, time_t onTime=FLASH_LED_TIME)
Sets a LED to be flashed every time a message is transmitted.
Definition: EnigmaIOTGateway.cpp:43
SLEEP_GET
@ SLEEP_GET
Definition: NodeList.h:44
CONTROL_DATA
@ CONTROL_DATA
Definition: EnigmaIOTGateway.h:39
EnigmaIOTRingBuffer::pop
bool pop()
Deletes older item from buffer, if buffer is not empty.
Definition: EnigmaIOTGateway.h:171
lastOTAmsg
time_t lastOTAmsg
Definition: EnigmaIOTGateway.cpp:31
SENSOR_DATA
@ SENSOR_DATA
Definition: EnigmaIOTGateway.h:35
DISCONNECT_ON_DATA_ERROR
static const bool DISCONNECT_ON_DATA_ERROR
Activates node invalidation in case of data error.
Definition: EnigmaIoTconfig.h:33
SHMSG_LEN
#define SHMSG_LEN
mac2str
char * mac2str(const uint8_t *mac, char *buffer)
Debug helper function that generates a string that represent a MAC address.
Definition: helperFunctions.cpp:84
EnigmaIOTRingBuffer::front
Telement * front()
Gets a pointer to older item in buffer, if buffer is not empty.
Definition: EnigmaIOTGateway.h:190
AAD_LENGTH
const uint8_t AAD_LENGTH
Number of bytes from last part of key that will be used for additional authenticated data.
Definition: EnigmaIoTconfig.h:61
Comms_halClass::send
virtual int32_t send(uint8_t *da, uint8_t *data, int len)=0
Sends data to the other peer.
USERDATA_GET
@ USERDATA_GET
Definition: NodeList.h:57
NUM_NODES
static const int NUM_NODES
Maximum number of nodes that this gateway can handle.
Definition: EnigmaIoTconfig.h:30
EnigmaIOTGatewayClass::processClockRequest
bool processClockRequest(const uint8_t mac[ENIGMAIOT_ADDR_LEN], const uint8_t *buf, size_t count, Node *node)
Starts clock sync procedure from node to gateway.
Definition: EnigmaIOTGateway.cpp:1543
CryptModule::random
static uint32_t random()
Gets a random number.
Definition: cryptModule.cpp:119
getNextNumber
int getNextNumber(char *&data, size_t &len)
Definition: EnigmaIOTGateway.cpp:145
msg_queue_item_t::data
uint8_t data[MAX_MESSAGE_LENGTH]
Definition: EnigmaIOTGateway.h:96
gatewayPayloadEncoding_t
gatewayPayloadEncoding_t
Definition: EnigmaIOTGateway.h:50
gateway_config_t::channel
uint8_t channel
Definition: EnigmaIOTGateway.h:89
CONFIG_FILE
const char CONFIG_FILE[]
Definition: EnigmaIOTGateway.cpp:27
EnigmaIOTGatewayClass::getTotalPackets
uint32_t getTotalPackets(uint8_t *address)
Gets total packets sent by node that has a specific address.
Definition: EnigmaIOTGateway.cpp:1309
EnigmaIOTGatewayClass::flashTx
bool flashTx
true if Tx LED should flash
Definition: EnigmaIOTGateway.h:207
EnigmaIOTGatewayClass::dns
DNSServer * dns
DNS server used by configuration portal.
Definition: EnigmaIOTGateway.h:231
msg_queue_item_t
Definition: EnigmaIOTGateway.h:94
EnigmaIOTGatewayClass::getStatus
void getStatus(uint8_t *mac_addr, uint8_t status)
Functrion to debug send status.
Definition: EnigmaIOTGateway.cpp:778
EnigmaIOTGatewayClass::getShouldSave
bool getShouldSave()
Gets flag that indicates if configuration should be saved.
Definition: EnigmaIOTGateway.cpp:39
EnigmaIOTGatewayClass::nodelist
NodeList nodelist
Node database that keeps status and shared keys.
Definition: EnigmaIOTGateway.h:210
msg_queue_item_t::len
size_t len
Definition: EnigmaIOTGateway.h:97
RANDOM_LENGTH
const uint8_t RANDOM_LENGTH
Length of random number generator values.
Definition: cryptModule.h:27
EnigmaIOTGateway
EnigmaIOTGatewayClass EnigmaIOTGateway
Definition: EnigmaIOTGateway.cpp:1747
MAX_MESSAGE_LENGTH
static const uint8_t MAX_MESSAGE_LENGTH
Maximum payload size on ESP-NOW.
Definition: EnigmaIoTconfig.h:13
EnigmaIOTGatewayClass::node
node_t node
temporary store to keep node data while processing a message
Definition: EnigmaIOTGateway.h:209
EnigmaIOTGatewayClass::txLedOnTime
unsigned long txLedOnTime
Flash duration for Tx LED.
Definition: EnigmaIOTGateway.h:214
EnigmaIOTGatewayClass::doSave
static void doSave(void)
Activates a flag that signals that configuration has to be saved.
Definition: EnigmaIOTGateway.cpp:34
MAX_KEY_VALIDITY
static const unsigned int MAX_KEY_VALIDITY
After this time (in ms) a nude is unregistered.
Definition: EnigmaIoTconfig.h:23
CRSMSG_LEN
#define CRSMSG_LEN
MACSTR
#define MACSTR
Definition: helperFunctions.cpp:82
Node
Class definition for a single sensor Node.
Definition: NodeList.h:93
shouldSave
bool shouldSave
Definition: EnigmaIOTGateway.cpp:29
NodeList::checkNodeName
int8_t checkNodeName(const char *name, const uint8_t *address)
Check Node name for duplicate.
Definition: NodeList.cpp:163
buildGetVersion
bool buildGetVersion(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:69
EnigmaIOTGatewayClass::gwConfig
gateway_config_t gwConfig
Gateway specific configuration to be stored on flash memory.
Definition: EnigmaIOTGateway.h:220
KEY_EXPIRED
@ KEY_EXPIRED
Definition: EnigmaIOTGateway.h:70
LED_OFF
#define LED_OFF
Definition: enigmaiot_led_flasher.ino:40
EnigmaIOTGatewayClass::processClientHello
bool processClientHello(const uint8_t mac[ENIGMAIOT_ADDR_LEN], const uint8_t *buf, size_t count, Node *node)
Gets a buffer containing a ClientHello message and process it. This carries node public key to be use...
Definition: EnigmaIOTGateway.cpp:1471
EnigmaIOTGatewayClass::tx_cb
static void tx_cb(uint8_t *mac_addr, uint8_t status)
Function that will be called anytime this gateway sends a message to indicate status result of sendin...
Definition: EnigmaIOTGateway.cpp:774
EnigmaIOTGatewayClass::saveFlashData
bool saveFlashData()
Saves configuration to flash memory.
Definition: EnigmaIOTGateway.cpp:624
COMM_GATEWAY
@ COMM_GATEWAY
Definition: Comms_hal.h:24
EnigmaIOTGatewayClass::rxled
int8_t rxled
I/O pin to connect a led that flashes when gateway receives data.
Definition: EnigmaIOTGateway.h:213
VERSION
@ VERSION
Definition: NodeList.h:42
EnigmaIOTGatewayClass::processNodeNameSet
bool processNodeNameSet(const uint8_t mac[ENIGMAIOT_ADDR_LEN], uint8_t *buf, size_t count, Node *node)
Processes new node name request fromn node.
Definition: EnigmaIOTGateway.cpp:1052
buildGetRSSI
bool buildGetRSSI(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:99
NAME_GET
@ NAME_GET
Definition: NodeList.h:52
data
@ data
Definition: GwOutput_generic.h:23
EnigmaIOTGatewayClass::downstreamDataMessage
bool downstreamDataMessage(Node *node, const uint8_t *data, size_t len, control_message_type_t controlData, gatewayPayloadEncoding_t encoding=ENIGMAIOT)
Builds, encrypts and sends a DownstreamData message.
Definition: EnigmaIOTGateway.cpp:1328
WRONG_DATA
@ WRONG_DATA
Definition: EnigmaIOTGateway.h:68
REGISTERED
@ REGISTERED
Definition: NodeList.h:28
SERVER_HELLO
@ SERVER_HELLO
Definition: EnigmaIOTGateway.h:46
MAX_INPUT_QUEUE_SIZE
static const int MAX_INPUT_QUEUE_SIZE
Input queue size for EnigmaIOT messages. Acts as a buffer to be able to handle messages during high l...
Definition: EnigmaIoTconfig.h:28
EnigmaIOTGatewayClass::sendDownstream
bool sendDownstream(uint8_t *mac, const uint8_t *data, size_t len, control_message_type_t controlData, gatewayPayloadEncoding_t payload_type=RAW, char *nodeName=NULL)
Starts a downstream data message transmission.
Definition: EnigmaIOTGateway.cpp:325
EnigmaIOTGatewayClass::notifyWiFiManagerStarted
onWiFiManagerStarted_t notifyWiFiManagerStarted
Function called when configuration portal is started.
Definition: EnigmaIOTGateway.h:234
CryptModule::getDH2
bool getDH2(const uint8_t *remotePubKey)
Starts second stage of Diffie Hellman key agreement algorithm and calculate shares key.
Definition: cryptModule.cpp:148
EnigmaIOTGatewayClass::getErrorPackets
uint32_t getErrorPackets(uint8_t *address)
Gets number of errored packets of node that has a specific address.
Definition: EnigmaIOTGateway.cpp:1315
NETWORK_NAME_LENGTH
static const uint8_t NETWORK_NAME_LENGTH
Maximum number of characters of network name.
Definition: EnigmaIoTconfig.h:18
CLOCK_REQUEST
@ CLOCK_REQUEST
Definition: EnigmaIOTGateway.h:41
EnigmaIOTGatewayClass::notifyNewNode
onNewNode_t notifyNewNode
Callback function that will be invoked when a new node is connected.
Definition: EnigmaIOTGateway.h:217
EnigmaIOTGatewayClass::getPacketsHour
double getPacketsHour(uint8_t *address)
Gets packet rate sent by node that has a specific address, in packets per hour.
Definition: EnigmaIOTGateway.cpp:1321
IKMSG_LEN
#define IKMSG_LEN
UNREGISTERED_NODE
@ UNREGISTERED_NODE
Definition: EnigmaIOTGateway.h:69
NODE_NAME_RESULT
@ NODE_NAME_RESULT
Definition: EnigmaIOTGateway.h:44
helperFunctions.h
Auxiliary function definition.
NodeList::getNodeFromID
Node * getNodeFromID(uint16_t nodeId)
Gets node that correspond with given nodeId.
Definition: NodeList.cpp:126
EnigmaIOTGateway.h
Library to build a gateway for EnigmaIoT system.
gwInvalidateReason_t
gwInvalidateReason_t
Key invalidation reason definition.
Definition: EnigmaIOTGateway.h:64
EnigmaIOTGatewayClass::serverHello
bool serverHello(const uint8_t *key, Node *node)
Build a ServerHello messange and send it to node.
Definition: EnigmaIOTGateway.cpp:1669
EnigmaIOTGatewayClass::loadFlashData
bool loadFlashData()
Loads configuration from flash memory.
Definition: EnigmaIOTGateway.cpp:553
EnigmaIoTUpdate.sleepyNode
bool sleepyNode
Definition: EnigmaIoTUpdate.py:13
CLIENT_HELLO
@ CLIENT_HELLO
Definition: EnigmaIOTGateway.h:45
control_message_type_t
enum control_message_type control_message_type_t
EnigmaIOTGatewayClass::nodeNameSetRespose
bool nodeNameSetRespose(Node *node, int8_t error)
Send back set name response.
Definition: EnigmaIOTGateway.cpp:996
buildGetName
bool buildGetName(uint8_t *data, size_t &dataLen, const uint8_t *inputData, size_t inputLen)
Definition: EnigmaIOTGateway.cpp:109
NAME_SET
@ NAME_SET
Definition: NodeList.h:54
EnigmaIOTGatewayClass::getPER
double getPER(uint8_t *address)
Gets packet error rate of node that has a specific address.
Definition: EnigmaIOTGateway.cpp:1299
KEY_LENGTH
const uint8_t KEY_LENGTH
Key length used by selected crypto algorythm. The only tested value is 32. Change it only if you know...
Definition: EnigmaIoTconfig.h:58
isHexChar
bool isHexChar(char c)
Definition: EnigmaIOTGateway.cpp:191
TAG_LENGTH
const uint8_t TAG_LENGTH
Authentication tag length. For Poly1305 it is always 16.
Definition: EnigmaIoTconfig.h:60
EnigmaIOTGatewayClass::plainNetKey
char plainNetKey[KEY_LENGTH]
Definition: EnigmaIOTGateway.h:222
EnigmaIOTGatewayClass::begin
void begin(Comms_halClass *comm, uint8_t *networkKey=NULL, bool useDataCounter=true)
Initalizes communication basic data and starts accepting node registration.
Definition: EnigmaIOTGateway.cpp:667
gateway_config_t::networkName
char networkName[NETWORK_NAME_LENGTH]
Definition: EnigmaIOTGateway.h:91
INVALIDATE_KEY
@ INVALIDATE_KEY
Definition: EnigmaIOTGateway.h:47
SLEEP_ANS
@ SLEEP_ANS
Definition: NodeList.h:46
EnigmaIOTGatewayClass::wifiManager
AsyncWiFiManager * wifiManager
Wifi configuration portal.
Definition: EnigmaIOTGateway.h:232
status
@ status
Definition: GwOutput_generic.h:25
EnigmaIOTGatewayClass::getInputMsgQueue
msg_queue_item_t * getInputMsgQueue(msg_queue_item_t *buffer)
Gets next item in the queue.
Definition: EnigmaIOTGateway.cpp:735
Comms_halClass
Interface for communication subsystem abstraction layer definition.
Definition: Comms_hal.h:33
UNENCRYPTED_NODE_DATA
@ UNENCRYPTED_NODE_DATA
Definition: EnigmaIOTGateway.h:36
EnigmaIOTGatewayClass::popInputMsgQueue
void popInputMsgQueue()
Deletes next item in the queue.
Definition: EnigmaIOTGateway.cpp:763