Browse Source

Version 6.2.5; Initial Version

platenspeler 5 years ago
parent
commit
83bf977eb3
21 changed files with 772 additions and 627 deletions
  1. 9 0
      CHANGELOG.md
  2. 16 15
      README.md
  3. 6 2
      platformio.ini
  4. 35 30
      src/ESP-sc-gway.ino
  5. 3 3
      src/_WiFi.ino
  6. 2 2
      src/_gatewayMgt.ino
  7. 97 73
      src/_loraFiles.ino
  8. 24 16
      src/_loraModem.ino
  9. 6 6
      src/_oLED.ino
  10. 20 20
      src/_sensor.ino
  11. 23 23
      src/_stateMachine.ino
  12. 1 1
      src/_tcpTTN.ino
  13. 55 95
      src/_txRx.ino
  14. 79 64
      src/_udpSemtech.ino
  15. 13 12
      src/_utils.ino
  16. 295 199
      src/_wwwServer.ino
  17. 59 47
      src/configGway.h
  18. 9 0
      src/configNode.h
  19. 6 6
      src/loraFiles.h
  20. 7 6
      src/loraModem.h
  21. 7 7
      src/oLED.h

+ 9 - 0
CHANGELOG.md

@@ -16,6 +16,15 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
 
 # Release Notes
 
+Features release 6.2.5 (April 30, 2020)
+- Repaired SF and BW for upstream
+- Rewrote Monitoring to output only the most significant messages for debug==1
+- Make definitions of LASTSEEN and PACKAGE STATISTICS dynamic. Allowing GUI resizing. 
+Look in expert mode to change these settings
+- Rewrote the addLog() function
+- Repaired typos
+- Removed unncessary serial and MONITOR prints
+
 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 

+ 16 - 15
README.md

@@ -1,7 +1,7 @@
 # Single Channel LoRaWAN Gateway
 
-Version 6.2.4, 
-Data: April 25, 2020  
+Version 6.2.5, 
+Data: May 21, 2020  
 Author: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 
@@ -13,13 +13,14 @@ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 
 Maintained by Maarten Westenberg (mw12554@hotmail.com) 
 
-
+![logo](https://github.com/things4u/ESP-1ch-Gateway/blob/master/images/illustration-Maarten-In.jpg?raw=true "aap")
+ 
 # Description
 
 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 
-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.
 
 I do have more than 10 Wemos D1 mini boards running, some I built myself, 
 some 10+ on Hallard, 3 on ComResult and 4 ESP32 boards. They ALL work without problems
@@ -55,23 +56,23 @@ At this moment the src directory contains the PlatformIO source, and therefore w
 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 
+When in PlatformIO, choose <File> and then <Add folder to Workspace...> and select your 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 your filesystem to work on the files. In this directory create the source directory "ESP-sc-gway" 
+Create a place on you filesystem to work on the files. In this directory create 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;
+of the "lib" directory to the Arduino IDE "libraries" directory;
 
 ## testing
 
 The single channel gateway has been tested on a gateway with the Wemos D1 Mini, 
 using a HopeRF RFM95W transceiver.  Tests were done on 868 version of LoRa and some 
 testing on 433 MHz.
-The LoRa nodes tested againts this gateway are:
+The LoRa nodes tested against this gateway are:
 
 - TeensyLC with HopeRF RFM95 radio
 - Arduino Pro-Mini (default Armega328 model, 8MHz 3.3V and 16MHz 3.3V)
@@ -203,13 +204,14 @@ Also the gateway may or may not support Class B, which is a superset of class A.
  
 ### Selecting you standard pin-out
 
-We support two pin-out configurations out-of-the-box: HALLARD and COMPRESULT.
-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 five pin-out configurations out-of-the-box, see below.
+If you use one of these, just set the parameter to the right value.
+If your pin definitions are different, update the loraModem.h and oLED.h file to reflect these settings.
 	1: HALLARD
 	2: COMRESULT pin out
-	3: ESP32 pin out
-	4: Other, define your own in loraModem.h
+	3: ESP32/Wemos based board
+	4: ESP32/TTGO based ESP32 boarda
+	5: ESP32/Heltec Wifi LoRA 32(V2)
 
  \#define _PIN_OUT 1
 
@@ -484,8 +486,7 @@ The following things are still on my wish list to make to the single channel gat
 - Use the SPIFFS for storing .css files
 - Look at Class B and C support
 
-![logo](https://github.com/things4u/ESP-1ch-Gateway/blob/master/images/illustration-Maarten-In.jpg?raw=true "aap")
- 
+
 # License
 
 The source files of the gateway sketch in this repository is made available under the MIT

+ 6 - 2
platformio.ini

@@ -15,33 +15,37 @@ board = d1_mini
 board_build.mcu = esp8266
 board_build.f_cpu = 80000000L
 build_flags =
+  -D _PIN_OUT=1
   -D _WIFIMANAGER=0
   -D _SPIFFS_FORMAT=0
   -D _OLED=0
   -D _DUSB=1
   -D _PROFILER=1
+  -D _STAT_LOG=1
 framework = arduino
 upload_protocol = espota
 board_build.flash_mode = qio
 upload_speed = 115200
 upload_port = 192.168.2.21
 
-[env:Gateway_30]
+[env:Gateway_29]
 platform = espressif8266
 board = d1_mini
 board_build.mcu = esp8266
 board_build.f_cpu = 80000000L
 build_flags =
+  -D _PIN_OUT=2
   -D _WIFIMANAGER=0
   -D _SPIFFS_FORMAT=0
   -D _OLED=0
   -D _DUSB=1
   -D _PROFILER=1
+  -D _STAT_LOG=0
 framework = arduino
 upload_protocol = espota
 board_build.flash_mode = qio
 upload_speed = 115200
-upload_port = 192.168.2.30
+upload_port = 192.168.2.29
 
 [env:Gateway_72]
 platform = espressif32

+ 35 - 30
src/ESP-sc-gway.ino

@@ -27,7 +27,7 @@
 #if defined (ARDUINO_ARCH_ESP32) || defined(ESP32)
 #	define ESP32_ARCH 1
 #	ifndef _PIN_OUT
-#		define _PIN_OUT 4										// For ESP32 this pin-out is standard
+#		define _PIN_OUT 4									// For ESP32 pin-out 4 is default
 #	endif
 #elif defined(ARDUINO_ARCH_ESP8266)
 	//
@@ -76,7 +76,7 @@ extern "C" {
 
 // ----------- Specific ESP32 stuff --------------
 #if defined(ESP32_ARCH)
-#	include <WiFi.h>										// MMM added 20Feb
+#	include <WiFi.h>
 #	include <ESPmDNS.h>
 #	include <SPIFFS.h>
 #	include <WiFiManager.h>								// Standard lib for ESP WiFi config through an AP
@@ -86,7 +86,7 @@ extern "C" {
 #	if _SERVER==1
 #		include <WebServer.h>								// Standard Webserver for ESP32
 #		include <Streaming.h>          						// http://arduiniana.org/libraries/streaming/
-		WebServer server(_SERVERPORT); // MMM added 20Feb
+		WebServer server(_SERVERPORT);
 #	endif //_SERVER
 
 #	if _OTA==1
@@ -130,7 +130,7 @@ extern "C" {
 // ----------- Declaration of variables --------------
 
 uint8_t debug=1;											// Debug level! 0 is no msgs, 1 normal, 2 extensive
-uint8_t pdebug= P_MAIN | P_GUI;								// Initially only MAIN and GUI
+uint8_t pdebug= P_MAIN ;									// Initially only MAIN and GUI
 
 #if _GATEWAYNODE==1
 #	if _GPS==1
@@ -152,8 +152,7 @@ uint8_t		MAC_array[6];
 // ----------------------------------------------------------------------------
 
 // Set spreading factor (SF7 - SF12)
-sf_t sf 			= _SPREADING;
-sf_t sfi 			= _SPREADING;							// Initial value of SF
+sf_t sf 			= _SPREADING;							// Initial value of SF					
 
 // Set location, description and other configuration parameters
 // Defined in ESP-sc_gway.h
@@ -183,7 +182,7 @@ 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 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
+uint32_t fileTime = 0;										// Write the configuration to file
 
 #define TX_BUFF_SIZE  1024									// Upstream buffer to send to MQTT
 #define RX_BUFF_SIZE  1024									// Downstream received from MQTT
@@ -286,6 +285,8 @@ void setup() {
 	MAC_char[18] = 0;
 	char hostname[12];										// hostname space
 
+	initConfig(&gwayConfig);
+		
 #	if _DUSB>=1
 		Serial.begin(_BAUDRATE);							// As fast as possible for bus
 		delay(500);
@@ -318,7 +319,7 @@ void setup() {
 		msg_oLED("FORMAT");
 		SPIFFS.format();
 		delay(500);
-		initConfig(&gwayConfig);
+		initConfig(&gwayConfig);							// After a format reinit variables
 	}
 	
 	// If we set SPIFFS_FORMAT in 
@@ -329,7 +330,7 @@ void setup() {
 	initConfig(&gwayConfig);
 	gwayConfig.formatCntr++;
 	if ((debug>=1) && (pdebug & P_MAIN)) {
-		mPrint("Format SPIFFS Filesystem Done");
+		mPrint("SPIFFS Format Done");
 	}
 #	endif //_SPIFFS_FORMAT>=1
 
@@ -349,8 +350,9 @@ void setup() {
 	// Read the config file for all parameters not set in the setup() or configGway.h file
 	// This file should be read just after SPIFFS is initializen and before
 	// other configuration parameters are used.
+	// It will overwrite any settings given by initConfig
 	//
-	if (readGwayCfg(CONFIGFILE, &gwayConfig) > 0) {			// read the Gateway Config
+	if (readGwayCfg(_CONFIGFILE, &gwayConfig) > 0) {			// read the Gateway Config
 #		if _MONITOR>=1
 		if (debug>=0) {
 			mPrint("readGwayCfg:: return OK");
@@ -400,7 +402,7 @@ void setup() {
 	yield();
 
 #	if _MONITOR>=1
-	if ((debug>=1) & ( pdebug & P_MAIN )) {
+	if ((debug>=1) & (pdebug & P_MAIN)) {
 		mPrint("setup:: WlanConnect="+String(WiFi.SSID()) );
 	}
 #	endif
@@ -461,7 +463,7 @@ void setup() {
 	pinMode(pins.rst, OUTPUT);
     pinMode(pins.dio0, INPUT);								// This pin is interrupt
 	pinMode(pins.dio1, INPUT);								// This pin is interrupt
-	//pinMode(pins.dio2, INPUT);							// XXX future expansion
+	//pinMode(pins.dio2, INPUT);								// XXX future expansion
 
 	// Init the SPI pins
 #if defined(ESP32_ARCH)
@@ -545,7 +547,7 @@ void setup() {
 		}
 #		endif //_MONITOR
 
-		writeGwayCfg(CONFIGFILE, &gwayConfig );
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );
 	}
 #	endif //NTP_INTR
 
@@ -613,17 +615,24 @@ void setup() {
 	// Or in the traditional Comresult case
 	else {
 		attachInterrupt(pins.dio0, Interrupt_0, RISING);	// Separate interrupts
-		attachInterrupt(pins.dio1, Interrupt_1, RISING);	// Separate interrupts		
+		attachInterrupt(pins.dio1, Interrupt_1, RISING);	// Separate interrupts
+		//attachInterrupt(pins.dio2, Interrupt_2, RISING);	// Separate interrupts		
 	}
-	
-	writeConfig(CONFIGFILE, &gwayConfig);					// Write config
+
+#	if _MONITOR>=1
+	if ((debug>=2) && (pdebug & P_TX)) {
+		mPrint("sendPacket:: STRICT=" + String(_STRICT_1CH) );
+	}
+#	endif //_MONITOR
+
+	writeConfig(_CONFIGFILE, &gwayConfig);					// Write config
 	writeSeen(_SEENFILE, listSeen);							// Write the last time record  is seen
 
 	// activate Oled display
 #	if _OLED>=1
 		acti_oLED();
 		addr_oLED();
-#	endif // _OLED
+#	endif //_OLED
 
 	mPrint(" --- Setup() ended, Starting loop() ---");
 
@@ -673,7 +682,7 @@ void loop ()
 	//
 	while( (packetSize= Udp.parsePacket()) > 0) {
 #		if _MONITOR>=1
-		if ((debug>=2) && (pdebug & P_TX)){
+		if ((debug>=3) && (pdebug & P_TX)) {
 			mPrint("loop:: readUdp available");
 		}
 #		endif //_MONITOR
@@ -712,11 +721,11 @@ void loop ()
 	// 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.
 	//
-	if ( ((nowSeconds - statr[0].time) > _MSG_INTERVAL ) &&
+	if ( ((nowSeconds - statr[0].time) > _MSG_INTERVAL) &&
 		(msgTime <= statr[0].time) ) 
 	{
 #		if _MONITOR>=1
-		if (( debug>=2 ) && ( pdebug & P_MAIN )) {
+		if ((debug>=2) && (pdebug & P_MAIN)) {
 			String response="";
 			response += "REINIT:: ";
 			response += String( _MSG_INTERVAL );
@@ -798,7 +807,7 @@ void loop ()
 				if ((debug>=1) || (pdebug & P_MAIN)) {
 					mPrint("sensorPacket: Error");
 				}
-#				endif// _MONITOR
+#				endif //_MONITOR
 			}
 		}
 #		endif//_GATEWAYNODE
@@ -818,7 +827,7 @@ void loop ()
 		pullTime = nowSeconds;
 		
 #		if _MONITOR>=1
-		if ((debug>=1) && (pdebug & P_RX)) {
+		if ((debug>=2) && (pdebug & P_RX)) {
 			String response = "UP ESP-sc-gway:: PKT_PULL_DATA message sent: micr=";
 			printInt(micros(), response);
 			mPrint(response);
@@ -867,22 +876,18 @@ void loop ()
 			}
 			else {
 				setTime(newTime);
-				if (year(now()) != 1970) {
-#					if _MONITOR>=1
-					if ((debug>=1) && (pdebug & P_MAIN)) {
-						ntptimer = nowSeconds;					// Do not when year(now())=="1970" beacause of "FORMAT"
-					}
-#					endif
+				if (year(now()) != 1970) {						// Do not when year(now())=="1970"
+					ntptimer = nowSeconds;						// beacause of "FORMAT"
 				}
 			}
 		}
 #	endif//NTP_INTR
 
-#	if _MAXSEEN >= 1
+#	if _MAXSEEN>=1
 		if ((nowSeconds - fileTime) >= _FILE_INTERVAL) {
 			writeSeen(_SEENFILE, listSeen);
 			fileTime = nowSeconds;
 		}
-#	endif // _MAXSEEN
+#	endif //_MAXSEEN
 
 }//loop

+ 3 - 3
src/_WiFi.ino

@@ -64,7 +64,7 @@ int WlanStatus() {
 #			endif //_MONITOR
 			break;
 		
-		// This code is generated as soonas the AP is out of range
+		// This code is generated as soon as the AP is out of range
 		// Whene detected, the program will search for a better AP in range
 		case WL_NO_SSID_AVAIL:
 #			if _MONITOR>=1
@@ -161,7 +161,7 @@ int wifiMgr()
 		switch (i) {
 			case 1: mPrint("WlanConnect:: WlanStatus Connected"); break;
 			case 0: mPrint("WlanConnect:: WlanStatus Disconnected"); break;
-			default: mPrint("WlatConnect:: WlanStatus other");
+			default: mPrint("WlanConnect:: WlanStatus other");
 		}
 	}
 #	endif //_MONITOR 
@@ -275,7 +275,7 @@ int WlanConnect(int maxTry) {
 			// -1	= No SSID or other cause			
 			int stat = WlanStatus();
 			if ( stat == 1) {
-				writeGwayCfg(CONFIGFILE, &gwayConfig );					// Write configuration to SPIFFS
+				writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Write configuration to SPIFFS
 				return(1);
 			}
 		

+ 2 - 2
src/_gatewayMgt.ino

@@ -59,7 +59,7 @@ void gateway_mgt(uint8_t size, uint8_t *buff) {
 		case MGT_RESET:
 #			if _MONITOR>=1
 				mPrint(F("gateway_mgt:: RESET"));
-#			endif // _MONITOR
+#			endif //_MONITOR
 			// No further parameters, just reset the GWay
 			setup();								// Call the sketch setup function
 			// Send Ack to server
@@ -74,7 +74,7 @@ void gateway_mgt(uint8_t size, uint8_t *buff) {
 		case MGT_SET_FREQ:
 #			if _MONITOR>=1
 				mPrint(F("gateway_mgt:: SET FREQ"));
-#			endif // _MONITOR
+#			endif //_MONITOR
 			// Byte [4] contains index of Frequency
 		break;
 		default:

+ 97 - 73
src/_loraFiles.ino

@@ -16,7 +16,7 @@
 // This file contains the LoRa filesystem specific code
 
 
-#if _MONITOR>=1
+
 // ----------------------------------------------------------------------------
 // LoRa Monitor logging code.
 // Define one print function and depending on the logging parameter output
@@ -24,14 +24,15 @@
 // ----------------------------------------------------------------------------
 int initMonitor(struct moniLine *monitor) 
 {
-	for (int i=0; i< _MAXMONITOR; i++) {
+#if _MONITOR>=1
+	for (int i=0; i< gwayConfig.maxMoni; i++) {
 		monitor[i].txt= "-";						// Make all lines empty
 	}
 	iMoni=0;										// Init the index
+#endif //_MONITOR
 	return(1);
 }
 
-#endif //_MONITOR
 
 
 // ============================================================================
@@ -45,7 +46,7 @@ int initMonitor(struct moniLine *monitor)
 void id_print (String id, String val) 
 {
 #if _MONITOR>=1
-	if (( debug>=0 ) && ( pdebug & P_MAIN )) {
+	if ((debug>=0) && (pdebug & P_MAIN)) {
 		Serial.print(id);
 		Serial.print(F("=\t"));
 		Serial.println(val);
@@ -78,6 +79,34 @@ void initConfig(struct espGwayConfig *c)
 	(*c).trusted = 1;
 	(*c).txDelay = 0;					// First Value without saving is 0;
 	(*c).dusbStat = true;
+	
+	(*c).maxSeen = _MAXSEEN;
+	(*c).maxStat = _MAXSTAT;
+	(*c).maxMoni = _MAXMONITOR;
+	
+	// We clean all the file statistics. Maybe we can leave them in, but after a fornat
+	// all data has disappeared.
+	(*c).logFileRec = 0;				// In new logFile start with record 0
+	(*c).logFileNo = 0;					// Increase file ID
+
+	// Declarations that are dependent on the init settings
+	// The structure definitions below make it possible to dynamically size and resize the
+	// information in the GUI
+	free(statr); delay(10);
+	statr = (struct stat_t *) malloc((*c).maxStat * sizeof(struct stat_t));
+	for (int i=0; i<(*c).maxStat; i++) {
+		//statr[i].data=0;
+		statr[i].time=0;						// Time since 1970 in seconds		
+		statr[i].node=0;						// 4-byte DEVaddr (the only one known to gateway)
+		statr[i].ch=0;							// Channel index to freqs array
+		statr[i].sf=0;							// Init Spreading Factor
+	}
+
+	free(listSeen); delay(10);
+	listSeen = (struct nodeSeen *) malloc((*c).maxSeen * sizeof(struct nodeSeen));
+	for (int i=0; i<(*c).maxSeen; i+=1) {
+		listSeen[i].idSeen=0;
+	}
 
 } // initConfig()
 
@@ -107,7 +136,7 @@ int readGwayCfg(const char *fn, struct espGwayConfig *c)
 		}
 #	endif
 
-	writeGwayCfg(CONFIGFILE, &gwayConfig );				// And writeback the configuration, not to miss a boot
+	writeGwayCfg(_CONFIGFILE, &gwayConfig );				// And writeback the configuration, not to miss a boot
 
 	return 1;
 	
@@ -141,7 +170,7 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 	while (f.available()) {
 		
 #		if _MONITOR>=1
-		if (( debug>=0 ) && ( pdebug & P_MAIN )) {
+		if ((debug>=0) && (pdebug & P_MAIN)) {
 			Serial.print('.');
 		}
 #		endif //_MONITOR
@@ -254,10 +283,6 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 			id_print(id, val);
 			(*c).logFileRec = (uint16_t) val.toInt();
 		}
-		else if (id == "FILENUM") {								// FILEREC setting
-			id_print(id, val);
-			(*c).logFileNum = (uint16_t) val.toInt();
-		}
 		else if (id == "EXPERT") {								// EXPERT button setting
 			id_print(id, val);
 			(*c).expert = (bool) val.toInt();
@@ -357,7 +382,6 @@ int writeConfig(const char *fn, struct espGwayConfig *c)
 	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("FILENO");	f.print('='); f.print((*c).logFileNo);	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("TRUSTED");	f.print('='); f.print((*c).trusted); 	f.print('\n');
@@ -387,86 +411,85 @@ int writeConfig(const char *fn, struct espGwayConfig *c)
 // ----------------------------------------------------------------------------
 int addLog(const unsigned char * line, int cnt) 
 {
-#	if _STAT_LOG==1
 
+#if _STAT_LOG==1
+	File f;
 	char fn[16];
+
+	// If the records does not fit in the file anymore, open a new file
+	
+	if (gwayConfig.logFileRec > LOGFILEREC) {		// If number of records is ;arger than filesize
 	
-	if (gwayConfig.logFileRec > LOGFILEREC) {		// Have to make define for this
 		gwayConfig.logFileRec = 0;					// In new logFile start with record 0
 		gwayConfig.logFileNo++;						// Increase file ID
-		gwayConfig.logFileNum++;					// Increase number of log files
-	}
-	gwayConfig.logFileRec++;
-	
-	// If we have too many logfies, delete the oldest
-	//
-	if (gwayConfig.logFileNum > LOGFILEMAX){
-		sprintf(fn,"/log-%d", gwayConfig.logFileNo - LOGFILEMAX);
-#		if _MONITOR>=1
-		if (( debug>=2 ) && ( pdebug & P_GUI )) {
-			mPrint("addLog:: Too many logfiles, deleting="+String(fn));
+		
+		f.close();									// Close the old file
+		
+		sprintf(fn,"/log-%d", gwayConfig.logFileNo);// Make the new name
+
+		if (gwayConfig.logFileNo > LOGFILEMAX) {	// If we have too many logfies, delete the oldest
+			sprintf(fn,"/log-%d", gwayConfig.logFileNo-LOGFILEMAX );
+#			if _MONITOR>=1
+			if ((debug>=1) && (pdebug & P_RX)) {
+				mPrint("addLog:: Too many logfiles, deleting="+String(fn));
+			}
+#			endif //_MONITOR
+			SPIFFS.remove(fn);
 		}
-#		endif //_MONITOR
-		SPIFFS.remove(fn);
-		gwayConfig.logFileNum--;
 	}
-	
-	// Make sure we have the right fileno
-	sprintf(fn,"/log-%d", gwayConfig.logFileNo); 
+
+	sprintf(fn,"/log-%d", gwayConfig.logFileNo);	// Make sure we have the right fileno
 	
 	// If there is no SPIFFS, Error
 	// Make sure to write the config record/line also
 	if (!SPIFFS.exists(fn)) {
 #		if _MONITOR>=1
-		if (( debug >= 2 ) && ( pdebug & P_GUI )) {
-			mPrint("addLog:: WARNING file="+String(fn)+" does not exist .. rec="+String(gwayConfig.logFileRec) );
+		if ((debug >= 1) && (pdebug & P_RX)) {
+			mPrint("addLog:: WARNING file="+String(fn)+" does not exist. record="+String(gwayConfig.logFileRec) );
 		}
 #		endif //_MONITOR
 	}
 	
-	File f = SPIFFS.open(fn, "a");
+	f = SPIFFS.open(fn, "a");
 	if (!f) {
 #		if _MONITOR>=1
-		if (( debug>=1 ) && ( pdebug & P_GUI )) {
+		if ((debug>=1) && (pdebug & P_RX)) {
 			mPrint("addLOG:: ERROR file open failed="+String(fn));
 		}
 #		endif //_MONITOR
 		return(0);								// If file open failed, return
 	}
-	
+#	if _MONITOR>=2
+	else {
+		mPrint("addLog:: Opening adding file="+String(fn));
+	}
+#	endif
+
+
 	int i=0;
 #	if _MONITOR>=1
-	if (( debug>=2 ) && ( pdebug & P_GUI )) {
-		Serial.print(F("addLog:: fileno="));
-		Serial.print(gwayConfig.logFileNo);
-		Serial.print(F(", rec="));
-		Serial.print(gwayConfig.logFileRec);
-
-		Serial.print(F(": "));
-#		if _MONITOR>=2
-		{
-			for (i=0; i< 12; i++) {				// The first 12 bytes contain non printable characters
-				Serial.print(line[i],HEX);
-				Serial.print(' ');
-			}
-		}
-#		else //_MONITOR>=2
-			i+=12;
-#		endif //_DUSB>=2
-		Serial.print((char *) &line[i]);	// The rest if the buffer contains ascii
-		Serial.println();
+	if ((debug>=1) && (pdebug & P_RX)) {
+		char s[256];
+		i+=12;									// First 12 chars are non printable
+		sprintf(s, "addLog:: fileno=%d, rec=%d : %s",gwayConfig.logFileNo,gwayConfig.logFileRec,&line[i]);
+		mPrint(s);
 	}
 #	endif //_MONITOR
 
-	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
 	//	f.print(line[i],HEX);
 		f.print('*');
 	}
-	f.write(&(line[i]), cnt-12);			// write/append the line to the file
+	f.print(now());
+	f.print(':');
+	f.write(&(line[i]), cnt-12);				// write/append the line to the file
 	f.print('\n');
-	f.close();								// Close the file after appending to it
+	
+	f.close();									// Close the file after appending to it
 
-#	endif //_STAT_LOG
+#endif //_STAT_LOG
+
+	gwayConfig.logFileRec++;
 
 	return(1);
 } //addLog()
@@ -480,7 +503,7 @@ int addLog(const unsigned char * line, int cnt)
 
 // ----------------------------------------------------------------------------
 // initSeen
-// Init the lisrScreen array
+// Init the listScreen array
 // Return:
 //	1: Success
 // Parameters:
@@ -488,8 +511,8 @@ int addLog(const unsigned char * line, int cnt)
 // ----------------------------------------------------------------------------
 int initSeen(struct nodeSeen *listSeen) 
 {
-#if _MAXSEEN >= 1
-	for (int i=0; i< _MAXSEEN; i++) {
+#if _MAXSEEN>=1
+	for (int i=0; i< gwayConfig.maxSeen; i++) {
 		listSeen[i].idSeen=0;
 		listSeen[i].sfSeen=0;
 		listSeen[i].cntSeen=0;
@@ -497,7 +520,7 @@ int initSeen(struct nodeSeen *listSeen)
 		listSeen[i].timSeen=(time_t) 0;					// 1 jan 1970 0:00:00 hrs
 	}
 	iSeen= 0;											// Init index to 0
-#endif // _MAXSEEN
+#endif //_MAXSEEN
 	return(1);
 
 } // initSeen()
@@ -515,7 +538,7 @@ int initSeen(struct nodeSeen *listSeen)
 // ----------------------------------------------------------------------------
 int readSeen(const char *fn, struct nodeSeen *listSeen)
 {
-#if _MAXSEEN >= 1
+#if _MAXSEEN>=1
 	int i;
 	iSeen= 0;												// Init the index at 0
 	
@@ -537,7 +560,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 
 	delay(1000);
 	
-	for (i=0; i<_MAXSEEN; i++) {
+	for (i=0; i<gwayConfig.maxSeen; i++) {
 		delay(200);
 		String val="";
 		
@@ -562,7 +585,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 	}
 	f.close();
 
-#endif // _MAXSEEN
+#endif //_MAXSEEN
 
 	// So we read iSeen records
 	return 1;
@@ -581,7 +604,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 // ----------------------------------------------------------------------------
 int writeSeen(const char *fn, struct nodeSeen *listSeen)
 {
-#if _MAXSEEN >= 1
+#if _MAXSEEN>=1
 	int i;
 	if (!SPIFFS.exists(fn)) {
 #		if _MONITOR>=1
@@ -608,9 +631,10 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen)
 	}
 	
 	f.close();
-#endif // _MAXSEEN
+#endif //_MAXSEEN
 	return(1);
-}
+	
+} //writeseen()
 
 
 
@@ -629,7 +653,7 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen)
 // ----------------------------------------------------------------------------
 int addSeen(struct nodeSeen *listSeen, struct stat_t stat) 
 {
-#if _MAXSEEN >= 1
+#if _MAXSEEN>=1
 	int i;
 	for (i=0; i<iSeen; i++) {						// For all known records
 
@@ -654,8 +678,8 @@ int addSeen(struct nodeSeen *listSeen, struct stat_t stat)
 		}
 	}
 	
-	// else: We did not find the current record so make a new Seen entry
-	if ((i>=iSeen) && (i<_MAXSEEN)) {
+	// else: We did not find the current record so make a new listSeen entry
+	if ((i>=iSeen) && (i<gwayConfig.maxSeen)) {
 		listSeen[i].idSeen = stat.node;
 		listSeen[i].chnSeen = stat.ch;
 		listSeen[i].sfSeen = stat.sf;				// The SF argument
@@ -679,11 +703,11 @@ int addSeen(struct nodeSeen *listSeen, struct stat_t stat)
 
 		mPrint(response);
 	}
-#	endif // _MONITOR
+#	endif //_MONITOR
 
 #endif //_MAXSEEN>=1 
 	return 1;
 	
-} // addSeen()
+} //addSeen()
 
 // End of File

+ 24 - 16
src/_loraModem.ino

@@ -196,7 +196,7 @@ void setRate(uint8_t sf, uint8_t crc)
 
 	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));
 		}
 #		endif //_MONITOR
@@ -351,7 +351,7 @@ void hop()
 	// the hop function until printed below
 	//
 #	if _MONITOR>=1
-	if (( debug>=2 ) && ( pdebug & P_RADIO )){
+	if ((debug>=2) && (pdebug & P_RADIO)){
 			String response = "hop:: hopTime:: " + String(micros() - hopTime);
 			mStat(0, response);
 			mPrint(response);
@@ -413,7 +413,7 @@ uint8_t receivePkt(uint8_t *payload)
     if (irqflags & IRQ_LORA_CRCERR_MASK)								// Is CRC error?
     {
 #		if _MONITOR>=1
-        if (( debug>=0) && ( pdebug & P_RADIO )) {
+        if ((debug>=0) && (pdebug & P_RADIO)) {
 			String response=("rxPkt:: Err CRC, t=");
 			stringTime(now(), response);
 			mPrint(response);
@@ -428,7 +428,7 @@ uint8_t receivePkt(uint8_t *payload)
 	else if ((irqflags & IRQ_LORA_HEADER_MASK) == false)				// Header not ok?
     {
 #		if _MONITOR>=1
-			if (( debug>=0) && ( pdebug & P_RADIO )) {
+			if ((debug>=0) && (pdebug & P_RADIO)) {
 				mPrint("rxPkt:: Err HEADER");
 			}
 #		endif //_MONITOR
@@ -448,8 +448,8 @@ uint8_t receivePkt(uint8_t *payload)
 		}
 
 		if (readRegister(REG_FIFO_RX_CURRENT_ADDR) != readRegister(REG_FIFO_RX_BASE_AD)) {
-#if			_MONITOR>=1
-			if (( debug>=1 ) && ( pdebug & P_RADIO )) {
+#		if _MONITOR>=1
+			if ((debug>=1) && (pdebug & P_RADIO)) {
 				mPrint("RX BASE <" + String(readRegister(REG_FIFO_RX_BASE_AD)) + "> != RX CURRENT <" + String(readRegister(REG_FIFO_RX_CURRENT_ADDR)) + ">"	);
 			}
 #			endif //_MONITOR
@@ -467,7 +467,7 @@ uint8_t receivePkt(uint8_t *payload)
 
 		if (receivedCount > PAYLOAD_LENGTH) {
 #			if _MONITOR>=1
-				if (( debug>=0 ) & ( pdebug & P_RADIO )) {
+				if ((debug>=0) & (pdebug & P_RADIO)) {
 					mPrint("rxPkt:: ERROR Payliad receivedCount="+String(receivedCount));
 				}
 #			endif //_MONITOR
@@ -484,7 +484,7 @@ uint8_t receivePkt(uint8_t *payload)
 		// As long as _MONITOR is enabled, and P_RX debug messages are selected,
 		// the received packet is displayed on the output.
 #		if _MONITOR>=1
-		if ((debug>=1) && (pdebug & P_RX)){
+		if ((debug>=1) && (pdebug & P_RX)) {
 		
 			String response = "UP receivePkt:: rxPkt: t=";
 			stringTime(now(), response);
@@ -517,7 +517,7 @@ uint8_t receivePkt(uint8_t *payload)
 					mPrint(", Ind="+String(index));
 				}
 				else if (debug>=1) {	
-					mPrint(", ERRRO No Index");
+					mPrint(", ERROR No Index");
 					return(receivedCount);
 				}	
 
@@ -557,11 +557,11 @@ uint8_t receivePkt(uint8_t *payload)
 					Serial.print(' ');
 				}
 			}
-#			endif // _TRUSTED_DECODE
+#			endif //_TRUSTED_DECODE
 			
 			mPrint(response);							// Print response for Serial or mPrint
 		}
-#		endif //MONITOR
+#		endif //_MONITOR
 		return(receivedCount);
     }
 
@@ -628,22 +628,30 @@ bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 
 void loraWait(struct LoraDown *LoraDown)
 {
+	if (LoraDown->imme == 1) {
+		if ((debug>=1) && (pdebug & P_TX)) {
+			mPrint("loraWait:: imme is 1");
+		}
+		return;
+	}
+	
 	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 ((delayTmst > 8000000) || (delayTmst < 0)) {		// Delay is  > 8 secs
 #		if _MONITOR>=1
+		if (delayTmst > 8000000) {
 			String response= "Dwn loraWait:: ERROR: ";
 			printDwn(LoraDown,response);
 			mPrint(response);
-#		endif // _MONITOR
+		}
+#		endif //_MONITOR
 		gwayConfig.waitErr++;
 		return;
 	}
 
 	// For larger delay times we use delay() since that is for > 15ms
 	// This is the most efficient way.
-	// MMM Check for huge wait times
 	while (delayTmst > 15000) {
 		delay(15);										// ms delay including yield, slightly shorter
 //		delayMicroseconds(15000);						// ms delay including yield, slightly shorter
@@ -754,7 +762,7 @@ void txLoraModem(struct LoraDown *LoraDown)
 	opmode(OPMODE_TX);											// set 0x01 to 0x03 (actual value becomes 0x83)
 
 #	if _MONITOR>=1
-	if (( debug>=1 ) && ( pdebug & P_TX )) {
+	if ((debug>=1) && (pdebug & P_TX)) {
 		String response = "Dwn txLoraModem:: end: ";
 		printDwn(LoraDown, response);
 		mPrint(response);
@@ -1045,7 +1053,7 @@ void startReceiver()
 	initLoraModem();								// XXX 180326, after adapting this function 
 	if (gwayConfig.cad) {
 #		if _DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_SCAN )) {
+		if ((debug>=1) && (pdebug & P_SCAN)) {
 			Serial.println(F("S PULL:: _state set to S_SCAN"));
 			if (debug>=2) Serial.flush();
 		}

+ 6 - 6
src/_oLED.ino

@@ -61,7 +61,7 @@ void acti_oLED()
 #if _OLED>=1
 	// Initialising the UI will init the display too.
 	display.clear();
-	
+
 # if _OLED==1
 	display.setFont(ArialMT_Plain_16);
 	display.drawString(0, 0, "READY,  SSID=");
@@ -74,11 +74,11 @@ void acti_oLED()
 	display.drawString(0, 16, WiFi.SSID());
 	display.drawString(0, 32, "IP=");
 	display.drawString(0, 48, WiFi.localIP().toString().c_str() );
-# endif
+# endif //_OLED
 
 	display.display();
-	
-#endif // _OLED
+
+#endif //_OLED
 	delay(4000);
 }
 
@@ -99,7 +99,7 @@ void msg_oLED(String mesg)
 
     display.display();
 	yield();
-#endif // _OLED
+#endif //_OLED
 }
 
 // Print a larger Oled message consisting of two strings
@@ -117,7 +117,7 @@ void msg_lLED(String mesg, String mesg2)
 	
     display.display();
 	yield();
-#endif // _OLED
+#endif //_OLED
 }
 
 // --------------------------------------------------------------------

+ 20 - 20
src/_sensor.ino

@@ -154,11 +154,11 @@ int LoRaSensors(uint8_t *buf) {
 			}
 			// Raw coding of LoRa messages to server so add the GPS data raw to the string
 #			if _MONITOR>=1
-			if ((debug>=1) && ( pdebug & P_MAIN )){
+			if ((debug>=1) && (pdebug & P_MAIN)){
 				mPrint("Gps raw:: lat="+String(gps.location.lat())+", lng="+String(gps.location.lng())+", alt="+String(gps.altitude.feet()/3.2808)+", sats="+String(gps.satellites.value()) );
 				//mPrint("Gps raw:: sizeof double="+String(sizeof(double)) );
 			}
-#			endif // _MONITOR
+#			endif //_MONITOR
 			// Length of lat and lng is double
 			double lat = gps.location.lat();
 			double lng = gps.location.lng();
@@ -181,7 +181,7 @@ int LoRaSensors(uint8_t *buf) {
 			memcpy((buf+tchars), &volts, sizeof(float)); tchars += sizeof(float);
 			
 #			if _MONITOR>=1
-			if ((debug>=1) && ( pdebug & P_MAIN )){
+			if ((debug>=1) && (pdebug & P_MAIN)){
 				mPrint("Battery raw="+String(volts));
 			}
 #			endif //_MONITOR
@@ -196,7 +196,7 @@ int LoRaSensors(uint8_t *buf) {
 
 // GENERAL part
 #	if _DUSB>=1 && _GPS==1
-	if (( debug>=2 ) && ( pdebug & P_MAIN )) {
+	if ((debug>=2) && (pdebug & P_MAIN)) {
 		Serial.print("GPS sensor");
 		Serial.print("\tLatitude  : ");
 		Serial.println(gps.location.lat(), 5);
@@ -552,7 +552,7 @@ int sensorPacket() {
 	uint8_t PayLength = LoRaSensors((uint8_t *)(LUP.payLoad + LUP.payLength));
 
 #if _DUSB>=1
-	if ((debug>=2) && (pdebug & P_RADIO )) {
+	if ((debug>=2) && (pdebug & P_RADIO)) {
 		String response="";
 		Serial.print(F("old: "));
 		for (int i=0; i<PayLength; i++) {
@@ -567,7 +567,7 @@ int sensorPacket() {
 	uint8_t CodeLength = encodePacket((uint8_t *)(LUP.payLoad + LUP.payLength), PayLength, (uint16_t)frameCount, DevAddr, AppSKey, 0);
 
 #if _DUSB>=1
-	if ((debug>=2) && (pdebug & P_RADIO )) {
+	if ((debug>=2) && (pdebug & P_RADIO)) {
 		Serial.print(F("new: "));
 		for (int i=0; i<CodeLength; i++) {
 			Serial.print(LUP.payLoad[i],HEX);
@@ -588,7 +588,7 @@ int sensorPacket() {
 	LUP.payLength += micPacket((uint8_t *)(LUP.payLoad), LUP.payLength, (uint16_t)frameCount, NwkSKey, 0);
 
 #if _DUSB>=1
-	if ((debug>=2) && (pdebug & P_RADIO )) {
+	if ((debug>=2) && (pdebug & P_RADIO)) {
 		Serial.print(F("mic: "));
 		for (int i=0; i<LUP.payLength; i++) {
 			Serial.print(LUP.payLoad[i],HEX);
@@ -608,7 +608,7 @@ int sensorPacket() {
 	frameCount++;
 	statc.msg_ttl++;					// XXX Should we count sensor messages as well?
 	statc.msg_sens++;
-	switch(gwayConfig.ch) {			// MMM remove when possible
+	switch(gwayConfig.ch) {
 		case 0: statc.msg_sens_0++; break;
 		case 1: statc.msg_sens_1++; break;
 		case 2: statc.msg_sens_2++; break;
@@ -619,7 +619,7 @@ int sensorPacket() {
 	// 10 value when restarting the gateway.
 	// NOTE: This means that preferences are NOT saved unless >=10 messages have been received.
 	//
-	if ((frameCount % 10)==0) writeGwayCfg(CONFIGFILE, &gwayConfig );
+	if ((frameCount % 10)==0) writeGwayCfg(_CONFIGFILE, &gwayConfig );
 	
 	if (buff_index > 512) {
 		if (debug>0) 
@@ -642,7 +642,7 @@ int sensorPacket() {
 #if _DUSB>=1
 	// If all is right, we should after decoding (which is the same as encoding) get
 	// the original message back again.
-	if ((debug>=2) && (pdebug & P_RADIO )) {
+	if ((debug>=2) && (pdebug & P_RADIO)) {
 		CodeLength = encodePacket((uint8_t *)(LUP.payLoad + 9), PayLength, (uint16_t)frameCount-1, DevAddr, AppSKey, 0);
 		Serial.print(F("rev: "));
 		for (int i=0; i<CodeLength; i++) {
@@ -656,7 +656,7 @@ int sensorPacket() {
 		}
 		Serial.println();
 	}
-#endif // _DUSB
+#endif //_DUSB
 
 	if (gwayConfig.cad) {
 		// Set the state to CAD scanning after sending a packet
@@ -704,15 +704,15 @@ int sensorPacket() {
 uint8_t encodePacket(uint8_t *Data, uint8_t DataLength, uint16_t FrameCount, uint8_t *DevAddr, uint8_t *AppSKey, uint8_t Direction)
 {
 
-#if _DUSB>=1
-	if (( debug>=2 ) && ( pdebug & P_GUI )) {
-		Serial.print(F("G encodePacket:: DevAddr="));
-		for (int i=0; i<4; i++ ) { Serial.print(DevAddr[i],HEX); Serial.print(' '); }
-		Serial.print(F("G encodePacket:: AppSKey="));
-		for (int i=0; i<16; i++ ) { Serial.print(AppSKey[i],HEX); Serial.print(' '); }
-		Serial.println();
+#if _MONITOR>=1
+	if ((debug>=2) && (pdebug & P_MAIN)) {
+		String response="encodePacket:: DevAddr=";
+		for (int i=0; i<4; i++ ) { response+=(String(DevAddr[i],HEX)+(' ')); }
+		response+=", encodePacket:: AppSKey=";
+		for (int i=0; i<16; i++ ) { response+=(String(AppSKey[i],HEX)+(' ')); }
+		mPrint(response);
 	}
-#endif // _DUSB
+#endif //_MONITOR
 
 	//unsigned char AppSKey[16] = _APPSKEY ;	// see configGway.h
 	uint8_t i, j;
@@ -762,4 +762,4 @@ uint8_t encodePacket(uint8_t *Data, uint8_t DataLength, uint16_t FrameCount, uin
 	return(DataLength);				// or only 16*(numBlocks-1)+bLen;
 }
 
-#endif // _GATEWAYNODE || _LOCALSERVER
+#endif //_GATEWAYNODE || _LOCALSERVER

+ 23 - 23
src/_stateMachine.ino

@@ -320,7 +320,7 @@ void stateMachine()
 			if (rssi > (RSSI_LIMIT - (gwayConfig.hop * 7)))		// Is set to 35, or 29 for HOP
 			{
 #				if _MONITOR>=1
-				if (( debug>=2 ) && ( pdebug & P_SCAN )) {
+				if ((debug>=2) && (pdebug & P_SCAN)) {
 					String response = "SCAN:: -> CAD: ";
 					mStat(intr, response);
 					mPrint(response);
@@ -334,7 +334,7 @@ void stateMachine()
 			// and go back to scanning
 			else {
 #				if _MONITOR>=1
-				if (( debug>=2 ) && ( pdebug & P_SCAN )) {
+				if ((debug>=2) && (pdebug & P_SCAN)) {
 					String response = "SCAN:: rssi=";
 					response += String(rssi);
 					response += ": ";
@@ -376,7 +376,7 @@ void stateMachine()
 		//
 		else {
 #			if _MONITOR>=1
-			if (( debug>=0 ) && ( pdebug & P_SCAN )) {
+			if ((debug>=0) && (pdebug & P_SCAN)) {
 				String response = "SCAN unknown:: ";
 				mStat(intr, response);
 				mPrint(response);
@@ -480,7 +480,7 @@ void stateMachine()
 				rssi = readRegister(REG_RSSI);						// Read the RSSI
 
 #				if _MONITOR>=1
-				if (( debug>=3 ) && ( pdebug & P_CAD )) {
+				if ((debug>=3) && (pdebug & P_CAD)) {
 					mPrint("S_CAD:: CDONE, SF=" + String(sf) );
 				}
 #				endif //_MONITOR
@@ -501,7 +501,7 @@ void stateMachine()
 				cadScanner();										// Which will reset SF to lowest SF
 
 #				if _MONITOR>=1		
-				if (( debug>=3 ) && ( pdebug & P_CAD )) {
+				if ((debug>=3) && (pdebug & P_CAD)) {
 					mPrint("CAD->SCAN:: " + String(intr) );
 				}
 #				endif //_MONITOR
@@ -518,7 +518,7 @@ void stateMachine()
 		//
 		else if (intr == 0x00) {
 #			if _MONITOR>=1
-			if (( debug>=3 ) && ( pdebug & P_CAD )) {
+			if ((debug>=3) && (pdebug & P_CAD)) {
 				mPrint ("CAD:: intr is 0x00");
 			}
 #			endif //_MONITOR
@@ -666,7 +666,7 @@ void stateMachine()
 			//
 			if (receivePacket() <= 0) {								// read is not successful
 #				if _MONITOR>=1
-				if (( debug>=0 ) && ( pdebug & P_RX )) {
+				if ((debug>=0) && (pdebug & P_RX)) {
 					mPrint("sMach:: ERROR receivePacket");
 				}
 #				endif //_MONITOR
@@ -711,7 +711,7 @@ void stateMachine()
 			if ((gwayConfig.cad) || (gwayConfig.hop)) {
 				// Set the state to CAD scanning
 #				if _MONITOR>=1
-				if (( debug>=2 ) && ( pdebug & P_RX )) {
+				if ((debug>=2) && (pdebug & P_RX)) {
 					String response = "RXTOUT:: ";
 					mStat(intr, response);
 					mPrint(response);
@@ -764,7 +764,7 @@ void stateMachine()
 		// as HEADER interrupt comes just before RXDONE
 		else {							
 #			if _MONITOR>=1
-			if (( debug>=0 ) && ( pdebug & P_RX )) {
+			if ((debug>=0) && (pdebug & P_RX)) {
 				mPrint("R S_RX:: no RXDONE, RXTOUT, HEADER:: " + String(intr));
 			}
 #			endif //_MONITOR
@@ -789,13 +789,19 @@ void stateMachine()
 		// we have a timeout in the main program (Keep Alive)
 		if (intr == 0x00) {
 #			if _MONITOR>=1
-			if (( debug>=2 ) && ( pdebug & P_TX )) {
+			if ((debug>=2) && (pdebug & P_TX)) {
 				mPrint("TX:: 0x00");
 			}
 #			endif //_MONITOR
 			_event= 1;
 		}
 
+#		if _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_MAIN)) {
+			mPrint("TX stateMachine:: calling loraWait");
+		}
+#		endif
+
 		loraWait(&LoraDown);
 	
 		// Set state to transmit
@@ -813,7 +819,7 @@ void stateMachine()
 		_event=1;													// Or remove the break below
 
 #		if _MONITOR>=1
-		if (( debug>=1 ) && ( pdebug & P_TX )) {
+		if ((debug>=1) && (pdebug & P_TX)) {
 			String response="TX fini:: ";
 			mStat(intr, response);
 			mPrint(response); 
@@ -835,11 +841,11 @@ void stateMachine()
 		if (intr & IRQ_LORA_TXDONE_MASK) {
 
 #			if _MONITOR>=1
-			if (( debug>=1 ) && ( pdebug & P_TX )) {
-				String response =  "Dwns TXDONE:: OK: rcvd=";
+			if ((debug>=1) && (pdebug & P_TX)) {
+				String response =  "Dwn stateMachine: TXDONE OK: rcvd=";
 				printInt(micros(),response);
 				if (micros() < LoraDown.tmst) {
-					response += ", diff=-" ;
+					response += ", diff=- " ;
 					printInt(LoraDown.tmst - micros(), response );
 				}
 				else {
@@ -865,18 +871,12 @@ void stateMachine()
 			_event=0;
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset interrupt flags
-			
-#			if _MONITOR>=1
-			if (( debug>=2 ) && ( pdebug & P_TX )) {
-				mPrint("TXDONE:: done OK");
-			}
-#			endif //_MONITOR
 		}
 		
 		// If a soft _event==0 interrupt and no transmission finished:
 		else if ( intr != 0 ) {
 #			if _MONITOR>=1
-			if (( debug>=0 ) && ( pdebug & P_TX )) {
+			if ((debug>=0) && (pdebug & P_TX)) {
 				String response =  "TXDONE:: Error unknown intr=";
 				mStat(intr, response);
 				mPrint(response);
@@ -897,7 +897,7 @@ void stateMachine()
 			if ( sendTime > micros() ) sendTime = 0;				// This could be omitted for usigned ints
 			if (( _state == S_TXDONE ) && (( micros() - sendTime) > 7000000 )) {
 #				if _MONITOR>=1
-				if (( debug>=1 ) && ( pdebug & P_TX )) {
+				if ((debug>=1) && (pdebug & P_TX)) {
 					mPrint("TXDONE:: reset TX");
 				}
 #				endif //_MONITOR
@@ -915,7 +915,7 @@ void stateMachine()
 	  // make sure that we pick up next interrupt
 	  default:
 #		if _MONITOR>=1
-		if (( debug>=0) && ( pdebug & P_PRE )) {
+		if ((debug>=0) && (pdebug & P_PRE)) {
 			mPrint("ERR state=" + String(_state));	
 		}
 #		endif //_MONITOR

+ 1 - 1
src/_tcpTTN.ino

@@ -62,4 +62,4 @@ int sendTtn(IPAddress server, int port, uint8_t *msg, int length) {
 
 
 
-#endif// _TTNROUTER
+#endif //_TTNROUTER

+ 55 - 95
src/_txRx.ino

@@ -20,7 +20,7 @@
 
 // ------------------------------- DOWN ----------------------------------------
 //
-// Send DOWN a LoRa packet over the air to the node. This function does all the 
+// Prepare DOWN a LoRa packet in down buffer. This function does all the 
 // decoding of the server message and prepares a Payload buffer.
 // The payload is actually transmitted by the sendPkt() function.
 // This function is used for regular downstream messages and for JOIN_ACCEPT
@@ -43,6 +43,7 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	// size	: 21
 	// tmst : 1800642 									// for example
 	// datr	: "SF7BW125"
+	// imme :											// Immediately transfer
 	
 	// 12-byte header;
 	//		HDR (1 byte)
@@ -56,13 +57,12 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	//		CFList (fill to 16 bytes)
 			
 	int i=0;
-	//StaticJsonDocument<312> jsonBuffer;							// Use of arduinoJson version 6!
 	char * bufPtr = (char *) (buf);
 	buf[length] = 0;
 	
 #	if _MONITOR>=1
-	if (( debug>=2) && (pdebug & P_TX)) {
-		mPrint("Dwn sendPacket:: " + String((char *)buf) + "< ");
+	if (( debug>=1) && (pdebug & P_TX)) {
+		mPrint("Dwn sendPacket:: " + String((char *)buf));
 	}
 #	endif //_MONITOR
 
@@ -89,19 +89,20 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	const char * data	= root["txpk"]["data"];			// Downstream Payload
 	uint8_t psize		= root["txpk"]["size"];			// Payload size
 	bool ipol			= root["txpk"]["ipol"];
-//	uint8_t powe		= root["txpk"]["powe"];			// power, e.g. 14 or 27
-	
-	// Not used in the protocol of Gateway TTN:
+
 	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"
-	//if (root["txpk"].containsKey("imme") ) {
-	//	const bool imme = root["txpk"]["imme"];			// Immediate Transmit (tmst don't care)
-	//}
+	if (root["txpk"].containsKey("imme") ) {
+		LoraDown.imme = root["txpk"]["imme"];			// Immediate Transmit (tmst don't care)
+	}
+	if (root["txpk"].containsKey("powe") ) {
+		uint8_t powe	= root["txpk"]["powe"];			// power, e.g. 14 or 27
+	}
 
 	if ( data != NULL ) {
 #		if _MONITOR>=1
-		if (( debug>=2 ) && ( pdebug & P_TX )) { 
+		if ((debug>=2) && (pdebug & P_TX)) { 
 			mPrint("sendPacket:: data=" + String(data)); 
 		}
 #		endif //_MONITOR
@@ -138,33 +139,6 @@ int sendPacket(uint8_t *buf, uint8_t length)
 
 	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, 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)
-	}
-	
-	else {
-#		if _MONITOR>=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 //_MONITOR
-		// And do not convert the down SF.
-	}
 
 #else
 // elif _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
@@ -178,6 +152,7 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	const float ff	= root["txpk"]["freq"];				// eg 869.525
 	// convert double frequency (MHz) into uint32_t frequency in Hz.
 	LoraDown.freq = (uint32_t) ((uint32_t)((ff+0.000035)*1000)) * 1000;
+
 #endif //_STRICT_1CH
 
 	yield();
@@ -185,10 +160,10 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	LoraDown.payLoad = payLoad;				
 
 #	if _MONITOR>=1
-	if (( debug>=2 ) && ( pdebug & P_TX)) {
+	if ((debug>=2) && (pdebug & P_TX)) {
 		mPrint("Dwn sendPacket:: TX tmst=" + String(LoraDown.tmst));
 	}
-#	endif // _MONITOR
+#	endif //_MONITOR
 
 	if (LoraDown.payLength != psize) {
 #		if _MONITOR>=1
@@ -198,7 +173,7 @@ int sendPacket(uint8_t *buf, uint8_t length)
 #		endif //_MONITOR
 	}
 #	if _MONITOR>=1
-	else if (( debug >= 2 ) && ( pdebug & P_TX )) {
+	else if ((debug >= 2) && (pdebug & P_TX)) {
 		Serial.print(F("T Payload="));
 		for (i=0; i<LoraDown.payLength; i++) {
 			Serial.print(payLoad[i],HEX); 
@@ -219,13 +194,7 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	// All data is in Payload and parameters and need to be transmitted.
 	// The function is called in user-space
 	_state = S_TX;										// _state set to transmit
-	
-#	if _MONITOR>=1
-	if ((debug>=2) && ( pdebug & P_TX)) {
-		mPrint("sendPacket:: STRICT=" + String(_STRICT_1CH) );
-	}
-#	endif //_MONITOR
-	
+
 	return 1;
 } //sendPacket DOWN
 
@@ -262,7 +231,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 #if _CHECK_MIC==1
 	unsigned char NwkSKey[16] = _NWKSKEY;
 	checkMic(message, messageLength, NwkSKey);
-#endif // _CHECK_MIC
+#endif //_CHECK_MIC
 
 	// Read SNR and RSSI from the register. Note: Not for internal sensors!
 	// For internal sensor we fake these values as we cannot read a register
@@ -282,7 +251,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	// and fill the new top line with the latest received sensor values.
 	// This works fine for the sensor, EXCEPT when we decode data for _LOCALSERVER
 	//
-	for (int m=( _MAXSTAT -1); m>0; m--) statr[m]=statr[m-1];
+	for (int m=( gwayConfig.maxStat -1); m>0; m--) statr[m]=statr[m-1];
 	
 	// From now on we can fill statr[0] with sensor data
 #if _LOCALSERVER==1
@@ -336,7 +305,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 		case SF11: statc.sf11++; break;
 		case SF12: statc.sf12++; break;
 	}
-#endif // _STATISTICS >= 2
+#endif //_STATISTICS >= 2
 
 
 
@@ -381,7 +350,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 #endif //_STATISTICS >= 2
 
 #if _MONITOR>=1	
-	if (( debug>=2 ) && ( pdebug & P_RADIO )){
+	if ((debug>=2) && (pdebug & P_RADIO)) {
 		Serial.print(F("R buildPacket:: pRSSI="));
 		Serial.print(prssi-rssicorr);
 		Serial.print(F(" RSSI: "));
@@ -399,7 +368,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 		Serial.println();
 		yield();										// only if debug>=2
 	}
-#endif // _MONITOR
+#endif //_MONITOR
 
 // Show received message status on Oled display
 #if _OLED>=1
@@ -430,7 +399,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
     display.drawString(40, 48, String((int)messageLength) );
     display.display();
 
-#endif // _OLED>=1
+#endif //_OLED>=1
 			
 //	int j;
 	
@@ -444,7 +413,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 		mPrint("R buildPacket:: b64 err, len=" + String(encodedLen));
 		return(-1);
 	}
-#	endif // _MONITOR
+#	endif //_MONITOR
 
 	base64_encode(b64, (char *) message, messageLength);// max 341
 	// start composing datagram with the header 
@@ -480,16 +449,15 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 #ifdef _JSONENCODE
 //------------------
 	StaticJsonDocument<400> doc;
-	// MMM Get rid of this code when ready
 	
-	//doc["time"] = "";
+	//doc["time"] = ""+now();
 
 	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["datr"] = "SF" + String(LoraUp->sf) + "BW" + String(freqs[gwayConfig.ch].upBW);
 	doc["rssi"] = "" +(prssi-rssicorr);
 	doc["lsnr"] = "" +(long)SNR;
 	doc["codr"] = "4/5";
@@ -506,7 +474,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	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
+#else //_JSONENCODE undefined, 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 */
@@ -524,15 +492,15 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 		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);
+		, ",\"datr\":\"SF%uBW%u\",\"codr\":\"4/5\",\"lsnr\":%li,\"rssi\":%d,\"size\":%u,\"data\":\""
+		, LoraUp->sf, freqs[gwayConfig.ch].upBW, (long)SNR, prssi-rssicorr, messageLength);
 
 	// Use gBase64 library to fill in the data string
 	encodedLen = base64_enc_len(messageLength);				// max 341
 	buff_index += base64_encode((char *)(buff_up + buff_index), (char *) message, messageLength);
 
 	
-	LoraUp->tmst = (uint32_t) micros()+ _RXDELAY1; 			// MMM Correct timing with defined number,
+	LoraUp->tmst = (uint32_t) micros()+ _RXDELAY1; 			// Correct timing with defined number,
 															// https://github.com/TheThingsNetwork/lorawan-stack/issues/277
 
 	// Get rid of this code when ready	
@@ -541,7 +509,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 		TX_BUFF_SIZE-buff_index, "\",\"tmst\":%u", 
 		LoraUp->tmst);	
 
-#endif // _JSONENCODE undefined or ==0
+#endif //_JSONENCODE undefined or ==0
 // ---------------------
 
 
@@ -556,19 +524,18 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	// 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
+#	if  _MAXSEEN>=1
 		addSeen(listSeen, statr[0]);
-#	endif
+#	endif //_MAXSEEN
 
-#	if _STAT_LOG == 1	
+#	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 ((debug>=2) && (pdebug & P_RX)) {			// debug: display JSON payload
+	if ((debug>=1) && (pdebug & P_RX)) {			// debug: display JSON payload
 		mPrint("UP RXPK:: "+String((char *)(buff_up + 12))+" , length="+String(buff_index));		
 	}
 #	endif
@@ -597,25 +564,20 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 int receivePacket()
 {
 	uint8_t buff_up[TX_BUFF_SIZE]; 						// buffer to compose the upstream packet to backend server
-	
+
 	// Regular message received, see SX1276 spec table 18
 	// Next statement could also be a "while" to combine several messages received
 	// in one UDP message as the Semtech Gateway spec does allow this.
 	// XXX Bit ... Not yet supported
 
-#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
 		if (LoraUp.payLength > 0) {
 
+#			ifdef _PROFILER
+				int32_t startTime = micros();
+#			endif //_PROFILER
+
 			// externally received packet, so last parameter is false (==LoRa external)
 			// Make a buffer to transmit later
             int build_index = buildPacket(buff_up, &LoraUp, false);
@@ -642,15 +604,15 @@ int receivePacket()
 			yield();
 			Udp.flush();								// MMM 200419
 
-#ifdef _PROFILER
+#			ifdef _PROFILER
 			if ((debug>=1) && (pdebug & P_RX)) {
-				String response = "UP receivePacket:: sendUdp: micr=";
-				printInt(micros(),response);
-				response += ", tmst=";
-				printInt(LoraUp.tmst,response);
+				int32_t endTime = micros();
+				String response = "UP receivePacket:: end="; printInt(endTime,response);
+				response += ", start="; printInt(startTime, response);
+				response += ", diff=" +String(endTime-startTime) + " uSec";
 				mPrint(response);
 			}
-#endif // _PROFILER
+#			endif //_PROFILER
 
 #			ifdef _THINGSERVER
 			// Use our own defined server or a second well known server
@@ -692,9 +654,9 @@ int receivePacket()
 				DevAddr[3]= LoraUp.payLoad[1];
 				//uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
 
-#if _DUSB>=1
+#if				_DUSB>=1
 				if ((debug>=2) && (pdebug & P_RX)) {
-					Serial.print(F("R receivePacket:: Ind="));
+					Serial.print(F("UP receivePacket:: Ind="));
 					Serial.print(index);
 					Serial.print(F(", Len="));
 					Serial.print(LoraUp.payLength);
@@ -711,27 +673,25 @@ int receivePacket()
 						Serial.print(statr[0].data[i],HEX);
 						Serial.print(' ');
 					}
-					Serial.println();
 				}
-#endif //DUSB
+#				endif //_DUSB
 
 			}
 #			if _MONITOR>=1
-			else if (( debug>=2 ) && ( pdebug & P_RX )) {
+			else if ((debug>=2) && (pdebug & P_RX)) {
 					mPrint("receivePacket:: No Index");
 			}
 #			endif //_MONITOR
-#endif // _LOCALSERVER
+#endif //_LOCALSERVER
 
 			// Reset the message area
 			LoraUp.payLength = 0;
 			LoraUp.payLoad[0] = 0x00;
-			
-			
+
 			return(build_index);
         }
-		
+
 	return(0);											// failure no message read
-	
+
 }//receivePacket
 

+ 79 - 64
src/_udpSemtech.ino

@@ -101,7 +101,7 @@ int readUdp(int packetSize)
 	uint8_t buff_down[RX_BUFF_SIZE];		// Buffer for downstream
 
 	// Make sure we are connected over WiFI
-	if (WlanConnect(10) < 0) {				// MMM 200316 Every call contains yield()
+	if (WlanConnect(10) < 0) {
 #		if _MONITOR>=1
 			mPrint("Dwn readUdp:: ERROR connecting to WLAN");
 #		endif //_MONITOR
@@ -109,8 +109,6 @@ int readUdp(int packetSize)
 		return(-1);
 	}
 	
-	//yield();								// MMM 200320 Clear buffer in kernel (?)
-	
 	if (packetSize > RX_BUFF_SIZE) {
 #		if _MONITOR>=1
 			mPrint("Dwn readUdp:: ERROR package of size: " + String(packetSize));
@@ -118,8 +116,6 @@ int readUdp(int packetSize)
 		Udp.flush();
 		return(-1);
 	}
-
-	//yield();								// MMM 200406
 	
 	// We assume here that we know the originator of the message.
 	// In practice however this can be any sender!
@@ -160,7 +156,7 @@ int readUdp(int packetSize)
 		uint8_t ident= buff_down[3];
 
 #		if _MONITOR>=1
-		if ((debug>=2) && (pdebug & P_TX)) {
+		if ((debug>=3) && (pdebug & P_TX)) {
 			mPrint("Dwn readUdp:: message ident="+String(ident));
 		}
 #		endif //_MONITOR
@@ -173,23 +169,37 @@ int readUdp(int packetSize)
 		// As this function is used for downstream only, this option
 		// will never be selected but is included as a reference only
 		// Para 5.2.1, Semtech Gateway to Server Interface document
+		//	Byte 0:		Version
+		//	byte 1+2:	Token
+		//	byte 3: 	Command code (0x00)
+		//
 		case PKT_PUSH_DATA: 							// 0x00 UP
 #			if _MONITOR>=1
 			if (debug>=1) {
 				mPrint("Dwn PKT_PUSH_DATA:: size "+String(packetSize)+" From "+String(remoteIpNo.toString()));
 			}
 #			endif //_MONITOR
-			//Udp.flush();
+			Udp.flush();
 		break;
 
 
 		// 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
+		// The length of this package is 4 bytes:
+		//	byte 0:		Protol version (0x01 or 0x02)
+		//	byte 1+2:	Token copied from requestor
+		//	byte 3:		0x01, ack PKT_PUSH_ACK
+		//
 		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())); 
+				char res[128];				
+				sprintf(res, "Dwn PKT_PUSH_ACK:: size=%u, IP=%d.%d.%d.%d, port=%d ", 
+					packetSize, 
+					remoteIpNo[0], remoteIpNo[1], remoteIpNo[2],remoteIpNo[3], 
+					remotePortNo);
+				mPrint(res);
 			}
 #			endif //_MONITOR
 			//Udp.flush();
@@ -200,13 +210,14 @@ int readUdp(int packetSize)
 		// 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 ((debug>=1) && (pdebug & P_RX)) {
-				mPrint("Dwn readUdp:: PKT_PULL_DATA");
+				mPrint("Dwn PKT_PULL_DATA");
 			}
 #			endif //_MONITOR
-			Udp.flush();					// MMM 200419 Added
+			Udp.flush();								// MMM 200419 Added
 		break;
 
 
@@ -224,24 +235,14 @@ int readUdp(int packetSize)
 		case PKT_PULL_ACK:								// 0x04 DOWN
 #			if _MONITOR>=1
 			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();
-				}
+				char res[128];				
+				sprintf(res, "Dwn PKT_PULL_ACK:: size=%u, IP=%d.%d.%d.%d, port=%d ", 
+					packetSize, 
+					remoteIpNo[0], remoteIpNo[1], remoteIpNo[2],remoteIpNo[3], 
+					remotePortNo);
+				mPrint(res);
 			}
 #			endif //_MONITOR
-
 			
 			yield();			
 			
@@ -258,13 +259,14 @@ int readUdp(int packetSize)
 		//	JOIN_ACCEPT_DELAY1	5 s
 		//	JOIN_ACCEPT_DELAY2	6 s
 		// Para 5.2.5, Semtech Gateway to Server Interface document
+		// or https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT
 		//
 		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() ));
+			if ((debug>=2) && (pdebug & P_TX)) {
+				mPrint("Dwn PKT_PULL_RESP:: start sendPacket: micros="+String(micros() ));
 			}
 #			endif //_PROFILER
 
@@ -301,27 +303,14 @@ int readUdp(int packetSize)
 			// (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 (( debug>=2 ) && ( pdebug & P_TX )) {
+			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())
+				String response = "Dwn readUdp:: PKT_PULL_RESP from IP="+String(remoteIpNo.toString())
 					+", micros=" + String(micros())
 					+", wait=";
 				if (sendTime < micros()) {
@@ -330,7 +319,12 @@ int readUdp(int packetSize)
 				else {
 					response += "-" + String(sendTime - micros()) ;
 				};
-				mPrint(response);
+
+
+				response+=", stat:: ";
+				mStat(intr, response);
+				mPrint(response); 
+
 			}
 #			endif //_MONITOR
 
@@ -338,19 +332,33 @@ int readUdp(int packetSize)
 			// So, more or less start at the "case TXDONE:"  
 			_state=S_TXDONE;
 			_event=1;										// Or remove the break below
-			
-			// No break!!
 
+//			Udp.flush();									// MMM 200509 flush UDP buffer
+
+			// No break!! so next secton will be executed
+
+#		ifdef _PROFILER
+		// measure the total time for transmissioon here
+			if ((debug>=2) && (pdebug & P_TX)) {
+				mPrint("Dwn PKT_PULL_RESP:: finit: micros="+String(micros() ));
+			}
+#		endif //_PROFILER
 
 		// 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.
+		//	byte 0:		Protocol version
+		//	byte 1+2:	Port number of originator
+		//	byte 3:		Message ID TX_ACK == 0x06
+		//	byte 4-11:	Gateway ident
+		//	byte 12-:	Optional Error Data
 		//
 		case PKT_TX_ACK:									// Message id: 0x05 UP
 
 			if (buff_down[0]== 1) {
 #				if _MONITOR>=1
-				if ((debug>=1) && (pdebug & P_TX)) {
+				if ((debug>=3) && (pdebug & P_TX)) {
 					mPrint("UP readUdp:: PKT_TX_ACK: protocol version 1");
+					
 					data = buff_down + 4;
 					data[packetSize] = 0;
 				}
@@ -358,11 +366,11 @@ int readUdp(int packetSize)
 				break;										// return
 			}
 
-#			ifdef _PROFILER
-			if ((debug>=1) && (pdebug & P_TX)) {
+#			if _MONITOR>=1
+			if ((debug>=2) && (pdebug & P_TX)) {
 				mPrint("UP readUDP:: TX_ACK protocol version 2+");
 			}
-#			endif //_PROFILER
+#			endif //_MONITOR
 
 
 			// Now respond with an PKT_TX_ACK; UP 
@@ -396,7 +404,7 @@ int readUdp(int packetSize)
 			}
 			else {
 #				if _MONITOR>=1
-				if ((debug>=0) && (pdebug & P_TX)) {
+				if ((debug>=2) && (pdebug & P_TX)) {
 					mPrint("UP readUdp:: PKT_TX_ACK: micros="+String(micros()));
 				}
 #				endif //_MONITOR
@@ -437,10 +445,18 @@ int readUdp(int packetSize)
 		}
 		
 #		if _MONITOR>=1
-		if (debug>=2) {
-			String response= "Dwn readUdp:: ret="+String(packetSize)+", data=";
-			for (int i=0; i<packetSize; i++) {
-				response+= String(buff_down[i]) + " ";
+		if ((debug>=3) && (pdebug & P_TX)) {
+			String response= "Dwn readUdp:: ident="+String(ident,HEX);
+			response+= ", tmst=" + String(LoraDown.tmst);
+			response+= ", imme=" + String(LoraDown.imme);
+			response+= ", sfTx=" + String(LoraDown.sfTx);
+			response+= ", freq=" + String(LoraDown.freq);
+			if (debug>=3) {
+				if (packetSize > 4) {
+					response+= ", size=" + String(packetSize) + ", data=";
+					buff_down[packetSize] = 0;
+					response+=String((char *)(buff_down+4));
+				}
 			}
 			mPrint(response); 
 		}
@@ -472,19 +488,18 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, uint16_t length)
 	// Check whether we are conected to Wifi and the internet
 	if (WlanConnect(3) < 0) {
 #		if _MONITOR>=1
-		if ( pdebug & P_MAIN ) {
+		if (pdebug & P_MAIN) {
 			mPrint("sendUdp: ERROR not connected to WiFi");
 		}
-#		endif //_MONITOR						// MMM 200426 We removed yield() 
+#		endif //_MONITOR
 		Udp.flush();
 		return(0);
 	}
 
-	//yield();									// MMM 200327 yield not necessary
 
 	//send the update
 #	if _MONITOR>=1
-	if (( debug>=2 ) && ( pdebug & P_MAIN )) {
+	if ((debug>=2) && (pdebug & P_MAIN)) {
 		mPrint("sendUdp: WlanConnect connected to="+WiFi.SSID()+". Server IP="+ String(WiFi.localIP().toString()) );
 	}
 #	endif //_MONITOR
@@ -526,7 +541,7 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, uint16_t length)
 
 
 
-// ----------------------------------------------------------------------------
+// --------------------------------- UP ---------------------------------------
 // pullData()
 // 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
@@ -591,14 +606,14 @@ void pullData()
 		}
 		Serial.println();
 	}
-#endif // _MONITOR
+#endif //_MONITOR
 
 	return;
 	
 } // pullData()
 
 
-// ----------------------------------------------------------------------------
+// ---------------------------------- UP --------------------------------------
 // sendstat()
 // Send UP periodic status message to server even when we do not receive any
 // data. 
@@ -655,8 +670,8 @@ void sendstat()
     status_report[stat_index] = 0; 							// add string terminator, for safety
 
 #	if _MONITOR>=1
-    if (( debug>=2 ) && ( pdebug & P_MAIN )) {
-		mPrint("M stat update: <"+String(stat_index)+"> "+String((char *)(status_report+12)) );
+    if ((debug>=2) && (pdebug & P_RX)) {
+		mPrint("RX stat update: <"+String(stat_index)+"> "+String((char *)(status_report+12)) );
 	}
 #	endif //_MONITOR
 

+ 13 - 12
src/_utils.ino

@@ -130,7 +130,7 @@ void printHexDigit(uint8_t digit, String & response)
 
 
 // ----------------------------------------------------------------------------------------
-// Print to the monitor console.
+// Print one line to the monitor console array.
 // 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.
 // With initMonitor() we init the index iMoni=0;
@@ -142,7 +142,14 @@ void printHexDigit(uint8_t digit, String & response)
 // ----------------------------------------------------------------------------------------
 void mPrint(String txt) 
 {
-#	if _MONITOR>=1
+
+#	if _DUSB>=1
+	if (gwayConfig.dusbStat>=1) {
+		Serial.println(txt);								// Copy to serial when configured
+	}
+#	endif //_DUSB
+
+#if _MONITOR>=1
 	time_t tt = now();
 	
 	monitor[iMoni].txt = "";
@@ -152,18 +159,12 @@ void mPrint(String txt)
 	
 	// 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) % gwayConfig.maxMoni	;				// And goto 0 when skipping over _MAXMONITOR
 	
-#	endif //_MONITOR
+#endif //_MONITOR
 
 	return;
-}
+} //mPrint
 
 
 // ----------------------------------------------------------------------------
@@ -495,7 +496,7 @@ int SerialName(uint32_t a, String & response)
 			return(i);
 		}
 	}
-#endif // _TRUSTED_NODES
+#endif //_TRUSTED_NODES
 
 	return(-1);									// If no success OR is TRUSTED NODES not defined
 } //SerialName

+ 295 - 199
src/_wwwServer.ino

@@ -110,21 +110,22 @@ void wwwFile(String fn)
 
 	if (!SPIFFS.exists(fn)) {
 #		if _MONITOR>=1
-			mPrint("wwwFile:: ERROR: SPIFFS file not found=");
+			mPrint("wwwFile:: ERROR: SPIFFS file not found="+fn);
 #		endif //_MONITOR
 		return;
 	} 
-	
 #	if _MONITOR>=1
-	else if (debug>=2) {
-		mPrint("wwwFile:: SPIFFS Filesystem existist= " + String(fn));
+	else if (debug>=1) {
+		mPrint("wwwFile:: SPIFFS Filesystem exists= " + String(fn));
 	}
+	uint16_t readFile = 0;
 #	endif //_MONITOR
 
 #	if _MONITOR>=1
+
 	File f = SPIFFS.open(fn, "r");					// Open the file for reading
-	
-	// MMM Change LOGFILEREC to file available
+
+	// If file is available
 	while (f.available()) {
 
 		String s=f.readStringUntil('\n');
@@ -134,16 +135,20 @@ void wwwFile(String fn)
 		}
 		server.sendContent(s.substring(12));		// Skip the first 12 Gateway specific binary characters
 		server.sendContent("\n");
+
+		readFile++;
+
 		yield();
 	}
 
 	f.close();
 
 #	endif //_MONITOR
+
 #endif //_STAT_LOG
 
 	return;
-	
+
 }
 
 // --------------------------------------------------------------------------------
@@ -185,9 +190,15 @@ void buttonDocu()
 void buttonLog() 
 {
 #if _STAT_LOG == 1	
+
+	int startFile = (gwayConfig.logFileNo > LOGFILEMAX ? (gwayConfig.logFileNo - LOGFILEMAX) : 0);
 	
-	for (int i=0; i< LOGFILEMAX; i++ ) {
-		String fn = "/log-" + String(gwayConfig.logFileNo - i);
+#	if _MONITOR>=1
+		mPrint("buttonLog:: gwayConfig.logFileNo="+String(gwayConfig.logFileNo)+", LOGFILEMAX="+String(LOGFILEMAX)+", startFile="+String(startFile)+", recs="+String(gwayConfig.logFileRec) );
+#	endif //_MONITOR
+
+	for (int i=startFile; i<= gwayConfig.logFileNo; i++ ) {
+		String fn = "/log-" + String(i);
 		wwwFile(fn);									// Display the file contents in the browser
 	}
 	
@@ -216,13 +227,15 @@ static void wwwButtons()
 #	if _STAT_LOG == 1
 	response += "<a href=\"LOG\" download><button type=\"button\">Log Files</button></a>";
 #	endif //__STAT_LOG
+
 	response += "<a href=\"EXPERT\" download><button type=\"button\">" + mode + "</button></a>";
 #	if _MONITOR>=1
 	response += "<a href=\"MONITOR\" download><button type=\"button\">" +moni+ "</button></a>";
-#	endif
+#	endif //_MONITOR
+
 #	if _MAXSEEN>=1
 	response += "<a href=\"SEEN\" download><button type=\"button\">" +seen+ "</button></a>";
-#	endif
+#	endif //_MAXSEEN
 	server.sendContent(response);							// Send to the screen
 	
 	return;
@@ -255,12 +268,12 @@ static void setVariables(const char *cmd, const char *arg)
 		else if (atoi(arg) == -1) {
 			debug = (debug+3)%4;
 		}
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 	
 	if (strcmp(cmd, "CAD")==0) {									// Set -cad on=1 or off=0
 		gwayConfig.cad=(bool)atoi(arg);
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 	
 	if (strcmp(cmd, "HOP")==0) {									// Set -hop on=1 or off=0
@@ -271,14 +284,14 @@ static void setVariables(const char *cmd, const char *arg)
 			sf = SF7;
 			cadScanner();
 		}
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 	
 	// DELAY, write txDelay for transmissions
 	//
 	if (strcmp(cmd, "DELAY")==0) {									// Set delay usecs
 		gwayConfig.txDelay+=atoi(arg)*1000;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 
 	// TRUSTED, write node trusted value 
@@ -291,7 +304,7 @@ static void setVariables(const char *cmd, const char *arg)
 		else if (atoi(arg) == -1) {
 			gwayConfig.trusted = (gwayConfig.trusted -1)%4;
 		}
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 	
 	// SF; Handle Spreading Factor Settings
@@ -304,7 +317,7 @@ static void setVariables(const char *cmd, const char *arg)
 			if (sf<=SF7) sf=SF12; else sf= (sf_t)((int)sf-1);
 		}
 		rxLoraModem();												// Reset the radio with the new spreading factor
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 	
 	// FREQ; Handle Frequency  Settings
@@ -322,7 +335,7 @@ static void setVariables(const char *cmd, const char *arg)
 		}
 		setFreq(freqs[gwayConfig.ch].upFreq);
 		rxLoraModem();												// Reset the radio with the new frequency
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );						// Save configuration to file
 	}
 
 	if (strcmp(cmd, "GETTIME")==0) { 								// Get the local time
@@ -338,14 +351,14 @@ static void setVariables(const char *cmd, const char *arg)
 #if _GATEWAYNODE==1
 	if (strcmp(cmd, "NODE")==0) {									// Set node on=1 or off=0
 		gwayConfig.isNode =(bool)atoi(arg);
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 	
 	// File Counter//
 	if (strcmp(cmd, "FCNT")==0)   { 
 		frameCount=0; 
 		rxLoraModem();												// Reset the radio with the new frequency
-		writeGwayCfg(CONFIGFILE, &gwayConfig );
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );
 	}
 #endif
 	
@@ -370,12 +383,12 @@ static void setVariables(const char *cmd, const char *arg)
 		String ssid = String(AP_NAME) + "-" + String(ESP_getChipId(), HEX);
 		
 #		if _MONITOR>=1
-		if ((debug>=1) && ( pdebug & P_GUI )) {
+		if ((debug>=1) && (pdebug & P_MAIN)) {
 			mPrint("Set Variables:: ssid="+ ssid );
 		}
 #		endif //_MONITOR
 
-		// wifiManager.startConfigPortal( ssid.c_str(), AP_PASSWD );		// MMM added 23Feb
+		// wifiManager.startConfigPortal( ssid.c_str(), AP_PASSWD );
 	}
 #endif //_WIFIMANAGER
 
@@ -384,7 +397,7 @@ static void setVariables(const char *cmd, const char *arg)
 	if (strcmp(cmd, "UPDATE")==0) {
 		if (atoi(arg) == 1) {
 			updateOtaa();
-			writeGwayCfg(CONFIGFILE, &gwayConfig );
+			writeGwayCfg(_CONFIGFILE, &gwayConfig );
 		}
 	}
 #endif
@@ -392,7 +405,7 @@ static void setVariables(const char *cmd, const char *arg)
 #if _REFRESH==1
 	if (strcmp(cmd, "REFR")==0) {									// Set refresh on=1 or off=0
 		gwayConfig.refresh =(bool)atoi(arg);
-		writeGwayCfg(CONFIGFILE, &gwayConfig );						// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );					// Save configuration to file
 	}
 #endif
 
@@ -406,7 +419,7 @@ static void setVariables(const char *cmd, const char *arg)
 // --------------------------------------------------------------------------------
 static void openWebPage()
 {
-	++gwayConfig.views;									// increment number of views
+	++gwayConfig.views;											// increment number of views
 	String response="";	
 
 	server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
@@ -486,7 +499,7 @@ static void gatewaySettings()
 	response +="<tr>";
 	response +="<th class=\"thead\">Setting</th>";
 	response +="<th colspan=\"2\" style=\"background-color: green; color: white; width:120px;\">Value</th>";
-	response +="<th colspan=\"4\" style=\"background-color: green; color: white; width:100px;\">Set</th>";
+	response +="<th colspan=\"2\" style=\"background-color: green; color: white; width:100px;\">Set</th>";
 	response +="</tr>";
 	
 	bg = " background-color: ";
@@ -649,29 +662,6 @@ static void gatewaySettings()
 	response +="</tr>";
 #endif
 
-	// Time Correction DELAY
-	if (gwayConfig.expert) {
-		response +="<tr><td class=\"cell\">Time Correction (uSec)</td><td class=\"cell\" colspan=\"2\">"; 
-		response += gwayConfig.txDelay; 
-		response +="</td>";
-		response +="<td class=\"cell\"><a href=\"DELAY=-1\"><button>-</button></a></td>";
-		response +="<td class=\"cell\"><a href=\"DELAY=1\"><button>+</button></a></td>";
-		response +="</tr>";
-	}
-
-	// Reset Accesspoint
-#if _WIFIMANAGER==1
-	response +="<tr><td><tr><td>";
-	response +="Click <a href=\"/NEWSSID\">here</a> to reset accesspoint<br>";
-	response +="</td><td></td></tr>";
-#endif //_WIFIMANAGER
-
-#if _UPDFIRMWARE==1
-	// Update Firmware
-	response +="<tr><td class=\"cell\">Update Firmware</td><td colspan=\"2\"></td>";
-	response +="<td class=\"cell\" colspan=\"2\" class=\"cell\"><a href=\"/UPDATE=1\"><button>UPDATE</button></a></td></tr>";
-#endif //_UPDFIRMWARE
-
 	// Format the Filesystem
 	response +="<tr><td class=\"cell\">Format SPIFFS</td>";
 	response +=String() + "<td class=\"cell\" colspan=\"2\" >"+gwayConfig.formatCntr+"</td>";
@@ -899,7 +889,7 @@ static void messageHistory()
 	server.sendContent(response);
 
 	// PRINT NODE CONTENT
-	for (int i=0; i< _MAXSTAT; i++) {										// For every Node in the list
+	for (int i=0; i< gwayConfig.maxStat; i++) {								// For every Node in the list
 		if (statr[i].sf == 0) break;
 		
 		response = "";
@@ -933,9 +923,9 @@ static void messageHistory()
 				break;
 		}
 		
-#else // _TRUSTED_NODES
+#else //_TRUSTED_NODES
 		printHex(statr[i].node,' ',response);
-#endif // _TRUSTED_NODES
+#endif //_TRUSTED_NODES
 
 		response += "</td>";
 		
@@ -981,7 +971,7 @@ static void messageHistory()
 // --------------------------------------------------------------------------------
 static void nodeHistory() 
 {
-#	if _MAXSEEN >= 1
+#	if _MAXSEEN>=1
 	if (gwayConfig.seen) {
 		// First draw the headers
 		String response= "";
@@ -1000,7 +990,7 @@ static void nodeHistory()
 		
 		// Now start the contents
 		
-		for (int i=0; i<_MAXSEEN; i++) {
+		for (int i=0; i<gwayConfig.maxSeen; i++) {
 			if (listSeen[i].idSeen == 0)
 			{
 #				if _MONITOR>=1
@@ -1046,7 +1036,7 @@ static void nodeHistory()
 				}	
 #			else
 				printHex(listSeen[i].idSeen,' ',response);
-#			endif // _TRUSTED_NODES
+#			endif //_TRUSTED_NODES
 			
 			response += "</td>";
 			
@@ -1087,12 +1077,12 @@ void monitorData()
 		response +="<th class=\"thead\">Monitor Console</th>";
 		response +="</tr>";
 		
-		for (int i= iMoni-1+_MAXMONITOR; i>=iMoni; i--) {
-			if (monitor[i % _MAXMONITOR].txt == "-") {			// If equal to init value '-'
+		for (int i= iMoni-1+gwayConfig.maxMoni; i>=iMoni; i--) {
+			if (monitor[i % gwayConfig.maxMoni].txt == "-") {	// If equal to init value '-'
 				break;
 			}
 			response +="<tr><td class=\"cell\">" ;
-			response += String(monitor[i % _MAXMONITOR].txt);
+			response += String(monitor[i % gwayConfig.maxMoni].txt);
 			response += "</td></tr>";
 		}
 		
@@ -1168,11 +1158,11 @@ static void systemStatus()
 		response +="<table class=\"config_table\">";
 		response +="<tr>";
 		response +="<th class=\"thead\">Parameter</th>";
-		response +="<th class=\"thead\">Value</th>";
-		response +="<th colspan=\"2\" class=\"thead\">Set</th>";
+		response +="<th class=\"thead\" style=\"width:120px;\">Value</th>";
+		response +="<th colspan=\"2\" class=\"thead width:120px;\">Set</th>";
 		response +="</tr>";
 	
-		response +="<tr><td style=\"border: 1px solid black; width:120px;\">Gateway ID</td>";
+		response +="<tr><td style=\"border: 1px solid black;\">Gateway ID</td>";
 		response +="<td class=\"cell\">";	
 		if (MAC_array[0]< 0x10) response +='0'; response +=String(MAC_array[0],HEX);	// The MAC array is always returned in lowercase
 		if (MAC_array[1]< 0x10) response +='0'; response +=String(MAC_array[1],HEX);
@@ -1186,19 +1176,56 @@ static void systemStatus()
 
 		response +="<tr><td class=\"cell\">Free heap</td><td class=\"cell\">"; response+=ESP.getFreeHeap(); response+="</tr>";
 // XXX We Should find an ESP32 alternative
-#if !defined ESP32_ARCH
-		response +="<tr><td class=\"cell\">ESP speed</td><td class=\"cell\">"; response+=ESP.getCpuFreqMHz(); 
-		response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=80\"><button>80</button></a></td>";
-		response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=160\"><button>160</button></a></td>";
-		response+="</tr>";
-		response +="<tr><td class=\"cell\">ESP Chip ID</td><td class=\"cell\">"; response+=ESP.getChipId(); response+="</tr>";
-#endif
+#		if !defined ESP32_ARCH
+			response +="<tr><td class=\"cell\">ESP speed</td><td class=\"cell\">"; response+=ESP.getCpuFreqMHz(); 
+			response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=80\"><button>80</button></a></td>";
+			response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=160\"><button>160</button></a></td>";
+			response+="</tr>";
+			response +="<tr><td class=\"cell\">ESP Chip ID</td><td class=\"cell\">"; response+=ESP.getChipId(); response+="</tr>";
+#		endif
 		response +="<tr><td class=\"cell\">OLED</td><td class=\"cell\">"; response+=_OLED; response+="</tr>";
 		
-#if _STATISTICS >= 1
-		response +="<tr><td class=\"cell\">WiFi Setups</td><td class=\"cell\">"; response+=gwayConfig.wifis; response+="</tr>";
-		response +="<tr><td class=\"cell\">WWW Views</td><td class=\"cell\">"; response+=gwayConfig.views; response+="</tr>";
-#endif
+#		if _STATISTICS >= 1
+			response +="<tr><td class=\"cell\">WiFi Setups</td><td class=\"cell\">"; response+=gwayConfig.wifis; response+="</tr>";
+			response +="<tr><td class=\"cell\">WWW Views</td><td class=\"cell\">"; response+=gwayConfig.views; response+="</tr>";
+#		endif
+
+		// Time Correction DELAY
+		response +="<tr><td class=\"cell\">Time Correction (uSec)</td><td class=\"cell\">"; 
+		response += gwayConfig.txDelay; 
+		response +="</td>";
+		response +="<td class=\"cell\"><a href=\"DELAY=-1\"><button>-</button></a></td>";
+		response +="<td class=\"cell\"><a href=\"DELAY=1\"><button>+</button></a></td>";
+		response +="</tr>";
+
+		// Package Statistics List
+		response +="<tr><td class=\"cell\">Package Statistics List</td><td class=\"cell\">"; 
+		response += gwayConfig.maxStat; 
+		response +="</td>";
+		response +="<td class=\"cell\"><a href=\"MAXSTAT=-5\"><button>-</button></a></td>";
+		response +="<td class=\"cell\"><a href=\"MAXSTAT=5\"><button>+</button></a></td>";
+		response +="</tr>";
+
+		// Last Seen Statistics
+		response +="<tr><td class=\"cell\">Last Seen List</td><td class=\"cell\">"; 
+		response += gwayConfig.maxSeen; 
+		response +="</td>";
+		response +="<td class=\"cell\"><a href=\"MAXSEEN-5\"><button>-</button></a></td>";
+		response +="<td class=\"cell\"><a href=\"MAXSEEN+5\"><button>+</button></a></td>";
+		response +="</tr>";
+
+		// Reset Accesspoint
+#		if _WIFIMANAGER==1
+			response +="<tr><td><tr><td>";
+			response +="Click <a href=\"/NEWSSID\">here</a> to reset accesspoint<br>";
+			response +="</td><td></td></tr>";
+#		endif //_WIFIMANAGER
+
+#		if _UPDFIRMWARE==1
+			// Update Firmware
+			response +="<tr><td class=\"cell\">Update Firmware</td><td colspan=\"2\"></td>";
+			response +="<td class=\"cell\" colspan=\"2\" class=\"cell\"><a href=\"/UPDATE=1\"><button>UPDATE</button></a></td></tr>";
+#		endif //_UPDFIRMWARE
 
 		response +="</table>";
 		server.sendContent(response);
@@ -1307,16 +1334,44 @@ static void interruptData()
 void setupWWW() 
 {
 	server.begin();									// Start the webserver
+
+	server.on("/", []() {
+		sendWebPage("","");							// Send the webPage string
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
+	});
 	
-	// -----------------
+	// --------------------------------
+	//     BUTTONS PART
+	// --------------------------------
 	// BUTTONS, define what should happen with the buttons we press on the homepage
 	
-	server.on("/", []() {
-		sendWebPage("","");							// Send the webPage string
+	// Display Expert mode or Simple mode
+	server.on("/EXPERT", []() {
+		server.sendHeader("Location", String("/"), true);
+		gwayConfig.expert = bool(1 - (int) gwayConfig.expert) ;
+		server.send( 302, "text/plain", "");
+	});
+
+#if _MONITOR>=1
+	// Display Monitor Console or not
+	server.on("/MONITOR", []() {
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		gwayConfig.monitor = bool(1 - (int) gwayConfig.monitor) ;
+		server.send( 302, "text/plain", "");
+	});
+#endif //_MONITOR
+	
+	// Display the SEEN statistics
+	server.on("/SEEN", []() {
+		server.sendHeader("Location", String("/"), true);
+		gwayConfig.seen = bool(1 - (int) gwayConfig.seen) ;
+		server.send( 302, "text/plain", "");
 	});
 
+	// --------------------------------
+	//     GATEWAY SETTINGS PART
+	// --------------------------------
 	
 	server.on("/HELP", []() {
 		sendWebPage("HELP","");					// Send the webPage string
@@ -1324,6 +1379,47 @@ void setupWWW()
 		server.send( 302, "text/plain", "");
 	});
 
+	// Set CAD function off/on
+	server.on("/CAD=1", []() {
+		gwayConfig.cad=(bool)1;
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
+	});
+	server.on("/CAD=0", []() {
+		gwayConfig.cad=(bool)0;
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
+	});
+
+
+	// Set debug parameter
+	server.on("/DEBUG=-1", []() {				// Set debug level 0-2. Note: +3 is same as -1					
+		debug = (debug+3)%4;
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
+#		if _DUSB>=1 || _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_GUI)) {
+			mPrint("DEBUG -1: config written");
+		}
+#		endif //_DUSB _MONITOR
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
+	});
+	
+	server.on("/DEBUG=1", []() {
+		debug = (debug+1)%4;
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
+#		if _MONITOR>=1
+		if (pdebug & P_GUI) {
+			mPrint("DEBUG +1: config written");
+		}
+#		endif //_MONITOR
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
+	});
+
+
 	// Format the filesystem
 	server.on("/FORMAT", []() {
 		Serial.print(F("FORMAT ..."));
@@ -1331,19 +1427,19 @@ void setupWWW()
 		SPIFFS.format();							// Normally not used. Use only when SPIFFS corrupt
 		initConfig(&gwayConfig);					// Well known values
 		gwayConfig.formatCntr++;
-		writeConfig(CONFIGFILE, &gwayConfig);
+		writeConfig(_CONFIGFILE, &gwayConfig);
 		writeSeen( _SEENFILE, listSeen);			// Write the last time record  is Seen
 #		if _MONITOR>=1
-		if ((debug>=1) && (pdebug & P_GUI )) {
+		if ((debug>=1) && (pdebug & P_MAIN )) {
 			mPrint("www:: manual Format DONE");
 		}
 #		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	
 	
-	// Reset the statistics (th egateway function) but not the system specific things
+	// Reset the statistics (the gateway function) but not the system specific things
 	server.on("/RESET", []() {
 		mPrint("RESET");
 		startTime= now() - 1;					// Reset all timers too (-1 to avoid division by 0)
@@ -1372,7 +1468,7 @@ void setupWWW()
 #endif
 
 #	if _STATISTICS >= 1
-		for (int i=0; i< _MAXSTAT; i++) { statr[i].sf = 0; }
+		for (int i=0; i< gwayConfig.maxStat; i++) { statr[i].sf = 0; }
 #		if _STATISTICS >= 2
 			statc.sf7 = 0;
 			statc.sf8 = 0;
@@ -1382,7 +1478,6 @@ void setupWWW()
 			statc.sf12= 0;
 		
 			statc.resets= 0;
-			writeGwayCfg(CONFIGFILE, &gwayConfig );
 			
 #			if _STATISTICS >= 3
 				statc.sf7_0 = 0; statc.sf7_1 = 0; statc.sf7_2 = 0;
@@ -1392,14 +1487,15 @@ void setupWWW()
 				statc.sf11_0= 0; statc.sf11_1= 0; statc.sf11_2= 0;
 				statc.sf12_0= 0; statc.sf12_1= 0; statc.sf12_2= 0;
 #			endif //_STATISTICS==3
-
+			
 #		endif //_STATISTICS==2
 #	endif //_STATISTICS==1
-			
+
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );			
 		initSeen(listSeen);						// Clear all Seen records as well.
 		
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 	// Reset the boot counter, and other system specific counters
@@ -1415,14 +1511,14 @@ void setupWWW()
 		gwayConfig.boots = 0;					//
 		gwayConfig.reents = 0;					// Re-entrance
 		
-		writeGwayCfg(CONFIGFILE, &gwayConfig );
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );
 #if _MONITOR>=1
 		if ((debug>=2) && (pdebug & P_GUI)) {
 			mPrint("wwwServer:: BOOT: config written");
 		}
 #endif
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 	// Reboot the Gateway
@@ -1430,7 +1526,7 @@ void setupWWW()
 	server.on("/REBOOT", []() {
 		sendWebPage("",""); 					// Send the webPage string
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 		ESP.restart();
 	});
 
@@ -1438,140 +1534,117 @@ void setupWWW()
 	server.on("/NEWSSID", []() {
 		sendWebPage("NEWSSID","");				// Send the webPage string
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
-	// Set debug parameter
-	server.on("/DEBUG=-1", []() {				// Set debug level 0-2. Note: +3 is same as -1					
-		debug = (debug+3)%4;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
-#		if _DUSB>=1 || _MONITOR>=1
-		if ((debug>=1) && (pdebug & P_GUI)) {
-			mPrint("DEBUG -1: config written");
-		}
-#		endif // _DUSB _MONITOR
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	
-	server.on("/DEBUG=1", []() {
-		debug = (debug+1)%4;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
-#		if _DUSB>=1 || _MONITOR>=1
-		if ((debug>=1) && (pdebug & P_GUI)) {
-			mPrint("DEBUG +1: config written");
-		}
-#		endif //_DUSB _MONITOR
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
+
 
 	// Set PDEBUG parameter
 	//
 	server.on("/PDEBUG=SCAN", []() {			// Set debug level 0x01						
 		pdebug ^= P_SCAN;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/PDEBUG=CAD", []() {				// Set debug level 0x02						
 		pdebug ^= P_CAD;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/PDEBUG=RX", []() {				// Set debug level 0x04						
 		pdebug ^= P_RX;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/PDEBUG=TX", []() {				// Set debug level 0x08						
 		pdebug ^= P_TX;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/PDEBUG=PRE", []() {				// Set debug level 0-2						
 		pdebug ^= P_PRE;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/PDEBUG=MAIN", []() {				// Set debug level 0-2						
 		pdebug ^= P_MAIN;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/PDEBUG=GUI", []() {				// Set debug level 0-2						
 		pdebug ^= P_GUI;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/PDEBUG=RADIO", []() {			// Set debug level 0-2						
 		pdebug ^= P_RADIO;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 	
 	// Set delay in microseconds
 	server.on("/DELAY=1", []() {
 		gwayConfig.txDelay+=5000;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #		if _MONITOR>=1
 		if ((debug>=1) && (pdebug & P_GUI)) {
 			mPrint("DELAY +, config written");
 		}
 #		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/DELAY=-1", []() {
 		gwayConfig.txDelay-=5000;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #		if _MONITOR>=1
 		if ((debug>=1) && (pdebug & P_GUI)) {
 			mPrint("DELAY -, config written");
 		}
 #		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 	// Set Trusted Node Parameter
 	server.on("/TRUSTED=1", []() {
 	gwayConfig.trusted = (gwayConfig.trusted +1)%4;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #		if _MONITOR>=1
 			mPrint("TRUSTED +, config written");
 #		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/TRUSTED=-1", []() {
 		gwayConfig.trusted = (gwayConfig.trusted -1)%4;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #		if _MONITOR>=1
 			mPrint("TRUSTED -, config written");
 #		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 	// Spreading Factor setting
 	server.on("/SF=1", []() {
 		if (sf>=SF12) sf=SF7; else sf= (sf_t)((int)sf+1);
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/SF=-1", []() {
 		if (sf<=SF7) sf=SF12; else sf= (sf_t)((int)sf-1);
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 	// Set Frequency of the GateWay node
@@ -1584,45 +1657,32 @@ void setupWWW()
 #endif
 		if (gwayConfig.ch==(nf-1)) gwayConfig.ch=0; else gwayConfig.ch++;
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/FREQ=-1", []() {
 		uint8_t nf = sizeof(freqs)/sizeof(freqs[0]);	// Number of elements in array
 		if (gwayConfig.ch==0) gwayConfig.ch=(nf-1); else gwayConfig.ch--;
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
-	// Set CAD function off/on
-	server.on("/CAD=1", []() {
-		gwayConfig.cad=(bool)1;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/CAD=0", []() {
-		gwayConfig.cad=(bool)0;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
 
 	// GatewayNode
 	server.on("/NODE=1", []() {
 #if _GATEWAYNODE==1
 		gwayConfig.isNode =(bool)1;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #endif //_GATEWAYNODE
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/NODE=0", []() {
 #if _GATEWAYNODE==1
 		gwayConfig.isNode =(bool)0;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #endif //_GATEWAYNODE
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 #if _GATEWAYNODE==1	
@@ -1631,11 +1691,11 @@ void setupWWW()
 
 		frameCount=0; 
 		rxLoraModem();							// Reset the radio with the new frequency
-		writeGwayCfg(CONFIGFILE, &gwayConfig );
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );
 
 		//sendWebPage("","");						// Send the webPage string
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 #endif
 
@@ -1643,46 +1703,46 @@ void setupWWW()
 	server.on("/REFR=1", []() {					// WWW page auto refresh ON
 #if _REFRESH==1
 		gwayConfig.refresh =1;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #endif		
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/REFR=0", []() {					// WWW page auto refresh OFF
 #if _REFRESH==1
 		gwayConfig.refresh =0;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 #endif
 		server.sendHeader("Location", String("/"), true);
-		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
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/DUSB=0", []() {					// WWW page Serial Print OFF
 		gwayConfig.dusbStat =0;
-		writeGwayCfg(CONFIGFILE, &gwayConfig );	// Save configuration to file
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	
 	// Switch off/on the HOP functions
 	server.on("/HOP=1", []() {
 		gwayConfig.hop=true;
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/HOP=0", []() {
 		gwayConfig.hop=false;
 		setFreq(freqs[gwayConfig.ch].upFreq);
 		rxLoraModem();
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 #if !defined ESP32_ARCH
@@ -1690,12 +1750,12 @@ void setupWWW()
 	server.on("/SPEED=80", []() {
 		system_update_cpu_freq(80);
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 	server.on("/SPEED=160", []() {
 		system_update_cpu_freq(160);
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 #endif
 	// Display Documentation pages
@@ -1703,7 +1763,7 @@ void setupWWW()
 
 		server.sendHeader("Location", String("/"), true);
 		buttonDocu();
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
 	// Display LOGging information
@@ -1713,40 +1773,76 @@ void setupWWW()
 		mPrint("LOG button");
 #endif //_MONITOR
 		buttonLog();
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
-	
-	// Display Expert mode or Simple mode
-	server.on("/EXPERT", []() {
+
+
+	// Update the sketch. Not yet implemented
+	server.on("/UPDATE=1", []() {
+		// Future work
 		server.sendHeader("Location", String("/"), true);
-		gwayConfig.expert = bool(1 - (int) gwayConfig.expert) ;
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
-#if _MONITOR>=1
-	// Display Monitor Console or not
-	server.on("/MONITOR", []() {
+
+	// ----------------------------
+	//    SYSTEM STATUS PART    
+	// ---------------------------- 
+	server.on("/MAXSTAT=-5", []() {
+		if (gwayConfig.maxStat>5) {
+			struct stat_t * oldStat = statr;
+			gwayConfig.maxStat-=5;
+			statr = (struct stat_t *) malloc(gwayConfig.maxStat * sizeof(struct stat_t));
+			for (int i=0; i<gwayConfig.maxStat; i+=1) {
+				statr[i]=oldStat[i];
+			}
+			free(oldStat);
+		}
 		server.sendHeader("Location", String("/"), true);
-		gwayConfig.monitor = bool(1 - (int) gwayConfig.monitor) ;
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
-#endif //_MONITOR
-	
-	// Display the SEEN statistics
-	server.on("/SEEN", []() {
+	server.on("/MAXSTAT=5", []() {
+		struct stat_t * oldStat = statr;
+		gwayConfig.maxStat+=5;
+		statr = (struct stat_t *) malloc(gwayConfig.maxStat * sizeof(struct stat_t));
+		for (int i=0; i<gwayConfig.maxStat; i+=1) {
+			if (i<(gwayConfig.maxStat-5)) {
+				statr[i]=oldStat[i];
+			}
+			else {
+				statr[i].sf=0;
+			}
+		}
+		free(oldStat);
 		server.sendHeader("Location", String("/"), true);
-		gwayConfig.seen = bool(1 - (int) gwayConfig.seen) ;
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
 	});
 
-	
-	// Update the sketch. Not yet implemented
-	server.on("/UPDATE=1", []() {
-#if _OTA==1
-		updateOtaa();
-#endif
+	server.on("/MAXSEEN-5", []() {
+		if (gwayConfig.maxSeen>5) {
+			struct nodeSeen * oldSeen = listSeen;
+			gwayConfig.maxSeen-=5;
+			listSeen = (struct nodeSeen *) malloc(gwayConfig.maxSeen * sizeof(struct nodeSeen));
+			for (int i=0; i<gwayConfig.maxSeen; i+=1) {
+				listSeen[i]=oldSeen[i];
+			}
+			if (gwayConfig.maxSeen<iSeen) iSeen = gwayConfig.maxSeen;			
+			free(oldSeen);
+		}
 		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
+		server.send( 302, "text/plain", "");
+	});
+	server.on("/MAXSEEN+5", []() {
+		struct nodeSeen * oldSeen = listSeen;
+		gwayConfig.maxSeen+=5;
+		listSeen = (struct nodeSeen *) malloc(gwayConfig.maxSeen * sizeof(struct nodeSeen));
+		for (int i=0; i<gwayConfig.maxSeen; i+=1) {
+			if (i<(gwayConfig.maxSeen-5)) listSeen[i]=oldSeen[i];
+			else listSeen[i].idSeen=0;
+		}
+		free(oldSeen);
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
 	});
 
 	// -----------
@@ -1757,7 +1853,7 @@ void setupWWW()
 	// package interrupt arrives at the gateway
 #	if _MONITOR>=1
 		mPrint("WWW Server started on port " + String(_SERVERPORT) );
-#	endif // _MONITOR
+#	endif //_MONITOR
 
 	return;
 } // setupWWW
@@ -1811,5 +1907,5 @@ static void websiteFooter()
 }
 
 
-#endif // _SERVER==1
+#endif //_SERVER==1
 

+ 59 - 47
src/configGway.h

@@ -1,7 +1,8 @@
 // 1-channel LoRa Gateway for ESP32 and ESP8266
 // Copyright (c) Maarten Westenberg 2016-2020 
 
-#define VERSION "V.6.2.4.EU868; PlatformIO 200428n"
+#define VERSION "V.6.2.5.EU868; PlatformIO 200524i"
+
 //
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway and many others.
 //
@@ -61,7 +62,7 @@
 // the special screen at the GUI.
 // 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
 
 
@@ -70,8 +71,9 @@
 // 1= Keep track of messages statistics, number determined by _MAXSTAT
 // 2= Option 1 + Keep track of messages received PER each SF (default)
 // 3= See Option 2, but with extra channel info (Not used when Hopping is not selected)
-#define _STATISTICS 3
-
+#if !defined _STATISTICS
+#	define _STATISTICS 3
+#endif
 
 // Define the frequency band the gateway will listen on. Valid options are
 // EU863_870	Europe 
@@ -128,13 +130,14 @@
 // Note: DIO3 must be connected for this to work (Heltec and later Wemos gateways). 
 #define _CRCCHECK 1
 
+
 // Definitions for the admin webserver.
 // _SERVER determines whether or not the admin webpage is included in the sketch.
 // Normally, leave it in!
 #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
+#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
@@ -142,7 +145,9 @@
 // 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 
 // connect with USB.
-#define _OTA 1
+#if !defined _OTA
+#	define _OTA 1
+#endif
 
 
 // We support a few pin-out configurations out-of-the-box: HALLARD, COMPRESULT and 
@@ -172,7 +177,8 @@
 // NOTE: In all other cases, value 0 works for most gateways with CAD enabled
 #if !defined _STRICT_1CH
 #	define _STRICT_1CH 1
-#endif //_STRICT_1CH
+#endif
+
 
 //
 // Also, normally the server will respond with SF12 in the RX2 timeslot.
@@ -189,12 +195,9 @@
 // This section defines whether we use the gateway as a repeater
 // For his, we use another output channel as the channel (default==0) we are 
 // receiving the messages on.
-#define _REPEATER 0
-
-
-// Will we use Mutex or not?
-// +SPI is input for SPI, SPO is output for SPI
-#define _MUTEX 0
+#if !defined _REPEATER
+#	define _REPEATER 0
+#endif
 
 
 // Define if Oled Display is connected to I2C bus. Note that defining an Oled display does not
@@ -220,42 +223,32 @@
 #define _GATEWAYMGT 0
 
 
-// Do extensive logging to file
+// Do extensive logging to file(s)
 // Use the ESP8266 SPIFS filesystem to do extensive logging.
 // 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.
 // Of course we must store enough records to make the filesystem work
+// NOTE:
+// Please do NOT USE file logging if you are concerned about downstream timing.
+//	The status logging taken about 6 ms (6000 uSec) for each write whereas
+//	normally this is less than 100 uSecs.
 #if !defined _STAT_LOG
 #	define _STAT_LOG 0
-#endif //_STAT_LOG
+#endif
 
 
 // Set the Server Settings (IMPORTANT)
 #define _LOCUDPPORT 1700					// UDP port of gateway! Often 1700 or 1701 is used for upstream comms
 
-// Timing
-#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 _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 _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 
-// as sort of backend decoding system for local sensors which decodes
+// as sort of backend decoding system for local sensors which decodes (such as TTGO T-Beam)
 // 1: _LOCALSERVER is used
 // 0: Do not use _LOCALSERVER 
-#define _LOCALSERVER 1						// See server definitions for decodes
-
-
-// Gateway Ident definitions. Where is the gateway located?
-#define _DESCRIPTION "ESP Gateway"			// Name of the gateway
-#define _EMAIL "mw12554@hotmail.com"		// Owner
-#define _PLATFORM "ESP8266"
-#define _LAT 52.237367
-#define _LON 5.978654
-#define _ALT 14								// Altitude
+#if !defined _LOCALSERVER
+#	define _LOCALSERVER 0					// See server definitions for decodes
+#endif
 
 
 // ntp
@@ -276,11 +269,11 @@
 // NOTE: The node is switched off by default. Switch it on in the GUI
 #if !defined _GATEWAYNODE
 #	define _GATEWAYNODE 0
-#endif //_GATEWAYNODE
+#endif
 
 
 // We can put the gateway in such a mode that it will (only) recognize
-// nodes that are put in a list of trusted nodes 
+// nodes that are put in a list of trusted nodes.
 // Values:
 // 0: Do not use names for trusted Nodes
 // 1: Use the nodes as a translation table for hex codes to names (in TLN)
@@ -290,20 +283,24 @@
 #define _TRUSTED_DECODE 1
 
 
-
 // ========================================================================
 // DO NOT CHANGE BELOW THIS LINE
 // Probably do not change items below this line, only if lists or 
 // configurations on configNode.h are not large enough for example.
 // ========================================================================
 
-// Maximum number of Message History statistics records gathered. 20 is a good maximum 
-// (memory intensive). For ESP32 maybe 30 could be used as well
-#define _MAXSTAT 20
+
+// Name of he configfile in SPIFFs	filesystem
+// In this file we store the configuration and other relevant info that should
+// survive a reboot of the gateway		
+#define _CONFIGFILE "/gwayConfig.txt"
 
 
-// Define the maximum amount of itemas we monitor on the screen
-#define _MAXMONITOR 20
+// Maximum number of Message History statistics records gathered. 20 is a good maximum 
+// (memory intensive). For ESP32 maybe 30 could be used as well
+#if !defined _MAXSTAT
+#	define _MAXSTAT 20
+#endif
 
 
 // We will log a list of LoRa nodes that was forwarded using this gateway.
@@ -316,13 +313,23 @@
 #if !defined _MAXSEEN
 #	define _MAXSEEN 20
 #endif
-#define _SEENFILE "/gwayNum.txt"
+#define _SEENFILE "/gwaySeen.txt"
 
 
-// Name of he configfile in SPIFFs	filesystem
-// In this file we store the configuration and other relevant info that should
-// survive a reboot of the gateway		
-#define CONFIGFILE "/gwayConfig.txt"
+// Define the maximum amount of items we monitor on the screen
+#if !defined _MAXMONITOR
+#	define _MAXMONITOR 20
+#endif
+
+
+// Timing
+#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 _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 _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
 
 
 // Define the correct radio type that you are using
@@ -334,6 +341,11 @@
 #define _BAUDRATE 115200						// Works for debug messages to serial momitor
 
 
+// Will we use Mutex or not?
+// +SPI is input for SPI, SPO is output for SPI
+#define _MUTEX 0
+
+
 // MQTT definitions, these settings should be standard for TTN
 // and need no changing
 #define _TTNSERVER "router.eu.thethings.network"

+ 9 - 0
src/configNode.h

@@ -132,6 +132,15 @@ wpas wpa[] = {
 //#define AP_PASSWD "ttnAutoPw"
 
 
+// Gateway Ident definitions. Where is the gateway located?
+#define _DESCRIPTION "ESP Gateway"			// Name of the gateway
+#define _EMAIL "mw12554@hotmail.com"		// Owner
+#define _PLATFORM "ESP8266"
+#define _LAT 52.237367
+#define _LON 5.978654
+#define _ALT 14								// Altitude
+
+
 // For asserting and testing the following defines are used.
 //
 #if !defined(CFG_noassert)

+ 6 - 6
src/loraFiles.h

@@ -69,7 +69,6 @@ struct espGwayConfig {
 	uint16_t ntps;
 	uint16_t logFileRec;		// Logging File Record number
 	uint16_t logFileNo;			// Logging File Number
-	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
@@ -82,6 +81,10 @@ struct espGwayConfig {
 	uint8_t pdebug;				// pattern debug, 
 	uint8_t trusted;			// pattern debug,
 	
+	uint8_t	maxSeen;			// Max Seen lines on GUI (not saved for reboots)
+	uint8_t maxMoni;			// Max Monitoring lines	(not saved)
+	uint8_t maxStat;			// Max history lines (not saved)
+	
 	bool cad;					// is CAD enabled?
 	bool hop;					// Is HOP enabled (Note: default be disabled)
 	bool isNode;				// Is gateway node enabled
@@ -99,13 +102,10 @@ struct espGwayConfig {
 
 // We do keep admin of logfiles by number
 // 
-//uint32_t logFileNo = 0;		// Included in struct espGwayConfig LogFile number
-//uint32_t logFileRec = 0;		// Number of records in a single logfile
-//uint32_t logFileNum = 1;		// Number of log files
 #define LOGFILEMAX 10
 #define LOGFILEREC 100
 
-#endif // _STAT_LOG
+#endif //_STAT_LOG
 
 // Define the node list structure
 //
@@ -126,7 +126,7 @@ struct nodeSeen {
 	uint8_t chnSeen;
 	uint8_t sfSeen;				// Encode the SF seen.This might differ per message!
 };
-struct nodeSeen listSeen[_MAXSEEN];
+struct nodeSeen * listSeen;
 
 
 // define the logging structure used for printout of error and warning messages

+ 7 - 6
src/loraModem.h

@@ -254,12 +254,11 @@ struct pins {
 #if _GPS==1
 #define GPS_RX 15
 #define GPS_TX 12
-#endif // _GPS
+#endif //_GPS
 
 #elif _PIN_OUT==5
-
 // ----------------------------------------------------------------------------
-// For ESP32/Heltec Wifi LoRA 32(V2) board with 0.9" OLED
+// For ESP32/Heltec Wifi LoRA 32(V2) HTIT-WB32LA board with 0.9" OLED
 //
 // SCK  == GPIO5/ PIN5
 // SS   == GPIO18/PIN18 CS
@@ -279,6 +278,7 @@ struct pins {
 #define RST 14				// Check
 #define SS 18
 
+
 #else
 // ----------------------------------------------------------------------------
 // Use your own pin definitions, and comment #error line below
@@ -291,7 +291,7 @@ struct pins {
 
 // stat_t contains the statistics that are kept for a message. 
 // 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 gwayConfig.maxStat message as statistics
 struct stat_t {
 	uint32_t time;							// Time since 1970 in seconds		
 	uint32_t node;							// 4-byte DEVaddr (the only one known to gateway)
@@ -352,12 +352,12 @@ struct stat_c statc;
 
 
 // History of received uplink and downlink messages from nodes
-struct stat_t statr[_MAXSTAT];
+struct stat_t * statr;
 
 
 
 
-#else // _STATISTICS==0
+#else //_STATISTICS==0
 struct stat_t	statr[1];					// Always have at least one element to store in
 #endif
 
@@ -372,6 +372,7 @@ struct LoraDown {
 	uint8_t		powe;
 	uint8_t		crc;
 	uint8_t		iiq;
+	uint8_t		imme;
 	uint8_t	* 	payLoad;
 } LoraDown;
 

+ 7 - 7
src/oLED.h

@@ -27,7 +27,7 @@
 // 2. 1.3" OLED with much better and larger display
 // 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.
@@ -45,10 +45,10 @@
 #define OLED_SDA 4								// GPIO4 / 
 #define OLED_RST 16								// Reset pin (Some OLED displays do not have it)
 
-#elif _PIN_OUT==5								// Heltec Wifi LoRA 32(V2) onboard OLED
-#define OLED_SCL 15								// GPIO22 / SCL
-#define OLED_SDA 4								// GPIO21 / SDA
-#define OLED_RST 16								// Reset pin
+#elif _PIN_OUT==5								// TTGO with external OLED
+#define OLED_SCL 22								// GPIO22 / SCL
+#define OLED_SDA 21								// GPIO21 / SDA
+#define OLED_RST 16								// Reset pin (Some OLED displays do not have it)
 
 #endif
 
@@ -60,7 +60,7 @@
 #include "SSD1306.h"
 #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
-#endif
+#endif //_OLED
 
 // This is an 1.3" OLED display which is running on I2C
 #if _OLED==2
@@ -69,4 +69,4 @@ SSD1306  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// _OLED>=1
+#endif //_OLED>=1