Browse Source

Version 6.2.4; Focus on Downstream messaging, and other improvements. Please look and CHANGELOG for all changes.

platenspeler 5 years ago
parent
commit
59d0cfa2e5
24 changed files with 1390 additions and 1075 deletions
  1. 22 2
      CHANGELOG.md
  2. 22 5
      README.md
  3. 2 2
      TODO.md
  4. 49 16
      platformio.ini
  5. 141 102
      src/ESP-sc-gway.ino
  6. 5 12
      src/_WiFi.ino
  7. 13 6
      src/_gatewayMgt.ino
  8. 85 134
      src/_loraFiles.ino
  9. 89 143
      src/_loraModem.ino
  10. 19 19
      src/_oLED.ino
  11. 3 3
      src/_otaServer.ino
  12. 1 1
      src/_repeater.ino
  13. 7 8
      src/_sensor.ino
  14. 59 67
      src/_stateMachine.ino
  15. 1 1
      src/_tcpTTN.ino
  16. 217 219
      src/_txRx.ino
  17. 270 120
      src/_udpSemtech.ino
  18. 96 42
      src/_utils.ino
  19. 110 66
      src/_wwwServer.ino
  20. 54 38
      src/configGway.h
  21. 93 43
      src/configNode.h
  22. 8 3
      src/loraFiles.h
  23. 18 17
      src/loraModem.h
  24. 6 6
      src/oLED.h

+ 22 - 2
CHANGELOG.md

@@ -1,6 +1,6 @@
 # Single Channel LoRaWAN Gateway
 # Single Channel LoRaWAN Gateway
 
 
-Version 6.2.0, January 29, 2020 
+Version 6.2.4, February 29, 2020 
 Author: M. Westenberg (mw12554@hotmail.com)  
 Author: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 
 
@@ -16,10 +16,30 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
 
 
 # Release Notes
 # Release Notes
 
 
+Features release 6.2.4 (April 25, 2020)
+- Changes the date layout used in the output to be more standard: 3 characters weekday, months and day 2 chars
+- Changed the configGway.h file a lot ro define default values for parameters while at the 
+	same time allowing changing through PlatformIO
+- Updated the documentation itself and updated link in the software
+- For Monitor output use the same stringTime() function
+- Added the _PROFILER definition to read the timing (PlatformIO only)
+- Adapt the documentation and start writing hardware guide (for compile options)
+- Changed the delay for TX (Downlink messages) -. Removed to 0 for _STIRCT_1CH
+- Index of iSeen messages was in Hex -> Changed to decimal
+- Added a timing correction for sending message of aound 700000 uSec (0.7 Sec) to make downlink work
+- Changed naming of tmst (TimeStamp) functions
+- Removed function printlog(), as it was not used
+- Moved the SPIFFS file operations to a timer function in loop() as it consumer far too much time. 
+As a result regular timestamp is reduced.
+- Removed the logging functions for the same reasons. User can choose to put those on again.
+- Added Udp.flush() when NTP messages arrive during operations 
+- Changed layout of webpage. Changed sequence to first OFF and then ON
+- Changed website to include loraWait statistics
+
 Features release 6.2.3 (February 23, 2020)
 Features release 6.2.3 (February 23, 2020)
 - Lots of bugs and documentation fixes
 - Lots of bugs and documentation fixes
 - Added customizable #define statements through platformio.ini file (Read!!!)
 - Added customizable #define statements through platformio.ini file (Read!!!)
-- Changed the WiFiManager code to better support both architectures: ESP8266 and ESP32\
+- Changed the WiFiManager code to better support both architectures: ESP8266 and ESP32
 
 
 Features release 6.2.1 (February 2, 2020)
 Features release 6.2.1 (February 2, 2020)
 - PlatformIO support
 - PlatformIO support

+ 22 - 5
README.md

@@ -1,7 +1,7 @@
 # Single Channel LoRaWAN Gateway
 # Single Channel LoRaWAN Gateway
 
 
-Version 6.2.0, 
-Data: January 29, 2020  
+Version 6.2.4, 
+Data: April 25, 2020  
 Author: M. Westenberg (mw12554@hotmail.com)  
 Author: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 
 
@@ -16,8 +16,8 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
 
 
 # Description
 # Description
 
 
-First of all: PLEASE READ THIS FILE AND [Documentation](https://things4u.github.io/Projects/SingleChannelGateway/UserGuide/Introduction%206.html) it should contain most of the 
-information you need to get going.
+First of all: PLEASE READ THIS FILE AND [Documentation](http://things4u.github.io/Projects/SingleChannelGateway) 
+it should contain most of the information you need to get going.
 Unfortunately I do not have the time to follow up on all emails, and as most information including pin-outs 
 Unfortunately I do not have the time to follow up on all emails, and as most information including pin-outs 
 etc etc are contained on these pages I hope you have the time to read them and post any remaining questions.
 etc etc are contained on these pages I hope you have the time to read them and post any remaining questions.
 
 
@@ -47,6 +47,24 @@ parameters at runtime.
 Full documentation of the Single Channel Gateway is found at things4u.github.io, please look at the Hardware Guide 
 Full documentation of the Single Channel Gateway is found at things4u.github.io, please look at the Hardware Guide 
 under the Gateway chapter.
 under the Gateway chapter.
 
 
+# PlatformIO or ArduinoIDE
+
+The source works on both environments, both the classic Arduino IDE and on PlatformIO. 
+Unfortunately there are small differences between these two envrironments. 
+At this moment the src directory contains the PlatformIO source, and therefore we will decribe how to connect to Arduino IDE.
+The applies to the libraries.
+
+## PlatformIO
+When in PlatformIO, choose <File> and then <Add folder to Workspace...> and select the new LoRa-1ch-ESP-Gateway 
+top directory.
+Then just open the ESP-sc-gway.ino file at src directory and build or upload
+
+## Arduino IDE
+
+Create a place on you filesystem wo work on the files. In thius directory creat the source directory "ESP-sc-gway" 
+and the libraries directory "libraries". When unpacking the source at github: 
+Copy the content of the "src" directory to the Aruino IDE "ESP-sc-gway" directory and copy the contents 
+of the "lib" to the Arduino IDE "libraries" directory;
 
 
 ## testing
 ## testing
 
 
@@ -467,7 +485,6 @@ The following things are still on my wish list to make to the single channel gat
 - Look at Class B and C support
 - Look at Class B and C support
 
 
 
 
-
 # License
 # License
 
 
 The source files of the gateway sketch in this repository is made available under the MIT
 The source files of the gateway sketch in this repository is made available under the MIT

+ 2 - 2
TODO.md

@@ -16,9 +16,9 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
 
 
 # ToDo Functions
 # ToDo Functions
 
 
-Features not in release 6.2.3
-
+Features not in release 6.2.4
 
 
+- Change Downstream timing to be interrupt driven.
 - Frequency: Support for eu433 frequencies (Standard)
 - Frequency: Support for eu433 frequencies (Standard)
 - Testing and timing of downlink functions (need quiet area)
 - Testing and timing of downlink functions (need quiet area)
 - Get HOP frequency functions to work on three frequencies
 - Get HOP frequency functions to work on three frequencies

+ 49 - 16
platformio.ini

@@ -8,54 +8,87 @@
 ; Please visit documentation for the other options and examples
 ; Please visit documentation for the other options and examples
 ; https://docs.platformio.org/page/projectconf.html
 ; https://docs.platformio.org/page/projectconf.html
 
 
+; Nr 21 has WIFIMANAGER set
 [env:Gateway_21]
 [env:Gateway_21]
 platform = espressif8266
 platform = espressif8266
 board = d1_mini
 board = d1_mini
 board_build.mcu = esp8266
 board_build.mcu = esp8266
 board_build.f_cpu = 80000000L
 board_build.f_cpu = 80000000L
 build_flags =
 build_flags =
-  -D _WIFIMANAGER=1
-  -D OLED=0
+  -D _WIFIMANAGER=0
+  -D _SPIFFS_FORMAT=0
+  -D _OLED=0
+  -D _DUSB=1
+  -D _PROFILER=1
 framework = arduino
 framework = arduino
 upload_protocol = espota
 upload_protocol = espota
 board_build.flash_mode = qio
 board_build.flash_mode = qio
 upload_speed = 115200
 upload_speed = 115200
 upload_port = 192.168.2.21
 upload_port = 192.168.2.21
 
 
-[env:Gateway_22]
+[env:Gateway_30]
 platform = espressif8266
 platform = espressif8266
 board = d1_mini
 board = d1_mini
 board_build.mcu = esp8266
 board_build.mcu = esp8266
 board_build.f_cpu = 80000000L
 board_build.f_cpu = 80000000L
 build_flags =
 build_flags =
-  -D OLED=1
+  -D _WIFIMANAGER=0
+  -D _SPIFFS_FORMAT=0
+  -D _OLED=0
+  -D _DUSB=1
+  -D _PROFILER=1
 framework = arduino
 framework = arduino
 upload_protocol = espota
 upload_protocol = espota
 board_build.flash_mode = qio
 board_build.flash_mode = qio
 upload_speed = 115200
 upload_speed = 115200
-upload_port = 192.168.2.22
+upload_port = 192.168.2.30
 
 
-[env:Gateway_31]
-platform = espressif8266
-board = d1_mini
-board_build.mcu = esp8266
-board_build.f_cpu = 80000000L
+[env:Gateway_72]
+platform = espressif32
+board = heltec_wifi_lora_32
+framework = arduino
 build_flags =
 build_flags =
-  -D _PIN_OUT=2
-  -D OLED=2
+  -D _SPIFFS_FORMAT=0
+  -D _WIFIMANAGER=0
+  -D _OLED=0
+  -D _DUSB=1
+  -D _PROFILER=1
+upload_protocol = espota
+board_build.flash_mode = qio
+upload_speed = 115200
+upload_port = 192.168.2.72
+
+[env:Gateway_138]
+platform = espressif32
+board = heltec_wifi_lora_32
 framework = arduino
 framework = arduino
+build_flags =
+  -D _WIFIMANAGER=0
+  -D _SPIFFS_FORMAT=0
+  -D _OLED=1
+  -D _DUSB=1
+  -D _PROFILER=1
+;  -D _JSONENCODE=1
+;  -D _MAXSEEN=0
 upload_protocol = espota
 upload_protocol = espota
 board_build.flash_mode = qio
 board_build.flash_mode = qio
 upload_speed = 115200
 upload_speed = 115200
-upload_port = 192.168.2.31
+upload_port = 192.168.2.138
 
 
-[env:Gateway_59]
+; Nr. 54 has WIFIMANAGER sometimes set
+; Also the Gateway is a T-Beam sensor for temperature and GPS (_GATEWAYNODE=1)
+[env:Gateway_54]
 platform = espressif32
 platform = espressif32
 board = heltec_wifi_lora_32
 board = heltec_wifi_lora_32
 build_flags =
 build_flags =
-  -D _WIFIMANAGER=1
+  -D _WIFIMANAGER=0
+  -D _SPIFFS_FORMAT=0
+  -D _DUSB=0
+  -D _OLED=0
+  -D _GATEWAYNODE=1
+  -D _PROFILER=1
 framework = arduino
 framework = arduino
 upload_protocol = espota
 upload_protocol = espota
 board_build.flash_mode = qio
 board_build.flash_mode = qio
 upload_speed = 115200
 upload_speed = 115200
-upload_port = 192.168.2.59
+upload_port = 192.168.2.54

+ 141 - 102
src/ESP-sc-gway.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg
 // Copyright (c) 2016-2020 Maarten Westenberg
 // Author: Maarten Westenberg (mw12554@hotmail.com)
 // Author: Maarten Westenberg (mw12554@hotmail.com)
 //
 //
@@ -81,16 +81,16 @@ extern "C" {
 
 
 #	define ESP_getChipId()   ((uint32_t)ESP.getEfuseMac())
 #	define ESP_getChipId()   ((uint32_t)ESP.getEfuseMac())
 
 
-#	if A_SERVER==1
+#	if _SERVER==1
 #		include <WebServer.h>								// Standard Webserver for ESP32
 #		include <WebServer.h>								// Standard Webserver for ESP32
 #		include <Streaming.h>          						// http://arduiniana.org/libraries/streaming/
 #		include <Streaming.h>          						// http://arduiniana.org/libraries/streaming/
-		WebServer server(A_SERVERPORT); // MMM added 20Feb
-#	endif //A_SERVER
+		WebServer server(_SERVERPORT); // MMM added 20Feb
+#	endif //_SERVER
 
 
-#	if A_OTA==1
+#	if _OTA==1
 //#		include <ESP32httpUpdate.h>							// Not yet available
 //#		include <ESP32httpUpdate.h>							// Not yet available
 #		include <ArduinoOTA.h>
 #		include <ArduinoOTA.h>
-#	endif //A_OTA
+#	endif //_OTA
 
 
 
 
 // ----------- Specific ESP8266 stuff --------------
 // ----------- Specific ESP8266 stuff --------------
@@ -105,16 +105,16 @@ extern "C" {
 
 
 #	define ESP_getChipId()   (ESP.getChipId())
 #	define ESP_getChipId()   (ESP.getChipId())
 
 
-#	if A_SERVER==1
+#	if _SERVER==1
 #		include <ESP8266WebServer.h>
 #		include <ESP8266WebServer.h>
 #		include <Streaming.h>          						// http://arduiniana.org/libraries/streaming/
 #		include <Streaming.h>          						// http://arduiniana.org/libraries/streaming/
-		ESP8266WebServer server(A_SERVERPORT);				// Standard IDE lib
-#	endif //A_SERVER
+		ESP8266WebServer server(_SERVERPORT);				// Standard IDE lib
+#	endif //_SERVER
 
 
-#	if A_OTA==1
+#	if _OTA==1
 #		include <ESP8266httpUpdate.h>
 #		include <ESP8266httpUpdate.h>
 #		include <ArduinoOTA.h>
 #		include <ArduinoOTA.h>
-#	endif //A_OTA
+#	endif //_OTA
 					
 					
 
 
 #else
 #else
@@ -163,6 +163,9 @@ char platform[24]	= _PLATFORM; 							// platform definition
 char email[40]		= _EMAIL;    							// used for contact email
 char email[40]		= _EMAIL;    							// used for contact email
 char description[64]= _DESCRIPTION;							// used for free form description 
 char description[64]= _DESCRIPTION;							// used for free form description 
 
 
+// JSON definitions
+StaticJsonDocument<312> jsonBuffer;							// Use of arduinoJson version 6!
+	
 // define servers
 // define servers
 
 
 IPAddress ntpServer;										// IP address of NTP_TIMESERVER
 IPAddress ntpServer;										// IP address of NTP_TIMESERVER
@@ -171,18 +174,20 @@ IPAddress thingServer;										// Only if we use a second (backup) server
 
 
 WiFiUDP Udp;
 WiFiUDP Udp;
 
 
-time_t startTime = 0;										// The time in seconds since 1970 that the server started. We use this variable since millis() is reset every 50 days...
+time_t startTime = 0;										// The time in seconds since 1970 that the server started. 
 uint32_t eventTime = 0;										// Timing of _event to change value (or not).
 uint32_t eventTime = 0;										// Timing of _event to change value (or not).
 uint32_t sendTime = 0;										// Time that the last message transmitted
 uint32_t sendTime = 0;										// Time that the last message transmitted
 uint32_t doneTime = 0;										// Time to expire when CDDONE takes too long
 uint32_t doneTime = 0;										// Time to expire when CDDONE takes too long
 uint32_t statTime = 0;										// last time we sent a stat message to server
 uint32_t statTime = 0;										// last time we sent a stat message to server
-uint32_t pullTime = 0;										// last time we sent a pull_data request to server
+uint32_t pullTime = 0;										// last time we sent a pull_data request to server\
+uint32_t rstTime  = 0;										// When to reset the timer
+uint32_t fileTime = 0;										// Wite the configuration to file
 
 
 #define TX_BUFF_SIZE  1024									// Upstream buffer to send to MQTT
 #define TX_BUFF_SIZE  1024									// Upstream buffer to send to MQTT
 #define RX_BUFF_SIZE  1024									// Downstream received from MQTT
 #define RX_BUFF_SIZE  1024									// Downstream received from MQTT
 #define STATUS_SIZE	  512									// Should(!) be enough based on the static text .. was 1024
 #define STATUS_SIZE	  512									// Should(!) be enough based on the static text .. was 1024
 
 
-#if A_SERVER==1
+#if _SERVER==1
 	uint32_t wwwtime = 0;
 	uint32_t wwwtime = 0;
 #endif
 #endif
 #if NTP_INTR==0
 #if NTP_INTR==0
@@ -191,6 +196,9 @@ uint32_t pullTime = 0;										// last time we sent a pull_data request to serv
 #if _GATEWAYNODE==1
 #if _GATEWAYNODE==1
 	uint16_t frameCount=0;									// We write this to SPIFF file
 	uint16_t frameCount=0;									// We write this to SPIFF file
 #endif
 #endif
+#ifdef _PROFILER
+	uint32_t endTmst=0;
+#endif
 
 
 // Init the indexes of the data we display on the webpage
 // Init the indexes of the data we display on the webpage
 // We use this for circular buffers
 // We use this for circular buffers
@@ -222,11 +230,11 @@ void setupWWW();														// _wwwServer.ino forward
 
 
 void mPrint(String txt);												// _utils.ino
 void mPrint(String txt);												// _utils.ino
 int getNtpTime(time_t *t);												// _utils.ino
 int getNtpTime(time_t *t);												// _utils.ino
-int mStat(uint8_t intr, String & response);								// _utils.ini
+int mStat(uint8_t intr, String & response);								// _utils.ino
 void SerialStat(uint8_t intr);											// _utils.ino
 void SerialStat(uint8_t intr);											// _utils.ino
 void printHexDigit(uint8_t digit, String & response);					// _utils.ino
 void printHexDigit(uint8_t digit, String & response);					// _utils.ino
 int inDecodes(char * id);												// _utils.ino
 int inDecodes(char * id);												// _utils.ino
-static void stringTime(time_t t, String & response);					// _urils.ino
+static void stringTime(time_t t, String & response);					// _utils.ino
 
 
 int initMonitor(struct moniLine *monitor);								// _loraFiles.ino
 int initMonitor(struct moniLine *monitor);								// _loraFiles.ino
 void initConfig(struct espGwayConfig *c);								// _loraFiles.ino
 void initConfig(struct espGwayConfig *c);								// _loraFiles.ino
@@ -250,7 +258,7 @@ void stateMachine();													// _stateMachine.ino
 
 
 bool connectUdp();														// _udpSemtech.ino
 bool connectUdp();														// _udpSemtech.ino
 int readUdp(int packetSize);											// _udpSemtech.ino
 int readUdp(int packetSize);											// _udpSemtech.ino
-int sendUdp(IPAddress server, int port, uint8_t *msg, int length);		// _udpSemtech.ino
+int sendUdp(IPAddress server, int port, uint8_t *msg, uint16_t length);		// _udpSemtech.ino
 void sendstat();														// _udpSemtech.ino
 void sendstat();														// _udpSemtech.ino
 void pullData();														// _udpSemtech.ino
 void pullData();														// _udpSemtech.ino
 
 
@@ -283,13 +291,13 @@ void setup() {
 #	endif //_DUSB
 #	endif //_DUSB
 
 
 
 
-#	if OLED>=1
-		init_oLED();										// When done display "STARTING" on OLED
-#	endif //OLED
+#	if _OLED>=1
+		init_oLED();										// When done display "STARTING" on Oled
+#	endif //_OLED
 
 
 #	if _GPS==1
 #	if _GPS==1
 		// Pins are defined in LoRaModem.h together with other pins
 		// Pins are defined in LoRaModem.h together with other pins
-		sGps.begin(9600, SERIAL_8N1, GPS_TX, GPS_RX);			// PIN 12-TX 15-RX
+		sGps.begin(9600, SERIAL_8N1, GPS_TX, GPS_RX);		// PIN 12-TX 15-RX
 #	endif //_GPS
 #	endif //_GPS
 
 
 	delay(500);
 	delay(500);
@@ -301,7 +309,7 @@ void setup() {
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
 	}
 	}
-	else {											// SPIFFS not found
+	else {													// SPIFFS not found
 		if (pdebug & P_MAIN) {
 		if (pdebug & P_MAIN) {
 			mPrint("SPIFFS.begin: not found, formatting");
 			mPrint("SPIFFS.begin: not found, formatting");
 		}
 		}
@@ -317,6 +325,7 @@ void setup() {
 	SPIFFS.format();										// Normally disabled. Enable only when SPIFFS corrupt
 	SPIFFS.format();										// Normally disabled. Enable only when SPIFFS corrupt
 	delay(500);
 	delay(500);
 	initConfig(&gwayConfig);
 	initConfig(&gwayConfig);
+	gwayConfig.formatCntr++;
 	if ((debug>=1) && (pdebug & P_MAIN)) {
 	if ((debug>=1) && (pdebug & P_MAIN)) {
 		mPrint("Format SPIFFS Filesystem Done");
 		mPrint("Format SPIFFS Filesystem Done");
 	}
 	}
@@ -349,13 +358,11 @@ void setup() {
 	else {
 	else {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
 		if (debug>=0) {
 		if (debug>=0) {
-			mPrint("setup:: readGwayCfg: ERROR readCfgCfg Failed");
+			mPrint("setup:: readGwayCfg: ERROR readGwayCfg Failed");
 		}
 		}
 #		endif	
 #		endif	
 	};							
 	};							
-
 	delay(500);
 	delay(500);
-	yield();
 
 
 #	if _WIFIMANAGER==1
 #	if _WIFIMANAGER==1
 		msg_oLED("WIFIMGR");
 		msg_oLED("WIFIMGR");
@@ -386,9 +393,10 @@ void setup() {
 			mPrint("setup:: Error Wifi network connect(0)");
 			mPrint("setup:: Error Wifi network connect(0)");
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
-		yield();
 	}
 	}
 
 
+	yield();
+
 #	if _MONITOR>=1
 #	if _MONITOR>=1
 	if ((debug>=1) & ( pdebug & P_MAIN )) {
 	if ((debug>=1) & ( pdebug & P_MAIN )) {
 		mPrint("setup:: WlanConnect="+String(WiFi.SSID()) );
 		mPrint("setup:: WlanConnect="+String(WiFi.SSID()) );
@@ -566,16 +574,16 @@ void setup() {
 
 
 	// The Over the Air updates are supported when we have a WiFi connection.
 	// The Over the Air updates are supported when we have a WiFi connection.
 	// The NTP time setting does not have to be precise for this function to work.
 	// The NTP time setting does not have to be precise for this function to work.
-#if A_OTA==1
+#if _OTA==1
 	setupOta(hostname);										// Uses wwwServer 
 	setupOta(hostname);										// Uses wwwServer 
-#endif //A_OTA
+#endif //_OTA
 
 
 	readSeen(_SEENFILE, listSeen);							// read the seenFile records
 	readSeen(_SEENFILE, listSeen);							// read the seenFile records
 
 
-#if A_SERVER==1	
+#if _SERVER==1	
 	// Setup the webserver
 	// Setup the webserver
 	setupWWW();
 	setupWWW();
-#endif //A_SERVER
+#endif //_SERVER
 
 
 	delay(100);												// Wait after setup
 	delay(100);												// Wait after setup
 	
 	
@@ -609,11 +617,11 @@ void setup() {
 	writeConfig(CONFIGFILE, &gwayConfig);					// Write config
 	writeConfig(CONFIGFILE, &gwayConfig);					// Write config
 	writeSeen(_SEENFILE, listSeen);							// Write the last time record  is seen
 	writeSeen(_SEENFILE, listSeen);							// Write the last time record  is seen
 
 
-	// activate OLED display
-#	if OLED>=1
+	// activate Oled display
+#	if _OLED>=1
 		acti_oLED();
 		acti_oLED();
 		addr_oLED();
 		addr_oLED();
-#	endif //OLED
+#	endif // _OLED
 
 
 	mPrint(" --- Setup() ended, Starting loop() ---");
 	mPrint(" --- Setup() ended, Starting loop() ---");
 
 
@@ -632,7 +640,7 @@ void setup() {
 // and the backend system cannot do its housekeeping, the watchdog
 // and the backend system cannot do its housekeeping, the watchdog
 // function will be executed which means effectively that the 
 // function will be executed which means effectively that the 
 // program crashes.
 // program crashes.
-// We use yield() a lot to avoid ANY watch dog activity of the program.
+// We use yield() to avoid ANY watch dog activity of the program.
 //
 //
 // NOTE2: For ESP make sure not to do large array declarations in loop();
 // NOTE2: For ESP make sure not to do large array declarations in loop();
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -641,6 +649,55 @@ void loop ()
 	int packetSize;
 	int packetSize;
 	uint32_t nowSeconds = now();
 	uint32_t nowSeconds = now();
 	
 	
+	// If we are not connected, try to connect.
+	// We will not read Udp in this loop cycle if not connected to Wlan
+	if (WlanConnect(1) < 0) {
+#		if _MONITOR>=1
+		if ((debug >= 0) && (pdebug & P_MAIN)) {
+			mPrint("loop:: ERROR reconnect WLAN");
+		}
+#		endif //_MONITOR
+		yield();
+		return;												// Exit loop if no WLAN connected
+	} //WlanConnect()
+
+	yield();												// MMM 200403 to make sure UDP buf filled
+
+	// So if we are connected 
+	// Receive UDP PUSH_ACK messages from server. (*2, par. 3.3)
+	// This is important since the TTN broker will return confirmation
+	// messages on UDP for every message sent by the gateway. So we have to consume them.
+	// As we do not know when the server will respond, we test in every loop.
+	//
+	while( (packetSize= Udp.parsePacket()) > 0) {
+#		if _MONITOR>=1
+		if ((debug>=2) && (pdebug & P_TX)){
+			mPrint("loop:: readUdp available");
+		}
+#		endif //_MONITOR
+
+		// DOWNSTREAM
+		// Packet may be PKT_PUSH_ACK (0x01), PKT_PULL_ACK (0x03) or PKT_PULL_RESP (0x04)
+		// This command is found in byte 4 (buffer[3])
+
+		if (readUdp(packetSize) < 0) {
+#			if _MONITOR>=1
+			if (debug>=0)
+				mPrint("Dwn readUdp ERROR, returning < 0");
+#			endif //_MONITOR
+			break;
+		}
+		// Now we know we succesfully received message from host
+		// If return value is 0, we received a NTP message,
+		// otherwise a UDP message with other TTN content, all ACKs are 4 bytes long
+		else {
+			//_event=1;									// Could be done double if more messages received
+			//mPrint("Dwn udp received="+String(micros())+", packetSize="+String(packetSize));
+		}
+	}
+
+	yield();
+
 	// check for event value, which means that an interrupt has arrived.
 	// check for event value, which means that an interrupt has arrived.
 	// In this case we handle the interrupt ( e.g. message received)
 	// In this case we handle the interrupt ( e.g. message received)
 	// in userspace in loop().
 	// in userspace in loop().
@@ -653,8 +710,8 @@ void loop ()
 	// So it will kick in if there are not many messages for the gateway.
 	// So it will kick in if there are not many messages for the gateway.
 	// Note: Be careful that it does not happen too often in normal operation.
 	// Note: Be careful that it does not happen too often in normal operation.
 	//
 	//
-	if ( ((nowSeconds - statr[0].tmst) > _MSG_INTERVAL ) &&
-		(msgTime <= statr[0].tmst) ) 
+	if ( ((nowSeconds - statr[0].time) > _MSG_INTERVAL ) &&
+		(msgTime <= statr[0].time) ) 
 	{
 	{
 #		if _MONITOR>=1
 #		if _MONITOR>=1
 		if (( debug>=2 ) && ( pdebug & P_MAIN )) {
 		if (( debug>=2 ) && ( pdebug & P_MAIN )) {
@@ -683,94 +740,47 @@ void loop ()
 		msgTime = nowSeconds;
 		msgTime = nowSeconds;
 	}
 	}
 
 
-#if A_SERVER==1
-	// Handle the Web server part of this sketch. Mainly used for administration 
-	// and monitoring of the node. This function is important so it is called at the
-	// start of the loop() function.
-	yield();
-	server.handleClient();
-#endif //A_SERVER
-
-#if A_OTA==1
+#if _OTA==1
 	// Perform Over the Air (OTA) update if enabled and requested by user.
 	// Perform Over the Air (OTA) update if enabled and requested by user.
 	// It is important to put this function early in loop() as it is
 	// It is important to put this function early in loop() as it is
 	// not called frequently but it should always run when called.
 	// not called frequently but it should always run when called.
 	//
 	//
 	yield();
 	yield();
 	ArduinoOTA.handle();
 	ArduinoOTA.handle();
-#endif //A_OTA
+#endif //_OTA
 
 
 	// If event is set, we know that we have a (soft) interrupt.
 	// If event is set, we know that we have a (soft) interrupt.
 	// After all necessary web/OTA services are scanned, we will
 	// After all necessary web/OTA services are scanned, we will
 	// reloop here for timing purposes. 
 	// reloop here for timing purposes. 
 	// Do as less yield() as possible.
 	// Do as less yield() as possible.
-	// XXX 180326
 	if (_event == 1) {
 	if (_event == 1) {
 		return;
 		return;
 	}
 	}
 	else yield();
 	else yield();
 
 
-	
-	// If we are not connected, try to connect.
-	// We will not read Udp in this loop cycle then
-	if (WlanConnect(1) < 0) {
-#		if _MONITOR>=1
-		if (( debug >= 0 ) && ( pdebug & P_MAIN )) {
-			mPrint("loop:: ERROR reconnect WLAN");
-		}
-#		endif //_MONITOR
-		yield();
-		return;												// Exit loop if no WLAN connected
-	} //WlanConnect
-	
-	// So if we are connected 
-	// Receive UDP PUSH_ACK messages from server. (*2, par. 3.3)
-	// This is important since the TTN broker will return confirmation
-	// messages on UDP for every message sent by the gateway. So we have to consume them.
-	// As we do not know when the server will respond, we test in every loop.
-	//
-	else {
-		while( (packetSize = Udp.parsePacket()) > 0) {
-#			if _MONITOR>=1
-			if (debug>=2) {
-				mPrint("loop:: readUdp calling");
-			}
-#			endif //_MONITOR
-			// DOWNSTREAM
-			// Packet may be PKT_PUSH_ACK (0x01), PKT_PULL_ACK (0x03) or PKT_PULL_RESP (0x04)
-			// This command is found in byte 4 (buffer[3])
-			if (readUdp(packetSize) < 0) {
-#				if _MONITOR>=1
-				if ( debug>=0 )
-					mPrint("readUdp ERROR,down returning < 0");
-#				endif //_MONITOR
-				break;
-			}
-			// Now we know we succesfully received message from host
-			// If return value is 0, we received a NTP message,
-			// otherwise a UDP message with other TTN content
-			else {
-				//_event=1;									// Could be done double if more messages received
-			}
-		}
-	}
+#if _SERVER==1
+	// Handle the Web server part of this sketch. Mainly used for administration 
+	// and monitoring of the node. This function is important so it is called at the
+	// start of the loop() function.
+	server.handleClient();
+#endif //_SERVER
+
 
 
-	yield();												// on 26/12/2017
 
 
 	// stat PUSH_DATA message (*2, par. 4)
 	// stat PUSH_DATA message (*2, par. 4)
 	//	
 	//	
-
     if ((nowSeconds - statTime) >= _STAT_INTERVAL) {		// Wake up every xx seconds
     if ((nowSeconds - statTime) >= _STAT_INTERVAL) {		// Wake up every xx seconds
+		yield();											// on 26/12/2017
         sendstat();											// Show the status message and send to server
         sendstat();											// Show the status message and send to server
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if (( debug>=2 ) && ( pdebug & P_MAIN )) {
+		if ((debug>=2) && (pdebug & P_MAIN)) {
 			mPrint("Send Pushdata sendstat");
 			mPrint("Send Pushdata sendstat");
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
 
 
 		// If the gateway behaves like a node, we do from time to time
 		// If the gateway behaves like a node, we do from time to time
 		// send a node message to the backend server.
 		// send a node message to the backend server.
-		// The Gateway node emessage has nothing to do with the STAT_INTERVAL
+		// The Gateway node message has nothing to do with the STAT_INTERVAL
 		// message but we schedule it in the same frequency.
 		// message but we schedule it in the same frequency.
 		//
 		//
 #		if _GATEWAYNODE==1
 #		if _GATEWAYNODE==1
@@ -792,21 +802,44 @@ void loop ()
 #		endif//_GATEWAYNODE
 #		endif//_GATEWAYNODE
 		statTime = nowSeconds;
 		statTime = nowSeconds;
     }
     }
-	
-	yield();
 
 
-	
+
 	// send PULL_DATA message (*2, par. 4)
 	// send PULL_DATA message (*2, par. 4)
 	//
 	//
+	// This message will also restart the server which taken approx. 3 ms.
 	nowSeconds = now();
 	nowSeconds = now();
     if ((nowSeconds - pullTime) >= _PULL_INTERVAL) {		// Wake up every xx seconds
     if ((nowSeconds - pullTime) >= _PULL_INTERVAL) {		// Wake up every xx seconds
+
+		yield();
         pullData();											// Send PULL_DATA message to server
         pullData();											// Send PULL_DATA message to server
-		startReceiver();
+		//startReceiver();
 		pullTime = nowSeconds;
 		pullTime = nowSeconds;
 		
 		
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if (( debug>=2) && ( pdebug & P_MAIN )) {
-			mPrint("ESP-sc-gway:: PULL_DATA message sent");
+		if ((debug>=1) && (pdebug & P_RX)) {
+			String response = "UP ESP-sc-gway:: PKT_PULL_DATA message sent: micr=";
+			printInt(micros(), response);
+			mPrint(response);
+		}
+#		endif //_MONITOR
+    }
+
+
+	// send RESET_DATA message (*2, par. 4)
+	//
+	// This message will also restart the server which taken approx. 3 ms.
+	nowSeconds = now();
+    if ((nowSeconds - rstTime) >= _RST_INTERVAL) {			// Wake up every xx seconds
+
+		yield();
+		startReceiver();
+		rstTime = nowSeconds;
+		
+#		if _MONITOR>=1
+		if ((debug>=2) && (pdebug & P_MAIN)) {
+			String response = "UP ESP-sc-gway:: RST_DATA message sent: micr=";
+			printInt(micros(), response);
+			mPrint(response);
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
     }
     }
@@ -820,7 +853,6 @@ void loop ()
 		//  as this function may collide with SPI and other interrupts
 		//  as this function may collide with SPI and other interrupts
 		// Note: It can be that we do not receive a time this loop (no worries)
 		// Note: It can be that we do not receive a time this loop (no worries)
 		yield();
 		yield();
-		nowSeconds = now();
 		if (nowSeconds - ntptimer >= _NTP_INTERVAL) {
 		if (nowSeconds - ntptimer >= _NTP_INTERVAL) {
 			yield();
 			yield();
 			time_t newTime;
 			time_t newTime;
@@ -844,4 +876,11 @@ void loop ()
 		}
 		}
 #	endif//NTP_INTR
 #	endif//NTP_INTR
 
 
+#	if _MAXSEEN >= 1
+		if ((nowSeconds - fileTime) >= _FILE_INTERVAL) {
+			writeSeen(_SEENFILE, listSeen);
+			fileTime = nowSeconds;
+		}
+#	endif // _MAXSEEN
+
 }//loop
 }//loop

+ 5 - 12
src/_WiFi.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -235,17 +235,17 @@ int WlanConnect(int maxTry) {
 	// Value 0 is reserved for setup() first time connect
 	// Value 0 is reserved for setup() first time connect
 	int i=0;
 	int i=0;
 
 
-	while ( (WiFi.status() != WL_CONNECTED) && (( i<= maxTry ) || (maxTry==0)) )
+	while ((WiFi.status() != WL_CONNECTED) && (( i<= maxTry ) || (maxTry==0)) )
 	{
 	{
 		// We try every SSID in wpa array until success
 		// We try every SSID in wpa array until success
-		for (int j=wpa_index; (j< (sizeof(wpa)/sizeof(wpa[0]))) && (WiFi.status() != WL_CONNECTED ); j++)
+		for (unsigned int j=wpa_index; (j<(sizeof(wpa)/sizeof(wpa[0]))) && (WiFi.status() != WL_CONNECTED ); j++)
 		{
 		{
 			// Start with well-known access points in the list
 			// Start with well-known access points in the list
 			char *ssid		= wpa[j].login;
 			char *ssid		= wpa[j].login;
 			char *password	= wpa[j].passw;
 			char *password	= wpa[j].passw;
 			
 			
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (debug>=1)  {
+			if ((debug>=1) && (pdebug & P_MAIN)) {
 				Serial.print(i);
 				Serial.print(i);
 				Serial.print(':');
 				Serial.print(':');
 				Serial.print(j); 
 				Serial.print(j); 
@@ -284,7 +284,7 @@ int WlanConnect(int maxTry) {
 			agains=1;
 			agains=1;
 			while ((WiFi.status() != WL_CONNECTED) && (agains < 8)) {
 			while ((WiFi.status() != WL_CONNECTED) && (agains < 8)) {
 				agains++;		
 				agains++;		
-				delay(8000);											//delay(agains*500);
+				delay(8000);											// delay(agains*500);
 #				if _MONITOR>=1
 #				if _MONITOR>=1
 				if ( debug>=0 ) {
 				if ( debug>=0 ) {
 					Serial.print(".");									// Serial only
 					Serial.print(".");									// Serial only
@@ -302,13 +302,6 @@ int WlanConnect(int maxTry) {
 		i++;			// Number of times we try to connect
 		i++;			// Number of times we try to connect
 	} //while
 	} //while
 
 
-
-#		if _MONITOR>=1
-		if ((debug>=2) & (pdebug & P_MAIN)) {
-			mPrint("WlanConnect:: Connected="+ String(WiFi.SSID()) );
-		}
-#		endif //_MONITOR
-
 	yield();
 	yield();
 	return(1);
 	return(1);
 	
 	

+ 13 - 6
src/_gatewayMgt.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg 
 // Copyright (c) 2016-2020 Maarten Westenberg 
 //
 //
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -57,23 +57,30 @@ void gateway_mgt(uint8_t size, uint8_t *buff) {
 	
 	
 	switch (opcode) {
 	switch (opcode) {
 		case MGT_RESET:
 		case MGT_RESET:
-			Serial.println(F("gateway_mgt:: RESET"));
+#			if _MONITOR>=1
+				mPrint(F("gateway_mgt:: RESET"));
+#			endif // _MONITOR
 			// No further parameters, just reset the GWay
 			// No further parameters, just reset the GWay
 			setup();								// Call the sketch setup function
 			setup();								// Call the sketch setup function
 			// Send Ack to server
 			// Send Ack to server
 			
 			
 		break;
 		break;
 		case MGT_SET_SF:
 		case MGT_SET_SF:
-			Serial.println(F("gateway_mgt:: SET SF"));
+#			if _MONITOR>=1
+				mPrint(F("gateway_mgt:: SET SF"));
+#			endif //_MONITOR
 			// byte [4] contains desired SF code (7 for SF7 and 12 for SF12)
 			// byte [4] contains desired SF code (7 for SF7 and 12 for SF12)
 		break;
 		break;
 		case MGT_SET_FREQ:
 		case MGT_SET_FREQ:
-			Serial.println(F("gateway_mgt:: SET FREQ"));
+#			if _MONITOR>=1
+				mPrint(F("gateway_mgt:: SET FREQ"));
+#			endif // _MONITOR
 			// Byte [4] contains index of Frequency
 			// Byte [4] contains index of Frequency
 		break;
 		break;
 		default:
 		default:
-			Serial.print(F("gateway_mgt:: Unknown UDP code=")); 
-			Serial.println(opcode);
+#			if _MONITOR>=1
+				mPrint(F("gateway_mgt:: Unknown UDP code=") + String(opcode) ); 
+#			endif
 			return;
 			return;
 		break;
 		break;
 	}
 	}

+ 85 - 134
src/_loraFiles.ino

@@ -54,7 +54,9 @@ void id_print (String id, String val)
 }
 }
 
 
 
 
-
+// ============================================================================
+// config functions
+//
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // INITCONFIG; Init the gateway configuration file
 // INITCONFIG; Init the gateway configuration file
@@ -75,7 +77,9 @@ void initConfig(struct espGwayConfig *c)
 	(*c).monitor = true;				// Monitoring is ON
 	(*c).monitor = true;				// Monitoring is ON
 	(*c).trusted = 1;
 	(*c).trusted = 1;
 	(*c).txDelay = 0;					// First Value without saving is 0;
 	(*c).txDelay = 0;					// First Value without saving is 0;
-}
+	(*c).dusbStat = true;
+
+} // initConfig()
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // Read the config file and fill the (copied) variables
 // Read the config file and fill the (copied) variables
@@ -95,6 +99,7 @@ int readGwayCfg(const char *fn, struct espGwayConfig *c)
 	}
 	}
 	debug	= (*c).debug;
 	debug	= (*c).debug;
 	pdebug	= (*c).pdebug;
 	pdebug	= (*c).pdebug;
+	(*c).boots++;										// Increment Boot Counter
 
 
 #	if _GATEWAYNODE==1
 #	if _GATEWAYNODE==1
 		if (gwayConfig.fcnt != (uint8_t) 0) {
 		if (gwayConfig.fcnt != (uint8_t) 0) {
@@ -102,8 +107,11 @@ int readGwayCfg(const char *fn, struct espGwayConfig *c)
 		}
 		}
 #	endif
 #	endif
 
 
+	writeGwayCfg(CONFIGFILE, &gwayConfig );				// And writeback the configuration, not to miss a boot
+
 	return 1;
 	return 1;
-}
+	
+} // readGwayCfg()
 
 
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -222,6 +230,14 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 			id_print(id, val);
 			id_print(id, val);
 			(*c).ntpErr = (uint16_t) val.toInt();
 			(*c).ntpErr = (uint16_t) val.toInt();
 		}
 		}
+		else if (id == "WAITERR") {								// WAITERR setting
+			id_print(id, val);
+			(*c).waitErr = (uint16_t) val.toInt();
+		}
+		else if (id == "WAITOK") {								// WAITOK setting
+			id_print(id, val);
+			(*c).waitOk = (uint16_t) val.toInt();
+		}
 		else if (id == "NTPETIM") {								// NTPERR setting
 		else if (id == "NTPETIM") {								// NTPERR setting
 			id_print(id, val);
 			id_print(id, val);
 			(*c).ntpErrTime = (uint32_t) val.toInt();
 			(*c).ntpErrTime = (uint32_t) val.toInt();
@@ -258,6 +274,10 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 			id_print(id, val);
 			id_print(id, val);
 			(*c).trusted= (int8_t) val.toInt();
 			(*c).trusted= (int8_t) val.toInt();
 		}
 		}
+		else if (id == "FORMAT") {								// TRUSTED setting
+			id_print(id, val);
+			(*c).formatCntr= (int8_t) val.toInt();
+		}
 		else {
 		else {
 #			if _MONITOR>=1
 #			if _MONITOR>=1
 				mPrint(F("readConfig:: tries++"));
 				mPrint(F("readConfig:: tries++"));
@@ -268,7 +288,8 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 	f.close();
 	f.close();
 
 
 	return(1);
 	return(1);
-}//readConfig
+	
+} // readConfig()
 
 
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -291,7 +312,8 @@ int writeGwayCfg(const char *fn, struct espGwayConfig *c)
 #	endif //_GATEWAYNODE
 #	endif //_GATEWAYNODE
 
 
 	return(writeConfig(fn, c));
 	return(writeConfig(fn, c));
-}
+} // writeGwayCfg
+
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // Write the configuration as found in the espGwayConfig structure
 // Write the configuration as found in the espGwayConfig structure
@@ -330,10 +352,13 @@ int writeConfig(const char *fn, struct espGwayConfig *c)
 	f.print("REENTS");	f.print('='); f.print((*c).reents);		f.print('\n');
 	f.print("REENTS");	f.print('='); f.print((*c).reents);		f.print('\n');
 	f.print("NTPETIM");	f.print('='); f.print((*c).ntpErrTime); f.print('\n');
 	f.print("NTPETIM");	f.print('='); f.print((*c).ntpErrTime); f.print('\n');
 	f.print("NTPERR");	f.print('='); f.print((*c).ntpErr);		f.print('\n');
 	f.print("NTPERR");	f.print('='); f.print((*c).ntpErr);		f.print('\n');
+	f.print("WAITERR");	f.print('='); f.print((*c).waitErr);	f.print('\n');
+	f.print("WAITOK");	f.print('='); f.print((*c).waitOk);		f.print('\n');
 	f.print("NTPS");	f.print('='); f.print((*c).ntps);		f.print('\n');
 	f.print("NTPS");	f.print('='); f.print((*c).ntps);		f.print('\n');
 	f.print("FILEREC");	f.print('='); f.print((*c).logFileRec); f.print('\n');
 	f.print("FILEREC");	f.print('='); f.print((*c).logFileRec); f.print('\n');
 	f.print("FILENO");	f.print('='); f.print((*c).logFileNo);	f.print('\n');
 	f.print("FILENO");	f.print('='); f.print((*c).logFileNo);	f.print('\n');
 	f.print("FILENUM");	f.print('='); f.print((*c).logFileNum); f.print('\n');
 	f.print("FILENUM");	f.print('='); f.print((*c).logFileNum); f.print('\n');
+	f.print("FORMAT");	f.print('='); f.print((*c).formatCntr); f.print('\n');
 	f.print("DELAY");	f.print('='); f.print((*c).txDelay); 	f.print('\n');
 	f.print("DELAY");	f.print('='); f.print((*c).txDelay); 	f.print('\n');
 	f.print("TRUSTED");	f.print('='); f.print((*c).trusted); 	f.print('\n');
 	f.print("TRUSTED");	f.print('='); f.print((*c).trusted); 	f.print('\n');
 	f.print("EXPERT");	f.print('='); f.print((*c).expert); 	f.print('\n');
 	f.print("EXPERT");	f.print('='); f.print((*c).expert); 	f.print('\n');
@@ -342,7 +367,7 @@ int writeConfig(const char *fn, struct espGwayConfig *c)
 	
 	
 	f.close();
 	f.close();
 	return(1);
 	return(1);
-}
+} // writeConfig()
 
 
 
 
 
 
@@ -363,6 +388,7 @@ int writeConfig(const char *fn, struct espGwayConfig *c)
 int addLog(const unsigned char * line, int cnt) 
 int addLog(const unsigned char * line, int cnt) 
 {
 {
 #	if _STAT_LOG==1
 #	if _STAT_LOG==1
+
 	char fn[16];
 	char fn[16];
 	
 	
 	if (gwayConfig.logFileRec > LOGFILEREC) {		// Have to make define for this
 	if (gwayConfig.logFileRec > LOGFILEREC) {		// Have to make define for this
@@ -417,12 +443,14 @@ int addLog(const unsigned char * line, int cnt)
 		Serial.print(gwayConfig.logFileRec);
 		Serial.print(gwayConfig.logFileRec);
 
 
 		Serial.print(F(": "));
 		Serial.print(F(": "));
-#		if _DUSB>=2
+#		if _MONITOR>=2
+		{
 			for (i=0; i< 12; i++) {				// The first 12 bytes contain non printable characters
 			for (i=0; i< 12; i++) {				// The first 12 bytes contain non printable characters
 				Serial.print(line[i],HEX);
 				Serial.print(line[i],HEX);
 				Serial.print(' ');
 				Serial.print(' ');
 			}
 			}
-#		else //_DUSB>=2
+		}
+#		else //_MONITOR>=2
 			i+=12;
 			i+=12;
 #		endif //_DUSB>=2
 #		endif //_DUSB>=2
 		Serial.print((char *) &line[i]);	// The rest if the buffer contains ascii
 		Serial.print((char *) &line[i]);	// The rest if the buffer contains ascii
@@ -441,44 +469,14 @@ int addLog(const unsigned char * line, int cnt)
 #	endif //_STAT_LOG
 #	endif //_STAT_LOG
 
 
 	return(1);
 	return(1);
-} //addLog
-
+} //addLog()
 
 
-// ----------------------------------------------------------------------------
-// Print (all) logfiles
-// Return:
-//	<none>
-// Parameters:
-//	<none>
-// ----------------------------------------------------------------------------
-void printLog()
-{
-#if _STAT_LOG==1
-	char fn[16];
 
 
-#	if _DUSB>=1
-	for (int i=0; i< LOGFILEMAX; i++ ) {
-		sprintf(fn,"/log-%d", gwayConfig.logFileNo - i);
-		if (!SPIFFS.exists(fn)) break;		// break the loop
 
 
-		// Open the file for reading
-		File f = SPIFFS.open(fn, "r");
-
-		for (int j=0; j<LOGFILEREC; j++) {
-			
-			String s=f.readStringUntil('\n');
-			if (s.length() == 0) break;
-
-			Serial.println(s.substring(12));			// Skip the first 12 Gateway specific binary characters
-			yield();
-		}
-	}
-#	endif //_DUSB
-#endif //_STAT_LOG
-} //printLog
-
-
-#if _MAXSEEN >= 1
+// ============================================================================
+// Below are the xxxSeen() functions. These functions keep track of the kast
+// time a device was seen bij the gateway.
+// These functions are not round-robin and they do not need to be.
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // initSeen
 // initSeen
@@ -490,6 +488,7 @@ void printLog()
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 int initSeen(struct nodeSeen *listSeen) 
 int initSeen(struct nodeSeen *listSeen) 
 {
 {
+#if _MAXSEEN >= 1
 	for (int i=0; i< _MAXSEEN; i++) {
 	for (int i=0; i< _MAXSEEN; i++) {
 		listSeen[i].idSeen=0;
 		listSeen[i].idSeen=0;
 		listSeen[i].sfSeen=0;
 		listSeen[i].sfSeen=0;
@@ -498,8 +497,10 @@ int initSeen(struct nodeSeen *listSeen)
 		listSeen[i].timSeen=(time_t) 0;					// 1 jan 1970 0:00:00 hrs
 		listSeen[i].timSeen=(time_t) 0;					// 1 jan 1970 0:00:00 hrs
 	}
 	}
 	iSeen= 0;											// Init index to 0
 	iSeen= 0;											// Init index to 0
+#endif // _MAXSEEN
 	return(1);
 	return(1);
-}
+
+} // initSeen()
 
 
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -514,6 +515,7 @@ int initSeen(struct nodeSeen *listSeen)
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 int readSeen(const char *fn, struct nodeSeen *listSeen)
 int readSeen(const char *fn, struct nodeSeen *listSeen)
 {
 {
+#if _MAXSEEN >= 1
 	int i;
 	int i;
 	iSeen= 0;												// Init the index at 0
 	iSeen= 0;												// Init the index at 0
 	
 	
@@ -540,10 +542,8 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 		String val="";
 		String val="";
 		
 		
 		if (!f.available()) {
 		if (!f.available()) {
-#			if _MONITOR>=1
-				String response="readSeen:: No more info left in file, i=";
-				response += i;
-				mPrint(response);
+#			if _MONITOR>=2
+				mPrint("readSeen:: No more info left in file, i=" + String(i));
 #			endif //_MONITOR
 #			endif //_MONITOR
 			break;
 			break;
 		}
 		}
@@ -561,16 +561,13 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 		iSeen++;											// Increase index, new record read
 		iSeen++;											// Increase index, new record read
 	}
 	}
 	f.close();
 	f.close();
-	
-#	if _MONITOR>=1
-	if ((debug >= 2) && (pdebug & P_MAIN)) {
-		Serial.print("readSeen:: ");
-		printSeen(listSeen);
-	}
-#	endif //_MONITOR
+
+#endif // _MAXSEEN
+
 	// So we read iSeen records
 	// So we read iSeen records
 	return 1;
 	return 1;
-}
+	
+} // readSeen()
 
 
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -584,6 +581,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 int writeSeen(const char *fn, struct nodeSeen *listSeen)
 int writeSeen(const char *fn, struct nodeSeen *listSeen)
 {
 {
+#if _MAXSEEN >= 1
 	int i;
 	int i;
 	if (!SPIFFS.exists(fn)) {
 	if (!SPIFFS.exists(fn)) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
@@ -610,48 +608,11 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen)
 	}
 	}
 	
 	
 	f.close();
 	f.close();
-#	if _DUSB>=1
-	if ((debug >= 2) && (pdebug & P_MAIN)) {
-		Serial.print("writeSeen:: ");
-		printSeen(listSeen);
-	}
-#	endif //_DUSB
+#endif // _MAXSEEN
 	return(1);
 	return(1);
 }
 }
 
 
-// ----------------------------------------------------------------------------
-// printSeen
-// - This function writes the last seen array to the USB !!
-// ----------------------------------------------------------------------------
-int printSeen(struct nodeSeen *listSeen) {
 
 
-#	if _DUSB>=1
-    int i;
-	if (( debug>=2 ) && ( pdebug & P_MAIN )) {
-	
-		Serial.println(F("printSeen:: "));
-		
-		for (i=0; i<iSeen; i++) {
-			if (listSeen[i].idSeen != 0) {
-				String response;
-				
-				response = i;
-				response += ", Tim=";
-
-				stringTime(listSeen[i].timSeen, response);
-
-				response += ", addr=0x";
-				printHex(listSeen[i].idSeen,' ', response);
-				
-				response += ", SF=0x";
-				response += listSeen[i].sfSeen;
-				Serial.println(response);
-			}
-		}
-	}
-#	endif //_DUSB
-	return(1);
-}
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // addSeen
 // addSeen
@@ -668,71 +629,61 @@ int printSeen(struct nodeSeen *listSeen) {
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 int addSeen(struct nodeSeen *listSeen, struct stat_t stat) 
 int addSeen(struct nodeSeen *listSeen, struct stat_t stat) 
 {
 {
-
-	int i=0;
+#if _MAXSEEN >= 1
+	int i;
 	for (i=0; i<iSeen; i++) {						// For all known records
 	for (i=0; i<iSeen; i++) {						// For all known records
 
 
+		// If the record node is equal, we found the record already.
+		// So increment cntSeen
 		if (listSeen[i].idSeen==stat.node) {
 		if (listSeen[i].idSeen==stat.node) {
-
-			listSeen[i].timSeen = (time_t)stat.tmst;
+		
+			listSeen[i].timSeen = (time_t)stat.time;
 			listSeen[i].cntSeen++;					// Not included on function para
 			listSeen[i].cntSeen++;					// Not included on function para
-			listSeen[i].idSeen = stat.node;
+			//listSeen[i].idSeen = stat.node;		// Not necessary, is the same
 			listSeen[i].chnSeen = stat.ch;
 			listSeen[i].chnSeen = stat.ch;
-			listSeen[i].sfSeen = stat.sf;			// Or the argument
-	
-			writeSeen(_SEENFILE, listSeen);
+			listSeen[i].sfSeen = stat.sf;			// The SF argument
+//			writeSeen(_SEENFILE, listSeen);
+			
+#			if _MONITOR>=2
+			if ((debug>=1) && (pdebug & P_MAIN)) {
+				mPrint("addSeen:: adding i="+String(i)+", node="+String(stat.node,HEX));
+			}
+#			endif
 
 
 			return 1;
 			return 1;
 		}
 		}
 	}
 	}
 	
 	
-	// Else: We did not find the current record so make a new Seen entry
+	// else: We did not find the current record so make a new Seen entry
 	if ((i>=iSeen) && (i<_MAXSEEN)) {
 	if ((i>=iSeen) && (i<_MAXSEEN)) {
 		listSeen[i].idSeen = stat.node;
 		listSeen[i].idSeen = stat.node;
 		listSeen[i].chnSeen = stat.ch;
 		listSeen[i].chnSeen = stat.ch;
-		listSeen[i].sfSeen = stat.sf;			// Or the argument
-		listSeen[i].timSeen = (time_t)stat.tmst;
-		listSeen[i].cntSeen = 1;					// Not included on function para	
+		listSeen[i].sfSeen = stat.sf;				// The SF argument
+		listSeen[i].timSeen = (time_t)stat.time;	// Timestamp correctly
+		listSeen[i].cntSeen = 1;					// We see this for the first time	
 		iSeen++;
 		iSeen++;
-		//return(1);
 	}
 	}
 
 
-#	if _MONITOR>=2
-	if ((debug>=1) && (pdebug & P_MAIN)) {
-		String response= "addSeen:: New i=";
+#	if _MONITOR>=1
+	if ((debug>=2) && (pdebug & P_MAIN)) {
+		String response= "addSeen:: i=";
 		response += i;
 		response += i;
 		response += ", tim=";
 		response += ", tim=";
-		stringTime(stat.tmst, response);
+		stringTime(stat.time, response);
 		response += ", iSeen=";
 		response += ", iSeen=";
-		response += String(iSeen,HEX);
+		response += String(iSeen);
 		response += ", node=";
 		response += ", node=";
 		response += String(stat.node,HEX);
 		response += String(stat.node,HEX);
 		response += ", listSeen[0]=";
 		response += ", listSeen[0]=";
-		
-		printHex(listSeen[0].idSeen,' ',response);
-		Serial.print("<"); Serial.print(listSeen[0].idSeen, HEX); Serial.print(">");
-
-		mPrint(response);
-		
-		response += ", listSeen[0]=";
-		printHex(listSeen[0].idSeen,' ',response);
+		printHex(listSeen[0].idSeen,':',response);
 
 
 		mPrint(response);
 		mPrint(response);
 	}
 	}
-#	endif
-
-	// USB Only
-#	if _DUSB>=2
-	if ((debug>=2) && (pdebug & P_MAIN)) {
-		Serial.print("addSeen i=");
-		Serial.print(i);
-		Serial.print(", id=");
-		Serial.print(listSeen[i].idSeen,HEX);
-		Serial.println();
-	}
-#	endif // _DUSB	
+#	endif // _MONITOR
 
 
+#endif //_MAXSEEN>=1 
 	return 1;
 	return 1;
-}
+	
+} // addSeen()
 
 
-#endif //_MAXSEEN>=1 End of File
+// End of File

+ 89 - 143
src/_loraModem.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -193,14 +193,15 @@ void writeBuffer(uint8_t addr, uint8_t *buf, uint8_t len)
 void setRate(uint8_t sf, uint8_t crc) 
 void setRate(uint8_t sf, uint8_t crc) 
 {
 {
 	uint8_t mc1=0, mc2=0, mc3=0;
 	uint8_t mc1=0, mc2=0, mc3=0;
-#	if _MONITOR>=2
+
 	if ((sf<SF7) || (sf>SF12)) {
 	if ((sf<SF7) || (sf>SF12)) {
+#		if _MONITOR>=2
 		if (( debug>=1 ) && ( pdebug & P_RADIO )) {
 		if (( debug>=1 ) && ( pdebug & P_RADIO )) {
 			mPrint("setRate:: SF=" + String(sf));
 			mPrint("setRate:: SF=" + String(sf));
 		}
 		}
-		return;
+#		endif //_MONITOR
+		sf=8;
 	}
 	}
-#	endif //_MONITOR
 
 
 	// Set rate based on Spreading Factor etc
 	// Set rate based on Spreading Factor etc
     if (sx1272) {
     if (sx1272) {
@@ -303,7 +304,8 @@ void  opmode(uint8_t mode)
 // This function should only be used for receiver operation. The current
 // This function should only be used for receiver operation. The current
 // receiver frequency is determined by gwayConfig.ch index like so: freqs[gwayConfig.ch] 
 // receiver frequency is determined by gwayConfig.ch index like so: freqs[gwayConfig.ch] 
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
-void hop() {
+void hop() 
+{
 
 
 	// 1. Set radio to standby
 	// 1. Set radio to standby
 	opmode(OPMODE_STANDBY);
 	opmode(OPMODE_STANDBY);
@@ -360,8 +362,8 @@ void hop() {
 }
 }
 	
 	
 
 
-// ----------------------------------------------------------------------------------------
-// UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP
+// ------------------------------------- UP -----------------------------------------------
+//
 // This LoRa function reads a message from the LoRa transceiver
 // This LoRa function reads a message from the LoRa transceiver
 // on Success: returns message length read when message correctly received.
 // on Success: returns message length read when message correctly received.
 // on Failure: it returns a negative value on error (CRC error for example).
 // on Failure: it returns a negative value on error (CRC error for example).
@@ -446,16 +448,11 @@ uint8_t receivePkt(uint8_t *payload)
 		}
 		}
 
 
 		if (readRegister(REG_FIFO_RX_CURRENT_ADDR) != readRegister(REG_FIFO_RX_BASE_AD)) {
 		if (readRegister(REG_FIFO_RX_CURRENT_ADDR) != readRegister(REG_FIFO_RX_BASE_AD)) {
-#if			_DUSB>=1
+#if			_MONITOR>=1
 			if (( debug>=1 ) && ( pdebug & P_RADIO )) {
 			if (( debug>=1 ) && ( pdebug & P_RADIO )) {
-				Serial.print(F("RX BASE <"));
-				Serial.print(readRegister(REG_FIFO_RX_BASE_AD));
-				Serial.print(F("> != RX CURRENT <"));
-				Serial.print(readRegister(REG_FIFO_RX_CURRENT_ADDR));
-				Serial.print(F(">"));
-				Serial.println();
+				mPrint("RX BASE <" + String(readRegister(REG_FIFO_RX_BASE_AD)) + "> != RX CURRENT <" + String(readRegister(REG_FIFO_RX_CURRENT_ADDR)) + ">"	);
 			}
 			}
-#			endif //_DUSB
+#			endif //_MONITOR
 		}
 		}
 		
 		
         //uint8_t currentAddr = readRegister(REG_FIFO_RX_CURRENT_ADDR);	// 0x10
         //uint8_t currentAddr = readRegister(REG_FIFO_RX_CURRENT_ADDR);	// 0x10
@@ -487,28 +484,23 @@ uint8_t receivePkt(uint8_t *payload)
 		// As long as _MONITOR is enabled, and P_RX debug messages are selected,
 		// As long as _MONITOR is enabled, and P_RX debug messages are selected,
 		// the received packet is displayed on the output.
 		// the received packet is displayed on the output.
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if (( debug>=1 ) && ( pdebug & P_RX )){
+		if ((debug>=1) && (pdebug & P_RX)){
 		
 		
-			String response = "rxPkt:: t=";
+			String response = "UP receivePkt:: rxPkt: t=";
 			stringTime(now(), response);
 			stringTime(now(), response);
+			response += ", f=" + String(gwayConfig.ch) + ", sf=" + String(sf);
 			
 			
-			Serial.print(F(", f="));
-			Serial.print(gwayConfig.ch);
-			Serial.print(F(", sf="));
-			Serial.print(sf);
-			
-			Serial.print(F(", a="));
-			if (payload[4]<0x10) Serial.print('0'); Serial.print(payload[4], HEX);
-			if (payload[3]<0x10) Serial.print('0'); Serial.print(payload[3], HEX);
-			if (payload[2]<0x10) Serial.print('0'); Serial.print(payload[2], HEX);
-			if (payload[1]<0x10) Serial.print('0'); Serial.print(payload[1], HEX);
+			response += ", a=";
+			uint8_t DevAddr [4];
+					DevAddr[0] = payload[4];
+					DevAddr[1] = payload[3];
+					DevAddr[2] = payload[2];
+					DevAddr[3] = payload[1];
+			printHex((IPAddress)DevAddr, ':', response);
 			
 			
-			Serial.print(F(", flags="));
-			Serial.print(irqflags,HEX);
-			Serial.print(F(", addr="));
-			Serial.print(currentAddr);
-			Serial.print(F(", len="));
-			Serial.print(receivedCount);
+			response += ", flags=" + String(irqflags,HEX);
+			response += ", addr=" + String(currentAddr);
+			response += ", len=" + String(receivedCount);
 
 
 			// If debug level 1 is specified, we display the content of the message as well
 			// If debug level 1 is specified, we display the content of the message as well
 			// We need to decode the message as well will it make any sense
 			// We need to decode the message as well will it make any sense
@@ -517,15 +509,9 @@ uint8_t receivePkt(uint8_t *payload)
 			if (debug>=1)  {							// Must be 1 for operational use
 			if (debug>=1)  {							// Must be 1 for operational use
 
 
 				int index;								// The index of the codex struct to decode
 				int index;								// The index of the codex struct to decode
-				String response="";
+				//String response="";
 
 
 				uint8_t data[receivedCount];
 				uint8_t data[receivedCount];
-				
-				uint8_t DevAddr [4];
-					DevAddr[0] = payload[4];
-					DevAddr[1] = payload[3];
-					DevAddr[2] = payload[2];
-					DevAddr[3] = payload[1];
 			
 			
 				if ((index = inDecodes((char *)(payload+1))) >=0 ) {	
 				if ((index = inDecodes((char *)(payload+1))) >=0 ) {	
 					mPrint(", Ind="+String(index));
 					mPrint(", Ind="+String(index));
@@ -570,12 +556,10 @@ uint8_t receivePkt(uint8_t *payload)
 					Serial.print(data[i], HEX);
 					Serial.print(data[i], HEX);
 					Serial.print(' ');
 					Serial.print(' ');
 				}
 				}
-			|
+			}
 #			endif // _TRUSTED_DECODE
 #			endif // _TRUSTED_DECODE
 			
 			
 			mPrint(response);							// Print response for Serial or mPrint
 			mPrint(response);							// Print response for Serial or mPrint
-			
-			if (debug>=2) Serial.flush();
 		}
 		}
 #		endif //MONITOR
 #		endif //MONITOR
 		return(receivedCount);
 		return(receivedCount);
@@ -586,13 +570,15 @@ uint8_t receivePkt(uint8_t *payload)
 		IRQ_LORA_RXTOUT_MASK |
 		IRQ_LORA_RXTOUT_MASK |
 		IRQ_LORA_HEADER_MASK | 
 		IRQ_LORA_HEADER_MASK | 
 		IRQ_LORA_CRCERR_MASK));							// 0x12; Clear RxDone IRQ_LORA_RXDONE_MASK
 		IRQ_LORA_CRCERR_MASK));							// 0x12; Clear RxDone IRQ_LORA_RXDONE_MASK
-    return 0;
+
+	return 0;
+	
 } //receivePkt UP
 } //receivePkt UP
 	
 	
 	
 	
 	
 	
-// ----------------------------------------------------------------------------------------
-// DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN 
+// ------------------------------ DOWN ----------------------------------------------------
+//
 // This DOWN function sends a payload to the LoRa node over the air
 // This DOWN function sends a payload to the LoRa node over the air
 // Radio must go back in standby mode as soon as the transmission is finished
 // Radio must go back in standby mode as soon as the transmission is finished
 // 
 // 
@@ -600,15 +586,14 @@ uint8_t receivePkt(uint8_t *payload)
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 {
 {
-#	if _DUSB>=2
+#	if _MONITOR>=2
 	if (payLength>=128) {
 	if (payLength>=128) {
 		if (debug>=1) {
 		if (debug>=1) {
-			Serial.print("sendPkt:: len=");
-			Serial.println(payLength);
+			mPrint("sendPkt Dwn:: len="+String(payLength));
 		}
 		}
 		return false;
 		return false;
 	}
 	}
-#	endif
+#	endif //_MONITOR
 	
 	
 	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_TX_BASE_AD));	// 0x0D, 0x0E
 	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_TX_BASE_AD));	// 0x0D, 0x0E
 	
 	
@@ -617,9 +602,10 @@ bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 	writeBuffer(REG_FIFO, (uint8_t *) payLoad, payLength);
 	writeBuffer(REG_FIFO, (uint8_t *) payLoad, payLength);
 	
 	
 	return true;
 	return true;
-}
+} // sendPkt()
 
 
-// ----------------------------------------------------------------------------------------
+
+// ------------------------------------------ DOWN ----------------------------------------
 // loraWait()
 // loraWait()
 // This function implements the wait protocol needed for downstream transmissions.
 // This function implements the wait protocol needed for downstream transmissions.
 // Note: Timing of downstream and JoinAccept messages is VERY critical.
 // Note: Timing of downstream and JoinAccept messages is VERY critical.
@@ -635,72 +621,46 @@ bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 // to make sure that delay() did not take too much time this works.
 // to make sure that delay() did not take too much time this works.
 // 
 // 
 // Parameter: uint32-t tmst gives the micros() value when transmission should start. (!!!)
 // Parameter: uint32-t tmst gives the micros() value when transmission should start. (!!!)
-// Note: We assume LoraDown.sfTx contains the SF we will use for downstream message.
+// so it contains the local Gateway time as a reference when to start Downlink.
+// Note: We assume LoraDown->sfTx contains the SF we will use for downstream message.
+//		gwayConfig.txDelay is the delay as specified in the GUI
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 
 
-void loraWait(const uint32_t timestamp)
+void loraWait(struct LoraDown *LoraDown)
 {
 {
-	uint32_t startMics = micros();						// Start of the loraWait function
-	uint32_t tmst = timestamp;
-
-	int32_t adjust=0;
-	switch (LoraDown.sfTx) {
-		case 7: adjust= 60000; break;					// Make time for SF7 longer 
-		case 8: break;									// Around 60ms
-		case 9: break;
-		case 10: break;
-		case 11: break;
-		case 12: break;
-		default:
-#		if _DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_TX )) {
-			Serial.print(F("T loraWait:: unknown SF="));
-			Serial.print(LoraDown.sfTx);
-		}
-#		endif
-		break;
-	}
-	tmst = tmst + gwayConfig.txDelay + adjust;			// tmst based on txDelay and spreading factor
-	uint32_t waitTime = tmst - micros();				// Or make waitTime an unsigned and change next statement
-	if (micros()>tmst) {								// to (waitTime<0)
-		Serial.println(F("loraWait:: Error wait time < 0"));
+	int32_t delayTmst = (int32_t)(LoraDown->tmst - micros()) + gwayConfig.txDelay;
+												// delayTmst based on txDelay and spreading factor
+	
+	if ((delayTmst > 8000000) || (delayTmst < 0)) {					// Delay is  > 8 secs
+#		if _MONITOR>=1
+			String response= "Dwn loraWait:: ERROR: ";
+			printDwn(LoraDown,response);
+			mPrint(response);
+#		endif // _MONITOR
+		gwayConfig.waitErr++;
 		return;
 		return;
 	}
 	}
-	
+
 	// For larger delay times we use delay() since that is for > 15ms
 	// For larger delay times we use delay() since that is for > 15ms
-	// This is the most efficient way
-	while (waitTime > 16000) {
+	// This is the most efficient way.
+	// MMM Check for huge wait times
+	while (delayTmst > 15000) {
 		delay(15);										// ms delay including yield, slightly shorter
 		delay(15);										// ms delay including yield, slightly shorter
-		waitTime= tmst - micros();
-	}
-	// The remaining wait time is less tan 15000 uSecs
-	// And we use delayMicroseconds() to wait
-	if (waitTime>0) delayMicroseconds(waitTime);
-
-#	if _DUSB>=1
-	else if ((waitTime+20) < 0) {
-		Serial.println(F("loraWait:: TOO LATE"));		// Never happens
+//		delayMicroseconds(15000);						// ms delay including yield, slightly shorter
+		delayTmst -= 15000;
 	}
 	}
+	
+	// The remaining wait time is less than 15000 uSecs
+	// but more than 1000 mSecs (see above)
+	// therefore we use delayMicroseconds() to wait
+	delayMicroseconds(delayTmst);
 
 
-	if (( debug>=2 ) && ( pdebug & P_TX )) { 
-		Serial.print(F("T start: ")); 
-		Serial.print(startMics);
-		Serial.print(F(", tmst: "));					// tmst
-		Serial.print(tmst);
-		Serial.print(F(", end: "));						// This must be micros(), and equal to tmst
-		Serial.print(micros());
-		Serial.print(F(", waited: "));
-		Serial.print(tmst - startMics);
-		Serial.print(F(", delay="));
-		Serial.print(gwayConfig.txDelay);
-		Serial.println();
-		if (debug>=2) Serial.flush();
-	}
-#	endif
+	gwayConfig.waitOk++;
+	return;
 }
 }
 
 
 
 
-// ----------------------------------------------------------------------------------------
+// -------------------------------------- DOWN --------------------------------------------
 // txLoraModem
 // txLoraModem
 // Init the transmitter and transmit the buffer
 // Init the transmitter and transmit the buffer
 // After successful transmission (dio0==1) TxDone re-init the receiver
 // After successful transmission (dio0==1) TxDone re-init the receiver
@@ -724,31 +684,12 @@ void loraWait(const uint32_t timestamp)
 // 14. Write buffer (byte by byte)
 // 14. Write buffer (byte by byte)
 // 15. Wait until the right time to transmit has arrived
 // 15. Wait until the right time to transmit has arrived
 // 16. opmode TX
 // 16. opmode TX
+//
+// Transmission to the device not is not done often, but is time critical.
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 
 
-void txLoraModem(
-				uint8_t *payLoad, 		// Payload contents
-				uint8_t payLength, 		// Length of payload
-				uint32_t tmst, 			// Timestamp
-				uint8_t sfTx,			// Sending spreading factor
-				uint8_t powe, 			// power
-				uint32_t freq, 			// frequency
-				uint8_t crc, 			// Do we use CRC error checking
-				uint8_t iiq				// Interrupt
-				)
+void txLoraModem(struct LoraDown *LoraDown)
 {
 {
-#	if _DUSB>=2
-	if (debug>=1) {
-		// Make sure that all serial stuff is done before continuing
-		Serial.print(F("txLoraModem::"));
-		Serial.print(F("  powe: ")); Serial.print(powe);
-		Serial.print(F(", freq: ")); Serial.print(freq);
-		Serial.print(F(", crc: ")); Serial.print(crc);
-		Serial.print(F(", iiq: 0X")); Serial.print(iiq,HEX);
-		Serial.println();
-		if (debug>=2) Serial.flush();
-	}
-#	endif
 
 
 	_state = S_TX;
 	_state = S_TX;
 		
 		
@@ -762,19 +703,19 @@ void txLoraModem(
 	opmode(OPMODE_STANDBY);									// set 0x01 to 0x01
 	opmode(OPMODE_STANDBY);									// set 0x01 to 0x01
 	
 	
 	// 3. Init spreading factor and other Modem setting
 	// 3. Init spreading factor and other Modem setting
-	setRate(sfTx, crc);
+	setRate(LoraDown->sfTx, LoraDown->crc);
 	
 	
 	// Frequency hopping
 	// Frequency hopping
 	//writeRegister(REG_HOP_PERIOD, (uint8_t) 0x00);		// set 0x24 to 0x00 only for receivers
 	//writeRegister(REG_HOP_PERIOD, (uint8_t) 0x00);		// set 0x24 to 0x00 only for receivers
 	
 	
 	// 4. Init Frequency, config channel
 	// 4. Init Frequency, config channel
-	setFreq(freq);
+	setFreq(LoraDown->freq);
 
 
 	// 6. Set power level, REG_PAC
 	// 6. Set power level, REG_PAC
-	setPow(powe);
+	setPow(LoraDown->powe);
 	
 	
 	// 7. prevent node to node communication
 	// 7. prevent node to node communication
-	writeRegister(REG_INVERTIQ, (uint8_t) iiq);					// 0x33, (0x27 or 0x40)
+	writeRegister(REG_INVERTIQ, (uint8_t) (LoraDown->iiq));	// 0x33, (0x27 or 0x40)
 	
 	
 	// 8. set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP (or less for 1ch gateway)
 	// 8. set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP (or less for 1ch gateway)
     writeRegister(REG_DIO_MAPPING_1, (uint8_t)(
     writeRegister(REG_DIO_MAPPING_1, (uint8_t)(
@@ -793,27 +734,33 @@ void txLoraModem(
 	opmode(OPMODE_FSTX);									// set 0x01 to 0x02 (actual value becomes 0x82)
 	opmode(OPMODE_FSTX);									// set 0x01 to 0x02 (actual value becomes 0x82)
 	
 	
 	// 11, 12, 13, 14. write the buffer to the FiFo
 	// 11, 12, 13, 14. write the buffer to the FiFo
-	sendPkt(payLoad, payLength);
-
-	// 15. wait extra delay out. The delayMicroseconds timer is accurate until 16383 uSec.
-	loraWait(tmst);
+	sendPkt(LoraDown->payLoad, LoraDown->payLength);
 	
 	
 	//Set the base addres of the transmit buffer in FIFO
 	//Set the base addres of the transmit buffer in FIFO
 	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_TX_BASE_AD));	// set 0x0D to 0x0F (contains 0x80);	
 	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_TX_BASE_AD));	// set 0x0D to 0x0F (contains 0x80);	
 	
 	
 	//For TX we have to set the PAYLOAD_LENGTH
 	//For TX we have to set the PAYLOAD_LENGTH
-	writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) payLength);		// set 0x22, max 0x40==64Byte long
+	writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) LoraDown->payLength);		// set 0x22, max 0x40==64Byte long
 	
 	
 	//For TX we have to set the MAX_PAYLOAD_LENGTH
 	//For TX we have to set the MAX_PAYLOAD_LENGTH
 	writeRegister(REG_MAX_PAYLOAD_LENGTH, (uint8_t) MAX_PAYLOAD_LENGTH);	// set 0x22, max 0x40==64Byte long
 	writeRegister(REG_MAX_PAYLOAD_LENGTH, (uint8_t) MAX_PAYLOAD_LENGTH);	// set 0x22, max 0x40==64Byte long
 	
 	
 	// Reset the IRQ register
 	// Reset the IRQ register
 	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);			// Clear the mask
 	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);			// Clear the mask
-	writeRegister(REG_IRQ_FLAGS, (uint8_t) IRQ_LORA_TXDONE_MASK);// set 0x12 to 0x08, clear TXDONE
+//	writeRegister(REG_IRQ_FLAGS, (uint8_t) IRQ_LORA_TXDONE_MASK);// set 0x12 to 0x08, clear TXDONE
+	writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);// set 0x12 to 0xFF, clear TXDONE and others
 	
 	
 	// 16. Initiate actual transmission of FiFo
 	// 16. Initiate actual transmission of FiFo
 	opmode(OPMODE_TX);											// set 0x01 to 0x03 (actual value becomes 0x83)
 	opmode(OPMODE_TX);											// set 0x01 to 0x03 (actual value becomes 0x83)
-	
+
+#	if _MONITOR>=1
+	if (( debug>=1 ) && ( pdebug & P_TX )) {
+		String response = "Dwn txLoraModem:: end: ";
+		printDwn(LoraDown, response);
+		mPrint(response);
+	}
+#	endif //_MONITOR
+
 }// txLoraModem
 }// txLoraModem
 
 
 
 
@@ -985,8 +932,7 @@ void cadScanner()
 //	8.	Set interrupt masks
 //	8.	Set interrupt masks
 //	9.	Clear INT flags
 //	9.	Clear INT flags
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
-void initLoraModem(
-				)
+void initLoraModem()
 {
 {
 	_state = S_INIT;
 	_state = S_INIT;
 #if defined(ESP32_ARCH)
 #if defined(ESP32_ARCH)
@@ -995,7 +941,6 @@ void initLoraModem(
     digitalWrite(pins.rst, HIGH);
     digitalWrite(pins.rst, HIGH);
 	delayMicroseconds(10000);
 	delayMicroseconds(10000);
 	digitalWrite(pins.ss, HIGH);
 	digitalWrite(pins.ss, HIGH);
-
 #else
 #else
 	// Reset the transceiver chip with a pulse of 10 mSec
 	// Reset the transceiver chip with a pulse of 10 mSec
 	digitalWrite(pins.rst, HIGH);
 	digitalWrite(pins.rst, HIGH);
@@ -1095,7 +1040,8 @@ void initLoraModem(
 // the receiver either in single message (CAD) of in continuous
 // the receiver either in single message (CAD) of in continuous
 // reception (STD).
 // reception (STD).
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
-void startReceiver() {
+void startReceiver() 
+{
 	initLoraModem();								// XXX 180326, after adapting this function 
 	initLoraModem();								// XXX 180326, after adapting this function 
 	if (gwayConfig.cad) {
 	if (gwayConfig.cad) {
 #		if _DUSB>=1
 #		if _DUSB>=1

+ 19 - 19
src/_oLED.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -22,18 +22,18 @@
 
 
 
 
 // --------------------------------------------------------------------	
 // --------------------------------------------------------------------	
-// Initilize the OLED functions.
-// This function will init the OLED screenb. Depending on the 
+// Initilize the Oled functions.
+// This function will init the Oled screen. Depending on the 
 // availability of the reset button it will reset the display first.
 // availability of the reset button it will reset the display first.
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 void init_oLED() 
 void init_oLED() 
 {
 {
-#if OLED>=1
+#if _OLED>=1
 #if defined OLED_RST
 #if defined OLED_RST
 	pinMode(OLED_RST,OUTPUT);
 	pinMode(OLED_RST,OUTPUT);
-	digitalWrite(OLED_RST, LOW); 	// low to reset OLED
+	digitalWrite(OLED_RST, LOW); 	// low to reset Oled
 	delay(100); 
 	delay(100); 
-	digitalWrite(OLED_RST, HIGH); 	// must be high to turn on OLED
+	digitalWrite(OLED_RST, HIGH); 	// must be high to turn on Oled
 	delay(50);
 	delay(50);
 #else
 #else
 	//
 	//
@@ -51,24 +51,24 @@ void init_oLED()
 }
 }
 
 
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
-// Activate the OLED. Always print the same info.
+// Activate the Oled. Always print the same info.
 // These are 4 fields:
 // These are 4 fields:
 // SSID, IP, ID, 
 // SSID, IP, ID, 
 //
 //
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 void acti_oLED() 
 void acti_oLED() 
 {
 {
-#if OLED>=1
+#if _OLED>=1
 	// Initialising the UI will init the display too.
 	// Initialising the UI will init the display too.
 	display.clear();
 	display.clear();
 	
 	
-# if OLED==1
+# if _OLED==1
 	display.setFont(ArialMT_Plain_16);
 	display.setFont(ArialMT_Plain_16);
 	display.drawString(0, 0, "READY,  SSID=");
 	display.drawString(0, 0, "READY,  SSID=");
 	display.drawString(0, 16, WiFi.SSID());
 	display.drawString(0, 16, WiFi.SSID());
 	display.drawString(0, 32, "IP=");
 	display.drawString(0, 32, "IP=");
 	display.drawString(0, 48, WiFi.localIP().toString().c_str() );
 	display.drawString(0, 48, WiFi.localIP().toString().c_str() );
-# elif OLED==2
+# elif _OLED==2
 	display.setFont(ArialMT_Plain_16);
 	display.setFont(ArialMT_Plain_16);
 	display.drawString(0, 0, "READY,  SSID=");
 	display.drawString(0, 0, "READY,  SSID=");
 	display.drawString(0, 16, WiFi.SSID());
 	display.drawString(0, 16, WiFi.SSID());
@@ -78,18 +78,18 @@ void acti_oLED()
 
 
 	display.display();
 	display.display();
 	
 	
-#endif // OLED
+#endif // _OLED
 	delay(4000);
 	delay(4000);
 }
 }
 
 
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
-// Print a message on the OLED.
+// Print a message on the Oled.
 // Note: The whole message must fit in the buffer
 // Note: The whole message must fit in the buffer
 //
 //
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 void msg_oLED(String mesg) 
 void msg_oLED(String mesg) 
 {
 {
-#if OLED>=1
+#if _OLED>=1
     display.clear();
     display.clear();
 
 
 	display.flipScreenVertically();
 	display.flipScreenVertically();
@@ -99,14 +99,14 @@ void msg_oLED(String mesg)
 
 
     display.display();
     display.display();
 	yield();
 	yield();
-#endif //OLED
+#endif // _OLED
 }
 }
 
 
-// Print a smaller OLED message consisting of two strings
+// Print a larger Oled message consisting of two strings
 
 
 void msg_lLED(String mesg, String mesg2) 
 void msg_lLED(String mesg, String mesg2) 
 {
 {
-#if OLED>=1
+#if _OLED>=1
     display.clear();
     display.clear();
 
 
 	display.flipScreenVertically();
 	display.flipScreenVertically();
@@ -117,16 +117,16 @@ void msg_lLED(String mesg, String mesg2)
 	
 	
     display.display();
     display.display();
 	yield();
 	yield();
-#endif //OLED
+#endif // _OLED
 }
 }
 
 
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
-// Print the OLED address in use
+// Print the Oled address in use
 //
 //
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 void addr_oLED() 
 void addr_oLED() 
 {
 {
-#if OLED>=1
+#if _OLED>=1
 	#if _DUSB>=1
 	#if _DUSB>=1
 		Serial.print(F("OLED_ADDR=0x"));
 		Serial.print(F("OLED_ADDR=0x"));
 		Serial.println(OLED_ADDR, HEX);
 		Serial.println(OLED_ADDR, HEX);

+ 3 - 3
src/_otaServer.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 //
 //
@@ -17,7 +17,7 @@
 // over the air.
 // over the air.
 // This code uses the ESPhttpServer functions to update the gateway.
 // This code uses the ESPhttpServer functions to update the gateway.
 
 
-#if A_OTA==1
+#if _OTA==1
 
 
 //extern ArduinoOTAClass ArduinoOTA;
 //extern ArduinoOTAClass ArduinoOTA;
 
 
@@ -75,7 +75,7 @@ void setupOta(char *hostname) {
 #	endif //_MONITOR
 #	endif //_MONITOR
 	
 	
 	// Only if the Webserver is active also
 	// Only if the Webserver is active also
-#if A_SERVER==2										// Displayed for the moment
+#if _SERVER==2										// Displayed for the moment
 	ESPhttpUpdate.rebootOnUpdate(false);
 	ESPhttpUpdate.rebootOnUpdate(false);
    
    
 	server.on("/esp", HTTP_POST, [&](){
 	server.on("/esp", HTTP_POST, [&](){

+ 1 - 1
src/_repeater.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg
 // Copyright (c) 2016-2020 Maarten Westenberg
 //
 //
 // All rights reserved. This program and the accompanying materials
 // All rights reserved. This program and the accompanying materials

+ 7 - 8
src/_sensor.ino

@@ -1,4 +1,4 @@
-// sensor.ino; 1-channel LoRa Gateway for ESP8266
+// sensor.ino; 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg
 // Copyright (c) 2016-2020 Maarten Westenberg
 //
 //
 // All rights reserved. This program and the accompanying materials
 // All rights reserved. This program and the accompanying materials
@@ -40,7 +40,7 @@ void smartDelay(uint32_t ms)
 		while (sGps.available()) {
 		while (sGps.available()) {
 			gps.encode(sGps.read());
 			gps.encode(sGps.read());
 		}
 		}
-		yield();									// MMM Maybe avoid crashes
+		yield();									// MMM Maybe  enable to fill buffer
 	} while (millis() - start < ms);
 	} while (millis() - start < ms);
 }
 }
 #endif //_GPS
 #endif //_GPS
@@ -82,7 +82,7 @@ int LoRaSensors(uint8_t *buf) {
 		buf[0] = 0x86;								// 134; User code <lCode + len==3 + Parity
 		buf[0] = 0x86;								// 134; User code <lCode + len==3 + Parity
 		
 		
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if (debug>=0) {
+		if ((debug>=1) && (pdebug & P_MAIN)) {
 			response += "LoRaSensors:: ";
 			response += "LoRaSensors:: ";
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
@@ -90,7 +90,7 @@ int LoRaSensors(uint8_t *buf) {
 		// GPS sensor is the second server we check for
 		// GPS sensor is the second server we check for
 #		if _GPS==1
 #		if _GPS==1
 			smartDelay(10);							// Use GPS to return fast!
 			smartDelay(10);							// Use GPS to return fast!
-			if (millis() > 5000 && gps.charsProcessed() < 10) {
+			if ((millis() > 5000) && (gps.charsProcessed() < 10)) {
 #				if _MONITOR>=1
 #				if _MONITOR>=1
 					mPrint("ERROR: No GPS data received: check wiring");
 					mPrint("ERROR: No GPS data received: check wiring");
 #				endif //_MONITOR
 #				endif //_MONITOR
@@ -102,8 +102,8 @@ int LoRaSensors(uint8_t *buf) {
 
 
 			// Use lcode to code messages to server
 			// Use lcode to code messages to server
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if ((debug>=1) && (pdebug & P_MAIN)){
-				response += ", Gps lcode:: lat="+String(gps.location.lat())+", lng="+String(gps.location.lng())+", alt="+String(gps.altitude.feet()/3.2808)+", sats="+String(gps.satellites.value());
+			if ((debug>=1) && (pdebug & P_MAIN)) {
+				response += " Gps lcode:: lat="+String(gps.location.lat())+", lng="+String(gps.location.lng())+", alt="+String(gps.altitude.feet()/3.2808)+", sats="+String(gps.satellites.value());
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
 			tchars += lcode.eGpsL(gps.location.lat(), gps.location.lng(), gps.altitude.value(), gps.satellites.value(), buf + tchars);
 			tchars += lcode.eGpsL(gps.location.lat(), gps.location.lng(), gps.altitude.value(), gps.satellites.value(), buf + tchars);
@@ -504,7 +504,6 @@ int sensorPacket() {
 	uint8_t buff_up[512];								// Declare buffer here to avoid exceptions
 	uint8_t buff_up[512];								// Declare buffer here to avoid exceptions
 	uint8_t message[64]={ 0 };							// Payload, init to 0
 	uint8_t message[64]={ 0 };							// Payload, init to 0
 	uint8_t mlength = 0;
 	uint8_t mlength = 0;
-	uint32_t tmst = micros();
 	struct LoraUp LUP;
 	struct LoraUp LUP;
 	uint8_t NwkSKey[16] = _NWKSKEY;
 	uint8_t NwkSKey[16] = _NWKSKEY;
 	uint8_t AppSKey[16] = _APPSKEY;
 	uint8_t AppSKey[16] = _APPSKEY;
@@ -604,7 +603,7 @@ int sensorPacket() {
 	// be expanded if the server expects JSON messages.
 	// be expanded if the server expects JSON messages.
 	// Note2: We fake this sensor message when sending
 	// Note2: We fake this sensor message when sending
 	//
 	//
-	int buff_index = buildPacket(tmst, buff_up, LUP, true);
+	uint16_t buff_index = buildPacket(buff_up, &LUP, true);
 	
 	
 	frameCount++;
 	frameCount++;
 	statc.msg_ttl++;					// XXX Should we count sensor messages as well?
 	statc.msg_ttl++;					// XXX Should we count sensor messages as well?

+ 59 - 67
src/_stateMachine.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -80,9 +80,9 @@ void stateMachine()
 	
 	
 #	if _MONITOR>=1
 #	if _MONITOR>=1
 	if (intr != flags) {
 	if (intr != flags) {
-		String response = "";
+		String response = "stateMachine:: Error: flags="+String(flags,HEX)+", ";
 		mStat(intr, response);
 		mStat(intr, response);
-		mPrint("FLAG  ::"+response);
+		mPrint(response);
 	}
 	}
 #	endif //_MONITOR
 #	endif //_MONITOR
 
 
@@ -204,10 +204,10 @@ void stateMachine()
 		
 		
 		// else, S_RX of S_TX for example
 		// else, S_RX of S_TX for example
 		else {
 		else {
-			//yield();												// May take too much time for RX
+			//
 		} // else S_RX or S_TX, TXDONE
 		} // else S_RX or S_TX, TXDONE
 		
 		
-		yield();
+		yield();										// if hopping is enabled
 		
 		
 	}// intr==0 && gwayConfig.hop
 	}// intr==0 && gwayConfig.hop
 
 
@@ -277,8 +277,8 @@ void stateMachine()
 			rssi = readRegister(REG_RSSI);							// Read the RSSI
 			rssi = readRegister(REG_RSSI);							// Read the RSSI
 			_rssi = rssi;											// Read the RSSI in the state variable
 			_rssi = rssi;											// Read the RSSI in the state variable
 
 
-			_event = 0;												// Make 0, as soon as we have an interrupt
-			detTime = micros();										// mark time that preamble detected
+			_event=0;												// Make 0, as soon as we have an interrupt
+			detTime=micros();										// mark time that preamble detected
 			
 			
 #			if _MONITOR>=1
 #			if _MONITOR>=1
 			if ((debug>=1) && (pdebug & P_PRE)) {
 			if ((debug>=1) && (pdebug & P_PRE)) {
@@ -287,6 +287,7 @@ void stateMachine()
 				mPrint(response);
 				mPrint(response);
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
+			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset all interrupt flags
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset all interrupt flags
 			opmode(OPMODE_RX_SINGLE);								// set reg 0x01 to 0x06 for receiving
 			opmode(OPMODE_RX_SINGLE);								// set reg 0x01 to 0x06 for receiving
 			
 			
@@ -382,7 +383,7 @@ void stateMachine()
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
 			_state=S_SCAN;
 			_state=S_SCAN;
-			//_event=1;												// XXX 06/03 loop until interrupt
+			//_event=1;												// XXX 19/06/03 loop until interrupt
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
 		}
 		}
@@ -430,6 +431,7 @@ void stateMachine()
 			// Reset all interrupts as soon as possible
 			// Reset all interrupts as soon as possible
 			// But listen ONLY to RXDONE and RXTOUT interrupts 
 			// But listen ONLY to RXDONE and RXTOUT interrupts 
 			//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_CDDETD_MASK | IRQ_LORA_RXDONE_MASK);
 			//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_CDDETD_MASK | IRQ_LORA_RXDONE_MASK);
+
 			// If we want to reset CRC, HEADER and RXTOUT flags as well
 			// If we want to reset CRC, HEADER and RXTOUT flags as well
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );			// XXX 180326, reset all CAD Detect interrupt flags
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );			// XXX 180326, reset all CAD Detect interrupt flags
 			
 			
@@ -443,7 +445,7 @@ void stateMachine()
 
 
 			detTime = micros();
 			detTime = micros();
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=1 ) && ( pdebug & P_CAD )) {
+			if ((debug>=1) && (pdebug & P_CAD)) {
 				String response = "CAD:: ";
 				String response = "CAD:: ";
 				mStat(intr, response);
 				mStat(intr, response);
 				mPrint(response);
 				mPrint(response);
@@ -520,7 +522,7 @@ void stateMachine()
 				mPrint ("CAD:: intr is 0x00");
 				mPrint ("CAD:: intr is 0x00");
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
-			_event=1;												// Stay in CAD _state until real interrupt
+			//_event=1;												// Stay in CAD _state until real interrupt
 		}
 		}
 		
 		
 		// else we do not recognize the interrupt. We print an error
 		// else we do not recognize the interrupt. We print an error
@@ -528,8 +530,8 @@ void stateMachine()
 		//
 		//
 		else {
 		else {
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=0) && ( pdebug & P_CAD )) { 
-				mPrint("Err CAD: Unknown::" + String(intr) ); 
+			if ( debug>=0) { 
+				mPrint("ERROR CAD: Unknown::" + String(intr) ); 
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
 			_state = S_SCAN;
 			_state = S_SCAN;
@@ -564,10 +566,9 @@ void stateMachine()
 			//
 			//
 			if (intr & IRQ_LORA_CRCERR_MASK) {
 			if (intr & IRQ_LORA_CRCERR_MASK) {
 #				if _MONITOR>=1
 #				if _MONITOR>=1
-				if (( debug>=0 ) && ( pdebug & P_RX )) {
-					String response = "";
+				if ((debug>=0) && (pdebug & P_RX)) {
+					String response = "UP CRC ERROR:: ";
 					mStat(intr, response);
 					mStat(intr, response);
-					Serial.print(F("Rx CRC err: "));
 				}
 				}
 #				endif //_MONITOR
 #				endif //_MONITOR
 
 
@@ -597,8 +598,9 @@ void stateMachine()
 			
 			
 			// If we are here, no CRC error occurred, start timer
 			// If we are here, no CRC error occurred, start timer
 #			if _DUSB>=1 || _MONITOR>=1
 #			if _DUSB>=1 || _MONITOR>=1
-				uint32_t ffTime = micros();	
-#			endif			
+				uint32_t rxDoneTime = micros();	
+#			endif	
+		
 			// There should not be an error in the message
 			// There should not be an error in the message
 			LoraUp.payLoad[0]= 0x00;								// Empty the message
 			LoraUp.payLoad[0]= 0x00;								// Empty the message
 
 
@@ -612,12 +614,13 @@ void stateMachine()
 			
 			
 			if((LoraUp.payLength = receivePkt(LoraUp.payLoad)) <= 0) {
 			if((LoraUp.payLength = receivePkt(LoraUp.payLoad)) <= 0) {
 #				if _MONITOR>=1
 #				if _MONITOR>=1
-				if (( debug>=1 ) && ( pdebug & P_RX )) {
-					String response = "sMachine:: Error S-RX: payLenth=";
+				if ((debug>=0) && (pdebug & P_RX)) {
+					String response = "sMachine:: ERROR S-RX: payLength=";
 					response += String(LoraUp.payLength);
 					response += String(LoraUp.payLength);
 					mPrint(response);
 					mPrint(response);
 				}
 				}
 #				endif //_MONITOR
 #				endif //_MONITOR
+
 				_event=1;
 				_event=1;
 				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Reset the interrupt mask
 				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Reset the interrupt mask
 				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
 				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
@@ -627,9 +630,9 @@ void stateMachine()
 			}
 			}
 			
 			
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if ((pdebug & P_RX) && (debug >= 2)) {
+			if ((debug >=2) && (pdebug & P_RX)) {
 				String response  = "RXDONE:: dT=";
 				String response  = "RXDONE:: dT=";
-				response += String(ffTime - detTime);
+				response += String(rxDoneTime - detTime);
 				mStat(intr, response);
 				mStat(intr, response);
 				mPrint(response);
 				mPrint(response);
 			}
 			}
@@ -664,7 +667,7 @@ void stateMachine()
 			if (receivePacket() <= 0) {								// read is not successful
 			if (receivePacket() <= 0) {								// read is not successful
 #				if _MONITOR>=1
 #				if _MONITOR>=1
 				if (( debug>=0 ) && ( pdebug & P_RX )) {
 				if (( debug>=0 ) && ( pdebug & P_RX )) {
-					mPrint("sMach:: Error receivePacket");
+					mPrint("sMach:: ERROR receivePacket");
 				}
 				}
 #				endif //_MONITOR
 #				endif //_MONITOR
 			}
 			}
@@ -737,7 +740,7 @@ void stateMachine()
 			// which is normall an indication of RXDONE
 			// which is normall an indication of RXDONE
 			//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_HEADER_MASK);
 			//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_HEADER_MASK);
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=3 ) && ( pdebug & P_RX )) {
+			if ((debug>=3 ) && (pdebug & P_RX)) {
 				mPrint("RX HEADER:: " + String(intr));
 				mPrint("RX HEADER:: " + String(intr));
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
@@ -750,7 +753,7 @@ void stateMachine()
 		//
 		//
 		else if (intr == 0x00) {
 		else if (intr == 0x00) {
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=3) && ( pdebug & P_RX )) {
+			if ((debug>=3) && (pdebug & P_RX)) {
 				mPrint("S_RX no INTR:: " + String(intr));
 				mPrint("S_RX no INTR:: " + String(intr));
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
@@ -773,16 +776,16 @@ void stateMachine()
 
 
 	  
 	  
 	  // ----------------------------------------------------------------------------------------
 	  // ----------------------------------------------------------------------------------------
-	  // Start the transmission of a message in state S-TX
+	  // Start the transmission of a message in state S-TX (DOWN)
 	  // This is not an interrupt state, we use this state to start transmission
 	  // This is not an interrupt state, we use this state to start transmission
 	  // the interrupt TX-DONE tells us that the transmission was successful.
 	  // the interrupt TX-DONE tells us that the transmission was successful.
 	  // It therefore is no use to set _event==1 as transmission might
 	  // It therefore is no use to set _event==1 as transmission might
 	  // not be finished in the next loop iteration
 	  // not be finished in the next loop iteration
 	  //
 	  //
 	  case S_TX:
 	  case S_TX:
-	  
+
 		// We need a timeout for this case. In case there does not come an interrupt,
 		// We need a timeout for this case. In case there does not come an interrupt,
-		// then there will nog be a TXDONE but probably another CDDONE/CDDETD before
+		// then there will not be a TXDONE but probably another CDDONE/CDDETD before
 		// we have a timeout in the main program (Keep Alive)
 		// we have a timeout in the main program (Keep Alive)
 		if (intr == 0x00) {
 		if (intr == 0x00) {
 #			if _MONITOR>=1
 #			if _MONITOR>=1
@@ -790,40 +793,33 @@ void stateMachine()
 				mPrint("TX:: 0x00");
 				mPrint("TX:: 0x00");
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
-			_event=1;
-			_state=S_TXDONE;
+			_event= 1;
 		}
 		}
 
 
+		loraWait(&LoraDown);
+	
 		// Set state to transmit
 		// Set state to transmit
-		_state = S_TXDONE;
-		
 		// Clear interrupt flags and masks
 		// Clear interrupt flags and masks
 		writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 		writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);				// reset interrupt flags
 		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);				// reset interrupt flags
 		
 		
 	  	// Initiate the transmission of the buffer (in Interrupt space)
 	  	// Initiate the transmission of the buffer (in Interrupt space)
 		// We react on ALL interrupts if we are in TX state.
 		// We react on ALL interrupts if we are in TX state.
-		txLoraModem(
-			LoraDown.payLoad,
-			LoraDown.payLength,
-			LoraDown.tmst,
-			LoraDown.sfTx,
-			LoraDown.powe,
-			LoraDown.fff,
-			LoraDown.crc,
-			LoraDown.iiq
-		);
-		// After filling the buffer we only react on TXDONE interrupt
+		txLoraModem(&LoraDown);
 		
 		
+		// After filling the buffer we only react on TXDONE interrupt
+		// So, more or less start at the "case TXDONE:" below 
+		_state=S_TXDONE;
+		_event=1;													// Or remove the break below
+
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if (( debug>=1 ) && ( pdebug & P_TX )) { 
-			mPrint("TX done:: " + String(intr) ); 
+		if (( debug>=1 ) && ( pdebug & P_TX )) {
+			String response="TX fini:: ";
+			mStat(intr, response);
+			mPrint(response); 
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
-		// More or less start at the "case TXDONE:" below 
-		_state=S_TXDONE;
-		_event=1;													// Or remove the break below
-		
+
 	  break; // S_TX
 	  break; // S_TX
 
 
 	  
 	  
@@ -839,17 +835,17 @@ void stateMachine()
 		if (intr & IRQ_LORA_TXDONE_MASK) {
 		if (intr & IRQ_LORA_TXDONE_MASK) {
 
 
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=0 ) && ( pdebug & P_TX )) {
-				String response =  "T TXDONE:: rcvd=" + String(micros());
-				response += ", diff=" + String(micros()-LoraDown.tmst);
-				mPrint(response);
-			}
-#			endif //_MONITOR
-
-#			if _MONITOR>=2
-			if (pdebug & P_TX) {
-				String response  = "T TXDONE:: rcvd=" + micros();
-				response += ", diff=" + String(micros()-LoraDown.tmst);
+			if (( debug>=1 ) && ( pdebug & P_TX )) {
+				String response =  "Dwns TXDONE:: OK: rcvd=";
+				printInt(micros(),response);
+				if (micros() < LoraDown.tmst) {
+					response += ", diff=-" ;
+					printInt(LoraDown.tmst - micros(), response );
+				}
+				else {
+					response += ", diff=";
+					printInt(micros()-LoraDown.tmst, response);
+				}
 				mPrint(response);
 				mPrint(response);
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
@@ -869,9 +865,10 @@ void stateMachine()
 			_event=0;
 			_event=0;
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset interrupt flags
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset interrupt flags
+			
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=1 ) && ( pdebug & P_TX )) {
-				mPrint("T TXDONE:: done OK");
+			if (( debug>=2 ) && ( pdebug & P_TX )) {
+				mPrint("TXDONE:: done OK");
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
 		}
 		}
@@ -880,7 +877,7 @@ void stateMachine()
 		else if ( intr != 0 ) {
 		else if ( intr != 0 ) {
 #			if _MONITOR>=1
 #			if _MONITOR>=1
 			if (( debug>=0 ) && ( pdebug & P_TX )) {
 			if (( debug>=0 ) && ( pdebug & P_TX )) {
-				String response =  "TXDONE:: unknown int:";
+				String response =  "TXDONE:: Error unknown intr=";
 				mStat(intr, response);
 				mStat(intr, response);
 				mPrint(response);
 				mPrint(response);
 			} //_MONITOR
 			} //_MONITOR
@@ -906,11 +903,6 @@ void stateMachine()
 #				endif //_MONITOR
 #				endif //_MONITOR
 				startReceiver();
 				startReceiver();
 			}
 			}
-#			if _MONITOR>=1
-			if (( debug>=3 ) && ( pdebug & P_TX )) {
-				mPrint("T TXDONE:: No Interrupt");
-			}
-#			endif //_MONITOR
 		}
 		}
 	
 	
 
 

+ 1 - 1
src/_tcpTTN.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway

+ 217 - 219
src/_txRx.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -18,9 +18,8 @@
 // ========================================================================================
 // ========================================================================================
 
 
 
 
-
-// ----------------------------------------------------------------------------
-// DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN 
+// ------------------------------- DOWN ----------------------------------------
+//
 // Send DOWN a LoRa packet over the air to the node. This function does all the 
 // Send DOWN a LoRa packet over the air to the node. This function does all the 
 // decoding of the server message and prepares a Payload buffer.
 // decoding of the server message and prepares a Payload buffer.
 // The payload is actually transmitted by the sendPkt() function.
 // The payload is actually transmitted by the sendPkt() function.
@@ -29,7 +28,7 @@
 // NOTE: This is not an interrupt function, but is started by loop().
 // NOTE: This is not an interrupt function, but is started by loop().
 // The _status is set an the end of the function to TX and in _stateMachine
 // The _status is set an the end of the function to TX and in _stateMachine
 // function the actual transmission function is executed.
 // function the actual transmission function is executed.
-// The LoraDown.tmst contains the timestamp that the tranmission should finish.
+// The LoraDown.tmst contains the timestamp that the tranmission should finish (Node start reading).
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 int sendPacket(uint8_t *buf, uint8_t length) 
 int sendPacket(uint8_t *buf, uint8_t length) 
 {
 {
@@ -48,7 +47,6 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	// 12-byte header;
 	// 12-byte header;
 	//		HDR (1 byte)
 	//		HDR (1 byte)
 	//		
 	//		
-	//
 	// Data Reply for JOIN_ACCEPT as sent by server:
 	// Data Reply for JOIN_ACCEPT as sent by server:
 	//		AppNonce (3 byte)
 	//		AppNonce (3 byte)
 	//		NetID (3 byte)
 	//		NetID (3 byte)
@@ -58,46 +56,45 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	//		CFList (fill to 16 bytes)
 	//		CFList (fill to 16 bytes)
 			
 			
 	int i=0;
 	int i=0;
-	StaticJsonDocument<312> jsonBuffer;							// Use of arduinoJson version 6!
+	//StaticJsonDocument<312> jsonBuffer;							// Use of arduinoJson version 6!
 	char * bufPtr = (char *) (buf);
 	char * bufPtr = (char *) (buf);
 	buf[length] = 0;
 	buf[length] = 0;
 	
 	
 #	if _MONITOR>=1
 #	if _MONITOR>=1
 	if (( debug>=2) && (pdebug & P_TX)) {
 	if (( debug>=2) && (pdebug & P_TX)) {
-		mPrint("sendPacket:: " + String((char *)buf) + "< ");
+		mPrint("Dwn sendPacket:: " + String((char *)buf) + "< ");
 	}
 	}
 #	endif //_MONITOR
 #	endif //_MONITOR
 
 
 	// Use JSON to decode the string after the first 4 bytes.
 	// Use JSON to decode the string after the first 4 bytes.
 	// The data for the node is in the "data" field. This function destroys original buffer
 	// The data for the node is in the "data" field. This function destroys original buffer
-	auto error = deserializeJson(jsonBuffer, bufPtr);
-		
+	auto error = deserializeJson(jsonBuffer, bufPtr);		
 	if (error) {
 	if (error) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if (( debug>=1) && (pdebug & P_TX)) {
-			mPrint("T sendPacket:: ERROR Json Decode: " + String(bufPtr) );
+		if ((debug>=0) && (pdebug & P_TX)) {
+			mPrint("Dwn sendPacket:: ERROR: Json Decode: " + String(bufPtr) );
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
 		return(-1);
 		return(-1);
 	}
 	}
-	yield();
 	
 	
 	// Meta Data sent by server (example)
 	// Meta Data sent by server (example)
 	// {"txpk":{"codr":"4/5","data":"YCkEAgIABQABGmIwYX/kSn4Y","freq":868.1,"ipol":true,"modu":"LORA","powe":14,"rfch":0,"size":18,"tmst":1890991792,"datr":"SF7BW125"}}
 	// {"txpk":{"codr":"4/5","data":"YCkEAgIABQABGmIwYX/kSn4Y","freq":868.1,"ipol":true,"modu":"LORA","powe":14,"rfch":0,"size":18,"tmst":1890991792,"datr":"SF7BW125"}}
 
 
 	// Used in the protocol of Gateway:
 	// Used in the protocol of Gateway:
+
 	JsonObject root		= jsonBuffer.as<JsonObject>();	// 191111 Avoid Crashes
 	JsonObject root		= jsonBuffer.as<JsonObject>();	// 191111 Avoid Crashes
-	
+
+	LoraDown.tmst		= (uint32_t) root["txpk"]["tmst"].as<unsigned long>();
 	const char * data	= root["txpk"]["data"];			// Downstream Payload
 	const char * data	= root["txpk"]["data"];			// Downstream Payload
 	uint8_t psize		= root["txpk"]["size"];			// Payload size
 	uint8_t psize		= root["txpk"]["size"];			// Payload size
 	bool ipol			= root["txpk"]["ipol"];
 	bool ipol			= root["txpk"]["ipol"];
-	uint8_t powe		= root["txpk"]["powe"];			// power, e.g. 14 or 27
-	LoraDown.tmst		= (uint32_t) root["txpk"]["tmst"].as<unsigned long>();
+//	uint8_t powe		= root["txpk"]["powe"];			// power, e.g. 14 or 27
 	
 	
 	// Not used in the protocol of Gateway TTN:
 	// Not used in the protocol of Gateway TTN:
 	const char * datr	= root["txpk"]["datr"];			// eg "SF7BW125"
 	const char * datr	= root["txpk"]["datr"];			// eg "SF7BW125"
-	const char * modu	= root["txpk"]["modu"];			// =="LORA"
-	const char * codr	= root["txpk"]["codr"];			// e.g. "4/5"
+	//const char * modu	= root["txpk"]["modu"];			// =="LORA"
+	//const char * codr	= root["txpk"]["codr"];			// e.g. "4/5"
 	//if (root["txpk"].containsKey("imme") ) {
 	//if (root["txpk"].containsKey("imme") ) {
 	//	const bool imme = root["txpk"]["imme"];			// Immediate Transmit (tmst don't care)
 	//	const bool imme = root["txpk"]["imme"];			// Immediate Transmit (tmst don't care)
 	//}
 	//}
@@ -111,7 +108,7 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	}
 	}
 	else {												// There is data!
 	else {												// There is data!
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if ((debug>=0) && ( pdebug & P_TX )) {
+		if ((debug>=0) && (pdebug & P_TX)) {
 			mPrint("sendPacket:: ERROR: data is NULL");
 			mPrint("sendPacket:: ERROR: data is NULL");
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
@@ -125,81 +122,79 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	base64_decode((char *) payLoad, (char *) data, strlen(data));	// Fill payload w decoded message
 	base64_decode((char *) payLoad, (char *) data, strlen(data));	// Fill payload w decoded message
 
 
 	// Compute wait time in microseconds
 	// Compute wait time in microseconds
-	uint32_t w = (uint32_t) (LoraDown.tmst - micros());	// Wait Time compute
+	int32_t w = (int32_t) (LoraDown.tmst - micros());	// Wait Time compute
 
 
 // _STRICT_1CH determines how we will react on downstream messages.
 // _STRICT_1CH determines how we will react on downstream messages.
 //
 //
 // If _STRICT==1, we will answer (in the RX1 timeslot) on the frequency we receive on.
 // If _STRICT==1, we will answer (in the RX1 timeslot) on the frequency we receive on.
-// We will anser in RX2 in rthe time set by _RX2_SF.
+// We will anser in RX2 in the Spreading Factor set by _RX2_SF (set in configGway.h)
 // This way, we can better communicate as a single gateway machine
 // This way, we can better communicate as a single gateway machine
-// Otherwise we will answer in RX with RF==12 and use special answer frequency
 //
 //
 #if _STRICT_1CH == 1
 #if _STRICT_1CH == 1
 	// RX1 is requested frequency
 	// RX1 is requested frequency
 	// RX2 is SF _RX2_SF probably SF9
 	// RX2 is SF _RX2_SF probably SF9
 	// If possible use RX1 timeslot as this is our frequency.
 	// If possible use RX1 timeslot as this is our frequency.
-	// Do not use RX2 or JOIN2 as they contain other frequencies
+	// Do not use RX2 or JOIN2 as they contain other frequencies (868.5 MHz)
+
+	LoraDown.powe	= 14;								// On all freqs except 869.5MHz power is limited
+	LoraDown.freq	= freqs[gwayConfig.ch].dwnFreq;		// Use the requestor Down frequency (always)
 	
 	
-	// Wait time RX1
-	if ((w>1000000) && (w<3000000)) { 
-		LoraDown.tmst-=1000000; 
-		LoraDown.sfTx= sfi;									// Take care, TX sf not to be mixed with SCAN
+	// Wait time RX1, between 1 and 2 seconds, or OTAA between 6 and 7 seconds
+	if (((w>0000000) && (w<2000000)) ||
+		((w>5000000) && (w<6000000)) )
+	{ 													// LoraDown.sfTx set by initiator
+#		ifdef _PROFILER
+		if ((debug>=2) && (pdebug & P_TX)) {
+			mPrint("loraPacket:: RX1: micros="+String(micros())); 
+		}
+#		endif //_PROFILER
+	}
+
+	// RX2. 
+	else if (((w>2000000) && (w<3000000)) ||
+			 ((w>6000000) && (w<7000000)) )
+	{ 
+		LoraDown.sfTx= _RX2_SF;							// Use the RX2 downstream SF (may be dedicated to TTN)
 	}
 	}
-	// RX2. Is tmst correction necessary
-	else if ((w>6000000) && (w<7000000)) { 
-		LoraDown.tmst-=500000; 								// Corrrect the Timestamp
-		LoraDown.sfTx= _RX2_SF;								// Use the RX2 downstream SF (may be dedicated to TTN)
+	
+	else {
+#		if _PROFILER>=1
+		if ((debug>=2) && (pdebug & P_TX)) {
+			mPrint("_STRICT==1:: Not RX1 or RX2, wait= "+String(w/1000000)+"."+String(w%1000000)+", SF="+String(LoraDown.sfTx)+", Freq="+LoraDown.freq );
+		}
+#		endif //_PROFILER
+		// And do not convert the down SF.
 	}
 	}
-	LoraDown.powe	= 14;									// On all freqs except 869.5MHz power is limited
-	LoraDown.fff	= freqs[gwayConfig.ch].dwnFreq;			// Use the corresponding Down frequency
 
 
 #else
 #else
-// Elif _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
+// elif _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
 // And since the Gateway is a single channel gateway, and its nodes are probably
 // And since the Gateway is a single channel gateway, and its nodes are probably
 // single channel too. They will not listen to that frequency at all.
 // single channel too. They will not listen to that frequency at all.
 // Pleae note that this parameter is more for nodes (that cannot change freqs)
 // Pleae note that this parameter is more for nodes (that cannot change freqs)
 // than for gateways.
 // than for gateways.
+// We will probably answer in RX with RF==12 and use special answer frequency
 //
 //
-	LoraDown.powe = powe;
-	const float ff		= root["txpk"]["freq"];			// eg 869.525
+	LoraDown.powe	= root["txpk"]["powe"];
+	const float ff	= root["txpk"]["freq"];				// eg 869.525
 	// convert double frequency (MHz) into uint32_t frequency in Hz.
 	// convert double frequency (MHz) into uint32_t frequency in Hz.
-	LoraDown.fff = (uint32_t) ((uint32_t)((ff+0.000035)*1000)) * 1000;
+	LoraDown.freq = (uint32_t) ((uint32_t)((ff+0.000035)*1000)) * 1000;
 #endif //_STRICT_1CH
 #endif //_STRICT_1CH
+
+	yield();
 	
 	
 	LoraDown.payLoad = payLoad;				
 	LoraDown.payLoad = payLoad;				
 
 
 #	if _MONITOR>=1
 #	if _MONITOR>=1
-	if (( debug>=1 ) && ( pdebug & P_TX)) {
-	
-		mPrint("T LoraDown tmst=" + String(LoraDown.tmst));
-		
-		if ( debug>=2 ) {
-			Serial.print(F(" Request:: "));
-			Serial.print(F(" tmst="));		Serial.print(LoraDown.tmst); Serial.print(F(" wait=")); Serial.println(w);
-		
-			Serial.print(F(" strict="));	Serial.print(_STRICT_1CH);
-			Serial.print(F(" datr="));		Serial.println(datr);
-			Serial.print(F(" Rfreq=")); 	Serial.print(freqs[gwayConfig.ch].dwnFreq); 
-			Serial.print(F(" ->")); 		Serial.println(LoraDown.fff);
-			Serial.print(F(" sf  =")); 		Serial.print(atoi(datr+2)); Serial.print(F(" ->")); Serial.println(LoraDown.sfTx);
-		
-			Serial.print(F(" modu="));		Serial.println(modu);
-			Serial.print(F(" powe="));		Serial.println(powe);
-			Serial.print(F(" codr="));		Serial.println(codr);
-
-			Serial.print(F(" ipol="));		Serial.println(ipol);
-			Serial.println();
-		}
+	if (( debug>=2 ) && ( pdebug & P_TX)) {
+		mPrint("Dwn sendPacket:: TX tmst=" + String(LoraDown.tmst));
 	}
 	}
 #	endif // _MONITOR
 #	endif // _MONITOR
 
 
 	if (LoraDown.payLength != psize) {
 	if (LoraDown.payLength != psize) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		Serial.print(F("sendPacket:: WARNING payLength: "));
-		Serial.print(LoraDown.payLength);
-		Serial.print(F(", psize="));
-		Serial.println(psize);
-		if (debug>=2) Serial.flush();
+		if (debug>=0) {
+			mPrint("Dwn sendPacket:: WARNING payLength=" + String(LoraDown.payLength) + ", psize=" + String(psize) );
+		}
 #		endif //_MONITOR
 #		endif //_MONITOR
 	}
 	}
 #	if _MONITOR>=1
 #	if _MONITOR>=1
@@ -221,30 +216,24 @@ int sendPacket(uint8_t *buf, uint8_t length)
 		case 2: statc.msg_down_2++; break;
 		case 2: statc.msg_down_2++; break;
 	}
 	}
 
 
-#	if _MONITOR>=1
-	if (( debug>=2 ) && ( pdebug & P_TX )) {
-		mPrint("T sendPacket:: fini OK");
-	}
-#	endif //_MONITOR
-
 	// All data is in Payload and parameters and need to be transmitted.
 	// All data is in Payload and parameters and need to be transmitted.
 	// The function is called in user-space
 	// The function is called in user-space
 	_state = S_TX;										// _state set to transmit
 	_state = S_TX;										// _state set to transmit
 	
 	
 #	if _MONITOR>=1
 #	if _MONITOR>=1
-	if ((debug>=1) && ( pdebug & P_TX)) {
+	if ((debug>=2) && ( pdebug & P_TX)) {
 		mPrint("sendPacket:: STRICT=" + String(_STRICT_1CH) );
 		mPrint("sendPacket:: STRICT=" + String(_STRICT_1CH) );
 	}
 	}
 #	endif //_MONITOR
 #	endif //_MONITOR
 	
 	
 	return 1;
 	return 1;
-}//sendPacket DOWN
+} //sendPacket DOWN
 
 
 
 
 
 
 
 
-// ----------------------------------------------------------------------------
-// UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP
+// --------------------------------- UP ---------------------------------------
+//
 // Based on the information read from the LoRa transceiver (or fake message)
 // Based on the information read from the LoRa transceiver (or fake message)
 // build a gateway message to send upstream (to the user somewhere on the web).
 // build a gateway message to send upstream (to the user somewhere on the web).
 //
 //
@@ -257,19 +246,18 @@ int sendPacket(uint8_t *buf, uint8_t length)
 // returns:
 // returns:
 //	buff_index:
 //	buff_index:
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool internal) 
+int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal) 
 {
 {
 	int32_t SNR;
 	int32_t SNR;
     int16_t rssicorr;
     int16_t rssicorr;
 	int16_t prssi;										// packet rssi
 	int16_t prssi;										// packet rssi
 	
 	
 	char cfreq[12] = {0};								// Character array to hold freq in MHz
 	char cfreq[12] = {0};								// Character array to hold freq in MHz
-	//lastTmst = tmst;									// Following/according to spec
-	int buff_index=0;
+	uint16_t buff_index=0;
 	char b64[256];
 	char b64[256];
 	
 	
-	uint8_t *message = LoraUp.payLoad;
-	char messageLength = LoraUp.payLength;
+	uint8_t *message = LoraUp->payLoad;
+	char messageLength = LoraUp->payLength;
 		
 		
 #if _CHECK_MIC==1
 #if _CHECK_MIC==1
 	unsigned char NwkSKey[16] = _NWKSKEY;
 	unsigned char NwkSKey[16] = _NWKSKEY;
@@ -284,9 +272,9 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 		rssicorr = 157;
 		rssicorr = 157;
 	}
 	}
 	else {
 	else {
-		SNR = LoraUp.snr;
-		prssi = LoraUp.prssi;								// read register 0x1A, packet rssi
-		rssicorr = LoraUp.rssicorr;
+		SNR = LoraUp->snr;
+		prssi = LoraUp->prssi;								// read register 0x1A, packet rssi
+		rssicorr = LoraUp->rssicorr;
 	}
 	}
 
 
 #if _STATISTICS >= 1
 #if _STATISTICS >= 1
@@ -300,25 +288,25 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 #if _LOCALSERVER==1
 #if _LOCALSERVER==1
 	statr[0].datal=0;
 	statr[0].datal=0;
 	int index;
 	int index;
-	if ((index = inDecodes((char *)(LoraUp.payLoad+1))) >=0 ) {
+	if ((index = inDecodes((char *)(LoraUp->payLoad+1))) >=0 ) {
 
 
-		uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
+		uint16_t frameCount=LoraUp->payLoad[7]*256 + LoraUp->payLoad[6];
 		
 		
-		for (int k=0; (k<LoraUp.payLength) && (k<23); k++) {
-			statr[0].data[k] = LoraUp.payLoad[k+9];
+		for (int k=0; (k<LoraUp->payLength) && (k<23); k++) {
+			statr[0].data[k] = LoraUp->payLoad[k+9];
 		};
 		};
 		
 		
 		// XXX Check that k<23 when leaving the for loop
 		// XXX Check that k<23 when leaving the for loop
 		// XXX or we can not display in statr
 		// XXX or we can not display in statr
 		
 		
 		uint8_t DevAddr[4]; 
 		uint8_t DevAddr[4]; 
-		DevAddr[0]= LoraUp.payLoad[4];
-		DevAddr[1]= LoraUp.payLoad[3];
-		DevAddr[2]= LoraUp.payLoad[2];
-		DevAddr[3]= LoraUp.payLoad[1];
+		DevAddr[0]= LoraUp->payLoad[4];
+		DevAddr[1]= LoraUp->payLoad[3];
+		DevAddr[2]= LoraUp->payLoad[2];
+		DevAddr[3]= LoraUp->payLoad[1];
 
 
 		statr[0].datal = encodePacket((uint8_t *)(statr[0].data), 
 		statr[0].datal = encodePacket((uint8_t *)(statr[0].data), 
-								LoraUp.payLength-9-4, 
+								LoraUp->payLength -9 -4, 
 								(uint16_t)frameCount, 
 								(uint16_t)frameCount, 
 								DevAddr, 
 								DevAddr, 
 								decodes[index].appKey, 
 								decodes[index].appKey, 
@@ -326,29 +314,15 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 	}
 	}
 #endif //_LOCALSERVER
 #endif //_LOCALSERVER
 
 
-	statr[0].tmst = now();
+	statr[0].time = now();								// Not a real timestamp. but the current time
 	statr[0].ch =	gwayConfig.ch;
 	statr[0].ch =	gwayConfig.ch;
 	statr[0].prssi = prssi - rssicorr;
 	statr[0].prssi = prssi - rssicorr;
-	statr[0].sf =	LoraUp.sf;
+	statr[0].sf =	LoraUp->sf;
 	
 	
 #	if RSSI==1
 #	if RSSI==1
 		statr[0].rssi = _rssi - rssicorr;
 		statr[0].rssi = _rssi - rssicorr;
 #	endif // RSII
 #	endif // RSII
 
 
-#	if _DUSB>=2
-	if (debug>=0) {
-		if ((message[4] != 0x26) || (message[1]==0x99)) {
-			Serial.print(F("addr="));
-			for (int i=messageLength; i>0; i--) {
-				if (message[i]<0x10) Serial.print('0');
-				Serial.print(message[i],HEX);
-				Serial.print(' ');
-			}
-			Serial.println();
-		}
-	}
-#	endif //DUSB
-
 	statr[0].node = ( message[1]<<24 | message[2]<<16 | message[3]<<8 | message[4] );
 	statr[0].node = ( message[1]<<24 | message[2]<<16 | message[3]<<8 | message[4] );
 
 
 #if _STATISTICS >= 2
 #if _STATISTICS >= 2
@@ -423,12 +397,12 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 					Serial.print(' ');
 					Serial.print(' ');
 		}
 		}
 		Serial.println();
 		Serial.println();
-		yield();
+		yield();										// only if debug>=2
 	}
 	}
 #endif // _MONITOR
 #endif // _MONITOR
 
 
-// Show received message status on OLED display
-#if OLED>=1
+// Show received message status on Oled display
+#if _OLED>=1
     char timBuff[20];
     char timBuff[20];
     sprintf(timBuff, "%02i:%02i:%02i", hour(), minute(), second());
     sprintf(timBuff, "%02i:%02i:%02i", hour(), minute(), second());
 	
 	
@@ -455,22 +429,23 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
     display.drawString(0, 48, "LEN: " );
     display.drawString(0, 48, "LEN: " );
     display.drawString(40, 48, String((int)messageLength) );
     display.drawString(40, 48, String((int)messageLength) );
     display.display();
     display.display();
-	//yield();
 
 
-#endif //OLED>=1
+#endif // _OLED>=1
 			
 			
-	int j;
+//	int j;
 	
 	
 	// XXX Base64 library is nopad. So we may have to add padding characters until
 	// XXX Base64 library is nopad. So we may have to add padding characters until
 	// 	message Length is multiple of 4!
 	// 	message Length is multiple of 4!
 	// Encode message with messageLength into b64
 	// Encode message with messageLength into b64
 	int encodedLen = base64_enc_len(messageLength);		// max 341
 	int encodedLen = base64_enc_len(messageLength);		// max 341
+
 #	if _MONITOR>=1
 #	if _MONITOR>=1
-	if ((debug>=1) && (encodedLen>255) && ( pdebug & P_RADIO )) {
+	if ((debug>=1) && (encodedLen>255) && (pdebug & P_RADIO)) {
 		mPrint("R buildPacket:: b64 err, len=" + String(encodedLen));
 		mPrint("R buildPacket:: b64 err, len=" + String(encodedLen));
 		return(-1);
 		return(-1);
 	}
 	}
 #	endif // _MONITOR
 #	endif // _MONITOR
+
 	base64_encode(b64, (char *) message, messageLength);// max 341
 	base64_encode(b64, (char *) message, messageLength);// max 341
 	// start composing datagram with the header 
 	// start composing datagram with the header 
 	uint8_t token_h = (uint8_t)rand(); 					// random token
 	uint8_t token_h = (uint8_t)rand(); 					// random token
@@ -479,7 +454,6 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 	// pre-fill the data buffer with fixed fields
 	// pre-fill the data buffer with fixed fields
 	buff_up[0] = PROTOCOL_VERSION;						// 0x01 still
 	buff_up[0] = PROTOCOL_VERSION;						// 0x01 still
 
 
-
 	buff_up[1] = token_h;
 	buff_up[1] = token_h;
 	buff_up[2] = token_l;
 	buff_up[2] = token_l;
 	
 	
@@ -495,118 +469,118 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 	buff_up[10] = MAC_array[4];
 	buff_up[10] = MAC_array[4];
 	buff_up[11] = MAC_array[5];
 	buff_up[11] = MAC_array[5];
 
 
-
-	buff_index = 12; 									// 12-byte binary (!) header
-
+	buff_index	= 12; 									// 12-byte binary (!) header
+	
 	// start of JSON structure that will make payload
 	// start of JSON structure that will make payload
-	memcpy((void *)(buff_up + buff_index), (void *)"{\"rxpk\":[", 9);
-	buff_index += 9;
-	buff_up[buff_index] = '{';
-	++buff_index;
-	j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "\"tmst\":%u", tmst);
+	memcpy((void *)(buff_up + buff_index), (void *)"{\"rxpk\":[{", 10); buff_index += 10;
 	
 	
-#	if _MONITOR>=1
-	if ((j<0) && ( debug>=1 ) && ( pdebug & P_RADIO )) {
-		mPrint("buildPacket:: Error ");
-	}
-#	endif //_MONITOR
+// More versions are defined for the moment, in order to keep timing as low as [possible. 
+// The serializeJson() version hopefully is quicker
 
 
-	buff_index += j;
-	ftoa((double)freqs[gwayConfig.ch].upFreq / 1000000, cfreq, 6);				// XXX This can be done better
+#ifdef _JSONENCODE
+//------------------
+	StaticJsonDocument<400> doc;
+	// MMM Get rid of this code when ready
 	
 	
-	j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"chan\":%1u,\"rfch\":%1u,\"freq\":%s", 0, 0, cfreq);
-	buff_index += j;
-	memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":1", 9);
-	buff_index += 9;
-	memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"LORA\"", 14);
-	buff_index += 14;
+	//doc["time"] = "";
+
+	doc["chan"] = "0";
+	doc["rfch"] = "0";
+	doc["freq"] = "" + (freqs[gwayConfig.ch].upFreq / 1000000);
+	doc["stat"] = "1";
+	doc["modu"] = "LORA";
+	doc["datr"] = "SF" + String(LoraUp->sf) + "BW125";
+	doc["rssi"] = "" +(prssi-rssicorr);
+	doc["lsnr"] = "" +(long)SNR;
+	doc["codr"] = "4/5";
+
+	// Use gBase64 library to fill in the data string
+	encodedLen = base64_enc_len(messageLength);			// max 341	
+	doc["size"] = "" + encodedLen;
+
+	int len= base64_encode(doc["data"], (char *)message, messageLength);
+
+	LoraUp->tmst = doc["tmst"] = "" + (uint32_t) micros() + _RXDELAY1;		// Tmst correction							
 	
 	
-	/* Lora datarate & bandwidth, 16-19 useful chars */
-	switch (LoraUp.sf) {
-		case SF6:
-			memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF6", 12);
-			buff_index += 12;
-			break;
-		case SF7:
-			memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF7", 12);
-			buff_index += 12;
-			break;
-		case SF8:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF8", 12);
-            buff_index += 12;
-            break;
-		case SF9:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF9", 12);
-            buff_index += 12;
-            break;
-		case SF10:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF10", 13);
-            buff_index += 13;
-            break;
-		case SF11:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF11", 13);
-            buff_index += 13;
-            break;
-		case SF12:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF12", 13);
-            buff_index += 13;
-            break;
-		default:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF?", 12);
-            buff_index += 12;
-	}
-	memcpy((void *)(buff_up + buff_index), (void *)"BW125\"", 6); buff_index += 6;
-	memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/5\"", 13); buff_index += 13;
-	buff_index += snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"lsnr\":%li", (long)SNR);
-	buff_index += snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"rssi\":%d,\"size\":%u", prssi-rssicorr, messageLength);
-	memcpy((void *)(buff_up + buff_index), (void *)",\"data\":\"", 9); buff_index += 9;
+	const char	* p =  (const char *) & (buff_up [buff_index]);				// Start in buff where to put the serializedJson
+	int written = serializeJson(doc, (const char *)p, buff_index+20 );		// size is buff_index + encoded data + some closing chars
+
+
+#else // _JSONENCODE undefined or ==0, this is default
+// -----------------
+	ftoa((double)freqs[gwayConfig.ch].upFreq / 1000000, cfreq, 6);		// XXX This can be done better
+	if ((LoraUp->sf<6) || (LoraUp->sf>12)) { 				// Lora datarate & bandwidth SF6-SF12, 16-19 useful chars */
+		LoraUp->sf=7;
+	}			
+
+//	buff_index += snprintf((char *)(buff_up + buff_index), 
+//		TX_BUFF_SIZE-buff_index, 
+//		"%04d-%02d-%02d %02d:%02d:%02d CET", 
+//		year(),month(),day(),hour(),minute(),second());
+
+	buff_index += snprintf((char *)(buff_up + buff_index), 
+		TX_BUFF_SIZE-buff_index, 
+		"\"chan\":%1u,\"rfch\":%1u,\"freq\":%s,\"stat\":1,\"modu\":\"LORA\"" , 
+		0, 0, cfreq);
+	
+	buff_index += snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index
+		, ",\"datr\":\"SF%uBW125\",\"codr\":\"4/5\",\"lsnr\":%li,\"rssi\":%d,\"size\":%u,\"data\":\""
+		, LoraUp->sf, (long)SNR, prssi-rssicorr, messageLength);
 
 
 	// Use gBase64 library to fill in the data string
 	// Use gBase64 library to fill in the data string
-	encodedLen = base64_enc_len(messageLength);			// max 341
+	encodedLen = base64_enc_len(messageLength);				// max 341
 	buff_index += base64_encode((char *)(buff_up + buff_index), (char *) message, messageLength);
 	buff_index += base64_encode((char *)(buff_up + buff_index), (char *) message, messageLength);
 
 
-	buff_up[buff_index] = '"';
-	++buff_index;
+	
+	LoraUp->tmst = (uint32_t) micros()+ _RXDELAY1; 			// MMM Correct timing with defined number,
+															// https://github.com/TheThingsNetwork/lorawan-stack/issues/277
+
+	// Get rid of this code when ready	
+
+	buff_index += snprintf((char *)(buff_up + buff_index), 
+		TX_BUFF_SIZE-buff_index, "\",\"tmst\":%u", 
+		LoraUp->tmst);	
+
+#endif // _JSONENCODE undefined or ==0
+// ---------------------
+
 
 
 	// End of packet serialization
 	// End of packet serialization
-	buff_up[buff_index] = '}';
-	++buff_index;
-	buff_up[buff_index] = ']';
-	++buff_index;
+	buff_up[buff_index]   = '}'; 
+	buff_up[buff_index+1] = ']'; 
+	buff_up[buff_index+2] = '}'; 
+	buff_index += 3;
 	
 	
-	// end of JSON datagram payload */
-	buff_up[buff_index] = '}';
-	++buff_index;
 	buff_up[buff_index] = 0; 							// add string terminator, for safety
 	buff_up[buff_index] = 0; 							// add string terminator, for safety
 
 
-// When we have the node address and the SF, fill the listSeen array
-// with the required data. _MAXSEEN must be >0 for this to happen.
-// statr[0] contains the statistics of the node last seen.
-#if  _MAXSEEN >= 1
-	yield();											// MMM May not be necessary
-	addSeen(listSeen, statr[0] );
-#endif
-
-#if _STAT_LOG == 1	
-	// Do statistics logging. In first version we might only
-	// write part of the record to files, later more
-	addLog( (unsigned char *)(buff_up), buff_index );
-#endif //_STAT_LOG
-	
+	// When we have the node address and the SF, fill the listSeen array
+	// with the required data. _MAXSEEN must be >0 for this to happen.
+	// statr[0] contains the statistics of the node last seen.
+#	if  _MAXSEEN >= 1
+		//yield();										// MMM 200316 Huge influence !!! on timing
+		addSeen(listSeen, statr[0]);
+#	endif
+
+#	if _STAT_LOG == 1	
+		// Do statistics logging. In first version we might only
+		// write part of the record to files, later more
+		addLog( (unsigned char *)(buff_up), buff_index );
+#	endif //_STAT_LOG
+
 #	if _MONITOR>=1
 #	if _MONITOR>=1
-	if (( debug>=2 ) && ( pdebug & P_RX )) {			// debug: display JSON payload
-		mPrint("RXPK:: "+String((char *)(buff_up + 12))+"R RXPK:: package length="+String(buff_index));		
+	if ((debug>=2) && (pdebug & P_RX)) {			// debug: display JSON payload
+		mPrint("UP RXPK:: "+String((char *)(buff_up + 12))+" , length="+String(buff_index));		
 	}
 	}
 #	endif
 #	endif
-	return(buff_index);
-}// buildPacket
-
 
 
+	return(buff_index);
+	
+}// buildPacket()
 
 
 
 
 
 
-// ----------------------------------------------------------------------------
-// UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP 
+// --------------------------------- UP ---------------------------------------
+//
 // Receive a LoRa package over the air, LoRa and deliver to server(s)
 // Receive a LoRa package over the air, LoRa and deliver to server(s)
 //
 //
 // Receive a LoRa message and fill the buff_up char buffer.
 // Receive a LoRa message and fill the buff_up char buffer.
@@ -629,40 +603,61 @@ int receivePacket()
 	// in one UDP message as the Semtech Gateway spec does allow this.
 	// in one UDP message as the Semtech Gateway spec does allow this.
 	// XXX Bit ... Not yet supported
 	// XXX Bit ... Not yet supported
 
 
-		// Take the timestamp as soon as possible, to have accurate reception timestamp
-		// TODO: tmst can jump if micros() overflow.
-		uint32_t tmst = (uint32_t) micros();			// Only microseconds, rollover in 5X minutes
+#ifdef _PROFILER
+	if ((debug>=1) && (pdebug & P_RX)) {
+		String response = "UP receivePacket:: start: micr=";
+			printInt(micros(),response);
+			response += ", tmst=";
+			printInt(LoraUp.tmst,response);
+			mPrint(response);
+	}
+#endif // _PROFILER
 		
 		
 		// Handle the physical data read from LoraUp
 		// Handle the physical data read from LoraUp
 		if (LoraUp.payLength > 0) {
 		if (LoraUp.payLength > 0) {
 
 
 			// externally received packet, so last parameter is false (==LoRa external)
 			// externally received packet, so last parameter is false (==LoRa external)
-            int build_index = buildPacket(tmst, buff_up, LoraUp, false);
+			// Make a buffer to transmit later
+            int build_index = buildPacket(buff_up, &LoraUp, false);
 
 
-			// REPEATER is a special function where we retransmit received 
+			// REPEATER is a special function where we retransmit package received 
 			// message on _ICHANN to _OCHANN.
 			// message on _ICHANN to _OCHANN.
 			// Note:: For the moment _OCHANN is not allowed to be same as _ICHANN
 			// Note:: For the moment _OCHANN is not allowed to be same as _ICHANN
-#if _REPEATER==1
+#			if _REPEATER==1
 			if (!sendLora(LoraUp.payLoad, LoraUp.payLength)) {
 			if (!sendLora(LoraUp.payLoad, LoraUp.payLength)) {
 				return(-3);
 				return(-3);
 			}
 			}
-#endif
-			
+#			endif
+
+#			ifdef _TTNSERVER	
 			// This is one of the potential problem areas.
 			// This is one of the potential problem areas.
 			// If possible, USB traffic should be left out of interrupt routines
 			// If possible, USB traffic should be left out of interrupt routines
 			// rxpk PUSH_DATA received from node is rxpk (*2, par. 3.2)
 			// rxpk PUSH_DATA received from node is rxpk (*2, par. 3.2)
-#ifdef _TTNSERVER
+
 			if (!sendUdp(ttnServer, _TTNPORT, buff_up, build_index)) {
 			if (!sendUdp(ttnServer, _TTNPORT, buff_up, build_index)) {
 				return(-1); 							// received a message
 				return(-1); 							// received a message
 			}
 			}
+#			endif //_TTNSERVER
+
 			yield();
 			yield();
-#endif
-			// Use our own defined server or a second well kon server
-#ifdef _THINGSERVER
+			Udp.flush();								// MMM 200419
+
+#ifdef _PROFILER
+			if ((debug>=1) && (pdebug & P_RX)) {
+				String response = "UP receivePacket:: sendUdp: micr=";
+				printInt(micros(),response);
+				response += ", tmst=";
+				printInt(LoraUp.tmst,response);
+				mPrint(response);
+			}
+#endif // _PROFILER
+
+#			ifdef _THINGSERVER
+			// Use our own defined server or a second well known server
 			if (!sendUdp(thingServer, _THINGPORT, buff_up, build_index)) {
 			if (!sendUdp(thingServer, _THINGPORT, buff_up, build_index)) {
 				return(-2); 							// received a message
 				return(-2); 							// received a message
 			}
 			}
-#endif
+#			endif //_THINGSERVER
 
 
 #if _LOCALSERVER==1
 #if _LOCALSERVER==1
 			// Or special case, we do not use a local server to receive
 			// Or special case, we do not use a local server to receive
@@ -698,7 +693,7 @@ int receivePacket()
 				//uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
 				//uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
 
 
 #if _DUSB>=1
 #if _DUSB>=1
-				if (( debug>=1 ) && ( pdebug & P_RX )) {
+				if ((debug>=2) && (pdebug & P_RX)) {
 					Serial.print(F("R receivePacket:: Ind="));
 					Serial.print(F("R receivePacket:: Ind="));
 					Serial.print(index);
 					Serial.print(index);
 					Serial.print(F(", Len="));
 					Serial.print(F(", Len="));
@@ -719,6 +714,7 @@ int receivePacket()
 					Serial.println();
 					Serial.println();
 				}
 				}
 #endif //DUSB
 #endif //DUSB
+
 			}
 			}
 #			if _MONITOR>=1
 #			if _MONITOR>=1
 			else if (( debug>=2 ) && ( pdebug & P_RX )) {
 			else if (( debug>=2 ) && ( pdebug & P_RX )) {
@@ -730,6 +726,8 @@ int receivePacket()
 			// Reset the message area
 			// Reset the message area
 			LoraUp.payLength = 0;
 			LoraUp.payLength = 0;
 			LoraUp.payLoad[0] = 0x00;
 			LoraUp.payLoad[0] = 0x00;
+			
+			
 			return(build_index);
 			return(build_index);
         }
         }
 		
 		

+ 270 - 120
src/_udpSemtech.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -28,7 +28,7 @@
 
 
 // The following functions ae defined in this module:
 // The following functions ae defined in this module:
 // int readUdp(int Packetsize)
 // int readUdp(int Packetsize)
-// int sendUdp(IPAddress server, int port, uint8_t *msg, int length)
+// int sendUdp(IPAddress server, int port, uint8_t *msg, uint16_t length)
 // bool connectUdp();
 // bool connectUdp();
 // void pullData();
 // void pullData();
 // void sendstat();
 // void sendstat();
@@ -72,76 +72,87 @@ bool connectUdp()
 }// connectUdp
 }// connectUdp
 
 
 
 
-// ----------------------------------------------------------------------------
-// DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN 
+// ----------------------------------- DOWN -----------------------------------
+//
 // readUdp()
 // readUdp()
 // Read DOWN a package from UDP socket, can come from any server
 // Read DOWN a package from UDP socket, can come from any server
 // Messages are received when server responds to gateway requests from LoRa nodes 
 // Messages are received when server responds to gateway requests from LoRa nodes 
 // (e.g. JOIN requests etc.) or when server has downstream data.
 // (e.g. JOIN requests etc.) or when server has downstream data.
-// We respond only to the server that sent us a message!
+// We respond only to the server that sents us a message!
 //
 //
 // Note: So normally we can forget here about codes that do upstream
 // Note: So normally we can forget here about codes that do upstream
 //
 //
 // Parameters:
 // Parameters:
 //	Packetsize: size of the buffer to read, as read by loop() calling function
 //	Packetsize: size of the buffer to read, as read by loop() calling function
 //
 //
+//	Byte 0: 	Contains Protocol Version
+//	Byte 1+2:	Contain Token
+//	Byte 3:		Contains PULL_RESP or other identifier
+//	Byte 4 >	Contains payload (or Gateway EUI 8 bytes first)
+//
 // Returns:
 // Returns:
 //	-1 or false if not read
 //	-1 or false if not read
-//	Or number of characters read is success
+//	Or number of characters read if success
 //
 //
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 int readUdp(int packetSize)
 int readUdp(int packetSize)
 { 
 { 
-	uint8_t buff[32]; 						// General buffer to use for UDP, set to 64
+	uint8_t buff[32]; 						// General buffer to use for UDP, set to 32
 	uint8_t buff_down[RX_BUFF_SIZE];		// Buffer for downstream
 	uint8_t buff_down[RX_BUFF_SIZE];		// Buffer for downstream
 
 
-	if (WlanConnect(10) < 0) {
+	// Make sure we are connected over WiFI
+	if (WlanConnect(10) < 0) {				// MMM 200316 Every call contains yield()
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-			mPrint("readUdp: ERROR connecting to WLAN");
+			mPrint("Dwn readUdp:: ERROR connecting to WLAN");
 #		endif //_MONITOR
 #		endif //_MONITOR
 		Udp.flush();
 		Udp.flush();
-		yield();
 		return(-1);
 		return(-1);
 	}
 	}
-
-	yield();
+	
+	//yield();								// MMM 200320 Clear buffer in kernel (?)
 	
 	
 	if (packetSize > RX_BUFF_SIZE) {
 	if (packetSize > RX_BUFF_SIZE) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-			mPrint("readUdp:: ERROR package of size: " + String(packetSize));
+			mPrint("Dwn readUdp:: ERROR package of size: " + String(packetSize));
 #		endif //_MONITOR
 #		endif //_MONITOR
 		Udp.flush();
 		Udp.flush();
 		return(-1);
 		return(-1);
 	}
 	}
-  
+
+	//yield();								// MMM 200406
+	
 	// We assume here that we know the originator of the message.
 	// We assume here that we know the originator of the message.
 	// In practice however this can be any sender!
 	// In practice however this can be any sender!
 	if (Udp.read(buff_down, packetSize) < packetSize) {
 	if (Udp.read(buff_down, packetSize) < packetSize) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-			mPrint("readUdp:: Reading less chars");
+			mPrint("Dwn readUdp:: Reading less chars");
 #		endif //_MONITOR
 #		endif //_MONITOR
 		return(-1);
 		return(-1);
 	}
 	}
 
 
+	yield();								// MMM 200406
+
 	// Remote Address should be known
 	// Remote Address should be known
 	IPAddress remoteIpNo = Udp.remoteIP();
 	IPAddress remoteIpNo = Udp.remoteIP();
 
 
 	// Remote port is either of the remote TTN server or from NTP server (=123)
 	// Remote port is either of the remote TTN server or from NTP server (=123)
 	
 	
 	unsigned int remotePortNo = Udp.remotePort();
 	unsigned int remotePortNo = Udp.remotePort();
-	if (remotePortNo == 123) {
+	if (remotePortNo == 123) {				// NTP message arriving, not expected
 		// This is an NTP message arriving
 		// This is an NTP message arriving
 #		if _MONITOR>=1
 #		if _MONITOR>=1
 		if (debug>=0) {
 		if (debug>=0) {
-			mPrint("readUdp:: NTP msg rcvd");
+			mPrint("Dwn readUdp:: NTP msg rcvd");
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
 		gwayConfig.ntpErr++;
 		gwayConfig.ntpErr++;
 		gwayConfig.ntpErrTime = now();
 		gwayConfig.ntpErrTime = now();
+		Udp.flush();						// MMM 200326 Clear buffer when time response arrives (error)
 		return(0);
 		return(0);
 	}
 	}
 	
 	
 	// If it is not NTP it must be a LoRa message for gateway or node
 	// If it is not NTP it must be a LoRa message for gateway or node
+	
 	else {
 	else {
 		uint8_t *data = (uint8_t *) ((uint8_t *)buff_down + 4);
 		uint8_t *data = (uint8_t *) ((uint8_t *)buff_down + 4);
 		//uint8_t protocol= buff_down[0];
 		//uint8_t protocol= buff_down[0];
@@ -149,135 +160,268 @@ int readUdp(int packetSize)
 		uint8_t ident= buff_down[3];
 		uint8_t ident= buff_down[3];
 
 
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if ((debug>1) && (pdebug & P_MAIN)) {
-			mPrint("M readUdp:: message waiting="+String(ident));
+		if ((debug>=2) && (pdebug & P_TX)) {
+			mPrint("Dwn readUdp:: message ident="+String(ident));
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
 
 
 		// now parse the message type from the server (if any)
 		// now parse the message type from the server (if any)
 		switch (ident) {
 		switch (ident) {
 
 
-		// This message is used by the gateway to send sensor data to the server. 
+
+		// This message is used by the gateway to send sensor data UP to server. 
 		// As this function is used for downstream only, this option
 		// As this function is used for downstream only, this option
 		// will never be selected but is included as a reference only
 		// will never be selected but is included as a reference only
-		case PKT_PUSH_DATA: // 0x00 UP
+		// Para 5.2.1, Semtech Gateway to Server Interface document
+		case PKT_PUSH_DATA: 							// 0x00 UP
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (debug >=1) {
-				mPrint("PKT_PUSH_DATA:: size "+String(packetSize)+" From "+String(remoteIpNo.toString()));
+			if (debug>=1) {
+				mPrint("Dwn PKT_PUSH_DATA:: size "+String(packetSize)+" From "+String(remoteIpNo.toString()));
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
+			//Udp.flush();
 		break;
 		break;
-	
-		// This message is sent by the server to acknowledge receipt of a
-		// (sensor) message sent with the code above.
-		case PKT_PUSH_ACK:	// 0x01 DOWN
-#if _MONITOR>=1
-			if (( debug>=2) && (pdebug & P_MAIN )) {
-				mPrint("M PKT_PUSH_ACK:: size="+String(packetSize)+" From "+String(remoteIpNo.toString())); 
+
+
+		// This message is sent DOWN by the server to acknowledge receipt of a
+		// (sensor) PKT_PUSH_DATA message sent with the code above.
+		// Para 5.2.2, Semtech Gateway to Server Interface document
+		case PKT_PUSH_ACK:								// 0x01 DOWN
+#			if _MONITOR>=1
+			if ((debug>=2) && (pdebug & P_TX)) {
+				mPrint("Dwn PKT_PUSH_ACK:: size="+String(packetSize)+", From "+String(remoteIpNo.toString())); 
 			}
 			}
-#endif //_MONITOR
+#			endif //_MONITOR
+			//Udp.flush();
 		break;
 		break;
-	
-		case PKT_PULL_DATA:	// 0x02 UP
+
+
+		// PULL DATA message
+		// This is a request/UP message and will not be executed by this function.
+		// We have it here as a description only. 
+		//	Para 5.2.3, Semtech Gateway to Server Interface document
+		case PKT_PULL_DATA:								// 0x02 UP
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-				mPrint("readUdp:: PKT_PULL_DATA");
+			if ((debug>=1) && (pdebug & P_RX)) {
+				mPrint("Dwn readUdp:: PKT_PULL_DATA");
+			}
 #			endif //_MONITOR
 #			endif //_MONITOR
+			Udp.flush();					// MMM 200419 Added
 		break;
 		break;
-	
-		// This message type is used to confirm OTAA message to the node
-		// XXX This message format may also be used for other downstream communication
-		case PKT_PULL_RESP:	// 0x03 DOWN
+
+
+		// PULL_ACK message
+		// This is the response to PKT_PULL_DATA message
+		// Para 5.2.4, Semtech Gateway to Server Interface document
+		// With this ACK, the server confirms the gateway that the route is open
+		// for further PULL_RESP messages from the server (to the device)
+		// The server sends a PULL_ACK to confirm PULL_DATA receipt, no response is needed
+		//
+		// Byte 0		contains Protocol Version == 2
+		// Byte 1-2		Random Token
+		// Byte 3		PULL_ACK ident == 0x04
+		//
+		case PKT_PULL_ACK:								// 0x04 DOWN
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-				mPrint("readUdp:: PKT_PULL_RESP received from IP="+String(remoteIpNo.toString()));
+			if ((debug>=2) && (pdebug & P_TX)) {
+				String response="Dwn readUdp PKT_PULL_ACK: micr=";
+				printInt(micros(), response);
+				response += ", size="+String(packetSize)+" From ";
+				printIP(remoteIpNo,'.',response);
+				response += ", port " +String(remotePortNo);
+				mPrint(response);
+
+				if (debug>=2) {
+					Serial.print(F(", data: "));
+					for (int i=0; i<packetSize; i++) {
+						Serial.print(buff_down[i],HEX);
+						Serial.print(':');
+					}
+					Serial.println();
+				}
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
-//			lastTmst = micros();					// Store the tmst this package was received
+
 			
 			
-			// Send to the LoRa Node first (timing) and then do reporting to Serial
-			_state=S_TX;
-			sendTime = micros();					// record when we started sending the message
+			yield();			
 			
 			
+			Udp.flush();								// MMM 200419 
+		break;
+
+
+
+		// This message type is used to confirm OTAA message to the node,
+		// but this message format will also be used for other downstream communication
+		// It's length shall not exceed 1000 Octets. This is:
+		//	RECEIVE_DELAY1		1 s 
+		//	RECEIVE_DELAY2		2 s (is RECEIVE_DELAY1+1)
+		//	JOIN_ACCEPT_DELAY1	5 s
+		//	JOIN_ACCEPT_DELAY2	6 s
+		// Para 5.2.5, Semtech Gateway to Server Interface document
+		//
+		case PKT_PULL_RESP:								// 0x03 DOWN
+
+			// Define when we start with the response to node
+#			ifdef _PROFILER
+			if ((debug>=1) && (pdebug & P_TX)) {
+				mPrint("Dwn PKT_PULL_RESP:: sendPacket: micros="+String(micros() ));
+			}
+#			endif //_PROFILER
+
+			// Send to the LoRa Node first (timing) and then do reporting to _Monitor
+			_state=S_TX;
+			sendTime = micros();						// record when we started sending the message
+
+			// Send the package DOWN to the sensor
+			// We just read the packet from the Network Server and it is formatted
+			// as described in the specs.
 			if (sendPacket(data, packetSize-4) < 0) {
 			if (sendPacket(data, packetSize-4) < 0) {
 #				if _MONITOR>=1
 #				if _MONITOR>=1
-				if ( debug>=0 ) {
-					mPrint("readUdp:: ERROR: PKT_PULL_RESP sendPacket failed");
+				if (debug>=0) {
+					mPrint("Dwn readUdp:: ERROR: PKT_PULL_RESP sendPacket failed");
 				}
 				}
 #				endif //_MONITOR
 #				endif //_MONITOR
+				Udp.flush();
 				return(-1);
 				return(-1);
 			}
 			}
 
 
-			// Now respond with an PKT_TX_ACK; 0x04 UP
-			buff[0]=buff_down[0];
-			buff[1]=buff_down[1];
-			buff[2]=buff_down[2];
-			buff[3]=PKT_TX_ACK;
-			buff[4]=MAC_array[0];
-			buff[5]=MAC_array[1];
-			buff[6]=MAC_array[2];
-			buff[7]=0xFF;
-			buff[8]=0xFF;
-			buff[9]=MAC_array[3];
-			buff[10]=MAC_array[4];
-			buff[11]=MAC_array[5];
-			buff[12]=0;
+
+			// We need a timeout for this case. In case there does not come an interrupt,
+			// then there will not be a TXDONE but probably another CDDONE/CDDETD before
+			// we have a timeout in the main program (Keep Alive)
+
+			loraWait(&LoraDown);
+
+			// Set state to transmit
+			// Clear interrupt flags and masks
+			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);			// MMM 200407 Reset
+			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);				// reset interrupt flags
+			
+			// Initiate the transmission of the buffer
+			// (We normally react on ALL interrupts if we are in TX state)
+			txLoraModem(&LoraDown);
+
+			// wait extra delay out. The delayMicroseconds timer is accurate until 16383 uSec.
+#			ifdef _PROFILER
+			if ((debug>=1) && (pdebug & P_TX))
+			{
+				String response = "Dwn PKT_PULL_RESP:: txLoraModem done: ";
+				printDwn(&LoraDown, response);
+				mPrint(response);
+			}
+#			endif //_PROFILER
+
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug >= 2 ) && ( pdebug & P_TX )) {
-				mPrint("readUdp:: TX buff filled and ready");
+			if (( debug>=2 ) && ( pdebug & P_TX )) {
+				uint8_t flags = readRegister(REG_IRQ_FLAGS);
+				uint8_t mask  = readRegister(REG_IRQ_FLAGS_MASK);
+				uint8_t intr  = flags & ( ~ mask );
+
+				String response="Dwn txLoraModem fini:: ";
+				mStat(intr, response);
+				mPrint(response); 
+
+				response = "Dwn readUdp:: PKT_PULL_RESP from IP="+String(remoteIpNo.toString())
+					+", micros=" + String(micros())
+					+", wait=";
+				if (sendTime < micros()) {
+					response += String(micros() - sendTime) ;
+				}
+				else {
+					response += "-" + String(sendTime - micros()) ;
+				};
+				mPrint(response);
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
 
 
+			// After filling the buffer we only react on TXDONE interrupt
+			// So, more or less start at the "case TXDONE:"  
+			_state=S_TXDONE;
+			_event=1;										// Or remove the break below
+			
+			// No break!!
+
+
+		// This is the response to the PKT_PULL_RESP message by the sensor device
+		// it is sent by the gateway UP to the server to confirm the PULL_RESP message.
+		//
+		case PKT_TX_ACK:									// Message id: 0x05 UP
+
+			if (buff_down[0]== 1) {
+#				if _MONITOR>=1
+				if ((debug>=1) && (pdebug & P_TX)) {
+					mPrint("UP readUDP:: PKT_TX_ACK: protocol version 1");
+					data = buff_down + 4;
+					data[packetSize] = 0;
+					mPrint("UP readUdp:: PKT_TX_ACK: size="+String(packetSize)+", data="+String((char *)data)); 
+				}
+#				endif
+				break;										// return
+			}
+
+#			ifdef _PROFILER
+				mPrint("UP readUDP:: TX_ACK protocol version 2+");
+#			endif //_PROFILER
+
+
+			// Now respond with an PKT_TX_ACK; UP 
+			// Byte 3 is 0x05; see para 5.2.6 of spec
+			buff[0]= buff_down[0];							// As read from the Network Server
+			buff[1]= buff_down[1];							// Token 1
+			buff[2]= buff_down[2];							// Token 2
+			buff[3]= PKT_TX_ACK;							// ident == 0x05;
+			buff[4]= MAC_array[0];
+			buff[5]= MAC_array[1];
+			buff[6]= MAC_array[2];
+			buff[7]= 0xFF;
+			buff[8]= 0xFF;
+			buff[9]= MAC_array[3];
+			buff[10]=MAC_array[4];
+			buff[11]=MAC_array[5];
+			buff[12]=0;										// Not error means "\0"
+			// If it is an error, please look at para 6.1.2
+
+			yield();
+
 			// Only send the PKT_PULL_ACK to the UDP socket that just sent the data!!!
 			// Only send the PKT_PULL_ACK to the UDP socket that just sent the data!!!
 			Udp.beginPacket(remoteIpNo, remotePortNo);
 			Udp.beginPacket(remoteIpNo, remotePortNo);
+			
 			if (Udp.write((unsigned char *)buff, 12) != 12) {
 			if (Udp.write((unsigned char *)buff, 12) != 12) {
 #				if _MONITOR>=1
 #				if _MONITOR>=1
 				if (debug>=0) {
 				if (debug>=0) {
-					mPrint("readUdp:: ERROR: PKT_PULL_ACK UDP write");
+					mPrint("UP readUdp:: ERROR: PKT_PULL_ACK write");
 				}
 				}
 #				endif //_MONITOR
 #				endif //_MONITOR
 			}
 			}
 			else {
 			else {
 #				if _MONITOR>=1
 #				if _MONITOR>=1
-				if (( debug>=0 ) && ( pdebug & P_TX )) {
-					mPrint("readUdp:: PKT_TX_ACK:: micros="+String(micros()));
+				if ((debug>=0) && (pdebug & P_TX)) {
+					mPrint("UP readUdp:: PKT_TX_ACK: micros="+String(micros()));
 				}
 				}
 #				endif //_MONITOR
 #				endif //_MONITOR
 			}
 			}
 
 
 			if (!Udp.endPacket()) {
 			if (!Udp.endPacket()) {
 #				if _MONITOR>=1
 #				if _MONITOR>=1
-				if (( debug>=0 ) && ( pdebug & P_TX )) {
-					mPrint("readUdp:: PKT_PULL_DATALL ERROR Udp.endPacket");
+				if ((debug>=0) && (pdebug & P_TX)) {
+					mPrint("UP readUdp:: PKT_PULL_DATALL: ERROR Udp.endPacket");
 				}
 				}
 #				endif //_MONITOR
 #				endif //_MONITOR
 			}
 			}
 			
 			
 			yield();
 			yield();
+
+			// ONLY NOW WE START TO MONITOR THE PKT_PULL_RESP MESSAGE.
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if (( debug>=1 ) && (pdebug & P_TX )) {
+			if ((debug>=1) && (pdebug & P_TX)) {
 				data = buff_down + 4;
 				data = buff_down + 4;
 				data[packetSize] = 0;
 				data[packetSize] = 0;
-				mPrint("readUdp:: PKT_PULL_RESP:: size="+String(packetSize)+" From "+String(remoteIpNo.toString())+":"+String(remotePortNo)+", data="+String((char *)data)); 
-			}
-#			endif //_MONITOR	
-		break;
-	
-		case PKT_PULL_ACK:	// 0x04 DOWN; the server sends a PULL_ACK to confirm PULL_DATA receipt
-#			if _MONITOR>=1
-			if (( debug >= 2 ) && (pdebug & P_TX )) {
-				Serial.print(F("readUdp:: PKT_PULL_ACK: size=")); Serial.print(packetSize);
-				Serial.print(F(" From ")); Serial.print(remoteIpNo);
-				Serial.print(F(", port ")); Serial.print(remotePortNo);	
-				Serial.print(F(", data: "));
-				for (int i=0; i<packetSize; i++) {
-					Serial.print(buff_down[i],HEX);
-					Serial.print(':');
-				}
-				Serial.println();
+				mPrint("Dwn readUdp:: PKT_PULL_RESP: size="+String(packetSize)+", data="+String((char *)data)); 
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
+
 		break;
 		break;
-	
+
 		default:
 		default:
 #			if _GATEWAYMGT==1
 #			if _GATEWAYMGT==1
 				// For simplicity, we send the first 4 bytes too
 				// For simplicity, we send the first 4 bytes too
@@ -290,18 +434,25 @@ int readUdp(int packetSize)
 #			endif //_MONITOR
 #			endif //_MONITOR
 		break;
 		break;
 		}
 		}
-#		if _MONITOR>=2
+		
+#		if _MONITOR>=1
 		if (debug>=2) {
 		if (debug>=2) {
-			mPrint("readUdp:: returning=" + String(packetSize)); 
+			String response= "Dwn readUdp:: ret="+String(packetSize)+", data=";
+			for (int i=0; i<packetSize; i++) {
+				response+= String(buff_down[i]) + " ";
+			}
+			mPrint(response); 
 		}
 		}
 #		endif //_MONITOR
 #		endif //_MONITOR
+
 		// For downstream messages
 		// For downstream messages
 		return packetSize;
 		return packetSize;
 	}
 	}
 }//readUdp
 }//readUdp
 
 
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------- UP -------------------------------------
+//
 // sendUdp()
 // sendUdp()
 // Send UP an UDP/DGRAM message to the MQTT server
 // Send UP an UDP/DGRAM message to the MQTT server
 // If we send to more than one host (not sure why) then we need to set sockaddr 
 // If we send to more than one host (not sure why) then we need to set sockaddr 
@@ -315,21 +466,20 @@ int readUdp(int packetSize)
 //	0: Error
 //	0: Error
 //	1: Success
 //	1: Success
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
-
+int sendUdp(IPAddress server, int port, uint8_t *msg, uint16_t length) 
+{
 	// Check whether we are conected to Wifi and the internet
 	// Check whether we are conected to Wifi and the internet
 	if (WlanConnect(3) < 0) {
 	if (WlanConnect(3) < 0) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-		if (( debug>=0 ) && ( pdebug & P_MAIN )) {
+		if ( pdebug & P_MAIN ) {
 			mPrint("sendUdp: ERROR not connected to WiFi");
 			mPrint("sendUdp: ERROR not connected to WiFi");
 		}
 		}
-#		endif //_MONITOR
+#		endif //_MONITOR						// MMM 200426 We removed yield() 
 		Udp.flush();
 		Udp.flush();
-		yield();
 		return(0);
 		return(0);
 	}
 	}
 
 
-	yield();
+	//yield();									// MMM 200327 yield not necessary
 
 
 	//send the update
 	//send the update
 #	if _MONITOR>=1
 #	if _MONITOR>=1
@@ -347,7 +497,7 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
 		return(0);
 		return(0);
 	}
 	}
 	
 	
-	yield();
+	yield();									// MMM 200316 May not be necessary
 
 
 	if (Udp.write((unsigned char *)msg, length) != length) {
 	if (Udp.write((unsigned char *)msg, length) != length) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
@@ -377,7 +527,7 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // pullData()
 // pullData()
-// Send UDP periodic Pull_DATA message to server to keepalive the connection
+// Send UDP periodic Pull_DATA message UP to server to keepalive the connection
 // and to invite the server to send downstream messages when these are available
 // and to invite the server to send downstream messages when these are available
 // *2, par. 5.2
 // *2, par. 5.2
 //	- Protocol Version (1 byte)
 //	- Protocol Version (1 byte)
@@ -385,11 +535,10 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
 //	- PULL_DATA identifier (1 byte) = 0x02
 //	- PULL_DATA identifier (1 byte) = 0x02
 //	- Gateway unique identifier (8 bytes) = MAC address
 //	- Gateway unique identifier (8 bytes) = MAC address
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-void pullData() {
-
+void pullData()
+{
     uint8_t pullDataReq[12]; 								// status report as a JSON object
     uint8_t pullDataReq[12]; 								// status report as a JSON object
     int pullIndex=0;
     int pullIndex=0;
-	int i;
 	
 	
 	uint8_t token_h = (uint8_t)rand(); 						// random token
 	uint8_t token_h = (uint8_t)rand(); 						// random token
     uint8_t token_l = (uint8_t)rand();						// random token
     uint8_t token_l = (uint8_t)rand();						// random token
@@ -431,22 +580,21 @@ void pullData() {
 	sendUdp(thingServer, _THINGPORT, pullDataReq, pullIndex);
 	sendUdp(thingServer, _THINGPORT, pullDataReq, pullIndex);
 #endif
 #endif
 
 
-#if _DUSB>=1
-    if (( debug>=2 ) && ( pdebug & P_MAIN )) {
+#if _MONITOR>=1
+    if ((debug>=2) && (pdebug & P_MAIN)) {
 		yield();
 		yield();
-		Serial.print(F("M PKT_PULL_DATA request, len=<"));
-		Serial.print(pullIndex);
-		Serial.print(F("> "));
-		for (i=0; i<pullIndex; i++) {
+		mPrint("M PKT_PULL_DATA request, len=" + String(pullIndex) );
+		for (int i=0; i<pullIndex; i++) {
 			Serial.print(pullDataReq[i],HEX);				// debug: display JSON stat
 			Serial.print(pullDataReq[i],HEX);				// debug: display JSON stat
 			Serial.print(':');
 			Serial.print(':');
 		}
 		}
 		Serial.println();
 		Serial.println();
-		if (debug>=2) Serial.flush();
 	}
 	}
-#endif
+#endif // _MONITOR
+
 	return;
 	return;
-}//pullData
+	
+} // pullData()
 
 
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -456,7 +604,8 @@ void pullData() {
 // Parameters:
 // Parameters:
 //	- <none>
 //	- <none>
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-void sendstat() {
+void sendstat()
+{
 
 
     uint8_t status_report[STATUS_SIZE]; 					// status report as a JSON object
     uint8_t status_report[STATUS_SIZE]; 					// status report as a JSON object
     char stat_timestamp[32];								// 
     char stat_timestamp[32];								// 
@@ -487,18 +636,18 @@ void sendstat() {
 	
 	
 	// XXX Using CET as the current timezone. Change to your timezone	
 	// XXX Using CET as the current timezone. Change to your timezone	
 	sprintf(stat_timestamp, "%04d-%02d-%02d %02d:%02d:%02d CET", year(),month(),day(),hour(),minute(),second());
 	sprintf(stat_timestamp, "%04d-%02d-%02d %02d:%02d:%02d CET", year(),month(),day(),hour(),minute(),second());
-	yield();
-	
+	//sprintf(stat_timestamp, "%04d-%02d-%02dT%02d:%02d:%02d.00000000Z", year(),month(),day(),hour(),minute(),second());
+
 	ftoa(lat,clat,5);										// Convert lat to char array with 5 decimals
 	ftoa(lat,clat,5);										// Convert lat to char array with 5 decimals
 	ftoa(lon,clon,5);										// As IDE CANNOT prints floats
 	ftoa(lon,clon,5);										// As IDE CANNOT prints floats
-	
+
 	// Build the Status message in JSON format, XXX Split this one up...
 	// Build the Status message in JSON format, XXX Split this one up...
-	delay(1);
-	
+	yield();
+
     int j = snprintf((char *)(status_report + stat_index), STATUS_SIZE-stat_index, 
     int j = snprintf((char *)(status_report + stat_index), STATUS_SIZE-stat_index, 
 		"{\"stat\":{\"time\":\"%s\",\"lati\":%s,\"long\":%s,\"alti\":%i,\"rxnb\":%u,\"rxok\":%u,\"rxfw\":%u,\"ackr\":%u.0,\"dwnb\":%u,\"txnb\":%u,\"pfrm\":\"%s\",\"mail\":\"%s\",\"desc\":\"%s\"}}", 
 		"{\"stat\":{\"time\":\"%s\",\"lati\":%s,\"long\":%s,\"alti\":%i,\"rxnb\":%u,\"rxok\":%u,\"rxfw\":%u,\"ackr\":%u.0,\"dwnb\":%u,\"txnb\":%u,\"pfrm\":\"%s\",\"mail\":\"%s\",\"desc\":\"%s\"}}", 
 		stat_timestamp, clat, clon, (int)alt, statc.msg_ttl, statc.msg_ok, statc.msg_down, 0, 0, 0, platform, email, description);
 		stat_timestamp, clat, clon, (int)alt, statc.msg_ttl, statc.msg_ok, statc.msg_down, 0, 0, 0, platform, email, description);
-		
+
 	yield();												// Give way to the internal housekeeping of the ESP8266
 	yield();												// Give way to the internal housekeeping of the ESP8266
 
 
     stat_index += j;
     stat_index += j;
@@ -512,22 +661,23 @@ void sendstat() {
 
 
 	if (stat_index > STATUS_SIZE) {
 	if (stat_index > STATUS_SIZE) {
 #		if _MONITOR>=1
 #		if _MONITOR>=1
-			mPrint("A sendstat:: ERROR buffer too big");
+			mPrint("sendstat:: ERROR buffer too big");
 #		endif //_MONITOR
 #		endif //_MONITOR
 		return;
 		return;
 	}
 	}
-	
+
     //send the update
     //send the update
 #	ifdef _TTNSERVER
 #	ifdef _TTNSERVER
 		sendUdp(ttnServer, _TTNPORT, status_report, stat_index);
 		sendUdp(ttnServer, _TTNPORT, status_report, stat_index);
-		yield();
 #	endif
 #	endif
 
 
 #	ifdef _THINGSERVER
 #	ifdef _THINGSERVER
+		yield();
 		sendUdp(thingServer, _THINGPORT, status_report, stat_index);
 		sendUdp(thingServer, _THINGPORT, status_report, stat_index);
 #	endif
 #	endif
 	return;
 	return;
-}//sendstat
+
+} // sendstat()
 
 
 
 
 #endif //_UDPROUTER
 #endif //_UDPROUTER

+ 96 - 42
src/_utils.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -20,6 +20,57 @@
 
 
 // ==================== STRING STRING STRING ==============================================
 // ==================== STRING STRING STRING ==============================================
 
 
+// --------------------------------------------------------------------------------
+// PRINT INT
+// The function printInt prints a number with Thousands seperator
+// Paraneters:
+//	i:			Integer containing Microseconds
+//	response:	String & value containig the converted number
+// Retur:
+//	<none>
+// --------------------------------------------------------------------------------
+void printInt (uint32_t i, String & response)
+{
+	response+=(String(i/1000000) + "." + String(i%1000000));
+}
+
+// --------------------------------------------------------------------------------
+// PRINT Dwn
+// IN a uniform way, this function prints the timstamp, the current time and the 
+// time the function must wait to execute. It will print all Downstream data
+// --------------------------------------------------------------------------------
+void printDwn(struct LoraDown *LoraDown, String & response)
+{
+	uint32_t i= LoraDown->tmst;
+	uint32_t m= micros();
+	
+	response += "micr=";	printInt(m, response);
+	response += ", tmst=";	printInt(i, response);
+
+	response += ", wait=";
+	if (i>m) {
+		response += String(i-m);
+	}
+	else {
+		response += "(";
+		response += String(m-i);
+		response += ")";
+	}
+
+	response += ", SF="		+String(LoraDown->sfTx);
+	response += ", Freq="	+String(LoraDown->freq);
+
+	response += ", a=";
+	uint8_t DevAddr [4];
+		DevAddr[0] = LoraDown->payLoad[4];
+		DevAddr[1] = LoraDown->payLoad[3];
+		DevAddr[2] = LoraDown->payLoad[2];
+		DevAddr[3] = LoraDown->payLoad[1];
+	printHex((IPAddress)DevAddr, ':', response);
+
+	yield();
+	return;
+}
 
 
 
 
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
@@ -73,9 +124,14 @@ void printHexDigit(uint8_t digit, String & response)
 
 
 }
 }
 
 
+// ========================= MONITOR FUNCTIONS ============================================
+// Monitor functions
+// These functions write to the Monitor and print the monitor.
+
+
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 // Print to the monitor console.
 // Print to the monitor console.
-// This function is used all over the gateway code as a substite for USB debug code.
+// This function is used all over the gateway code as a substitute for USB debug code.
 // It allows webserver users to view printed/debugging code.
 // It allows webserver users to view printed/debugging code.
 // With initMonitor() we init the index iMoni=0;
 // With initMonitor() we init the index iMoni=0;
 //
 //
@@ -86,39 +142,32 @@ void printHexDigit(uint8_t digit, String & response)
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 void mPrint(String txt) 
 void mPrint(String txt) 
 {
 {
-	
-#	if _DUSB>=1
-		Serial.println(txt);
-		if (debug>=2) Serial.flush();
-#	endif //_DUSB
-
 #	if _MONITOR>=1
 #	if _MONITOR>=1
 	time_t tt = now();
 	time_t tt = now();
-
-	monitor[iMoni].txt  = String(day(tt))	+ "-";
-	monitor[iMoni].txt += String(month(tt))	+ "-";
-	monitor[iMoni].txt += String(year(tt))	+ " ";
 	
 	
-	uint8_t _hour   = hour(tt);
-	uint8_t _minute = minute(tt);
-	uint8_t _second = second(tt);
-
-	if (_hour   < 10) monitor[iMoni].txt += "0"; monitor[iMoni].txt += String( _hour )+ ":";
-	if (_minute < 10) monitor[iMoni].txt += "0"; monitor[iMoni].txt += String(_minute) + ":";
-	if (_second < 10) monitor[iMoni].txt += "0"; monitor[iMoni].txt += String(_second) + "- ";
+	monitor[iMoni].txt = "";
+	stringTime(tt, monitor[iMoni].txt);
 	
 	
-	monitor[iMoni].txt += String(txt);
+	monitor[iMoni].txt += "- " + String(txt);
 	
 	
 	// Use the circular buffer to increment the index
 	// Use the circular buffer to increment the index
+
+#	if _DUSB>=1
+	if (gwayConfig.dusbStat>=1) {
+		Serial.println(monitor[iMoni].txt);			// Copy to serial when configured
+	}
+#	endif //_DUSB
+
 	iMoni = (iMoni+1) % _MAXMONITOR	;				// And goto 0 when skipping over _MAXMONITOR
 	iMoni = (iMoni+1) % _MAXMONITOR	;				// And goto 0 when skipping over _MAXMONITOR
 	
 	
 #	endif //_MONITOR
 #	endif //_MONITOR
+
 	return;
 	return;
 }
 }
 
 
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-// mStat
+// mStat (Monitor-Statistics)
 // Print the statistics on Serial (USB) port and/or Monitor
 // Print the statistics on Serial (USB) port and/or Monitor
 // Depending on setting of _DUSB and _MONITOR.
 // Depending on setting of _DUSB and _MONITOR.
 // Note: This function does not initialise the response var, will only append.
 // Note: This function does not initialise the response var, will only append.
@@ -137,23 +186,24 @@ int mStat(uint8_t intr, String & response)
 	
 	
 		response += "I=";
 		response += "I=";
 
 
-		if (intr & IRQ_LORA_RXTOUT_MASK) response += String("RXTOUT ");		// 0x80
-		if (intr & IRQ_LORA_RXDONE_MASK) response += String("RXDONE ");		// 0x40
+		if (intr & IRQ_LORA_RXTOUT_MASK) response += "RXTOUT ";		// 0x80
+		if (intr & IRQ_LORA_RXDONE_MASK) response += "RXDONE ";		// 0x40
 		if (intr & IRQ_LORA_CRCERR_MASK) response += "CRCERR ";		// 0x20
 		if (intr & IRQ_LORA_CRCERR_MASK) response += "CRCERR ";		// 0x20
 		if (intr & IRQ_LORA_HEADER_MASK) response += "HEADER ";		// 0x10
 		if (intr & IRQ_LORA_HEADER_MASK) response += "HEADER ";		// 0x10
 		if (intr & IRQ_LORA_TXDONE_MASK) response += "TXDONE ";		// 0x08
 		if (intr & IRQ_LORA_TXDONE_MASK) response += "TXDONE ";		// 0x08
-		if (intr & IRQ_LORA_CDDONE_MASK) response += String("CDDONE ");		// 0x04
+		if (intr & IRQ_LORA_CDDONE_MASK) response += "CDDONE ";		// 0x04
 		if (intr & IRQ_LORA_FHSSCH_MASK) response += "FHSSCH ";		// 0x02
 		if (intr & IRQ_LORA_FHSSCH_MASK) response += "FHSSCH ";		// 0x02
 		if (intr & IRQ_LORA_CDDETD_MASK) response += "CDDETD ";		// 0x01
 		if (intr & IRQ_LORA_CDDETD_MASK) response += "CDDETD ";		// 0x01
 
 
 		if (intr == 0x00) response += "  --  ";
 		if (intr == 0x00) response += "  --  ";
 			
 			
 		response += ", F=" + String(gwayConfig.ch);
 		response += ", F=" + String(gwayConfig.ch);
+		
 		response += ", SF=" + String(sf);
 		response += ", SF=" + String(sf);
+		
 		response += ", E=" + String(_event);
 		response += ", E=" + String(_event);
 			
 			
 		response += ", S=";
 		response += ", S=";
-
 		switch (_state) {
 		switch (_state) {
 			case S_INIT:
 			case S_INIT:
 				response += "INIT ";
 				response += "INIT ";
@@ -165,7 +215,7 @@ int mStat(uint8_t intr, String & response)
 				response += "CAD  ";
 				response += "CAD  ";
 			break;
 			break;
 			case S_RX:
 			case S_RX:
-				response += String("RX   ");
+				response += "RX   ";
 			break;
 			break;
 			case S_TX:
 			case S_TX:
 				response += "TX   ";
 				response += "TX   ";
@@ -178,10 +228,9 @@ int mStat(uint8_t intr, String & response)
 		}
 		}
 		response += ", eT=";
 		response += ", eT=";
 		response += String( micros() - eventTime );
 		response += String( micros() - eventTime );
+		
 		response += ", dT=";
 		response += ", dT=";
 		response += String( micros() - doneTime );
 		response += String( micros() - doneTime );
-
-		//mPrint(response);							// Do actual printing
 	}
 	}
 #endif //_MONITOR
 #endif //_MONITOR
 	return(1);
 	return(1);
@@ -217,7 +266,7 @@ void ftoa(float f, char *val, int p)
 	strcat(val,".");										// Copy decimal point
 	strcat(val,".");										// Copy decimal point
 	
 	
 	itoa(fval,b,10);										// Copy fraction part base 10
 	itoa(fval,b,10);										// Copy fraction part base 10
-	for (int i=0; i<(p-strlen(b)); i++) {
+	for (unsigned int i=0; i<(p-strlen(b)); i++) {
 		strcat(val,"0");									// first number of 0 of faction?
 		strcat(val,"0");									// first number of 0 of faction?
 	}
 	}
 	
 	
@@ -272,18 +321,22 @@ static void stringTime(time_t t, String & response)
 	byte _minute = minute(eTime);
 	byte _minute = minute(eTime);
 	byte _second = second(eTime);
 	byte _second = second(eTime);
 	
 	
+	byte _month = month(eTime);
+	byte _day = day(eTime);
+	
 	switch(weekday(eTime)) {
 	switch(weekday(eTime)) {
-		case 1: response += "Sunday "; break;
-		case 2: response += "Monday "; break;
-		case 3: response += "Tuesday "; break;
-		case 4: response += "Wednesday "; break;
-		case 5: response += "Thursday "; break;
-		case 6: response += "Friday "; break;
-		case 7: response += "Saturday "; break;
+		case 1: response += "Sun "; break;
+		case 2: response += "Mon "; break;
+		case 3: response += "Tue "; break;
+		case 4: response += "Wed "; break;
+		case 5: response += "Thu "; break;
+		case 6: response += "Fri "; break;
+		case 7: response += "Sat "; break;
 	}
 	}
-	response += String(day(eTime)) + "-";
-	response += String(month(eTime)) + "-";
+	if (_day < 10) response += "0"; response += String(_day) + "-";
+	if (_month < 10) response += "0"; response += String(_month) + "-";
 	response += String(year(eTime)) + " ";	
 	response += String(year(eTime)) + " ";	
+	
 	if (_hour < 10) response += "0";   response += String(_hour) + ":";
 	if (_hour < 10) response += "0";   response += String(_hour) + ":";
 	if (_minute < 10) response += "0"; response += String(_minute) + ":";
 	if (_minute < 10) response += "0"; response += String(_minute) + ":";
 	if (_second < 10) response += "0"; response += String(_second);
 	if (_second < 10) response += "0"; response += String(_second);
@@ -317,7 +370,8 @@ int sendNtpRequest(IPAddress timeServerIP)
 		return(0);	
 		return(0);	
 	}
 	}
 	return(1);
 	return(1);
-}
+	
+} // sendNtpRequest()
 
 
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -428,11 +482,11 @@ int SerialName(uint32_t a, String & response)
 	uint8_t * in = (uint8_t *)(& a);
 	uint8_t * in = (uint8_t *)(& a);
 	uint32_t id = ((in[0]<<24) | (in[1]<<16) | (in[2]<<8) | in[3]);
 	uint32_t id = ((in[0]<<24) | (in[1]<<16) | (in[2]<<8) | in[3]);
 
 
-	for (int i=0; i< (sizeof(nodes)/sizeof(nodex)); i++) {
+	for (unsigned int i=0; i< (sizeof(nodes)/sizeof(nodex)); i++) {
 
 
 		if (id == nodes[i].id) {
 		if (id == nodes[i].id) {
 #			if _MONITOR>=1
 #			if _MONITOR>=1
-			if ((debug>=2) && (pdebug & P_MAIN )) {
+			if ((debug>=3) && (pdebug & P_MAIN )) {
 				mPrint("SerialName:: i="+String(i)+", Name="+String(nodes[i].nm)+". for node=0x"+String(nodes[i].id,HEX));
 				mPrint("SerialName:: i="+String(i)+", Name="+String(nodes[i].nm)+". for node=0x"+String(nodes[i].id,HEX));
 			}
 			}
 #			endif //_MONITOR
 #			endif //_MONITOR
@@ -460,7 +514,7 @@ int inDecodes(char * id) {
 
 
 	uint32_t ident = ((id[3]<<24) | (id[2]<<16) | (id[1]<<8) | id[0]);
 	uint32_t ident = ((id[3]<<24) | (id[2]<<16) | (id[1]<<8) | id[0]);
 
 
-	for (int i=0; i< (sizeof(decodes)/sizeof(codex)); i++) {
+	for (unsigned int i=0; i< (sizeof(decodes)/sizeof(codex)); i++) {
 		if (ident == decodes[i].id) {
 		if (ident == decodes[i].id) {
 			return(i);
 			return(i);
 		}
 		}

+ 110 - 66
src/_wwwServer.ino

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by many people and making use of several libraries.
 // 	based on work done by many people and making use of several libraries.
@@ -34,9 +34,9 @@
 
 
 
 
 //
 //
-// The remainder of the file ONLY works is A_SERVER=1 is set.
+// The remainder of the file ONLY works is _SERVER=1 is set.
 //
 //
-#if A_SERVER==1
+#if _SERVER==1
 
 
 // ================================================================================
 // ================================================================================
 // WEBSERVER DECLARATIONS 
 // WEBSERVER DECLARATIONS 
@@ -106,7 +106,6 @@ boolean YesNo()
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 void wwwFile(String fn)
 void wwwFile(String fn)
 {
 {
-
 #if _STAT_LOG == 1
 #if _STAT_LOG == 1
 
 
 	if (!SPIFFS.exists(fn)) {
 	if (!SPIFFS.exists(fn)) {
@@ -127,8 +126,7 @@ void wwwFile(String fn)
 	
 	
 	// MMM Change LOGFILEREC to file available
 	// MMM Change LOGFILEREC to file available
 	while (f.available()) {
 	while (f.available()) {
-//	for (int j=0; j<LOGFILEREC; j++) {
-			
+
 		String s=f.readStringUntil('\n');
 		String s=f.readStringUntil('\n');
 		if (s.length() == 0) {
 		if (s.length() == 0) {
 			Serial.print(F("wwwFile:: String length 0"));
 			Serial.print(F("wwwFile:: String length 0"));
@@ -138,11 +136,14 @@ void wwwFile(String fn)
 		server.sendContent("\n");
 		server.sendContent("\n");
 		yield();
 		yield();
 	}
 	}
-	
+
 	f.close();
 	f.close();
 
 
 #	endif //_MONITOR
 #	endif //_MONITOR
 #endif //_STAT_LOG
 #endif //_STAT_LOG
+
+	return;
+	
 }
 }
 
 
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
@@ -163,13 +164,15 @@ void buttonDocu()
 	response += "    txt += \"Click OK to continue viewing documentation,\\n\"; ";
 	response += "    txt += \"Click OK to continue viewing documentation,\\n\"; ";
 	response += "    txt += \"or Cancel to return to the home page.\\n\\n\"; ";
 	response += "    txt += \"or Cancel to return to the home page.\\n\\n\"; ";
 	response += "    if(confirm(txt)) { ";
 	response += "    if(confirm(txt)) { ";
-	response += "      document.location.href = \"https://things4u.github.io/Projects/SingleChannelGateway/1ch_GWay.html\"; ";
+	response += "      document.location.href = \"https://things4u.github.io/Projects/SingleChannelGateway/index.html\"; ";
 	response += "    }";
 	response += "    }";
 	response += "  }";
 	response += "  }";
 	response += "}";
 	response += "}";
 	
 	
 	response += "</script>";
 	response += "</script>";
 	server.sendContent(response);
 	server.sendContent(response);
+	
+	return;
 }
 }
 
 
 
 
@@ -189,6 +192,8 @@ void buttonLog()
 	}
 	}
 	
 	
 #endif //_STAT_LOG
 #endif //_STAT_LOG
+
+	return;
 }
 }
 
 
 
 
@@ -219,6 +224,8 @@ static void wwwButtons()
 	response += "<a href=\"SEEN\" download><button type=\"button\">" +seen+ "</button></a>";
 	response += "<a href=\"SEEN\" download><button type=\"button\">" +seen+ "</button></a>";
 #	endif
 #	endif
 	server.sendContent(response);							// Send to the screen
 	server.sendContent(response);							// Send to the screen
+	
+	return;
 }
 }
 
 
 
 
@@ -237,7 +244,8 @@ static void wwwButtons()
 // Returns:
 // Returns:
 //		<none>
 //		<none>
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-static void setVariables(const char *cmd, const char *arg) {
+static void setVariables(const char *cmd, const char *arg)
+{
 
 
 	// DEBUG settings; These can be used as a single argument
 	// DEBUG settings; These can be used as a single argument
 	if (strcmp(cmd, "DEBUG")==0) {									// Set debug level 0-2
 	if (strcmp(cmd, "DEBUG")==0) {									// Set debug level 0-2
@@ -372,7 +380,7 @@ static void setVariables(const char *cmd, const char *arg) {
 #endif //_WIFIMANAGER
 #endif //_WIFIMANAGER
 
 
 	// Update the software (from User Interface)
 	// Update the software (from User Interface)
-#if A_OTA==1
+#if _OTA==1
 	if (strcmp(cmd, "UPDATE")==0) {
 	if (strcmp(cmd, "UPDATE")==0) {
 		if (atoi(arg) == 1) {
 		if (atoi(arg) == 1) {
 			updateOtaa();
 			updateOtaa();
@@ -381,7 +389,7 @@ static void setVariables(const char *cmd, const char *arg) {
 	}
 	}
 #endif
 #endif
 
 
-#if A_REFRESH==1
+#if _REFRESH==1
 	if (strcmp(cmd, "REFR")==0) {									// Set refresh on=1 or off=0
 	if (strcmp(cmd, "REFR")==0) {									// Set refresh on=1 or off=0
 		gwayConfig.refresh =(bool)atoi(arg);
 		gwayConfig.refresh =(bool)atoi(arg);
 		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
 		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
@@ -412,7 +420,7 @@ static void openWebPage()
 	server.send(200, "text/html", "");
 	server.send(200, "text/html", "");
 	String tt=""; printIP((IPAddress)WiFi.localIP(),'.',tt);	// Time with separator
 	String tt=""; printIP((IPAddress)WiFi.localIP(),'.',tt);	// Time with separator
 	
 	
-#if A_REFRESH==1
+#if _REFRESH==1
 	if (gwayConfig.refresh) {
 	if (gwayConfig.refresh) {
 		response += String() + "<!DOCTYPE HTML><HTML><HEAD><meta http-equiv='refresh' content='"+_WWW_INTERVAL+";http://";
 		response += String() + "<!DOCTYPE HTML><HTML><HEAD><meta http-equiv='refresh' content='"+_WWW_INTERVAL+";http://";
 		response += tt;
 		response += tt;
@@ -446,6 +454,7 @@ static void openWebPage()
 	uint8_t _minute = minute(secs);
 	uint8_t _minute = minute(secs);
 	uint8_t _second = second(secs);
 	uint8_t _second = second(secs);
 	response += String(days) + "-";
 	response += String(days) + "-";
+	
 	if (_hour < 10) response += "0"; response += String(_hour) + ":";
 	if (_hour < 10) response += "0"; response += String(_hour) + ":";
 	if (_minute < 10) response += "0"; response += String(_minute) + ":";
 	if (_minute < 10) response += "0"; response += String(_minute) + ":";
 	if (_second < 10) response += "0"; 	response += String(_second);
 	if (_second < 10) response += "0"; 	response += String(_second);
@@ -485,8 +494,8 @@ static void gatewaySettings()
 	response +="<tr><td class=\"cell\">CAD</td>";
 	response +="<tr><td class=\"cell\">CAD</td>";
 	response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
 	response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
 	response += ( gwayConfig.cad ? "ON" : "OFF" );
 	response += ( gwayConfig.cad ? "ON" : "OFF" );
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=1\"><button>ON</button></a></td>";
 	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=0\"><button>OFF</button></a></td>";
 	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=0\"><button>OFF</button></a></td>";
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=1\"><button>ON</button></a></td>";
 	response +="</tr>";
 	response +="</tr>";
 	
 	
 	bg = " background-color: ";
 	bg = " background-color: ";
@@ -494,8 +503,8 @@ static void gatewaySettings()
 	response +="<tr><td class=\"cell\">HOP</td>";
 	response +="<tr><td class=\"cell\">HOP</td>";
 	response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
 	response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
 	response += ( gwayConfig.hop ? "ON" : "OFF" );
 	response += ( gwayConfig.hop ? "ON" : "OFF" );
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=1\"><button>ON</button></a></td>";
 	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=0\"><button>OFF</button></a></td>";
 	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=0\"><button>OFF</button></a></td>";
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=1\"><button>ON</button></a></td>";
 	response +="</tr>";
 	response +="</tr>";
 	
 	
 	response +="<tr><td class=\"cell\">SF Setting</td><td class=\"cell\" colspan=\"2\">";
 	response +="<tr><td class=\"cell\">SF Setting</td><td class=\"cell\" colspan=\"2\">";
@@ -598,13 +607,29 @@ static void gatewaySettings()
 	response +="<button>RDIO</button></a></td>";
 	response +="<button>RDIO</button></a></td>";
 	response +="</tr>";
 	response +="</tr>";
 #endif
 #endif
+
 	// USB Debug, Serial Debugging
 	// USB Debug, Serial Debugging
-	response +="<tr><td class=\"cell\">Usb Debug</td><td class=\"cell\" colspan=\"2\">"; 
-	response += _DUSB; 
+	bg = " background-color: ";
+	bg += ( (gwayConfig.dusbStat == 1) ? "LightGreen" : "orange" );
+	response +="<tr><td class=\"cell\">Usb Debug</td>";
+	response +="<td class=\"cell\" colspan=\"2\" style=\"border: 1px solid black; " + bg + "\">";
+	response += ( (gwayConfig.dusbStat == true) ? "ON" : "OFF" );
 	response +="</td>";
 	response +="</td>";
-	//response +="<td class=\"cell\"> </td>";
-	//response +="<td class=\"cell\"> </td>";
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"DUSB=0\"><button>OFF</button></a></td>";
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"DUSB=1\"><button>ON</button></a></td>";
+	response +="</tr>";
+
+	/// WWW Refresh
+#if _REFRESH==1
+	bg = " background-color: ";
+	bg += ( (gwayConfig.refresh == 1) ? "LightGreen" : "orange" );
+	response +="<tr><td class=\"cell\">WWW Refresh</td>";
+	response +="<td class=\"cell\" colspan=\"2\" style=\"border: 1px solid black; " + bg + "\">";
+	response += ( (gwayConfig.refresh == 1) ? "ON" : "OFF" );
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=0\"><button>OFF</button></a></td>";
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=1\"><button>ON</button></a></td>";
 	response +="</tr>";
 	response +="</tr>";
+#endif
 	
 	
 #if _GATEWAYNODE==1
 #if _GATEWAYNODE==1
 	response +="<tr><td class=\"cell\">Framecounter Internal Sensor</td>";
 	response +="<tr><td class=\"cell\">Framecounter Internal Sensor</td>";
@@ -624,18 +649,6 @@ static void gatewaySettings()
 	response +="</tr>";
 	response +="</tr>";
 #endif
 #endif
 
 
-	/// WWW Refresh
-#if A_REFRESH==1
-	bg = " background-color: ";
-	bg += ( (gwayConfig.refresh == 1) ? "LightGreen" : "orange" );
-	response +="<tr><td class=\"cell\">WWW Refresh</td>";
-	response +="<td class=\"cell\" colspan=\"2\" style=\"border: 1px solid black; " + bg + "\">";
-	response += ( (gwayConfig.refresh == 1) ? "ON" : "OFF" );
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=1\"><button>ON</button></a></td>";
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=0\"><button>OFF</button></a></td>";
-	response +="</tr>";
-#endif
-
 	// Time Correction DELAY
 	// Time Correction DELAY
 	if (gwayConfig.expert) {
 	if (gwayConfig.expert) {
 		response +="<tr><td class=\"cell\">Time Correction (uSec)</td><td class=\"cell\" colspan=\"2\">"; 
 		response +="<tr><td class=\"cell\">Time Correction (uSec)</td><td class=\"cell\" colspan=\"2\">"; 
@@ -661,7 +674,7 @@ static void gatewaySettings()
 
 
 	// Format the Filesystem
 	// Format the Filesystem
 	response +="<tr><td class=\"cell\">Format SPIFFS</td>";
 	response +="<tr><td class=\"cell\">Format SPIFFS</td>";
-	response +=String() + "<td class=\"cell\" colspan=\"2\" >"+""+"</td>";
+	response +=String() + "<td class=\"cell\" colspan=\"2\" >"+gwayConfig.formatCntr+"</td>";
 	response +="<td style=\"width:30px;\" colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"FORMAT\" onclick=\"ynDialog(\'Do you really want to format?\',\'FORMAT\')\" /></td></tr>";
 	response +="<td style=\"width:30px;\" colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"FORMAT\" onclick=\"ynDialog(\'Do you really want to format?\',\'FORMAT\')\" /></td></tr>";
 
 
 	// Reset all statistics
 	// Reset all statistics
@@ -678,6 +691,7 @@ static void gatewaySettings()
 	
 	
 	response +="</table>";
 	response +="</table>";
 	
 	
+	
 	server.sendContent(response);
 	server.sendContent(response);
 }
 }
 
 
@@ -891,7 +905,7 @@ static void messageHistory()
 		response = "";
 		response = "";
 		
 		
 		response += String() + "<tr><td class=\"cell\">";					// Tmst
 		response += String() + "<tr><td class=\"cell\">";					// Tmst
-		stringTime((statr[i].tmst), response);								// XXX Change tmst not to be millis() dependent
+		stringTime((statr[i].time), response);								// XXX Change tmst not to be millis() dependent
 		response += "</td>";
 		response += "</td>";
 		
 		
 		response += String() + "<td class=\"cell\">"; 						// Node
 		response += String() + "<td class=\"cell\">"; 						// Node
@@ -967,7 +981,7 @@ static void messageHistory()
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 static void nodeHistory() 
 static void nodeHistory() 
 {
 {
-#if _MAXSEEN >= 1
+#	if _MAXSEEN >= 1
 	if (gwayConfig.seen) {
 	if (gwayConfig.seen) {
 		// First draw the headers
 		// First draw the headers
 		String response= "";
 		String response= "";
@@ -1045,17 +1059,20 @@ static void nodeHistory()
 		}
 		}
 		server.sendContent("</table>");
 		server.sendContent("</table>");
 	}
 	}
-#endif //_MAXSEEN
+#	endif //_MAXSEEN
+
+	return;
 } // nodeHistory()
 } // nodeHistory()
 
 
 
 
 
 
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // MONITOR DATA
 // MONITOR DATA
+// This is a cicular buffer that starts at the latest mPrint line and then goes
+// down until there are no lines left (or we reach the limit).
 // This function will print monitor data for the gateway based on the settings in
 // This function will print monitor data for the gateway based on the settings in
 // _MONITOR in file configGway.h
 // _MONITOR in file configGway.h
-// Only when the _MONITOR is positive then the function will be executed. 
-// If less then nothing will be displayed.
+//
 // XXX We have to make the function such that when printed, the webpage refreshes.
 // XXX We have to make the function such that when printed, the webpage refreshes.
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 void monitorData() 
 void monitorData() 
@@ -1071,13 +1088,12 @@ void monitorData()
 		response +="</tr>";
 		response +="</tr>";
 		
 		
 		for (int i= iMoni-1+_MAXMONITOR; i>=iMoni; i--) {
 		for (int i= iMoni-1+_MAXMONITOR; i>=iMoni; i--) {
-			if (monitor[i % _MAXMONITOR].txt == "-") {		// If equal to init value '-'
+			if (monitor[i % _MAXMONITOR].txt == "-") {			// If equal to init value '-'
 				break;
 				break;
 			}
 			}
 			response +="<tr><td class=\"cell\">" ;
 			response +="<tr><td class=\"cell\">" ;
 			response += String(monitor[i % _MAXMONITOR].txt);
 			response += String(monitor[i % _MAXMONITOR].txt);
 			response += "</td></tr>";
 			response += "</td></tr>";
-
 		}
 		}
 		
 		
 		response +="</table>";
 		response +="</table>";
@@ -1131,7 +1147,6 @@ static void wifiConfig()
 		response +="</tr>";
 		response +="</tr>";
 #endif
 #endif
 
 
-
 		response +="</table>";
 		response +="</table>";
 
 
 		server.sendContent(response);
 		server.sendContent(response);
@@ -1178,7 +1193,7 @@ static void systemStatus()
 		response+="</tr>";
 		response+="</tr>";
 		response +="<tr><td class=\"cell\">ESP Chip ID</td><td class=\"cell\">"; response+=ESP.getChipId(); response+="</tr>";
 		response +="<tr><td class=\"cell\">ESP Chip ID</td><td class=\"cell\">"; response+=ESP.getChipId(); response+="</tr>";
 #endif
 #endif
-		response +="<tr><td class=\"cell\">OLED</td><td class=\"cell\">"; response+=OLED; response+="</tr>";
+		response +="<tr><td class=\"cell\">OLED</td><td class=\"cell\">"; response+=_OLED; response+="</tr>";
 		
 		
 #if _STATISTICS >= 1
 #if _STATISTICS >= 1
 		response +="<tr><td class=\"cell\">WiFi Setups</td><td class=\"cell\">"; response+=gwayConfig.wifis; response+="</tr>";
 		response +="<tr><td class=\"cell\">WiFi Setups</td><td class=\"cell\">"; response+=gwayConfig.wifis; response+="</tr>";
@@ -1220,43 +1235,55 @@ static void interruptData()
 			case S_CAD: response +="CAD"; break;
 			case S_CAD: response +="CAD"; break;
 			case S_RX: response +="RX"; break;
 			case S_RX: response +="RX"; break;
 			case S_TX: response +="TX"; break;
 			case S_TX: response +="TX"; break;
+			case S_TXDONE: response +="TXDONE"; break;
 			default: response +="unknown"; break;
 			default: response +="unknown"; break;
 		}
 		}
 		response +="</td></tr>";
 		response +="</td></tr>";
 		
 		
 		response +="<tr><td class=\"cell\">_STRICT_1CH</td>";
 		response +="<tr><td class=\"cell\">_STRICT_1CH</td>";
 		response +="<td class=\"cell\">" ;
 		response +="<td class=\"cell\">" ;
-		response += String() + _STRICT_1CH;
+		response += String(_STRICT_1CH);
 		response +="</td></tr>";		
 		response +="</td></tr>";		
 
 
 		response +="<tr><td class=\"cell\">flags (8 bits)</td>";
 		response +="<tr><td class=\"cell\">flags (8 bits)</td>";
 		response +="<td class=\"cell\">0x";
 		response +="<td class=\"cell\">0x";
 		if (flags <16) response += "0";
 		if (flags <16) response += "0";
-		response +=String(flags,HEX); response+="</td></tr>";
+		response +=String(flags,HEX); 
+		response+="</td></tr>";
 
 
 		
 		
 		response +="<tr><td class=\"cell\">mask (8 bits)</td>";
 		response +="<tr><td class=\"cell\">mask (8 bits)</td>";
 		response +="<td class=\"cell\">0x"; 
 		response +="<td class=\"cell\">0x"; 
 		if (mask <16) response += "0";
 		if (mask <16) response += "0";
-		response +=String(mask,HEX); response+="</td></tr>";
+		response +=String(mask,HEX); 
+		response+="</td></tr>";
 		
 		
 		response +="<tr><td class=\"cell\">Re-entrant cntr</td>";
 		response +="<tr><td class=\"cell\">Re-entrant cntr</td>";
 		response +="<td class=\"cell\">"; 
 		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.reents;
+		response += String(gwayConfig.reents);
 		response +="</td></tr>";
 		response +="</td></tr>";
 
 
 		response +="<tr><td class=\"cell\">ntp call cntr</td>";
 		response +="<tr><td class=\"cell\">ntp call cntr</td>";
 		response +="<td class=\"cell\">"; 
 		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.ntps;
+		response += String(gwayConfig.ntps);
 		response+="</td></tr>";
 		response+="</td></tr>";
 		
 		
 		response +="<tr><td class=\"cell\">ntpErr cntr</td>";
 		response +="<tr><td class=\"cell\">ntpErr cntr</td>";
 		response +="<td class=\"cell\">"; 
 		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.ntpErr;
+		response += String(gwayConfig.ntpErr);
 		response +="</td>";
 		response +="</td>";
 		response +="<td colspan=\"2\" style=\"border: 1px solid black;\">";
 		response +="<td colspan=\"2\" style=\"border: 1px solid black;\">";
 		stringTime(gwayConfig.ntpErrTime, response);
 		stringTime(gwayConfig.ntpErrTime, response);
+		response +="</td></tr>";
+
+		response +="<tr><td class=\"cell\">loraWait errors/success</td>";
+		response +="<td class=\"cell\">"; 
+		response += String(gwayConfig.waitErr);
 		response +="</td>";
 		response +="</td>";
+		response +="<td colspan=\"2\" style=\"border: 1px solid black;\">";
+		response += String(gwayConfig.waitOk);
+		response +="</td></tr>";
+		
 		response +="</tr>";
 		response +="</tr>";
 		
 		
 		response +="</table>";
 		response +="</table>";
@@ -1294,7 +1321,7 @@ void setupWWW()
 	server.on("/HELP", []() {
 	server.on("/HELP", []() {
 		sendWebPage("HELP","");					// Send the webPage string
 		sendWebPage("HELP","");					// Send the webPage string
 		server.sendHeader("Location", String("/"), true);
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	});
 
 
 	// Format the filesystem
 	// Format the filesystem
@@ -1303,7 +1330,8 @@ void setupWWW()
 		msg_oLED("FORMAT");		
 		msg_oLED("FORMAT");		
 		SPIFFS.format();							// Normally not used. Use only when SPIFFS corrupt
 		SPIFFS.format();							// Normally not used. Use only when SPIFFS corrupt
 		initConfig(&gwayConfig);					// Well known values
 		initConfig(&gwayConfig);					// Well known values
-		writeConfig( CONFIGFILE, &gwayConfig);
+		gwayConfig.formatCntr++;
+		writeConfig(CONFIGFILE, &gwayConfig);
 		writeSeen( _SEENFILE, listSeen);			// Write the last time record  is Seen
 		writeSeen( _SEENFILE, listSeen);			// Write the last time record  is Seen
 #		if _MONITOR>=1
 #		if _MONITOR>=1
 		if ((debug>=1) && (pdebug & P_GUI )) {
 		if ((debug>=1) && (pdebug & P_GUI )) {
@@ -1315,7 +1343,7 @@ void setupWWW()
 	});
 	});
 	
 	
 	
 	
-	// Reset the statistics
+	// Reset the statistics (th egateway function) but not the system specific things
 	server.on("/RESET", []() {
 	server.on("/RESET", []() {
 		mPrint("RESET");
 		mPrint("RESET");
 		startTime= now() - 1;					// Reset all timers too (-1 to avoid division by 0)
 		startTime= now() - 1;					// Reset all timers too (-1 to avoid division by 0)
@@ -1364,27 +1392,29 @@ void setupWWW()
 				statc.sf11_0= 0; statc.sf11_1= 0; statc.sf11_2= 0;
 				statc.sf11_0= 0; statc.sf11_1= 0; statc.sf11_2= 0;
 				statc.sf12_0= 0; statc.sf12_1= 0; statc.sf12_2= 0;
 				statc.sf12_0= 0; statc.sf12_1= 0; statc.sf12_2= 0;
 #			endif //_STATISTICS==3
 #			endif //_STATISTICS==3
+
 #		endif //_STATISTICS==2
 #		endif //_STATISTICS==2
 #	endif //_STATISTICS==1
 #	endif //_STATISTICS==1
-
+			
 		initSeen(listSeen);						// Clear all Seen records as well.
 		initSeen(listSeen);						// Clear all Seen records as well.
 		
 		
 		server.sendHeader("Location", String("/"), true);
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 		server.send ( 302, "text/plain", "");
 	});
 	});
 
 
-	// Reset the boot counter
+	// Reset the boot counter, and other system specific counters
 	server.on("/BOOT", []() {
 	server.on("/BOOT", []() {
 		mPrint("BOOT");
 		mPrint("BOOT");
-#if _STATISTICS >= 2
-		gwayConfig.boots = 0;
+#if _STATISTICS >= 2		
 		gwayConfig.wifis = 0;
 		gwayConfig.wifis = 0;
 		gwayConfig.views = 0;
 		gwayConfig.views = 0;
 		gwayConfig.ntpErr = 0;					// NTP errors
 		gwayConfig.ntpErr = 0;					// NTP errors
 		gwayConfig.ntpErrTime = 0;				// NTP last error time
 		gwayConfig.ntpErrTime = 0;				// NTP last error time
 		gwayConfig.ntps = 0;					// Number of NTP calls
 		gwayConfig.ntps = 0;					// Number of NTP calls
 #endif
 #endif
+		gwayConfig.boots = 0;					//
 		gwayConfig.reents = 0;					// Re-entrance
 		gwayConfig.reents = 0;					// Re-entrance
+		
 		writeGwayCfg(CONFIGFILE, &gwayConfig );
 		writeGwayCfg(CONFIGFILE, &gwayConfig );
 #if _MONITOR>=1
 #if _MONITOR>=1
 		if ((debug>=2) && (pdebug & P_GUI)) {
 		if ((debug>=2) && (pdebug & P_GUI)) {
@@ -1404,6 +1434,7 @@ void setupWWW()
 		ESP.restart();
 		ESP.restart();
 	});
 	});
 
 
+	// New SSID for the machine
 	server.on("/NEWSSID", []() {
 	server.on("/NEWSSID", []() {
 		sendWebPage("NEWSSID","");				// Send the webPage string
 		sendWebPage("NEWSSID","");				// Send the webPage string
 		server.sendHeader("Location", String("/"), true);
 		server.sendHeader("Location", String("/"), true);
@@ -1515,7 +1546,7 @@ void setupWWW()
 	server.on("/TRUSTED=1", []() {
 	server.on("/TRUSTED=1", []() {
 	gwayConfig.trusted = (gwayConfig.trusted +1)%4;
 	gwayConfig.trusted = (gwayConfig.trusted +1)%4;
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
-#		if _MONITOR>=2
+#		if _MONITOR>=1
 			mPrint("TRUSTED +, config written");
 			mPrint("TRUSTED +, config written");
 #		endif //_MONITOR
 #		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
 		server.sendHeader("Location", String("/"), true);
@@ -1524,9 +1555,9 @@ void setupWWW()
 	server.on("/TRUSTED=-1", []() {
 	server.on("/TRUSTED=-1", []() {
 		gwayConfig.trusted = (gwayConfig.trusted -1)%4;
 		gwayConfig.trusted = (gwayConfig.trusted -1)%4;
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
-#if _DUSB>=2
-		Serial.println(F("TRUSTED +, config written"));
-#endif
+#		if _MONITOR>=1
+			mPrint("TRUSTED -, config written");
+#		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 		server.send ( 302, "text/plain", "");
 	});
 	});
@@ -1607,9 +1638,10 @@ void setupWWW()
 		server.send ( 302, "text/plain", "");
 		server.send ( 302, "text/plain", "");
 	});
 	});
 #endif
 #endif
+
 	// WWW Page refresh function
 	// WWW Page refresh function
 	server.on("/REFR=1", []() {					// WWW page auto refresh ON
 	server.on("/REFR=1", []() {					// WWW page auto refresh ON
-#if A_REFRESH==1
+#if _REFRESH==1
 		gwayConfig.refresh =1;
 		gwayConfig.refresh =1;
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
 #endif		
 #endif		
@@ -1617,7 +1649,7 @@ void setupWWW()
 		server.send ( 302, "text/plain", "");
 		server.send ( 302, "text/plain", "");
 	});
 	});
 	server.on("/REFR=0", []() {					// WWW page auto refresh OFF
 	server.on("/REFR=0", []() {					// WWW page auto refresh OFF
-#if A_REFRESH==1
+#if _REFRESH==1
 		gwayConfig.refresh =0;
 		gwayConfig.refresh =0;
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
 		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
 #endif
 #endif
@@ -1625,6 +1657,19 @@ void setupWWW()
 		server.send ( 302, "text/plain", "");
 		server.send ( 302, "text/plain", "");
 	});
 	});
 
 
+	// WWW Page serial print function
+	server.on("/DUSB=1", []() {					// WWW page Serial Print ON
+		gwayConfig.dusbStat =1;
+		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		server.sendHeader("Location", String("/"), true);
+		server.send ( 302, "text/plain", "");
+	});
+	server.on("/DUSB=0", []() {					// WWW page Serial Print OFF
+		gwayConfig.dusbStat =0;
+		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		server.sendHeader("Location", String("/"), true);
+		server.send ( 302, "text/plain", "");
+	});
 	
 	
 	// Switch off/on the HOP functions
 	// Switch off/on the HOP functions
 	server.on("/HOP=1", []() {
 	server.on("/HOP=1", []() {
@@ -1664,7 +1709,7 @@ void setupWWW()
 	// Display LOGging information
 	// Display LOGging information
 	server.on("/LOG", []() {
 	server.on("/LOG", []() {
 		server.sendHeader("Location", String("/"), true);
 		server.sendHeader("Location", String("/"), true);
-#if _MONITOR>=2
+#if _MONITOR>=1
 		mPrint("LOG button");
 		mPrint("LOG button");
 #endif //_MONITOR
 #endif //_MONITOR
 		buttonLog();
 		buttonLog();
@@ -1697,7 +1742,7 @@ void setupWWW()
 	
 	
 	// Update the sketch. Not yet implemented
 	// Update the sketch. Not yet implemented
 	server.on("/UPDATE=1", []() {
 	server.on("/UPDATE=1", []() {
-#if A_OTA==1
+#if _OTA==1
 		updateOtaa();
 		updateOtaa();
 #endif
 #endif
 		server.sendHeader("Location", String("/"), true);
 		server.sendHeader("Location", String("/"), true);
@@ -1710,10 +1755,9 @@ void setupWWW()
 	// Maybe not all information should be put on the screen since it
 	// Maybe not all information should be put on the screen since it
 	// may take too much time to serve all information before a next
 	// may take too much time to serve all information before a next
 	// package interrupt arrives at the gateway
 	// package interrupt arrives at the gateway
-#	if _DUSB>=1
-		Serial.print(F("WWW Server started on port "));
-		Serial.println(A_SERVERPORT);
-#	endif //_DUSB
+#	if _MONITOR>=1
+		mPrint("WWW Server started on port " + String(_SERVERPORT) );
+#	endif // _MONITOR
 
 
 	return;
 	return;
 } // setupWWW
 } // setupWWW
@@ -1767,5 +1811,5 @@ static void websiteFooter()
 }
 }
 
 
 
 
-#endif // A_SERVER==1
+#endif // _SERVER==1
 
 

+ 54 - 38
src/configGway.h

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP32 and ESP8266
 // 1-channel LoRa Gateway for ESP32 and ESP8266
 // Copyright (c) Maarten Westenberg 2016-2020 
 // Copyright (c) Maarten Westenberg 2016-2020 
 
 
-#define VERSION "V.6.2.3.E.EU868; PlatformIO 200223a"
+#define VERSION "V.6.2.4.EU868; PlatformIO 200425m"
 //
 //
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway and many others.
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway and many others.
 //
 //
@@ -23,11 +23,11 @@
 // "ESP32 Dev Module" or "Heltec WiFi Lora 32"
 // "ESP32 Dev Module" or "Heltec WiFi Lora 32"
 // 
 // 
 // For ESP8266 Wemos: compile with "Wemos R1 D1" and choose
 // For ESP8266 Wemos: compile with "Wemos R1 D1" and choose
-// the right _PIN_OUT below. Selecting OLED while that is not connected does not 
+// the right _PIN_OUT below. Selecting Oled while that is not connected does not 
 // really matter (so you can leave that in).
 // really matter (so you can leave that in).
 //
 //
-// The source has been optimized for PlatformIO usage. Than means the some variables
-// can be define in the .platformio.ini file. Pleas look at the example file to see 
+// The source has been optimized for PlatformIO usage. That means some variables
+// can be defined in the .platformio.ini file. Please look at the example file to see 
 // how to set these #defines
 // how to set these #defines
 //
 //
 // ========================================================================================
 // ========================================================================================
@@ -60,7 +60,9 @@
 // Define the monitor screen. When it is greater than 0 then logging is displayed in
 // Define the monitor screen. When it is greater than 0 then logging is displayed in
 // the special screen at the GUI.
 // the special screen at the GUI.
 // If _DUSB is also set to 1 then most messages will also be copied to USB devices.
 // If _DUSB is also set to 1 then most messages will also be copied to USB devices.
+#if !defined _MONITOR
 #define _MONITOR 1
 #define _MONITOR 1
+#endif
 
 
 
 
 // Gather statistics on sensor and Wifi status
 // Gather statistics on sensor and Wifi status
@@ -119,6 +121,7 @@
 // device and also connect enable dio1 to detect this state. 
 // device and also connect enable dio1 to detect this state. 
 #define _CAD 1
 #define _CAD 1
 
 
+
 // CRCCHECK
 // CRCCHECK
 // Defines whether we should check on the CRC of RXDONE messages (see stateMachine.ino)
 // Defines whether we should check on the CRC of RXDONE messages (see stateMachine.ino)
 // This should prevent us from getting a lot os stranges messgages of unknown nodes.
 // This should prevent us from getting a lot os stranges messgages of unknown nodes.
@@ -126,12 +129,12 @@
 #define _CRCCHECK 1
 #define _CRCCHECK 1
 
 
 // Definitions for the admin webserver.
 // Definitions for the admin webserver.
-// A_SERVER determines whether or not the admin webpage is included in the sketch.
+// _SERVER determines whether or not the admin webpage is included in the sketch.
 // Normally, leave it in!
 // Normally, leave it in!
-#define A_SERVER 1				// Define local WebServer only if this define is set
-#define A_REFRESH 1				// Allow the webserver refresh or not?
-#define A_SERVERPORT 80			// Local webserver port (normally 80)
-#define A_MAXBUFSIZE 192		// Must be larger than 128, but small enough to work
+#define _SERVER 1				// Define local WebServer only if this define is set
+#define _REFRESH 1				// Allow the webserver refresh or not?
+#define _SERVERPORT 80			// Local webserver port (normally 80)
+#define _MAXBUFSIZE 192		// Must be larger than 128, but small enough to work
 
 
 
 
 // Definitions for over the air updates. At the moment we support OTA with IDE
 // Definitions for over the air updates. At the moment we support OTA with IDE
@@ -139,16 +142,18 @@
 // Bonjour is included in iTunes (which is free) and OTA is recommended to install 
 // Bonjour is included in iTunes (which is free) and OTA is recommended to install 
 // the firmware on your router witout having to be really close to the gateway and 
 // the firmware on your router witout having to be really close to the gateway and 
 // connect with USB.
 // connect with USB.
-#define A_OTA 1
+#define _OTA 1
 
 
 
 
-// We support a few pin-out configurations out-of-the-box: HALLARD, COMPRESULT and TTGO ESP32.
-// If you use one of these two, just set the parameter to the right value.
-// If your pin definitions are different, update the loraModem.h file to reflect these settings.
+// We support a few pin-out configurations out-of-the-box: HALLARD, COMPRESULT and 
+// Heltec/TTGO ESP32.
+// If you use one of these, just set the parameter to the right value.
+// If your pin definitions are different, update the loraModem.h file to reflect the
+// hardware settings.
 //	1: HALLARD
 //	1: HALLARD
 //	2: COMRESULT pin out
 //	2: COMRESULT pin out
 //	3: ESP32, Wemos pin out (Not used)
 //	3: ESP32, Wemos pin out (Not used)
-//	4: ESP32, Heltec and TTGO pin out (should work for Heltec, 433 and OLED too).
+//	4: ESP32, Heltec and TTGO pin out (should work for Heltec, 433 and Oled too).
 //	5: Other, define your own in loraModem.h (does not include GPS Code)
 //	5: Other, define your own in loraModem.h (does not include GPS Code)
 #if !defined _PIN_OUT
 #if !defined _PIN_OUT
 #	define _PIN_OUT 1
 #	define _PIN_OUT 1
@@ -165,13 +170,20 @@
 // NOTE: If your node has only one frequency enabled and one SF, you must set this to 1
 // NOTE: If your node has only one frequency enabled and one SF, you must set this to 1
 //		in order to receive downlink messages. This is the default mode.
 //		in order to receive downlink messages. This is the default mode.
 // NOTE: In all other cases, value 0 works for most gateways with CAD enabled
 // NOTE: In all other cases, value 0 works for most gateways with CAD enabled
-#define _STRICT_1CH 1
-
+#if !defined _STRICT_1CH
+#	define _STRICT_1CH 1
+#endif //_STRICT_1CH
 
 
 //
 //
 // Also, normally the server will respond with SF12 in the RX2 timeslot.
 // Also, normally the server will respond with SF12 in the RX2 timeslot.
-// For TTN, thr RX2 timeslot is SF9, and we should use that one for TTN
-#define _RX2_SF 9
+// For TTN, the RX2 timeslot is SF9, so we should use that one for TTN
+#if !defined _RXDELAY1
+#	define _RXDELAY1 1000
+#endif
+
+#if !defined _RX2_SF
+#	define _RX2_SF 9
+#endif
 
 
 
 
 // This section defines whether we use the gateway as a repeater
 // This section defines whether we use the gateway as a repeater
@@ -185,14 +197,14 @@
 #define _MUTEX 0
 #define _MUTEX 0
 
 
 
 
-// Define if OLED Display is connected to I2C bus. Note that defining an OLED display does not
-// impact performance negatively, certainly if no OLED is connected. Wrong OLED will not show
-// sensible results on the OLED display
-// OLED==0; No OLED display connected
-// OLED==1; 0.9" Oled Screen based on SSD1306
-// OLED==2;	1.3" Oled screens for Wemos, 128x64 SH1106
-#if !defined OLED
-#	define OLED 1
+// Define if Oled Display is connected to I2C bus. Note that defining an Oled display does not
+// impact performance negatively, certainly if no Oled is connected. Wrong Oled will not show
+// sensible results on the Oled display
+// _OLED==0;	No Oled display connected
+// _OLED==1;	0.9" Oled Screen based on SSD1306
+// _OLED==2;	1.3" Oled screens for Wemos, 128x64 SH1106
+#if !defined _OLED
+#	define _OLED 1
 #endif
 #endif
 
 
 
 
@@ -208,25 +220,27 @@
 #define _GATEWAYMGT 0
 #define _GATEWAYMGT 0
 
 
 
 
-// Do extensive logging
+// Do extensive logging to file
 // Use the ESP8266 SPIFS filesystem to do extensive logging.
 // Use the ESP8266 SPIFS filesystem to do extensive logging.
 // We must take care that the filesystem never(!) is full, and for that purpose we
 // We must take care that the filesystem never(!) is full, and for that purpose we
 // rather have new records/line of statistics than very old.
 // rather have new records/line of statistics than very old.
 // Of course we must store enough records to make the filesystem work
 // Of course we must store enough records to make the filesystem work
-#define _STAT_LOG 1
-
+#if !defined _START_LOG
+#	define _STAT_LOG 0
+#endif //_START_LOG
 
 
 
 
 // Set the Server Settings (IMPORTANT)
 // Set the Server Settings (IMPORTANT)
 #define _LOCUDPPORT 1700					// UDP port of gateway! Often 1700 or 1701 is used for upstream comms
 #define _LOCUDPPORT 1700					// UDP port of gateway! Often 1700 or 1701 is used for upstream comms
 
 
 // Timing
 // Timing
-#define _MSG_INTERVAL 15					// Reset timer in seconds
-#define _PULL_INTERVAL 55					// PULL_DATA messages to server to get downstream in milliseconds
+#define _PULL_INTERVAL 20					// PULL_DATA messages to server to get downstream in seconds
 #define _STAT_INTERVAL 120					// Send a 'stat' message to server
 #define _STAT_INTERVAL 120					// Send a 'stat' message to server
 #define _NTP_INTERVAL 3600					// How often do we want time NTP synchronization
 #define _NTP_INTERVAL 3600					// How often do we want time NTP synchronization
-#define _WWW_INTERVAL	60					// Number of seconds before we refresh the WWW page
-
+#define _WWW_INTERVAL 60					// Number of seconds before we refresh the WWW page
+#define _FILE_INTERVAL 30					// Number of timer (in secs) before writing to files
+#define _MSG_INTERVAL 31					// Message timeout timer in seconds
+#define _RST_INTERVAL 90					// Reset interval in seconds, total chip reset
 
 
 // This defines whether or not we would use the gateway as 
 // This defines whether or not we would use the gateway as 
 // as sort of backend decoding system for local sensors which decodes
 // as sort of backend decoding system for local sensors which decodes
@@ -247,7 +261,7 @@
 // ntp
 // ntp
 // Please add daylight saving time to NTP_TIMEZONES when desired
 // Please add daylight saving time to NTP_TIMEZONES when desired
 #define NTP_TIMESERVER "nl.pool.ntp.org"	// Country and region specific
 #define NTP_TIMESERVER "nl.pool.ntp.org"	// Country and region specific
-#define NTP_TIMEZONES	1					// How far is our Timezone from UTC (excl daylight saving/summer time)
+#define NTP_TIMEZONES	2					// How far is our Timezone from UTC (excl daylight saving/summer time)
 #define SECS_IN_HOUR	3600
 #define SECS_IN_HOUR	3600
 #define NTP_INTR 0							// Do NTP processing with interrupts or in loop();
 #define NTP_INTR 0							// Do NTP processing with interrupts or in loop();
 
 
@@ -260,7 +274,9 @@
 // as a regular sensor value.
 // as a regular sensor value.
 // Set its LoRa address and key below in this file, See spec. para 4.3.2
 // Set its LoRa address and key below in this file, See spec. para 4.3.2
 // NOTE: The node is switched off by default. Switch it on in the GUI
 // NOTE: The node is switched off by default. Switch it on in the GUI
-#define _GATEWAYNODE 0
+#if !defined _GATEWAYNODE
+#	define _GATEWAYNODE 0
+#endif //_GATEWAYNODE
 
 
 
 
 // We can put the gateway in such a mode that it will (only) recognize
 // We can put the gateway in such a mode that it will (only) recognize
@@ -297,7 +313,9 @@
 //	- SF seen (8-bit integer with SF per bit)
 //	- SF seen (8-bit integer with SF per bit)
 // The initial version _NUMMAX stores max this many nodes, please make
 // The initial version _NUMMAX stores max this many nodes, please make
 // _MAXSEEN==0 when not used
 // _MAXSEEN==0 when not used
-#define _MAXSEEN 20
+#if !defined _MAXSEEN
+#	define _MAXSEEN 20
+#endif
 #define _SEENFILE "/gwayNum.txt"
 #define _SEENFILE "/gwayNum.txt"
 
 
 
 
@@ -320,5 +338,3 @@
 // and need no changing
 // and need no changing
 #define _TTNSERVER "router.eu.thethings.network"
 #define _TTNSERVER "router.eu.thethings.network"
 #define _TTNPORT 1700							// Standard port for TTN
 #define _TTNPORT 1700							// Standard port for TTN
-
-

+ 93 - 43
src/configNode.h

@@ -1,4 +1,4 @@
-// sensor.h; 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -11,8 +11,7 @@
 //
 //
 // NO WARRANTY OF ANY KIND IS PROVIDED
 // NO WARRANTY OF ANY KIND IS PROVIDED
 //
 //
-// Author: Maarten Westenberg (mw12554@hotmail.com) 
-
+// Author: Maarten Westenberg (mw12554@hotmail.com)
 //
 //
 // This file contains a number of compile-time settings and declarations that are'
 // This file contains a number of compile-time settings and declarations that are'
 // specific to the LoRa rfm95, sx1276, sx1272 radio of the gateway.
 // specific to the LoRa rfm95, sx1276, sx1272 radio of the gateway.
@@ -23,23 +22,22 @@
 // It is possible to use the gateway as a normal sensor node also. In this case,
 // It is possible to use the gateway as a normal sensor node also. In this case,
 // substitute the node info below.
 // substitute the node info below.
 #if _GATEWAYNODE==1
 #if _GATEWAYNODE==1
-
-// Valid coding for internal sensors are LCODE and RAW. 
-// Make sure to only select one.
-//#define _LCODE 1
-#define _RAW 1
-#define _CHECK_MIC 1
-#define _SENSOR_INTERVAL 300
-
-#define _DEVADDR { 0xAA, 0xAA, 0xAA, 0xAA }
-#define _APPSKEY { 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB }
-#define _NWKSKEY { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }
-#define _SENSOR_INTERVAL 300
-// For ESP32 based T_BEAM/TTGO boards these two are normally included
-// If included make value 1, else if not, make them 0
-#define _GPS 1
-#define _BATTERY 1
-
+	// Valid coding for internal sensors are LCODE and RAW.
+	// Make sure to only select one.
+#	define _LCODE 1
+//#	define _RAW 1
+#	define _CHECK_MIC 1
+#	define _SENSOR_INTERVAL 300
+
+	// Sensor and app address information
+#	define _DEVADDR { 0x26, 0x01, 0x1B, 0x96 }
+#	define _APPSKEY { 0x02, 0x02, 0x04, 0x32, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+#	define _NWKSKEY { 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+
+	// For ESP32 based T_BEAM/TTGO boards these two are normally included
+	// If included make value 1, else if not, make them 0
+#	define _GPS 1
+#	define _BATTERY 1
 #endif //_GATEWAYNODE
 #endif //_GATEWAYNODE
 
 
 
 
@@ -54,6 +52,26 @@ nodex nodes[] = {
 	{ 0x260116BD , "lora-34 PIR node" },						// F=0
 	{ 0x260116BD , "lora-34 PIR node" },						// F=0
 	{ 0x26011152 , "lora-35 temp+humi node" },					// F=0
 	{ 0x26011152 , "lora-35 temp+humi node" },					// F=0
 	{ 0x2601148C , "lora-36 test node"  },						// F=0
 	{ 0x2601148C , "lora-36 test node"  },						// F=0
+// LoRa 37
+	{ 0x26011B90 , "lora-39 temp DS18B20" },					// F=1
+	{ 0x260119A6 , "lora-40 airquality" },						// F=0
+	{ 0x2601117D , "lora-41 temp+humi SR04T" },
+	{ 0x26011593 , "lora-42 temp DS18B20" },					// F=0	
+	{ 0x26011514 , "lora-43 temp DS18B20" },					// F=0
+	{ 0x2601145C , "lora-44 Distance" },						// F=0
+	{ 0x26011D77 , "lora-45 no sensor" },
+	{ 0x2601160F , "lora-46 HTU21 metal case" },				// F=0
+	{ 0x26011E71 , "lora-47 Dallas temperature" },				// F=0
+	{ 0x26011215 , "lora-48 AM2315 temp/Humi" },				// F=0
+	{ 0x2601168F , "lora-49 EU433 Sensor" },					// 433, F=0
+	{ 0x26011b96 , "lora-50 Internal T-Beam gway" },			// F=0
+//	{ 0xAABBCCDD , "lora-51 Heltec OTAA" },						// F=ALL
+	{ 0x26011199 , "lora-52 CubeCell sensor" },					// F=ALL
+	{ 0x26011E52 , "lora-53 gas sensor" },						// F=ALL
+	{ 0x26011F66 , "lora-62 CubeCell Capsule" },				// F=ALL
+	{ 0x260110ED , "lora-63 CubeCell Board" },					// F=ALL
+	{ 0x26011A2B , "lora-64 Metal temp humi" },					// F=0
+	{ 0x260114EA , "lora-65 Waterproof temp humi" },			// F=0
 	{ 0x00000000 , "lora-00 well known sensor" }				// F=0
 	{ 0x00000000 , "lora-00 well known sensor" }				// F=0
 };
 };
 
 
@@ -69,7 +87,7 @@ nodex nodes[] = {
 #if _LOCALSERVER==1
 #if _LOCALSERVER==1
 struct codex  {
 struct codex  {
 	uint32_t id;				// This is the device ID (coded in 4 bytes uint32_t
 	uint32_t id;				// This is the device ID (coded in 4 bytes uint32_t
-	unsigned char nm[32];			// A name string which is free to choose
+	unsigned char nm[32];		// A name string which is free to choose
 	uint8_t nwkKey[16];			// The Network Session Key of 16 bytes
 	uint8_t nwkKey[16];			// The Network Session Key of 16 bytes
 	uint8_t appKey[16];			// The Application Session Key of 16 bytes
 	uint8_t appKey[16];			// The Application Session Key of 16 bytes
 };
 };
@@ -81,30 +99,53 @@ struct codex  {
 // Definition of all nodes that we want to decode locally on the gateway.
 // Definition of all nodes that we want to decode locally on the gateway.
 //
 //
 codex decodes[] = {
 codex decodes[] = {
-	{ 0xAAAAAAAA , "lora-EE", 	// F=0
-		{ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB },
-		{ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC } 
+	{	0x26011152 , "lora-35",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x23, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 } 
+	},
+	{	0x2601148C , "lora-36",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 } 
+	},
+	{	0x26011B90 , "lora-39",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x27, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+	},
+	{	0x26011593 , "lora-42",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+	},
+	{	0x26011D77 , "lora-43",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+	},
+	{	0x27000599 , "lora-44",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
 	},
 	},
-	{ 0xBBBBBBBB , "lora-FF", 	// F=0
-		{ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB },
-		{ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC } 
+	{	0x26011B96 , "lora-50",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x32, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
 	},
 	},
-	{ 0x00000000 , "lora-00",	// F=0
+	{	0x26011B96 , "lora-62",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+	},
+	{	0x26011B96 , "lora-63",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+	},
+	{	0x260114EA , "lora-65",	// F=0
+		{ 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 },
+		{ 0x02, 0x02, 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x34, 0x55 }
+	},
+	{	0x00000000 , "lora-00",	// F=0
 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
 	}					
 	}					
 };
 };
 #endif //_LOCALSERVER
 #endif //_LOCALSERVER
 
 
-// If you have a second back-end server defined such as Semtech or loriot.io
-// your can define _THINGPORT and _THINGSERVER with your own value.
-// If not, make sure that you do not define these, which will save CPU time
-// Port is UDP port in this program
-//
-// Default for testing: Switched off
-// #define _THINGSERVER "your.extra.server"		// Server URL of the LoRa-udp.js handler
-// #define _THINGPORT 1700						// Port 1700 is old compatibility
-
 
 
 // Wifi definitions
 // Wifi definitions
 // WPA is an array with SSID and password records. Set WPA size to number of entries in array
 // WPA is an array with SSID and password records. Set WPA size to number of entries in array
@@ -122,16 +163,25 @@ struct wpas {
 // below. This is needed to get the gateway working
 // below. This is needed to get the gateway working
 //
 //
 wpas wpa[] = {
 wpas wpa[] = {
-	{ "yourSSID", "yourPassword" },
-	{ "Your2SSID", "your2Password" }
+	{ "platenspeler", "maanlama@16" }
 };
 };
 
 
 
 
-// Define the name of the accesspoint if the gateway is in accesspoint mode (is
-// getting WiFi SSID and password using WiFiManager)
-#define AP_NAME "ESP8266-Gway-Things4U"
-#define AP_PASSWD "ttnAutoPw"
+// If you have a second back-end server defined such as Semtech or loriot.io
+// your can define _THINGPORT and _THINGSERVER with your own value.
+// If not, make sure that you do not define these, which will save CPU time
+// Port is UDP port in this program
+//
+// Default for testing: Switched off
+// #define _THINGSERVER "westenberg.org"		// Server URL of the LoRa-udp.js handler
+// #define _THINGPORT 1700						// Port 1700 is old compatibility
+
 
 
+// Define the name of the accesspoint if the gateway is in accesspoint mode (is
+// getting WiFi SSID and password using WiFiManager). 
+// If you do not need them, comment out.
+//#define AP_NAME "Gway-Things4U"
+//#define AP_PASSWD "ttnAutoPw"
 
 
 
 
 // For asserting and testing the following defines are used.
 // For asserting and testing the following defines are used.

+ 8 - 3
src/loraFiles.h

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP mcu's
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP mcu's
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -66,17 +66,21 @@ struct espGwayConfig {
 	uint16_t views;				// Number of sendWebPage() calls
 	uint16_t views;				// Number of sendWebPage() calls
 	uint16_t wifis;				// Number of WiFi Setups
 	uint16_t wifis;				// Number of WiFi Setups
 	uint16_t reents;			// Number of re-entrant interrupt handler calls
 	uint16_t reents;			// Number of re-entrant interrupt handler calls
-	uint16_t ntpErr;			// Number of UTP requests that failed
 	uint16_t ntps;
 	uint16_t ntps;
 	uint16_t logFileRec;		// Logging File Record number
 	uint16_t logFileRec;		// Logging File Record number
 	uint16_t logFileNo;			// Logging File Number
 	uint16_t logFileNo;			// Logging File Number
 	uint16_t logFileNum;		// Number of log files max
 	uint16_t logFileNum;		// Number of log files max
+	uint16_t formatCntr;		// Count the number of formats
+
+	uint16_t ntpErr;			// Number of UTP requests that failed
+	uint16_t waitErr;			// Number of times the loraWait() call failed
+	uint16_t waitOk;			// Number of times the loraWait() call success
 	
 	
 	uint8_t ch;					// index to freqs array, freqs[gwayCofnig.ch]=868100000 default
 	uint8_t ch;					// index to freqs array, freqs[gwayCofnig.ch]=868100000 default
 	uint8_t sf;					// range from SF7 to SF12
 	uint8_t sf;					// range from SF7 to SF12
 	uint8_t debug;				// range 0 to 4
 	uint8_t debug;				// range 0 to 4
 	uint8_t pdebug;				// pattern debug, 
 	uint8_t pdebug;				// pattern debug, 
-	uint8_t trusted;			// pattern debug, 
+	uint8_t trusted;			// pattern debug,
 	
 	
 	bool cad;					// is CAD enabled?
 	bool cad;					// is CAD enabled?
 	bool hop;					// Is HOP enabled (Note: default be disabled)
 	bool hop;					// Is HOP enabled (Note: default be disabled)
@@ -85,6 +89,7 @@ struct espGwayConfig {
 	bool seen;
 	bool seen;
 	bool expert;
 	bool expert;
 	bool monitor;
 	bool monitor;
+	bool dusbStat;				// Status of _DUSB
 	
 	
 } gwayConfig;
 } gwayConfig;
 
 

+ 18 - 17
src/loraModem.h

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -56,7 +56,7 @@
 // Set center frequency. If in doubt, choose the first one, comment out all others
 // Set center frequency. If in doubt, choose the first one, comment out all others
 // Each "real" gateway should support the first 3 frequencies according to LoRa spec.
 // Each "real" gateway should support the first 3 frequencies according to LoRa spec.
 // NOTE: This means you have to specify at least 3 frequencies here for the single
 // NOTE: This means you have to specify at least 3 frequencies here for the single
-//	channel gateway to work. 
+//	channel gateway to work according to spec. 
 struct vector {
 struct vector {
 	// Upstream messages
 	// Upstream messages
 	uint32_t upFreq;							// 4 bytes
 	uint32_t upFreq;							// 4 bytes
@@ -70,7 +70,8 @@ struct vector {
 	uint8_t  dwnHi;								// 1 bytes
 	uint8_t  dwnHi;								// 1 bytes
 };
 };
 
 
-
+// Define all the relevant LoRa Regions
+//==
 #ifdef EU863_870
 #ifdef EU863_870
 // This the the EU863_870 format as used in most of Europe
 // This the the EU863_870 format as used in most of Europe
 // It is also the default for most of the single channel gateway work.
 // It is also the default for most of the single channel gateway work.
@@ -106,7 +107,7 @@ vector freqs [] = {
 };
 };
 
 
 #elif defined(US902_928)
 #elif defined(US902_928)
-// The frequency plan for USA is a difficult one. As yout can see, the uplink protocol uses
+// The frequency plan for USA is a difficult one. As you can see, the uplink protocol uses
 // SF7-SF10 and BW125 whereas the downlink protocol uses SF7-SF12 and BW500.
 // SF7-SF10 and BW125 whereas the downlink protocol uses SF7-SF12 and BW500.
 // Also the number of chanels is not equal.
 // Also the number of chanels is not equal.
 vector freqs [] = {
 vector freqs [] = {
@@ -180,10 +181,9 @@ volatile uint8_t _event=0;
 // so we need to store the current value we like to work with
 // so we need to store the current value we like to work with
 uint8_t _rssi;	
 uint8_t _rssi;	
 
 
-uint32_t nowTime=0;
-uint32_t msgTime=0;
-uint32_t hopTime=0;
-uint32_t detTime=0;
+uint32_t msgTime=0;							// in seconds, Thru nowSeconds, now()
+uint32_t hopTime=0;							// in micros()
+uint32_t detTime=0;							// In micros()
 
 
 #if _PIN_OUT==1
 #if _PIN_OUT==1
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -271,7 +271,7 @@ struct pins {
 // Each time a message is received or sent the statistics are updated.
 // Each time a message is received or sent the statistics are updated.
 // In case _STATISTICS==1 we define the last _MAXSTAT messages as statistics
 // In case _STATISTICS==1 we define the last _MAXSTAT messages as statistics
 struct stat_t {
 struct stat_t {
-	time_t tmst;							// Time since 1970 in seconds		
+	uint32_t time;							// Time since 1970 in seconds		
 	uint32_t node;							// 4-byte DEVaddr (the only one known to gateway)
 	uint32_t node;							// 4-byte DEVaddr (the only one known to gateway)
 	uint8_t ch;								// Channel index to freqs array
 	uint8_t ch;								// Channel index to freqs array
 	uint8_t sf;
 	uint8_t sf;
@@ -342,27 +342,28 @@ struct stat_t	statr[1];					// Always have at least one element to store in
 // Define the payload structure used to separate interrupt and SPI
 // Define the payload structure used to separate interrupt and SPI
 // processing from the loop() part
 // processing from the loop() part
 uint8_t payLoad[128];						// Payload i
 uint8_t payLoad[128];						// Payload i
-struct LoraBuffer {
-	uint8_t	* 	payLoad;
+struct LoraDown {
+	uint32_t	tmst;						//
+	uint32_t	freq;
 	uint8_t		payLength;
 	uint8_t		payLength;
-	uint32_t	tmst;						// in millis()
 	uint8_t		sfTx;
 	uint8_t		sfTx;
 	uint8_t		powe;
 	uint8_t		powe;
-	uint32_t	fff;
 	uint8_t		crc;
 	uint8_t		crc;
 	uint8_t		iiq;
 	uint8_t		iiq;
+	uint8_t	* 	payLoad;
 } LoraDown;
 } LoraDown;
 
 
 // Up buffer (from Lora sensor to UDP)
 // Up buffer (from Lora sensor to UDP)
 // This struct contains all data of the buffer received from devices to gateway
 // This struct contains all data of the buffer received from devices to gateway
 
 
 struct LoraUp {
 struct LoraUp {
-	uint8_t		payLoad[128];
-	uint8_t		payLength;
-	int			prssi; 
 	int32_t		snr;
 	int32_t		snr;
-	int			rssicorr;
+	uint32_t	tmst;
+	int16_t		prssi; 
+	int16_t		rssicorr;
+	uint8_t		payLength;
 	uint8_t		sf;
 	uint8_t		sf;
+	uint8_t		payLoad[128];
 } LoraUp;
 } LoraUp;
 
 
 
 

+ 6 - 6
src/oLED.h

@@ -1,4 +1,4 @@
-// 1-channel LoRa Gateway for ESP8266
+// 1-channel LoRa Gateway for ESP8266 and ESP32
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 // Copyright (c) 2016-2020 Maarten Westenberg version for ESP8266
 //
 //
 // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
@@ -13,7 +13,7 @@
 //
 //
 // Author: Maarten Westenberg (mw12554@hotmail.com)
 // Author: Maarten Westenberg (mw12554@hotmail.com)
 //
 //
-// This file contains a number of compile-time settings and definitions for OLED support.
+// This file contains a number of compile-time settings and definitions for Oled support.
 //
 //
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 
 
@@ -27,7 +27,7 @@
 // 2. 1.3" OLED with much better and larger display
 // 2. 1.3" OLED with much better and larger display
 // 4. TTGO board
 // 4. TTGO board
 
 
-#if OLED>=1										// If OLED is used
+#if _OLED>=1										// If OLED is used
 
 
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 // Define the different PIN's used for SCL/SDA for each arch.
 // Define the different PIN's used for SCL/SDA for each arch.
@@ -56,17 +56,17 @@
 // ----------------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------------
 // Define the different OLED versions
 // Define the different OLED versions
 //
 //
-#if OLED==1
+#if _OLED==1
 #include "SSD1306.h"
 #include "SSD1306.h"
 #define OLED_ADDR 0x3C							// Default 0x3C for 0.9", for 1.3" it is 0x78
 #define OLED_ADDR 0x3C							// Default 0x3C for 0.9", for 1.3" it is 0x78
 SSD1306  display(OLED_ADDR, OLED_SDA, OLED_SCL);// i2c ADDR & SDA, SCL on wemos
 SSD1306  display(OLED_ADDR, OLED_SDA, OLED_SCL);// i2c ADDR & SDA, SCL on wemos
 #endif
 #endif
 
 
 // This is an 1.3" OLED display which is running on I2C
 // This is an 1.3" OLED display which is running on I2C
-#if OLED==2
+#if _OLED==2
 #include "SH1106.h"
 #include "SH1106.h"
 #define OLED_ADDR 0x3C							// Default 0x3C for 1.3" SH1106
 #define OLED_ADDR 0x3C							// Default 0x3C for 1.3" SH1106
 SH1106  display(OLED_ADDR, OLED_SDA, OLED_SCL);	// i2c ADDR & SDA, SCL on wemos
 SH1106  display(OLED_ADDR, OLED_SDA, OLED_SCL);	// i2c ADDR & SDA, SCL on wemos
 #endif
 #endif
 
 
-#endif//OLED>=1
+#endif// _OLED>=1