瀏覽代碼

Version 6.1.6

platenspeler 5 年之前
父節點
當前提交
40f3f40a98

+ 18 - 3
CHANGELOG.md

@@ -1,6 +1,6 @@
 # Single Channel LoRaWAN Gateway
 
-Version 6.1.4, November 25, 2019	  
+Version 6.1.5, December 20, 2019	  
 Author: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 
@@ -16,7 +16,22 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
 
 # Release Notes
 
-Features release 6.1.4 (November 29, 2019)
+Features release 6.1.5 (December 20, 2019)
+- Bug fix for "#define _DUSB 0"
+- Added number of times a node has been called to the history records listSeen
+- Fix LastSeen issues.
+- Added 3 Indian frequencies as published by TTN
+- Changes configGway.h to contain better info
+- Added a message console on the GUI page (_define _MONITOR 1)
+- Changed the DNS code to allow .local domains with MDNS
+- Added buttons for Expert mode, Monitor and Last Seen.
+- Added code for "REBOOT" to be used from the API only *http://your_IP/REBOOT '
+- Added the IP to the www server header (visible in browser).
+- Removed version 5 of pi-out as it is the same as version 4.
+- Added "monitor" functions. This allows to write to monitor screen on browser or use 
+USB for desbugging messages.
+
+Features release 6.1.4 (November 25, 2019)
 - Compacting Code and Solve Errors
 - Look at _DUSB define and add to Serial.print directive where not found
 - Renewed the GPS functions, changed "Serial1" to "sGps" to avoid double definitions.
@@ -264,7 +279,7 @@ New features in version 3.1 (September 29, 2016)):
 New features in version 3.0 (September 27, 2016):
 
 - WiFiManager support
-- Limited SPIFF (filesystem) support for persistent data storage
+- Limited SPIFFS (filesystem) support for persistent data storage
 - Added functions to webserver. Webserver port now 80 by default (!)
 
 Other

+ 179 - 174
ESP-sc-gway/ESP-sc-gway.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 // Author: Maarten Westenberg (mw12554@hotmail.com)
 //
 // Based on work done by Thomas Telkamp for Raspberry PI 1-ch gateway and many others.
@@ -102,6 +102,7 @@ extern "C" {
 #include <ESP8266WebServer.h>
 #include <Streaming.h>          							// http://arduiniana.org/libraries/streaming/
 #endif //A_SERVER
+
 #if A_OTA==1
 #include <ESP8266httpUpdate.h>
 #include <ArduinoOTA.h>
@@ -111,7 +112,7 @@ extern "C" {
 
 // ----------- Declaration of vars --------------
 uint8_t debug=1;											// Debug level! 0 is no msgs, 1 normal, 2 extensive
-uint8_t pdebug=0xFF;										// Allow all atterns (departments)
+uint8_t pdebug=0xFF;										// Allow all patterns for debugging
 
 #if GATEWAYNODE==1
 
@@ -140,8 +141,6 @@ bool sx1272 = true;											// Actually we use sx1276/RFM95
 uint8_t	 ifreq = 0;											// Channel Index
 //unsigned long freq = 0;
 
-
-
 uint8_t MAC_array[6];
 
 // ----------------------------------------------------------------------------
@@ -152,7 +151,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 sfi 			= _SPREADING;							// Initial value of SF
 
 // Set location, description and other configuration parameters
 // Defined in ESP-sc_gway.h
@@ -220,10 +219,14 @@ static void printIP(IPAddress ipa, const char sep, String& response);	// _wwwSer
 void setupWWW();											// _wwwServer.ino forward
 
 void SerialTime();											// _utils.ino forward
+static void mPrint(String txt);								// _utils.ino (static void)
+int mStat(uint8_t intr, String & response);					// _utils.ini
 void SerialStat(uint8_t intr);								// _utils.ino
 void printHexDigit(uint8_t digit);							// _utils.ino
 int inDecodes(char * id);									// _utils.ino
 
+int initMonitor(struct moniLine *monitor);					// _loraFiles.ino
+
 void init_oLED();											// _oLED.ino
 void acti_oLED();											// _oLED.ino
 void addr_oLED();											// _oLED.ino
@@ -259,8 +262,9 @@ void ICACHE_FLASH_ATTR ReleaseMutex(int *mutex);
 void die(const char *s)
 {
 	Serial.println(s);
+#	if _DUSB>=1 || _MONITOR>=1
 	if (debug>=2) Serial.flush();
-
+#	endif //_DUSB _MONITOR
 	delay(50);
 	// system_restart();									// SDK function
 	// ESP.reset();				
@@ -272,11 +276,14 @@ void die(const char *s)
 //
 // ----------------------------------------------------------------------------
 void gway_failed(const char *file, uint16_t line) {
-	Serial.print(F("Program failed in file: "));
-	Serial.print(file);
-	Serial.print(F(", line: "));
-	Serial.println(line);
-	if (debug>=2) Serial.flush();
+#if _DUSB>=1 || _MONITOR>=1
+	String response="";
+	response += "Program failed in file: ";
+	response += String(file);
+	response += ", line: ";
+	response += String(line);
+	mPrint(response);
+#endif //_DUSB||_MONITOR
 }
 
 
@@ -356,8 +363,9 @@ time_t getNtpTime()
 	
     if (!sendNtpRequest(ntpServer))							// Send the request for new time
 	{
-		if (( debug>=0 ) && ( pdebug & P_MAIN ))
-			Serial.println(F("M sendNtpRequest failed"));
+		if (pdebug & P_MAIN) {
+			mPrint("M sendNtpRequest failed");
+		}
 		return(0);
 	}
 	
@@ -396,11 +404,12 @@ time_t getNtpTime()
 	// So increase the counter
 	gwayConfig.ntpErr++;
 	gwayConfig.ntpErrTime = now();
-#if _DUSB>=1
-	if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("M getNtpTime:: read failed"));
+
+#	if _MONITOR>=1
+	if (pdebug & P_MAIN) {
+		mPrint("getNtpTime:: read failed");
 	}
-#endif
+#	endif //_MONITOR
 	return(0); 												// return 0 if unable to get the time
 }
 
@@ -429,57 +438,57 @@ void setup() {
 	char MAC_char[19];										// XXX Unbelievable
 	MAC_char[18] = 0;
 
-	Serial.begin(_BAUDRATE);								// As fast as possible for bus
+#	if _DUSB>=1
+		Serial.begin(_BAUDRATE);							// As fast as possible for bus
+#	endif
 	delay(500);	
 
+#if _MONITOR>=1
+	initMonitor(monitor);
+#endif
+
+
 #if _GPS==1
 	// Pins are define in LoRaModem.h together with other pins
 	sGps.begin(9600, SERIAL_8N1, GPS_TX, GPS_RX);// PIN 12-TX 15-RX
-#endif
+#endif //_GPS
 
 #ifdef ESP32
-#if _DUSB>=1
-	Serial.print(F("ESP32 defined, freq="));
-	Serial.print(freqs[0].upFreq);
-	Serial.println();
-#endif
-#endif
-#ifdef ARDUINO_ARCH_ESP32
-#if _DUSB>=1
-	Serial.println(F("ARDUINO_ARCH_ESP32 defined"));
-#endif
-#endif
+#	if _MONITOR>=1
+		mPrint("ESP32 defined, freq=" + String(freqs[0].upFreq));
+#	endif //_MONITOR
+#endif //ESP32
 
+#ifdef ARDUINO_ARCH_ESP32
+#	if _MONITOR>=1
+		mPrint("ARDUINO_ARCH_ESP32 defined");
+#	endif //_MONITOR
+#endif //ARDUINO_ARCH_ESP32
 
-#if _DUSB>=1
-	Serial.flush();
 
+#	if _DUSB>=1
+		Serial.flush();
+#	endif //_DUSB
 	delay(500);
 
 	if (SPIFFS.begin()) {
-#if _DUSB>=1
-		Serial.println(F("SPIFFS init success"));
-#endif
+#		if _MONITOR>=1
+			mPrint("SPIFFS init success");
+#		endif //_MONITOR
 	}
 	else {
-#if _DUSB>=1
-		Serial.println(F("SPIFFS not found"));
-#endif
-	}
-#endif	
-#if _SPIFF_FORMAT>=1
-#if _DUSB>=1
-	if (( debug >= 0 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("M Format Filesystem ... "));
+		if (pdebug & P_MAIN) {
+			mPrint("SPIFFS not found");
+		}
 	}
-#endif
+	
+#	if _SPIFF_FORMAT>=1
 	SPIFFS.format();										// Normally disabled. Enable only when SPIFFS corrupt
-#if _DUSB>=1
-	if (( debug >= 0 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("Format Done"));
+	if ((debug>=1) && (pdebug & P_MAIN)) {
+		mPrint("Format SPIFFS Filesystem Done");
 	}
-#endif
-#endif
+#	endif //_SPIFF_FORMAT>=1
+
 	delay(500);
 	
 	// Read the config file for all parameters not set in the setup() or configGway.h file
@@ -489,26 +498,21 @@ void setup() {
 	readConfig(CONFIGFILE, &gwayConfig);
 	readSeen(_SEENFILE, listSeen);							// read the seenFile records
 
-	Serial.print(F("Assert="));
-#if defined CFG_noassert
-	Serial.println(F("No Asserts"));
-#else
-	Serial.println(F("Do Asserts"));
-#endif
+#	if _MONITOR>=1
+		mPrint("Assert=");
+#		if defined CFG_noassert
+			mPrint("No Asserts");
+#		else
+			mPrint("Do Asserts");
+#		endif //CFG_noassert
+#	endif //_MONITOR
 
 #if OLED>=1
 	init_oLED();											// When done display "STARTING" on OLED
-#endif
+#endif //OLED
 
 	delay(500);
 	yield();
-#if _DUSB>=1	
-	if (debug>=1) {
-		Serial.print(F("debug=")); 
-		Serial.println(debug);
-		yield();
-	}
-#endif
 
 	WiFi.mode(WIFI_STA);
 	WiFi.setAutoConnect(true);
@@ -542,21 +546,23 @@ void setup() {
 #else
 	sprintf(hostname, "%s%02x%02x%02x", "esp8266-", MAC_array[3], MAC_array[4], MAC_array[5]);
 	wifi_station_set_hostname( hostname );
-#endif	
+#endif	//ESP32_ARCH
 
-	
-	Serial.print(F("Host "));
+#	if _DUSB>=1
+		Serial.print(F("Host "));
 #if ESP32_ARCH==1
-	Serial.print(WiFi.getHostname());
+		Serial.print(WiFi.getHostname());
 #else
-	Serial.print(wifi_station_get_hostname());
-#endif
-	Serial.print(F(" WiFi Connected to "));
-	Serial.print(WiFi.SSID());
-	Serial.print(F(" on IP="));
-	Serial.print(WiFi.localIP());
-	Serial.println();
-	
+		Serial.print(wifi_station_get_hostname());
+#endif //ESP32_ARCH
+
+		Serial.print(F(" WiFi Connected to "));
+		Serial.print(WiFi.SSID());
+		Serial.print(F(" on IP="));
+		Serial.print(WiFi.localIP());
+		Serial.println();
+#	endif //_DUSB	
+
 	delay(500);
 	// If we are here we are connected to WLAN
 	
@@ -567,12 +573,15 @@ void setup() {
 	}
 #elif defined(_TTNROUTER)
 	if (!connectTtn()) {
+#	if _DUSB>=1
 		Serial.println(F("Error connectTtn"));
+#	endif //_DUSB
 	}
 #else
-	Serial.print(F("Setup:: No UDP or TCP Connection defined"));
-	
-#endif
+#	if _MONITOR>=1
+		mPrint(F("Setup:: ERROR, No UDP or TCP Connection defined"));
+#	endif //_MONITOR	
+#endif //_UDPROUTER
 	delay(200);
 	
 	// Pins are defined and set in loraModem.h
@@ -580,78 +589,75 @@ 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);
+	//pinMode(pins.dio2, INPUT);							// XXX
 
 	// Init the SPI pins
 #if ESP32_ARCH==1
 	SPI.begin(SCK, MISO, MOSI, SS);
 #else
 	SPI.begin();
-#endif
+#endif //ESP32_ARCH==1
 
 	delay(500);
 	
 	// We choose the Gateway ID to be the Ethernet Address of our Gateway card
     // display results of getting hardware address
 	//
-
-    Serial.print(F("Gateway ID: "));
-	printHexDigit(MAC_array[0]);
-    printHexDigit(MAC_array[1]);
-    printHexDigit(MAC_array[2]);
-	printHexDigit(0xFF);
-	printHexDigit(0xFF);
-    printHexDigit(MAC_array[3]);
-    printHexDigit(MAC_array[4]);
-    printHexDigit(MAC_array[5]);
-
-    Serial.print(F(", Listening at SF"));
-	Serial.print(sf);
-	Serial.print(F(" on "));
-	Serial.print((double)freqs[ifreq].upFreq/1000000);
-	Serial.println(" MHz.");
-
-	if (!WiFi.hostByName(NTP_TIMESERVER, ntpServer))		// Get IP address of Timeserver
-	{
-		die("Setup:: ERROR hostByName NTP");
-	};
+#	if _DUSB>=1
+		Serial.print(F("Gateway ID: "));
+		printHexDigit(MAC_array[0]);
+		printHexDigit(MAC_array[1]);
+		printHexDigit(MAC_array[2]);
+		printHexDigit(0xFF);
+		printHexDigit(0xFF);
+		printHexDigit(MAC_array[3]);
+		printHexDigit(MAC_array[4]);
+		printHexDigit(MAC_array[5]);
+
+		Serial.print(F(", Listening at SF"));
+		Serial.print(sf);
+		Serial.print(F(" on "));
+		Serial.print((double)freqs[ifreq].upFreq/1000000);
+		Serial.println(" MHz.");
+#	endif //_DUSB
+
+	ntpServer = resolveHost(NTP_TIMESERVER);
+#	if _MONITOR>=1
+		if (debug>=1) mPrint("NTP Server found and contacted");
+#	endif
 	delay(100);
+	
 #ifdef _TTNSERVER
-	if (!WiFi.hostByName(_TTNSERVER, ttnServer))			// Use DNS to get server IP once
-	{
-		die("Setup:: ERROR hostByName TTN");
-	};
+	ttnServer = resolveHost(_TTNSERVER);					// Use DNS to get server IP
 	delay(100);
-#endif
+#endif //_TTNSERVER
+
 #ifdef _THINGSERVER
-	if (!WiFi.hostByName(_THINGSERVER, thingServer))
-	{
-		die("Setup:: ERROR hostByName THING");
-	}
+	thingServer = resolveHost(_THINGSERVER);					// Use DNS to get server IP
 	delay(100);
-#endif
+#endif //_THINGSERVER
 
 	// The Over the Air updates are supported when we have a WiFi connection.
 	// The NTP time setting does not have to be precise for this function to work.
 #if A_OTA==1
 	setupOta(hostname);										// Uses wwwServer 
-#endif
+#endif //A_OTA
 
 	// Set the NTP Time
 	// As long as the time has not been set we try to set the time.
 #if NTP_INTR==1
 	setupTime();											// Set NTP time host and interval
-#else
+#else //NTP_INTR
 	// If not using the standard libraries, do a manual setting
 	// of the time. This method works more reliable than the 
 	// interrupt driven method.
 	
 	//setTime((time_t)getNtpTime());
 	while (timeStatus() == timeNotSet) {
-#if _DUSB>=1
+#		if _DUSB>=1 || _MONITOR>=1
 		if (( debug>=0 ) && ( pdebug & P_MAIN )) 
-			Serial.println(F("M setupTime:: Time not set (yet)"));
-#endif
+			mPrint("setupTime:: Time not set (yet)");
+#		endif //_DUSB
 		delay(500);
 		time_t newTime;
 		newTime = (time_t)getNtpTime();
@@ -659,24 +665,21 @@ void setup() {
 	}
 	// When we are here we succeeded in getting the time
 	startTime = now();										// Time in seconds
-#if _DUSB>=1
-	Serial.print("Time: "); printTime();
-	Serial.println();
-#endif
+#	if _DUSB>=1
+		Serial.print("writeGwayCfg: "); printTime();
+		Serial.println();
+	#endif //_DUSB
 	writeGwayCfg(CONFIGFILE );
-#if _DUSB>=1
-	Serial.println(F("Gateway configuration saved"));
-#endif
 #endif //NTP_INTR
 
 #if A_SERVER==1	
 	// Setup the webserver
 	setupWWW();
-#endif
+#endif //A_SERVER
 
 	delay(100);												// Wait after setup
 	
-	// Setup and initialise LoRa state machine of _loramModem.ino
+	// Setup and initialise LoRa state machine of _loraModem.ino
 	_state = S_INIT;
 	initLoraModem();
 	
@@ -708,16 +711,18 @@ void setup() {
 	
 	writeConfig(CONFIGFILE, &gwayConfig);					// Write config
 	writeSeen( _SEENFILE, listSeen);						// Write the last time record  is seen
-#if _DUSB>=1
-	printSeen(listSeen);
-#endif	
+
 	// activate OLED display
 #if OLED>=1
 	acti_oLED();
 	addr_oLED();
-#endif
+#endif //OLED
+
+#	if _DUSB>=1
+		Serial.println(F("--------------------------------------"));
+#	endif //_DUSB
 
-	Serial.println(F("--------------------------------------"));
+	mPrint("Setup() ended, Starting loop()");
 }//setup
 
 
@@ -752,22 +757,25 @@ void loop ()
 	// After a quiet period, make sure we reinit the modem and state machine.
 	// The interval is in seconds (about 15 seconds) as this re-init
 	// is a heavy operation. 
-	// SO it will kick in if there are not many messages for the gateway.
+	// So it will kick in if there are not many messages for the gateway.
 	// Note: Be careful that it does not happen too often in normal operation.
 	//
 	if ( ((nowSeconds - statr[0].tmst) > _MSG_INTERVAL ) &&
 		(msgTime <= statr[0].tmst) ) 
 	{
-#if _DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.print("M REINIT:: ");
-			Serial.print( _MSG_INTERVAL );
-			Serial.print(F(" "));
-			SerialStat(0);
+#		if _MONITOR>=1
+		if (( debug>=2 ) && ( pdebug & P_MAIN )) {
+			String response="";
+			response += "REINIT:: ";
+			response += String( _MSG_INTERVAL );
+			response += (" ");
+			mStat(0, response);
+			mPrint(response);
 		}
-#endif
+#		endif //_MONITOR
+
+		yield();											// Allow buffer operations to finish
 
-		// startReceiver() ??
 		if ((_cad) || (_hop)) {
 			_state = S_SCAN;
 			sf = SF7;
@@ -788,7 +796,7 @@ void loop ()
 	// start of the loop() function.
 	yield();
 	server.handleClient();
-#endif
+#endif //A_SERVER
 
 #if A_OTA==1
 	// Perform Over the Air (OTA) update if enabled and requested by user.
@@ -797,7 +805,7 @@ void loop ()
 	//
 	yield();
 	ArduinoOTA.handle();
-#endif
+#endif //A_OTA
 
 	// If event is set, we know that we have a (soft) interrupt.
 	// After all necessary web/OTA services are scanned, we will
@@ -813,10 +821,11 @@ void loop ()
 	// If we are not connected, try to connect.
 	// We will not read Udp in this loop cycle then
 	if (WlanConnect(1) < 0) {
-#if _DUSB>=1
-		if (( debug >= 0 ) && ( pdebug & P_MAIN ))
-			Serial.println(F("M ERROR reconnect WLAN"));
-#endif
+#		if _DUSB>=1 || _MONITOR>=1
+		if (( debug >= 0 ) && ( pdebug & P_MAIN )) {
+			mPrint("M ERROR reconnect WLAN");
+		}
+#		endif //_DUSB || _MONITOR
 		yield();
 		return;												// Exit loop if no WLAN connected
 	}
@@ -829,17 +838,19 @@ void loop ()
 	//
 	else {
 		while( (packetSize = Udp.parsePacket()) > 0) {
-#if _DUSB>=2
-			Serial.println(F("loop:: readUdp calling"));
-#endif
+#			if _MONITOR>=1
+				if (debug>=2) {
+					mPrint("loop:: readUdp calling");
+				}
+#			endif //_MONITOR
 			// DOWNSTREAM
 			// Packet may be PKT_PUSH_ACK (0x01), PKT_PULL_ACK (0x03) or PKT_PULL_RESP (0x04)
 			// This command is found in byte 4 (buffer[3])
 			if (readUdp(packetSize) <= 0) {
-#if _DUSB>=1
-				if (( debug>0 ) && ( pdebug & P_MAIN ))
-					Serial.println(F("M readUdp error"));
-#endif
+				#if _MONITOR>=1
+				if ( debug>=0 )
+					mPrint("readUdp ERROR, retuning <=0");
+#				endif //_MONITOR
 				break;
 			}
 			// Now we know we succesfully received message from host
@@ -849,25 +860,18 @@ void loop ()
 		}
 	}
 	
-	yield();					// XXX 26/12/2017
+	yield();					// on 26/12/2017
 
 	// stat PUSH_DATA message (*2, par. 4)
 	//	
 
     if ((nowSeconds - statTime) >= _STAT_INTERVAL) {		// Wake up every xx seconds
-#if _DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.print(F("M STAT:: ..."));
-			Serial.flush();
-		}
-#endif
         sendstat();											// Show the status message and send to server
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.println(F(" done"));
-			if (debug>=2) Serial.flush();
+			mPrint("Send sendstat");
 		}
-#endif	
+#		endif //_MONITOR
 
 		// If the gateway behaves like a node, we do from time to time
 		// send a node message to the backend server.
@@ -883,12 +887,14 @@ void loop ()
 			// could be battery but also other status info or sensor info
 		
 			if (sensorPacket() < 0) {
-#if _DUSB>=1
-				Serial.println(F("sensorPacket: Error"));
-#endif
+#			if _MONITOR>=1
+				if ((debug>=1) || (pdebug & P_MAIN)) {
+					mPrint("sensorPacket: Error");
+				}
+#			endif// _MONITOR
 			}
 		}
-#endif
+#endif//GATEWAYNODE
 		statTime = nowSeconds;
     }
 	
@@ -899,12 +905,11 @@ void loop ()
 	//
 	nowSeconds = now();
     if ((nowSeconds - pulltime) >= _PULL_INTERVAL) {		// Wake up every xx seconds
-#if _DUSB>=1
+#		if _DUSB>=1 || _MONITOR>=1
 		if (( debug>=2) && ( pdebug & P_MAIN )) {
-			Serial.println(F("M PULL"));
-			if (debug>=1) Serial.flush();
+			mPrint("M PULL");
 		}
-#endif
+#		endif//_DUSB _MONITOR
         pullData();											// Send PULL_DATA message to server
 		startReceiver();
 	
@@ -927,7 +932,7 @@ void loop ()
 		if (newTime != 0) setTime(newTime);
 		ntptimer = nowSeconds;
 	}
-#endif
+#endif//NTP_INTR
 	
 
 }//loop

+ 105 - 67
ESP-sc-gway/_WiFi.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -34,25 +34,23 @@ int WlanStatus() {
 
 	switch (WiFi.status()) {
 		case WL_CONNECTED:
-#if _DUSB>=1
-			if ( debug>=0 ) {
-				Serial.print(F("A WlanStatus:: CONNECTED to "));				// 3
-				Serial.println(WiFi.SSID());
+#			if _MONITOR>=1
+			if ( debug>=1 ) {
+				mPrint("A WlanStatus:: CONNECTED to " + String(WiFi.SSID()));	// 3
 			}
-#endif
-			WiFi.setAutoReconnect(true);				// Reconenct to this AP if DISCONNECTED
+#			endif //_MONITOR
+			WiFi.setAutoReconnect(true);				// Reconect to this AP if DISCONNECTED
 			return(1);
 			break;
 
 		// In case we get disconnected from the AP we loose the IP address.
 		// The ESP is configured to reconnect to the last router in memory.
 		case WL_DISCONNECTED:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 ) {
-				Serial.print(F("A WlanStatus:: DISCONNECTED, IP="));			// 6
-				Serial.println(WiFi.localIP());
+				mPrint("A WlanStatus:: DISCONNECTED, IP=" + String(WiFi.localIP().toString())); // 6
 			}
-#endif
+#			endif
 			//while (! WiFi.isConnected() ) {
 				// Wait
 				delay(1);
@@ -62,61 +60,60 @@ int WlanStatus() {
 
 		// When still pocessing
 		case WL_IDLE_STATUS:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 ) {
-				Serial.println(F("A WlanStatus:: IDLE"));					// 0
+				mPrint("A WlanStatus:: IDLE");								// 0
 			}
-#endif
+#			endif //_MONITOR
 			break;
 		
 		// This code is generated as soonas the AP is out of range
 		// Whene detected, the program will search for a better AP in range
 		case WL_NO_SSID_AVAIL:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 )
-				Serial.println(F("WlanStatus:: NO SSID"));					// 1
-#endif
+				mPrint("WlanStatus:: NO SSID");								// 1
+#			endif //_MONITOR
 			break;
 			
 		case WL_CONNECT_FAILED:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: FAILED"));					// 4
-#endif
+				mPrint("A WlanStatus:: FAILED");							// 4
+#			endif //_MONITOR
 			break;
 			
 		// Never seen this code
 		case WL_SCAN_COMPLETED:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: SCAN COMPLETE"));			// 2
-#endif
+				mPrint("A WlanStatus:: SCAN COMPLETE");						// 2
+#			endif //_MONITOR
 			break;
 			
 		// Never seen this code
 		case WL_CONNECTION_LOST:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: LOST"));					// 5
-#endif
+				mPrint("A WlanStatus:: Connection LOST");					// 5
+#			endif //_MONITOR
 			break;
 			
 		// This code is generated for example when WiFi.begin() has not been called
 		// before accessing WiFi functions
 		case WL_NO_SHIELD:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: WL_NO_SHIELD"));				// 
-#endif
+				Serial.println(F("A WlanStatus:: WL_NO_SHIELD"));			// 
+#			endif //_MONITOR
 			break;
 			
 		default:
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if ( debug>=0 ) {
-				Serial.print(F("A WlanStatus Error:: code="));
-				Serial.println(WiFi.status());								// 255 means ERROR
+				mPrint("A WlanStatus Error:: code=" + String(WiFi.status()));	// 255 means ERROR
 			}
-#endif
+#			endif //_MONITOR
 			break;
 	}
 	return(-1);
@@ -173,15 +170,11 @@ int WlanReadWpa() {
 #if _WIFIMANAGER==1
 int WlanWriteWpa( char* ssid, char *pass) {
 
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (( debug >=0 ) && ( pdebug & P_MAIN )) {
-		Serial.print(F("M WlanWriteWpa:: ssid=")); 
-		Serial.print(ssid);
-		Serial.print(F(", pass=")); 
-		Serial.print(pass); 
-		Serial.println();
+		mPrint("WlanWriteWpa:: ssid="+mPrint(ssid)+", pass="+mPrint(pass)); 
 	}
-#endif
+#	endif //_MONITOR
 	// Version 3.3 use of config file
 	String s((char *) ssid);
 	gwayConfig.ssid = s;
@@ -189,9 +182,9 @@ int WlanWriteWpa( char* ssid, char *pass) {
 	String p((char *) pass);
 	gwayConfig.pass = p;
 
-#if GATEWAYNODE==1	
-	gwayConfig.fcnt = frameCount;
-#endif
+#	if GATEWAYNODE==1	
+		gwayConfig.fcnt = frameCount;
+#	endif
 	gwayConfig.ch = ifreq;
 	gwayConfig.sf = sf;
 	gwayConfig.cad = _cad;
@@ -240,7 +233,9 @@ int WlanConnect(int maxTry) {
 	// We clear the WiFi memory and start with previous AP.
 	//
 	if (maxTry==0) {
-		Serial.println(F("WlanConnect:: Init para 0"));
+#		if _MONITOR>=1
+		mPrint("WlanConnect:: Init para 0");
+#		endif //_MONITOR
 		WiFi.persistent(false);
 		WiFi.mode(WIFI_OFF);   // this is a temporary line, to be removed after SDK update to 1.5.4
 		if (gwayConfig.ssid.length() >0) {
@@ -295,7 +290,7 @@ int WlanConnect(int maxTry) {
 			// -1 = No SSID or other cause			
 			int stat = WlanStatus();
 			if ( stat == 1) {
-				writeGwayCfg(CONFIGFILE);					// XXX Write configuration to SPIFFS
+				writeGwayCfg(CONFIGFILE);					// Write configuration to SPIFFS
 				return(1);
 			}
 		
@@ -305,16 +300,16 @@ int WlanConnect(int maxTry) {
 			while (((WiFi.status()) != WL_CONNECTED) && (agains < 10)) {
 				agains++;
 				delay(agains*500);
-#if _DUSB>=1
+#				if _DUSB>=1
 				if ( debug>=0 ) {
 					Serial.print(".");
 				}
-#endif
+#				endif //_DUSB
 			}
-#if _DUSB>=1
-			Serial.println();
-#endif		
-			//if ( WiFi.status() == WL_DISCONNECTED) return(0);				// XXX 180811 removed
+#			if _DUSB>=1
+				Serial.println();
+#			endif //_DUSB		
+			//if ( WiFi.status() == WL_DISCONNECTED) return(0);				// 180811 removed
 
 
 			// Make sure that we can connect to different AP's than 1
@@ -332,13 +327,12 @@ int WlanConnect(int maxTry) {
 	// we can invoike _WIFIMANAGER or else return unsuccessful.
 	if (WiFi.status() != WL_CONNECTED) {
 #if _WIFIMANAGER==1
-#if _DUSB>=1
-		Serial.println(F("Starting Access Point Mode"));
-		Serial.print(F("Connect Wifi to accesspoint: "));
-		Serial.print(AP_NAME);
-		Serial.print(F(" and connect to IP: 192.168.4.1"));
-		Serial.println();
-#endif
+#		if _MONITOR>=1
+		if (debug>=1) {
+			mPrint("Starting Access Point Mode"));
+			mPrint("Connect Wifi to accesspoint: "+mPrint(AP_NAME)+" and connect to IP: 192.168.4.1");
+		}
+#		endif //_MONITOR
 		wifiManager.autoConnect(AP_NAME, AP_PASSWD );
 		//wifiManager.startConfigPortal(AP_NAME, AP_PASSWD );
 		// At this point, there IS a Wifi Access Point found and connected
@@ -353,16 +347,11 @@ int WlanConnect(int maxTry) {
 		//WlanWriteWpa(ssidBuf, (char *)sta_conf.password);
 		WlanWriteWpa((char *)sta_conf.ssid, (char *)sta_conf.password);
 #else
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (debug>=0) {
-			Serial.println(F("WlanConnect:: Not connected after all"));
-			Serial.print(F("WLAN retry="));
-			Serial.print(i);
-			Serial.print(F(" , stat="));
-			Serial.print(WiFi.status() );						// Status. 3 is WL_CONNECTED
-			Serial.println();
+			mPrint("WlanConnect:: Not connected, WLAN retry="+String(i)+", stat="+String(WiFi.status()) );
 		}
-#endif// _DUSB
+#		endif // _MONITOR
 		return(-1);
 #endif
 	}
@@ -370,3 +359,52 @@ int WlanConnect(int maxTry) {
 	yield();
 	return(1);
 }
+
+// ----------------------------------------------------------------------------
+// resolveHost
+// This function will use MDNS or DNS to resolve a hostname. 
+// So it may be .local or a normal hostname.
+// Return:
+//	svrIP: 4 byte IP address of machine resolved
+// ----------------------------------------------------------------------------
+IPAddress resolveHost(String svrName) 
+{
+	IPAddress svrIP;
+	
+#	if MONITOR>=1
+		mPrint("Server " + String(svrName));
+#	endif
+
+	if (svrName.endsWith(".local")) {
+#		if ESP32_ARCH==1
+			svrName=svrName.substring(0,svrName.length()-6);
+			svrIP = MDNS.queryHost(svrName);
+			for (byte i=0; i<5; i++) {						// Try 5 times MDNS
+				svrIP = MDNS.queryHost(svrName);
+				if (svrIP.toString() != "0.0.0.0") break;
+#				if (_MONITOR>=1)
+					mPrint("ReTrying to resolve with mDNS");
+#				endif
+				die("resolveHost:: ERROR hostByName .local");
+				delay(1000);
+			}
+#		else
+			char cc[svrName.length() +1 ];
+			strcpy(cc, svrName.c_str());
+			if (!WiFi.hostByName(cc, svrIP)) 		// Use DNS to get server IP once
+			{
+				die("resolveHost:: ERROR hostByName");
+			};
+#		endif
+	}
+	else 
+	{
+		char cc[svrName.length() +1 ];
+		strcpy(cc, svrName.c_str());
+		if (!WiFi.hostByName(cc, svrIP)) // Use DNS to get server IP once
+		{
+			die("resolveHost:: ERROR hostByName");
+		};
+	}
+	return svrIP;
+}

+ 2 - 2
ESP-sc-gway/_gatewayMgt.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg 
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // and many others.

+ 104 - 52
ESP-sc-gway/_loraFiles.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4		
-// Date: 2019-11-29	
+// Version 6.1.5		
+// Date: 2019-12-20	
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -18,6 +18,24 @@
 // This file contains the LoRa filesystem specific code
 
 
+#if _MONITOR>=1
+// ----------------------------------------------------------------------------
+// LoRa Monitor logging code.
+// Define one print function and depending on the loggin parameter output
+// to _USB of to the www screen function
+// ----------------------------------------------------------------------------
+int initMonitor(struct moniLine *monitor) {
+	for (int i=0; i< _MONITOR; i++) {
+		//monitor[i].txt[0]=0;
+		monitor[i].txt="";
+	}
+	return(1);
+}
+
+
+
+#endif //_MONITOR
+
 // ============================================================================
 // LORA SPIFFS FILESYSTEM FUNCTIONS
 //
@@ -33,9 +51,12 @@ void id_print (String id, String val) {
 		Serial.print(F("=\t"));
 		Serial.println(val);
 	}
-#endif
+#endif //_DUSB
 }
 
+
+
+
 // ----------------------------------------------------------------------------
 // INITCONFIG; Init the gateway configuration file
 // Espcecially when calling SPIFFS.format() the gateway is left in an init
@@ -49,7 +70,9 @@ int initConfig(struct espGwayConfig *c) {
 	(*c).pdebug = P_GUI;
 	(*c).cad = _CAD;
 	(*c).hop = false;
+	(*c).seen = false;
 	(*c).expert = false;
+	(*c).monitor = false;
 	(*c).txDelay = 0;					// First Value without saving is 0;
 	(*c).trusted = 1;
 }
@@ -63,13 +86,14 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
 	int tries = 0;
 #if _DUSB>=1
 	Serial.println(F("readConfig:: Starting "));
-#endif
+#endif //_DUSB
+
 	if (!SPIFFS.exists(fn)) {
 #if _DUSB>=1
 		Serial.print(F("readConfig ERR:: file="));
 		Serial.print(fn);
 		Serial.println(F(" does not exist .. Formatting"));
-#endif
+#endif //_DUSB
 		SPIFFS.format();
 		initConfig(c);					// If we cannot read teh config, at least init known values
 		return(-1);
@@ -79,7 +103,7 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
 	if (!f) {
 #if _DUSB>=1
 		Serial.println(F("ERROR:: SPIFFS open failed"));
-#endif
+#endif //_DUSB
 		return(-1);
 	}
 
@@ -89,16 +113,17 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
 		if (( debug>=0 ) && ( pdebug & P_MAIN )) {
 			Serial.print('.');
 		}
-#endif
+#endif //_DUSB
 		// If we wait for more than 10 times, reformat the filesystem
 		// We do this so that the system will be responsive (over OTA for example).
 		//
 		if (tries >= 10) {
 			f.close();
 #if _DUSB>=1
-			if (( debug>=0 ) && ( pdebug & P_MAIN ))
+			if (( debug>=0 ) && ( pdebug & P_MAIN )) {
 				Serial.println(F("Formatting"));
-#endif
+			}
+#endif //_DUSB
 			SPIFFS.format();
 			initConfig(c);
 			f = SPIFFS.open(fn, "r");
@@ -114,7 +139,7 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
 		Serial.print(F("="));
 		Serial.print(val);
 		Serial.println();
-#endif	
+#endif //_DUSB
 
 		if (id == "SSID") {										// WiFi SSID
 			id_print(id, val);
@@ -204,10 +229,18 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
 			id_print(id, val);
 			(*c).logFileNum = (uint16_t) val.toInt();
 		}
-		else if (id == "EXPERT") {								// EXPERT setting
+		else if (id == "EXPERT") {								// EXPERT button setting
 			id_print(id, val);
 			(*c).expert = (uint8_t) val.toInt();
 		}
+		else if (id == "SEEN") {								// SEEN button setting
+			id_print(id, val);
+			(*c).seen = (uint8_t) val.toInt();
+		}
+		else if (id == "MONITOR") {								// MONITOR button setting
+			id_print(id, val);
+			(*c).monitor = (uint8_t) val.toInt();
+		}
 		else if (id == "DELAY") {								// DELAY setting
 			id_print(id, val);
 			(*c).txDelay = (int32_t) val.toInt();
@@ -219,7 +252,7 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
 		else {
 #if _DUSB>=1
 			Serial.print(F("readConfig:: tries++"));
-#endif
+#endif //_DUSB
 			tries++;
 		}
 	}
@@ -230,7 +263,7 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
 		Serial.println(F("readConfig:: Fini"));
 	}
 	Serial.println();
-#endif
+#endif //_DUSB
 
 	return(1);
 }//readConfig
@@ -256,7 +289,7 @@ int writeGwayCfg(const char *fn) {
 
 #if GATEWAYNODE==1
 	gwayConfig.fcnt = frameCount;
-#endif
+#endif //GATEWAYNODE
 	return(writeConfig(fn, &gwayConfig));
 }
 
@@ -275,16 +308,22 @@ int writeConfig(const char *fn, struct espGwayConfig *c) {
 	// If it is not there we should format first.
 	// NOTE: Do not format for other files!
 	if (!SPIFFS.exists(fn)) {
+#if _DUSB>=1
 		Serial.print("WARNING:: writeConfig, file not exists, formatting ");
+#endif //_DUSB
 		SPIFFS.format();
 		initConfig(c);		// XXX make all initial declarations here if config vars need to have a value
+#if _DUSB>=1		
 		Serial.println(fn);
+#endif //_DUSB
 	}
 	File f = SPIFFS.open(fn, "w");
 	if (!f) {
+#if _DUSB>=1	
 		Serial.print("writeConfig: ERROR open file=");
 		Serial.print(fn);
 		Serial.println();
+#endif //_DUSB
 		return(-1);
 	}
 
@@ -313,6 +352,8 @@ int writeConfig(const char *fn, struct espGwayConfig *c) {
 	f.print("DELAY");  f.print('='); f.print((*c).txDelay); f.print('\n');
 	f.print("TRUSTED");  f.print('='); f.print((*c).trusted); f.print('\n');
 	f.print("EXPERT");  f.print('='); f.print((*c).expert); f.print('\n');
+	f.print("SEEN");  f.print('='); f.print((*c).seen); f.print('\n');
+	f.print("MONITOR");  f.print('='); f.print((*c).monitor); f.print('\n');
 	
 	f.close();
 	return(1);
@@ -325,6 +366,7 @@ int writeConfig(const char *fn, struct espGwayConfig *c) {
 // the function without STAT_LOG being proper defined
 // ToDo: Store the fileNo and the fileRec in the status file to save for 
 // restarts
+//
 // Parameters:
 //		line; char array with characters to write to log
 //		cnt;
@@ -352,7 +394,7 @@ int addLog(const unsigned char * line, int cnt)
 			Serial.print(F("G addLog:: Too many logfile, deleting="));
 			Serial.println(fn);
 		}
-#endif
+#endif //_DUSB
 		SPIFFS.remove(fn);
 		gwayConfig.logFileNum--;
 	}
@@ -371,7 +413,7 @@ int addLog(const unsigned char * line, int cnt)
 			Serial.print(gwayConfig.logFileRec);
 			Serial.println();
 		}
-#endif
+#endif //_DUSB
 	}
 	
 	File f = SPIFFS.open(fn, "a");
@@ -381,7 +423,7 @@ int addLog(const unsigned char * line, int cnt)
 			Serial.println("G file open failed=");
 			Serial.println(fn);
 		}
-#endif
+#endif //_DUSB
 		return(0);								// If file open failed, return
 	}
 	
@@ -401,12 +443,12 @@ int addLog(const unsigned char * line, int cnt)
 		}
 #else
 		i+=12;
-#endif
+#endif //_DUSB>=2
 		Serial.print((char *) &line[i]);	// The rest if the buffer contains ascii
 
 		Serial.println();
 	}
-#endif //DUSB
+#endif //_DUSB
 
 
 	for (i=0; i< 12; i++) {					// The first 12 bytes contain non printable characters
@@ -448,12 +490,30 @@ void printLog()
 		}
 		i++;
 	}
-#endif
+#endif //_DUSB
 } //printLog
 
 
 #if _SEENMAX>0
 
+
+// ----------------------------------------------------------------------------
+// initSeen
+// Init the lisrScreen array
+// ----------------------------------------------------------------------------
+int initSeen(struct nodeSeen *listSeen) {
+	int i;
+	for (i=0; i< _SEENMAX; i++) {
+		listSeen[i].idSeen=0;
+		listSeen[i].sfSeen=0;
+		listSeen[i].cntSeen=0;
+		listSeen[i].chnSeen=0;
+		listSeen[i].timSeen=0;
+	}
+	return(1);
+}
+
+
 // ----------------------------------------------------------------------------
 // readSeen
 // This function read the stored information from writeSeen.
@@ -466,16 +526,18 @@ int readSeen(const char *fn, struct nodeSeen *listSeen) {
 	if (!SPIFFS.exists(fn)) {
 #if _DUSB>=1
 		Serial.print("WARNING:: readSeen, history file not exists ");
-#endif
+#endif //_DUSB
 		initSeen(listSeen);		// XXX make all initial declarations here if config vars need to have a value
 		Serial.println(fn);
 		return(-1);
 	}
 	File f = SPIFFS.open(fn, "r");
 	if (!f) {
+#if _DUSB>=1
 		Serial.print("readConfig:: ERROR open file=");
 		Serial.print(fn);
 		Serial.println();
+#endif //_DUSB
 		return(-1);
 	}
 	for (i=0; i<_SEENMAX; i++) {
@@ -483,7 +545,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen) {
 		if (!f.available()) {
 #if _DUSB>=1
 			Serial.println(F("readSeen:: No more info left in file"));
-#endif
+#endif //_DUSB
 		}
 		val=f.readStringUntil('\t'); listSeen[i].timSeen = (uint32_t) val.toInt();
 		val=f.readStringUntil('\t'); listSeen[i].idSeen = (uint32_t) val.toInt();
@@ -494,7 +556,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen) {
 	f.close();
 #if _DUSB>=1
 	printSeen(listSeen);
-#endif
+#endif //_DUSB
 }
 
 
@@ -512,15 +574,19 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen) {
 	if (!SPIFFS.exists(fn)) {
 #if _DUSB>=1
 		Serial.print("WARNING:: writeSeen, file not exists, formatting ");
-#endif
+#endif //_DUSB
 		initSeen(listSeen);		// XXX make all initial declarations here if config vars need to have a value
+#if _DUSB>=1
 		Serial.println(fn);
+#endif //_DUSB
 	}
 	File f = SPIFFS.open(fn, "w");
 	if (!f) {
+#if _DUSB>=1
 		Serial.print("writeConfig:: ERROR open file=");
 		Serial.print(fn);
 		Serial.println();
+#endif //_DUSB
 		return(-1);
 	}
 
@@ -528,13 +594,13 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen) {
 
 			unsigned long timSeen;
 			f.print(listSeen[i].timSeen);		f.print('\t');
-			// Typecast to long to avoid errors in unsigned conversion.
-			f.print((long) listSeen[i].idSeen);		f.print('\t');
-			//f.print(listSeen[i].datSeen);		f.print('\t');
+			// Typecast to long to avoid errors in unsigned conversion!
+			f.print((long) listSeen[i].idSeen);	f.print('\t');
 			f.print(listSeen[i].cntSeen);		f.print('\t');
 			f.print(listSeen[i].chnSeen);		f.print('\t');
+			f.print(listSeen[i].sfSeen);		f.print('\n');
 			//f.print(listSeen[i].rssiSeen);	f.print('\t');
-			f.print(listSeen[i].sfSeen);		f.print('\n');		
+			//f.print(listSeen[i].datSeen);		f.print('\n');			
 	}
 	
 	f.close();
@@ -544,12 +610,12 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen) {
 
 // ----------------------------------------------------------------------------
 // printSeen
-// - Once every few messages, update the SPIFFS file and write the array.
+// - This function writes the last seen array to the USB
 // ----------------------------------------------------------------------------
 int printSeen(struct nodeSeen *listSeen) {
     int i;
 #if _DUSB>=1
-	if (( debug>=0 ) && ( pdebug & P_MAIN )) {
+	if (( debug>=2 ) && ( pdebug & P_MAIN )) {
 		Serial.println(F("printSeen:: "));
 		for (i=0; i<_SEENMAX; i++) {
 			if (listSeen[i].idSeen != 0) {
@@ -569,7 +635,7 @@ int printSeen(struct nodeSeen *listSeen) {
 			}
 		}
 	}
-#endif
+#endif //_DUSB
 	return(1);
 }
 
@@ -594,7 +660,7 @@ int addSeen(struct nodeSeen *listSeen, struct stat_t stat) {
 				Serial.print(F("addSeen:: index="));
 				Serial.print(i);
 			}
-#endif
+#endif //_DUSB
 			listSeen[i].idSeen = stat.node;
 			listSeen[i].chnSeen = stat.ch;
 			listSeen[i].sfSeen |= stat.sf;			// Or the argument
@@ -612,7 +678,7 @@ int addSeen(struct nodeSeen *listSeen, struct stat_t stat) {
 			Serial.print(F("addSeen:: exit=0, index="));
 			Serial.println(i);
 		}
-#endif
+#endif //_DUSB
 		return(0);
 	}
 
@@ -620,23 +686,6 @@ int addSeen(struct nodeSeen *listSeen, struct stat_t stat) {
 }
 
 
-// ----------------------------------------------------------------------------
-// initSeen
-// Init the lisrScreen array
-// ----------------------------------------------------------------------------
-int initSeen(struct nodeSeen *listSeen) {
-	int i;
-	for (i=0; i< _SEENMAX; i++) {
-		listSeen[i].idSeen=0;
-		listSeen[i].sfSeen=0;
-		listSeen[i].cntSeen=0;
-		listSeen[i].chnSeen=0;
-		listSeen[i].timSeen=0;
-	}
-	return(1);
-}
-
-
 
 // ----------------------------------------------------------------------------
 // listDir
@@ -646,6 +695,9 @@ void listDir(char * dir)
 {
 #if _DUSB>=1
 	// Nothing here
-#endif
+#endif //_DUSB
 }
-#endif //_SEENMAX>0
+
+
+
+#endif //_SEENMAX>0 End of File

+ 188 - 176
ESP-sc-gway/_loraModem.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -17,6 +17,7 @@
 //
 // This file contains the LoRa modem specific code enabling to receive
 // and transmit packages/messages.
+// The functions implemented work in user-space so not with interrupt.
 // ========================================================================================
 //
 //
@@ -122,7 +123,7 @@ uint8_t readRegister(uint8_t addr)
 }
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Write value to a register with address addr. 
 // Function writes one byte at a time.
 // Parameters:
@@ -130,7 +131,7 @@ uint8_t readRegister(uint8_t addr)
 //	value: The value to write to address
 // Returns:
 //	<void>
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 
 // define the settings for SPI writing
 SPISettings writeSettings(SPISPEED, MSBFIRST, SPI_MODE0);
@@ -149,7 +150,7 @@ void writeRegister(uint8_t addr, uint8_t value)
 }
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Write a buffer to a register with address addr. 
 // Function writes one byte at a time.
 // Parameters:
@@ -157,7 +158,7 @@ void writeRegister(uint8_t addr, uint8_t value)
 //	value: The value to write to address
 // Returns:
 //	<void>
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 
 void writeBuffer(uint8_t addr, uint8_t *buf, uint8_t len)
 {
@@ -175,7 +176,7 @@ void writeBuffer(uint8_t addr, uint8_t *buf, uint8_t len)
 	SPI.endTransaction();
 }
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 //  setRate is setting rate and spreading factor and CRC etc. for transmission
 //  for example
 //		Modem Config 1 (MC1) == 0x72 for sx1276
@@ -187,21 +188,21 @@ void writeBuffer(uint8_t addr, uint8_t *buf, uint8_t len)
 //		CRC_ON == 0x04
 //
 //	sf is SF7 to SF12
-//	crc is 0x00 (off) or 
-// ----------------------------------------------------------------------------
+//	CRC is 0x00 (off) or 
+// ----------------------------------------------------------------------------------------
 
 void setRate(uint8_t sf, uint8_t crc) 
 {
 	uint8_t mc1=0, mc2=0, mc3=0;
-#if _DUSB>=2
+#	if _MONITOR>=2
 	if ((sf<SF7) || (sf>SF12)) {
 		if (( debug>=1 ) && ( pdebug & P_RADIO )) {
-			Serial.print(F("setRate:: SF="));
-			Serial.println(sf);
+			mPrint("setRate:: SF=" + String(sf));
 		}
 		return;
 	}
-#endif
+#	endif //_MONITOR
+
 	// Set rate based on Spreading Factor etc
     if (sx1272) {
 		mc1= 0x0A;				// SX1276_MC1_BW_250 0x80 | SX1276_MC1_CR_4_5 0x02
@@ -229,7 +230,7 @@ void setRate(uint8_t sf, uint8_t crc)
         if (sf == SF11 || sf == SF12) { mc3|= 0x08; }		// 0x08 | 0x04
     }
 	
-	// Implicit Header (IH), for class b beacons (&& SF6)
+	// Implicit Header (IH), for CLASS B beacons (&& SF6)
 	//if (getIh(LMIC.rps)) {
     //   mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;
     //    writeRegister(REG_PAYLOAD_LENGTH, getIh(LMIC.rps)); // required length
@@ -249,11 +250,11 @@ void setRate(uint8_t sf, uint8_t crc)
 }
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Set the frequency for our gateway
 // The function has no parameter other than the freq setting used in init.
 // Since we are using a 1ch gateway this value is set fixed.
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 
 void  setFreq(uint32_t freq)
 {
@@ -267,9 +268,9 @@ void  setFreq(uint32_t freq)
 }
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 //	Set Power for our gateway
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void setPow(uint8_t powe)
 {
 	if (powe >= 16) powe = 15;
@@ -281,36 +282,18 @@ void setPow(uint8_t powe)
 	uint8_t pac = (0x80 | (powe & 0xF)) & 0xFF;
 	writeRegister(REG_PAC, (uint8_t)pac);								// set 0x09 to pac
 	
-	// XXX Power settings for CFG_sx1272 are different
+	// Note: Power settings for CFG_sx1272 are different
 	
 	return;
 }
 
 
-// ----------------------------------------------------------------------------
-// Used to set the radio to LoRa mode (transmitter)
-// Please note that this mode can only be set in SLEEP mode and not in Standby.
-// Also there should be not need to re-init this mode is set in the setup() 
-// function.
-// For high freqs (>860 MHz) we need to & with 0x08 otherwise with 0x00
-// ----------------------------------------------------------------------------
 
-//void ICACHE_RAM_ATTR opmodeLora()
-//{
-//#ifdef CFG_sx1276_radio
-//       uint8_t u = OPMODE_LORA | 0x80;   					// TBD: sx1276 high freq 
-//#else // SX-1272
-//	    uint8_t u = OPMODE_LORA | 0x08;
-//#endif
-//    writeRegister(REG_OPMODE, (uint8_t) u);
-//}
-
-
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Set the opmode to a value as defined on top
 // Values are 0x00 to 0x07
 // The value is set for the lowest 3 bits, the other bits are as before.
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void  opmode(uint8_t mode)
 {
 	if (mode == OPMODE_LORA) 
@@ -319,11 +302,11 @@ void  opmode(uint8_t mode)
 		writeRegister(REG_OPMODE, (uint8_t)((readRegister(REG_OPMODE) & ~OPMODE_MASK) | mode));
 }
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Hop to next frequency as defined by NUM_HOPS
 // This function should only be used for receiver operation. The current
 // receiver frequency is determined by ifreq index like so: freqs[ifreq] 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void hop() {
 
 	// 1. Set radio to standby
@@ -359,7 +342,6 @@ void hop() {
 	
 	// Set 0x4D PADAC for SX1276 ; XXX register is 0x5a for sx1272
 	writeRegister(REG_PADAC_SX1276,  0x84); 					// set 0x4D (PADAC) to 0x84
-	//writeRegister(REG_PADAC, readRegister(REG_PADAC) | 0x4);
 	
 	// 8. Reset interrupt Mask, enable all interrupts
 	writeRegister(REG_IRQ_FLAGS_MASK, 0x00);
@@ -370,74 +352,88 @@ void hop() {
 	// Be aware that micros() has increased significantly from calling 
 	// the hop function until printed below
 	//
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (( debug>=2 ) && ( pdebug & P_RADIO )){
-			Serial.print(F("hop:: hopTime:: "));
-			Serial.print(micros() - hopTime);
-			Serial.print(F(", "));
-			SerialStat(0);
+			String response = "hop:: hopTime:: " + String(micros() - hopTime);
+			mStat(0, response);
+			mPrint(response);
 	}
-#endif
+#	endif //_MONITOR
 	// Remember the last time we hop
 	hopTime = micros();									// At what time did we hop
 }
 	
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP
 // This LoRa function reads a message from the LoRa transceiver
-// on Success: returns message length read when message correctly received
+// on Success: returns message length read when message correctly received.
 // on Failure: it returns a negative value on error (CRC error for example).
-// UP function
 // This is the "lowlevel" receive function called by stateMachine()
-// dealing with the radio specific LoRa functions
+// dealing with the radio specific LoRa functions.
+//
+// |         | CR = 4/8  | CR= Coding Rate      |             |
+// |Preamble |Header| CRC| Payload              | Payload CRC |
+// |---------|------|----|----------------------|-------------|
+//
+// The function deals with Explicit Header Mode. Implicit header mode is only
+// valid for SF6 and only for Uplink so it does not work for LoraWAN.
 //
 // Parameters:
 //		Payload: uint8_t[] message. when message is read it is returned in payload.
 // Returns:
 //		Length of payload received
 //
-// 9 bytes header
-// followed by data N bytes
-// 4 bytes MIC end
-// ----------------------------------------------------------------------------
+// 9 bytes header (Explicit Header mode only)
+//	Code Rate is 4/8 for Header, might be different for Payload content
+//
+//	1: Payload Length (in bytes)
+//	2: Forward Error Correction Rate
+//	3: Optional 16 Bit (2 Byte) PHDR_CRC for the PHDR (Physical Header)
+//
+// followed by data N bytes Payload (Max 255)
+//
+// 4 bytes MIC end 
+//
+// ----------------------------------------------------------------------------------------
 uint8_t receivePkt(uint8_t *payload)
 {
-    uint8_t irqflags = readRegister(REG_IRQ_FLAGS);			// 0x12; read back flags
 
-    statc.msg_ttl++;											// Receive statistics counter
+    statc.msg_ttl++;													// Receive statistics counter
 
-	uint8_t crcUsed = readRegister(REG_HOP_CHANNEL);
+    uint8_t irqflags = readRegister(REG_IRQ_FLAGS);						// 0x12; read back flags											
+	uint8_t crcUsed = readRegister(REG_HOP_CHANNEL);					// Is CRC used? (Register 0x1C)
 	if (crcUsed & 0x40) {
-#if _DUSB>=1
+#	if _DUSB>=1
 		if (( debug>=2) && (pdebug & P_RX )) {
 			Serial.println(F("R rxPkt:: CRC used"));
 		}
-#endif
+#	endif //_DUSB
 	}
 	
     //  Check for payload IRQ_LORA_CRCERR_MASK=0x20 set
-    if (irqflags & IRQ_LORA_CRCERR_MASK)
+    if (irqflags & IRQ_LORA_CRCERR_MASK)								// Is CRC error?
     {
-#if _DUSB>=1
+#		if _DUSB>=1
         if (( debug>=0) && ( pdebug & P_RADIO )) {
-			Serial.print(F("rxPkt:: Err CRC, ="));
+			Serial.print(F("rxPkt:: Err CRC, t="));
 			SerialTime();
 			Serial.println();
 		}
-#endif
+#		endif //_DUSB
 		return 0;
     }
 	
 	// Is header OK?
 	// Please note that if we reset the HEADER interrupt in RX,
 	// that we would here conclude that there is no HEADER
-	else if ((irqflags & IRQ_LORA_HEADER_MASK) == false)
+	else if ((irqflags & IRQ_LORA_HEADER_MASK) == false)				// Header not ok?
     {
-#if _DUSB>=1
-        if (( debug>=0) && ( pdebug & P_RADIO )) {
-			Serial.println(F("rxPkt:: Err HEADER"));
-		}
-#endif
+#		if _DUSB>=1
+			if (( debug>=0) && ( pdebug & P_RADIO )) {
+				Serial.println(F("rxPkt:: Err HEADER"));
+			}
+#		endif //_DUSB
 		// Reset VALID-HEADER flag 0x10
         writeRegister(REG_IRQ_FLAGS, (uint8_t)(IRQ_LORA_HEADER_MASK  | IRQ_LORA_RXDONE_MASK));	// 0x12; clear HEADER (== 0x10) flag
         return 0;
@@ -454,7 +450,8 @@ uint8_t receivePkt(uint8_t *payload)
 		}
 
 		if (readRegister(REG_FIFO_RX_CURRENT_ADDR) != readRegister(REG_FIFO_RX_BASE_AD)) {
-			if (( debug>=0 ) && ( pdebug & P_RADIO )) {
+#if			_DUSB>=1
+			if (( debug>=1 ) && ( pdebug & P_RADIO )) {
 				Serial.print(F("RX BASE <"));
 				Serial.print(readRegister(REG_FIFO_RX_BASE_AD));
 				Serial.print(F("> != RX CURRENT <"));
@@ -462,40 +459,41 @@ uint8_t receivePkt(uint8_t *payload)
 				Serial.print(F(">"));
 				Serial.println();
 			}
+#			endif //_DUSB
 		}
 		
         //uint8_t currentAddr = readRegister(REG_FIFO_RX_CURRENT_ADDR);	// 0x10
 		uint8_t currentAddr = readRegister(REG_FIFO_RX_BASE_AD);		// 0x0F
         uint8_t receivedCount = readRegister(REG_RX_NB_BYTES);			// 0x13; How many bytes were read
-#if _DUSB>=1
-		if ((debug>=0) && (currentAddr > 64)) {
-			Serial.print(F("rxPkt:: Rx addr>64"));
-			Serial.println(currentAddr);
-		}
-#endif
+#		if _DUSB>=1
+			if ((debug>=1) && (currentAddr > 64)) {						// More than 64 read?
+				Serial.print(F("rxPkt:: Rx addr>64"));
+				Serial.println(currentAddr);
+			}
+#		endif //_DUSB
         writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) currentAddr);		// 0x0D 
 
 		if (receivedCount > PAYLOAD_LENGTH) {
-#if _DUSB>=1
-			if (( debug>=0 ) & ( pdebug & P_RADIO )) {
-				Serial.print(F("rxPkt:: receivedCount="));
-				Serial.println(receivedCount);
-			}
-#endif
+#			if _DUSB>=1
+				if (( debug>=1 ) & ( pdebug & P_RADIO )) {
+					Serial.print(F("rxPkt:: receivedCount="));
+					Serial.println(receivedCount);
+				}
+#			endif //_DUSB
 			receivedCount=PAYLOAD_LENGTH;
 		}
 
         for(int i=0; i < receivedCount; i++)
         {
-            payload[i] = readRegister(REG_FIFO);			// 0x00, FIFO will auto shift register
+            payload[i] = readRegister(REG_FIFO);						// 0x00, FIFO will auto shift register
         }
 
-		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);		// Reset ALL interrupts
+		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);					// Reset ALL interrupts
 		
-		// A long as _DUSB is enabled, and RX debug messages are selected,
-		//the received packet is displayed on the output.
-#if _DUSB>=1
-		if (( debug>=0 ) && ( pdebug & P_RX )){
+		// A long as _DUSB is enabled, and P_RX debug messages are selected,
+		// the received packet is displayed on the output.
+#		if _DUSB>=1
+		if (( debug>=1 ) && ( pdebug & P_RX )){
 		
 			Serial.print(F("rxPkt:: t="));
 			SerialTime();
@@ -519,8 +517,9 @@ uint8_t receivePkt(uint8_t *payload)
 			// If debug level 1 is specified, we display the content of the message as well
 			// We need to decode the message as well will it make any sense
 
+#			if _TRUSTED_DECODE>=2
 			if (debug>=1)  {							// Must be 1 for operational use
-#if _TRUSTED_DECODE==2
+
 				int index;								// The index of the codex struct to decode
 				String response="";
 
@@ -531,13 +530,13 @@ uint8_t receivePkt(uint8_t *payload)
 					DevAddr[1] = payload[3];
 					DevAddr[2] = payload[2];
 					DevAddr[3] = payload[1];
-				
-				if ((index = inDecodes((char *)(payload+1))) >=0 ) {
+			
+				if ((index = inDecodes((char *)(payload+1))) >=0 ) {	
 					Serial.print(F(", Ind="));
 					Serial.print(index);
 					//Serial.println();
 				}
-				else if (debug>=1) {
+				else if (debug>=1) {	
 					Serial.print(F(", No Index"));
 					Serial.println();
 					return(receivedCount);
@@ -546,15 +545,10 @@ uint8_t receivePkt(uint8_t *payload)
 				// ------------------------------
 				
 				Serial.print(F(", data="));
-				for (int i=0; i<receivedCount; i++) { data[i] = payload[i]; }		// Copy array
-				
-				//for (int i=0; i<receivedCount; i++) {
-				//	if (payload[i]<=0xF) Serial.print('0');
-				//	Serial.print(payload[i], HEX);
-				//	Serial.print(' ');
-				//}
-
 
+				for (int i=0; i<receivedCount; i++) { 			// Copy array
+					data[i] = payload[i]; 
+				}
 
 				uint16_t frameCount=payload[7]*256 + payload[6];
 				
@@ -567,7 +561,9 @@ uint8_t receivePkt(uint8_t *payload)
 				Serial.print(F(", addr="));
 				
 				for (int i=0; i<4; i++) {
-					if (DevAddr[i]<=0xF) Serial.print('0');
+					if (DevAddr[i]<=0xF) {
+						Serial.print('0');
+					}
 					Serial.print(DevAddr[i], HEX);
 					Serial.print(' ');
 				}
@@ -581,14 +577,14 @@ uint8_t receivePkt(uint8_t *payload)
 					Serial.print(data[i], HEX);
 					Serial.print(' ');
 				}
-#endif // _TRUSTED_DECODE
-			}
+			|
+#			endif // _TRUSTED_DECODE
 			
 			Serial.println();
 			
 			if (debug>=2) Serial.flush();
 		}
-#endif //DUSB
+#		endif //DUSB
 		return(receivedCount);
     }
 
@@ -598,19 +594,20 @@ uint8_t receivePkt(uint8_t *payload)
 		IRQ_LORA_HEADER_MASK | 
 		IRQ_LORA_CRCERR_MASK));							// 0x12; Clear RxDone IRQ_LORA_RXDONE_MASK
     return 0;
-} //receivePkt
+} //receivePkt UP
 	
 	
 	
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN 
 // This DOWN function sends a payload to the LoRa node over the air
 // Radio must go back in standby mode as soon as the transmission is finished
 // 
 // NOTE:: writeRegister functions should not be used outside interrupts
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 {
-#if _DUSB>=2
+#	if _DUSB>=2
 	if (payLength>=128) {
 		if (debug>=1) {
 			Serial.print("sendPkt:: len=");
@@ -618,16 +615,18 @@ bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 		}
 		return false;
 	}
-#endif
+#	endif
+	
 	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_TX_BASE_AD));	// 0x0D, 0x0E
 	
 	writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) payLength);				// 0x22
-	payLoad[payLength] = 0x00;
+	payLoad[payLength] = 0x00;											// terminate buffer
 	writeBuffer(REG_FIFO, (uint8_t *) payLoad, payLength);
+	
 	return true;
 }
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // loraWait()
 // This function implements the wait protocol needed for downstream transmissions.
 // Note: Timing of downstream and JoinAccept messages is VERY critical.
@@ -644,13 +643,13 @@ bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 // 
 // Parameter: uint32-t tmst gives the micros() value when transmission should start. (!!!)
 // Note: We assume LoraDown.sfTx contains the SF we will use for downstream message.
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 
 void loraWait(const uint32_t timestamp)
 {
 	uint32_t startMics = micros();						// Start of the loraWait function
 	uint32_t tmst = timestamp;
-// XXX
+
 	int32_t adjust=0;
 	switch (LoraDown.sfTx) {
 		case 7: adjust= 60000; break;					// Make time for SF7 longer 
@@ -660,12 +659,12 @@ void loraWait(const uint32_t timestamp)
 		case 11: break;
 		case 12: break;
 		default:
-#if _DUSB>=1
+#		if _DUSB>=1
 		if (( debug>=1 ) && ( pdebug & P_TX )) {
 			Serial.print(F("T loraWait:: unknown SF="));
 			Serial.print(LoraDown.sfTx);
 		}
-#endif
+#		endif
 		break;
 	}
 	tmst = tmst + gwayConfig.txDelay + adjust;			// tmst based on txDelay and spreading factor
@@ -685,7 +684,7 @@ void loraWait(const uint32_t timestamp)
 	// And we use delayMicroseconds() to wait
 	if (waitTime>0) delayMicroseconds(waitTime);
 
-#if _DUSB>=1
+#	if _DUSB>=1
 	else if ((waitTime+20) < 0) {
 		Serial.println(F("loraWait:: TOO LATE"));		// Never happens
 	}
@@ -704,11 +703,11 @@ void loraWait(const uint32_t timestamp)
 		Serial.println();
 		if (debug>=2) Serial.flush();
 	}
-#endif
+#	endif
 }
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // txLoraModem
 // Init the transmitter and transmit the buffer
 // After successful transmission (dio0==1) TxDone re-init the receiver
@@ -732,7 +731,7 @@ void loraWait(const uint32_t timestamp)
 // 14. Write buffer (byte by byte)
 // 15. Wait until the right time to transmit has arrived
 // 16. opmode TX
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 
 void txLoraModem(
 				uint8_t *payLoad, 		// Payload contents
@@ -745,7 +744,7 @@ void txLoraModem(
 				uint8_t iiq				// Interrupt
 				)
 {
-#if _DUSB>=2
+#	if _DUSB>=2
 	if (debug>=1) {
 		// Make sure that all serial stuff is done before continuing
 		Serial.print(F("txLoraModem::"));
@@ -756,7 +755,8 @@ void txLoraModem(
 		Serial.println();
 		if (debug>=2) Serial.flush();
 	}
-#endif
+#	endif
+
 	_state = S_TX;
 		
 	// 1. Select LoRa modem from sleep mode
@@ -824,7 +824,7 @@ void txLoraModem(
 }// txLoraModem
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Setup the LoRa receiver on the connected transceiver.
 // - Determine the correct transceiver type (sx1272/RFM92 or sx1276/RFM95)
 // - Set the frequency to listen to (1-channel remember)
@@ -836,11 +836,11 @@ void txLoraModem(
 // 3. Set Frequency
 // 4. Spreading Factor
 // 5. Set interrupt mask
-// 6. Clear all interrupt flags
+// 6. 
 // 7. Set opmode to OPMODE_RX
 // 8. Set _state to S_RX
 // 9. Reset all interrupts
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 
 void rxLoraModem()
 {
@@ -864,7 +864,7 @@ void rxLoraModem()
 	//For TX we have to set the PAYLOAD_LENGTH
     //writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) PAYLOAD_LENGTH);	// set 0x22, 0x40==64Byte long
 
-	// Set CRC Protection or MAX payload protection
+	// Set CRC Protection for MAX payload protection
 	//writeRegister(REG_MAX_PAYLOAD_LENGTH, (uint8_t) MAX_PAYLOAD_LENGTH);	// set 0x23 to 0x80==128
 	
 	//Set the start address for the FiFO (Which should be 0)
@@ -873,7 +873,7 @@ void rxLoraModem()
 	// Low Noise Amplifier used in receiver
 	writeRegister(REG_LNA, (uint8_t) LNA_MAX_GAIN);  						// 0x0C, 0x23
 	
-	// Accept no interrupts except RXDONE, RXTOUT en RXCRC
+	// 5. Accept no interrupts except RXDONE, RXTOUT en RXCRC
 	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~(
 		IRQ_LORA_RXDONE_MASK | 
 		IRQ_LORA_RXTOUT_MASK | 
@@ -895,19 +895,23 @@ void rxLoraModem()
 			MAP_DIO2_LORA_NOP |			
 			MAP_DIO3_LORA_CRC));
 
-	// Set the opmode to either single or continuous receive. The first is used when
+	// 7+8.  Set the opmode to either single or continuous receive. The first is used when
 	// every message can come on a different SF, the second when we have fixed SF
 	if (_cad) {
 		// cad Scanner setup, set _state to S_RX
-		// Set Single Receive Mode, goes in STANDBY mode after receipt
-		_state= S_RX;
-		opmode(OPMODE_RX_SINGLE);								// 0x80 | 0x06 (listen one message)
+		// Set Single Receive Mode, and go in STANDBY mode after receipt
+		_state= S_RX;											// 8.
+		opmode(OPMODE_RX_SINGLE);								// 7. 0x80 | 0x06 (listen one message)
 	}
 	else {
 		// Set Continous Receive Mode, useful if we stay on one SF
-		_state= S_RX;
-		if (_hop) Serial.println(F("rxLoraModem:: ERROR continuous receive in hop mode"));
-		opmode(OPMODE_RX);										// 0x80 | 0x05 (listen)
+		_state= S_RX;											// 8.
+#		if _DUSB>=1
+		if (_hop) {
+			Serial.println(F("rxLoraModem:: ERROR continuous receive in hop mode"));
+		}
+#		endif
+		opmode(OPMODE_RX);										// 7. 0x80 | 0x05 (listen)
 	}
 	
 	// 9. clear all radio IRQ flags
@@ -917,7 +921,7 @@ void rxLoraModem()
 }// rxLoraModem
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // function cadScanner()
 //
 // CAD Scanner will scan on the given channel for a valid Symbol/Preamble signal.
@@ -926,7 +930,7 @@ void rxLoraModem()
 // we will set the radio to the SF with best rssi (indicating reception on that sf).
 // The function sets the _state to S_SCAN
 // NOTE: DO not set the frequency here but use the frequency hopper
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void cadScanner()
 {
 	// 1. Put system in LoRa mode (which destroys all other modes)
@@ -974,11 +978,20 @@ void cadScanner()
 }// cadScanner
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // First time initialisation of the LoRa modem
 // Subsequent changes to the modem state etc. done by txLoraModem or rxLoraModem
 // After initialisation the modem is put in rx mode (listen)
-// ----------------------------------------------------------------------------
+//	1.	Set Radio to sleep
+//	2.	Set opmode to LoRa
+//	3.	Set Frequency
+//	4.	Set rate and Spreading Factor
+//	5.	Set chip version
+//	6.	Set SYNC word
+//	7.	Set ranp-up time
+//	8.	Set interrupt masks
+//	9.	Clear INT flags
+// ----------------------------------------------------------------------------------------
 void initLoraModem(
 				)
 {
@@ -989,9 +1002,6 @@ void initLoraModem(
     digitalWrite(pins.rst, HIGH);
 	delayMicroseconds(10000);
 	digitalWrite(pins.ss, HIGH);
-#if _DUSB>=1
-
-#endif
 
 #else
 	// Reset the transceiver chip with a pulse of 10 mSec
@@ -1000,10 +1010,10 @@ void initLoraModem(
     digitalWrite(pins.rst, LOW);
 	delayMicroseconds(10000);
 #endif
-	// 2. Set radio to sleep
+	// 1. Set radio to sleep
 	opmode(OPMODE_SLEEP);										// set register 0x01 to 0x00
 
-	// 1 Set LoRa Mode
+	// 2 Set LoRa Mode
 	opmode(OPMODE_LORA);										// set register 0x01 to 0x80
 	
 	// 3. Set frequency based on value in freq
@@ -1014,24 +1024,26 @@ void initLoraModem(
 	
 	// Low Noise Amplifier used in receiver
     writeRegister(REG_LNA, (uint8_t) LNA_MAX_GAIN);  			// 0x0C, 0x23
-#if _PIN_OUT==4
-	delay(1);
-#endif
+#	if _PIN_OUT==4
+		delay(1);
+#	endif
+
+	// 5. Set chip type/version
     uint8_t version = readRegister(REG_VERSION);				// Read the LoRa chip version id
     if (version == 0x22) {
         // sx1272
-#if _DUSB>=2
-        Serial.println(F("WARNING:: SX1272 detected"));
-#endif
+#		if _DUSB>=2
+			Serial.println(F("WARNING:: SX1272 detected"));
+#		endif
         sx1272 = true;
     } 
 	
 	else if (version == 0x12) {
         // sx1276?
-#if _DUSB>=2
+#			if _DUSB>=2
             if (debug >=1) 
 				Serial.println(F("SX1276 starting"));
-#endif
+#			endif
             sx1272 = false;
 	}
 	else {
@@ -1039,22 +1051,22 @@ void initLoraModem(
 		// therefore specified the wrong type of wiring/pins to the software
 		// Maybe this issue can be resolved of we try one of the other defined 
 		// boards. (Comresult or Hallard or ...)
-#if _DUSB>=1
-		Serial.print(F("Unknown transceiver="));
-		Serial.print(version,HEX);
-		Serial.print(F(", pins.rst ="));	Serial.print(pins.rst);
-		Serial.print(F(", pins.ss  ="));	Serial.print(pins.ss);
-		Serial.print(F(", pins.dio0 ="));	Serial.print(pins.dio0);
-		Serial.print(F(", pins.dio1 ="));	Serial.print(pins.dio1);
-		Serial.print(F(", pins.dio2 ="));	Serial.print(pins.dio2);
-		Serial.println();
-		Serial.flush();
-#endif
+#		if _DUSB>=1
+			Serial.print(F("Unknown transceiver="));
+			Serial.print(version,HEX);
+			Serial.print(F(", pins.rst ="));	Serial.print(pins.rst);
+			Serial.print(F(", pins.ss  ="));	Serial.print(pins.ss);
+			Serial.print(F(", pins.dio0 ="));	Serial.print(pins.dio0);
+			Serial.print(F(", pins.dio1 ="));	Serial.print(pins.dio1);
+			Serial.print(F(", pins.dio2 ="));	Serial.print(pins.dio2);
+			Serial.println();
+			Serial.flush();
+#		endif
 		die("");												// Maybe first try another kind of receiver
     }
 	// If we are here, the chip is recognized successfully
 	
-	// 7. set sync word
+	// 6. set sync word
 	writeRegister(REG_SYNC_WORD, (uint8_t) 0x34);				// set 0x39 to 0x34 LORA_MAC_PREAMBLE
 	
 	// prevent node to node communication
@@ -1068,14 +1080,14 @@ void initLoraModem(
 	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_RX_BASE_AD));	// set reg 0x0D to 0x0F
 	writeRegister(REG_HOP_PERIOD,0x00);							// reg 0x24, set to 0x00
 
-	// 5. Config PA Ramp up time								// set reg 0x0A  
+	// 7. Config PA Ramp up time								// set reg 0x0A  
 	writeRegister(REG_PARAMP, (readRegister(REG_PARAMP) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
 	
 	// Set 0x4D PADAC for SX1276 ; XXX register is 0x5a for sx1272
 	writeRegister(REG_PADAC_SX1276,  0x84); 					// set 0x4D (PADAC) to 0x84
 	//writeRegister(REG_PADAC, readRegister(REG_PADAC) | 0x4);
 	
-	// Reset interrupt Mask, enable all interrupts
+	// 8. Reset interrupt Mask, enable all interrupts
 	writeRegister(REG_IRQ_FLAGS_MASK, 0x00);
 	
 	// 9. clear all radio IRQ flags
@@ -1083,22 +1095,22 @@ void initLoraModem(
 }// initLoraModem
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Void function startReceiver.
 // This function starts the receiver loop of the LoRa service.
 // It starts the LoRa modem with initLoraModem(), and then starts
 // the receiver either in single message (CAD) of in continuous
 // reception (STD).
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void startReceiver() {
 	initLoraModem();								// XXX 180326, after adapting this function 
 	if (_cad) {
-#if _DUSB>=1
+#		if _DUSB>=1
 		if (( debug>=1 ) && ( pdebug & P_SCAN )) {
 			Serial.println(F("S PULL:: _state set to S_SCAN"));
 			if (debug>=2) Serial.flush();
 		}
-#endif
+#		endif
 		_state = S_SCAN;
 		sf = SF7;
 		cadScanner();
@@ -1112,21 +1124,21 @@ void startReceiver() {
 }
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Interrupt_0 Handler.
 // Both interrupts DIO0 and DIO1 are mapped on GPIO15. Se we have to look at 
 // the interrupt flags to see which interrupt(s) are called.
 //
 // NOTE:: This method may work not as good as just using more GPIO pins on 
 //  the ESP8266 mcu. But in practice it works good enough
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void ICACHE_RAM_ATTR Interrupt_0()
 {
 	_event=1;
 }
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Interrupt handler for DIO1 having High Value
 // As DIO0 and DIO1 may be multiplexed on one GPIO interrupt handler
 // (as we do) we have to be careful only to call the right Interrupt_x
@@ -1136,15 +1148,15 @@ void ICACHE_RAM_ATTR Interrupt_0()
 //		- CDDETD
 //		- RXTIMEOUT
 //		- (RXDONE error only)
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void ICACHE_RAM_ATTR Interrupt_1()
 {
 	_event=1;
 }
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // Frequency Hopping Channel (FHSS) dio2
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 void ICACHE_RAM_ATTR Interrupt_2() 
 {
 	_event=1;

+ 4 - 2
ESP-sc-gway/_oLED.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -99,8 +99,10 @@ void msg_oLED(String tim, String sf) {
 // --------------------------------------------------------------------
 void addr_oLED() 
 {
+#if _DUSB>=1
 	Serial.print(F("OLED_ADDR=0x"));
 	Serial.println(OLED_ADDR, HEX);
+#endif //_DUSB
 }
 
 #endif

+ 12 - 10
ESP-sc-gway/_otaServer.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29	
+// Version 6.1.5
+// Date: 2019-12-20	
 //
 //
 // All rights reserved. This program and the accompanying materials
@@ -32,9 +32,11 @@
 void setupOta(char *hostname) {
 
 	ArduinoOTA.begin();
-#if _DUSB>=1
-	Serial.println(F("setupOta:: Started"));
-#endif	
+	
+#	if _MONITOR>=1
+		mPrint("setupOta:: Started");
+#	endif	 //_MONITOR
+
 	// Hostname defaults to esp8266-[ChipID] for ESP8266 nodes
 	ArduinoOTA.setHostname(hostname);
 	
@@ -68,11 +70,11 @@ void setupOta(char *hostname) {
 		else if (error == OTA_END_ERROR) Serial.println("End Failed");
 	});
 	
-#if _DUSB>=1
-	Serial.println("Ready");
-	Serial.print("IP address: ");
-	Serial.println(WiFi.localIP());
-#endif
+#	if _MONITOR>=1
+		if (debug>=1) {
+			mPrint("Ready IP address: " + String(WiFi.localIP().toString()));
+		}
+#	endif //_MONITOR
 	
 	// Only if the Webserver is active also
 #if A_SERVER==2										// Displayed for the moment

+ 2 - 2
ESP-sc-gway/_repeater.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg
-// Verison 6.1.4
-// Date: 2019-11-29
+// Verison 6.1.5
+// Date: 2019-12-20
 //
 // All rights reserved. This program and the accompanying materials
 // are made available under the terms of the MIT License

+ 27 - 26
ESP-sc-gway/_sensor.ino

@@ -1,7 +1,7 @@
 // sensor.ino; 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg
-// Verison 6.1.4
-// Date: 2019-11-29
+// Verison 6.1.5
+// Date: 2019-12-20
 //
 // All rights reserved. This program and the accompanying materials
 // are made available under the terms of the MIT License
@@ -75,16 +75,19 @@ static int LoRaSensors(uint8_t *buf) {
 	uint8_t tchars = 1;
 	buf[0] = 0x86;									// 134; User code <lCode + len==3 + Parity
 
-#if _DUSB>=1
-	if (debug>=0)
-		Serial.print(F("LoRaSensors:: "));
-#endif
+#	if _MONITOR>=1
+	if (debug>=0) {
+		SmPrint("LoRaSensors:: ");
+	}
+#	endif //_MONITOR
 
 #if _BATTERY==1
-#if _DUSB>=1
-	if (debug>=0)
-		Serial.print(F("Battery "));
-#endif
+#	if _MONITOR>=1
+	if (debug>=0) {
+		mPrint("Battery ");
+	}
+#	endif //_MONITOR
+
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ESP32)
 	// For ESP there is no standard battery library
 	// What we do is to measure GPIO35 pin which has a 100K voltage divider
@@ -103,11 +106,13 @@ static int LoRaSensors(uint8_t *buf) {
 #endif
 
 #if _GPS==1
-#if _DUSB>=1
-	if (debug>=0)
-		Serial.print(F("M GPS "));
+#	if _MONITOR>=1
+	if (debug>=1)
+		mPrint("GPS sensor"));
+#	endif //_MONITOR
 
-	if (( debug>=1 ) && ( pdebug & P_MAIN )) {
+#	if _DUSB>=1
+	if (( debug>=2 ) && ( pdebug & P_MAIN )) {
 		Serial.print("\tLatitude  : ");
 		Serial.println(gps.location.lat(), 5);
 		Serial.print("\tLongitude : ");
@@ -124,14 +129,14 @@ static int LoRaSensors(uint8_t *buf) {
 		Serial.print(":");
 		Serial.println(gps.time.second());
 	}
-#endif
+#	endif //_DUSB
 
 	smartDelay(1000);
 	
 	if (millis() > 5000 && gps.charsProcessed() < 10) {
-#if _DUSB>=1
-		Serial.println(F("No GPS data received: check wiring"));
-#endif
+#		if _MONITOR>=1
+			mPrint("No GPS data received: check wiring");
+#		endif //_MONITOR
 		return(0);
 	}
 	
@@ -143,11 +148,6 @@ static int LoRaSensors(uint8_t *buf) {
 
 #endif
 
-#if _DUSB>=1
-	if (debug>=0)
-		Serial.println();
-#endif
-
 	// If all sensor data is encoded, we encode the buffer	
 	lcode.eMsg(buf, tchars);								// Fill byte 0 with bytecount and Parity
 	
@@ -226,9 +226,9 @@ static void generate_subkey(uint8_t *key, uint8_t *k1, uint8_t *k2) {
 //
 // Although our own handler may choose not to interpret the last 4 (MIC) bytes
 // of a PHYSPAYLOAD physical payload message of in internal sensor,
-// The official TTN (and other) backends will intrpret the complete message and
+// The official TTN (and other) backends will interpret the complete message and
 // conclude that the generated message is bogus.
-// So we sill really simulate internal messages coming from the -1ch gateway
+// So we will really simulate internal messages coming from the -1ch gateway
 // to come from a real sensor and append 4 MIC bytes to every message that are 
 // perfectly legimate
 // Parameters:
@@ -517,8 +517,9 @@ int sensorPacket() {
 #endif
 
 	// So now our package is ready, and we can send it up through the gateway interface
-	// Note Be aware that the sensor message (which is bytes) in message will be
+	// Note: Be aware that the sensor message (which is bytes) in message will be
 	// be expanded if the server expects JSON messages.
+	// Note2: We fake this sensor message when sending
 	//
 	int buff_index = buildPacket(tmst, buff_up, LUP, true);
 	

+ 175 - 166
ESP-sc-gway/_stateMachine.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -80,12 +80,13 @@ void stateMachine()
 	uint8_t rssi;
 	_event=0;													// Reset the interrupt detector	
 	
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (intr != flags) {
 		Serial.print(F("FLAG  ::"));
 		SerialStat(intr);
 	}
-#endif
+	String response = "";
+#	endif //_MONITOR
 
 	// If Hopping is selected AND if there is NO event interrupt detected 
 	// and the state machine is called anyway
@@ -113,10 +114,11 @@ void stateMachine()
 				case S_TXDONE:	eventWait = EVENT_WAIT * 4; break;
 				default:
 					eventWait=0;
-#if _DUSB>=1
-					Serial.print(F("DEFAULT :: "));
-					SerialStat(intr);
-#endif
+#					if _MONITOR>=1
+						response = "DEFAULT :: ";
+						mStat(intr, response);
+						mPrint(response);
+#					endif //_MONITOR
 			}
 			
 			// doneWait is the time that we received CDDONE interrupt
@@ -134,12 +136,11 @@ void stateMachine()
 				case SF12:	doneWait *= 32;	break;
 				default:
 					doneWait *= 1;
-#if _DUSB>=1
+#					if _MONITOR>=1
 					if (( debug>=0 ) && ( pdebug & P_PRE )) {
-						Serial.print(F("PRE:: DEF set"));
-						Serial.println();
+						mPrint("PRE:: DEF set");
 					}
-#endif
+#					endif //_MONITOR
 					break;
 			}
 
@@ -155,12 +156,13 @@ void stateMachine()
 				_state = S_SCAN;
 				hop();											// increment ifreq = (ifreq + 1) % NUM_HOPS ;
 				cadScanner();									// Reset to initial SF, leave frequency "freqs[ifreq]"
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug >= 1 ) && ( pdebug & P_PRE )) {
-					Serial.print(F("DONE  :: "));
-					SerialStat(intr);
+					response = "DONE  :: ";
+					mStat(intr, response);
+					mPrint(response);							// Can move down for timing reasons
 				}
-#endif
+#				endif //_MONITOR
 				eventTime=micros();								// reset the timer on timeout
 				doneTime=micros();								// reset the timer on timeout
 				return;
@@ -173,12 +175,13 @@ void stateMachine()
 				_state = S_SCAN;
 				hop();											// increment ifreq = (ifreq + 1) % NUM_HOPS ;
 				cadScanner();									// Reset to initial SF, leave frequency "freqs[ifreq]"
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug >= 2 ) && ( pdebug & P_PRE )) {
-					Serial.print(F("HOP ::  "));
-					SerialStat(intr);
+					response = "HOP ::  ";
+					mStat(intr, response);
+					mPrint(response);
 				}
-#endif
+#				endif //_MONITOR
 				eventTime=micros();								// reset the timer on timeout
 				doneTime=micros();								// reset the timer on timeout
 				return;
@@ -188,16 +191,17 @@ void stateMachine()
 			// If we are here, NO timeout has occurred 
 			// So we need to return to the main State Machine
 			// as there was NO interrupt
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=3 ) && ( pdebug & P_PRE )) {
-				Serial.print(F("PRE:: eventTime="));
-				Serial.print(eventTime);
-				Serial.print(F(", micros="));
-				Serial.print(micros());
-				Serial.print(F(": "));
-				SerialStat(intr);
-			}
-#endif
+				response  = "PRE:: eventTime=";
+				response += String(eventTime);
+				response += ", micros=";
+				response += String(micros());
+				response += ": ";
+				mStat(intr, response);
+				mPrint(response);
+			}
+#			endif //_MONITOR
 		} // if SCAN or CAD
 		
 		// else, S_RX of S_TX for example
@@ -224,11 +228,11 @@ void stateMachine()
 	  // The initLoraModem() function is already called in setup();
 	  //
 	  case S_INIT:
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug>=1 ) && ( pdebug & P_PRE )) { 
-			Serial.println(F("S_INIT")); 
+			mPrint("S_INIT"); 
 		}
-#endif
+#		endif //_MONITOR
 		// new state, needed to startup the radio (to S_SCAN)
 		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );				// Clear ALL interrupts
 		writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 );			// Clear ALL interrupts
@@ -278,12 +282,13 @@ void stateMachine()
 			_event = 0;												// Make 0, as soon as we have an interrupt
 			detTime = micros();										// mark time that preamble detected
 			
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=1 ) && ( pdebug & P_SCAN )) {
-				Serial.print(F("SCAN:: "));
-				SerialStat(intr);
+				response = "SCAN:: ";
+				mStat(intr, response);
+				mPrint(response);
 			}
-#endif
+#			endif //_MONITOR
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );			// reset all interrupt flags
 			opmode(OPMODE_RX_SINGLE);								// set reg 0x01 to 0x06 for receiving
 			
@@ -300,27 +305,28 @@ void stateMachine()
 			opmode(OPMODE_CAD);
 			rssi = readRegister(REG_RSSI);							// Read the RSSI
 
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=2 ) && ( pdebug & P_SCAN )) {
-				Serial.print(F("SCAN:: CDDONE: "));
-				SerialStat(intr);
+				response = "SCAN:: CDDONE: ";
+				mStat(intr, response);
+				mPrint(response);
 			}
-#endif
+#			endif //_MONITOR
 			// We choose the generic RSSI as a sorting mechanism for packages/messages
 			// The pRSSI (package RSSI) is calculated upon successful reception of message
 			// So we expect that this value makes little sense for the moment with CDDONE.
 			// Set the rssi as low as the noise floor. Lower values are not recognized then.
 			// Every cycle starts with ifreq==0 and sf=SF7 (or the set init SF)
 			//
-			//if ( rssi > RSSI_LIMIT )								// Is set to 35
 			if ( rssi > (RSSI_LIMIT - (_hop * 7)))					// Is set to 35, or 29 for HOP
 			{
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug>=2 ) && ( pdebug & P_SCAN )) {
-					Serial.print(F("SCAN:: -> CAD: "));
-					SerialStat(intr);
+					response = "SCAN:: -> CAD: ";
+					mStat(intr, response);
+					mPrint(response);
 				}
-#endif
+#				endif //_MONITOR
 				_state = S_CAD;										// promote to next level
 				_event=0;
 			}
@@ -328,16 +334,16 @@ void stateMachine()
 			// If the RSSI is not big enough we skip the CDDONE
 			// and go back to scanning
 			else {
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug>=2 ) && ( pdebug & P_SCAN )) {
-					Serial.print("SCAN:: rssi=");
-					Serial.print(rssi);
-					Serial.print(F(": "));
-					SerialStat(intr);
+					response = "SCAN:: rssi=";
+					response += String(rssi);
+					response += ": ";
+					mStat(intr, response);
+					mPrint(response);
 				}
-#endif
+#				endif //_MONITOR
 				_state = S_SCAN;
-				//_event=1;											// loop() scan until CDDONE
 			}
 
 			// Clear the CADDONE flag
@@ -370,12 +376,13 @@ void stateMachine()
 		// Unkown Interrupt, so we have an error
 		//
 		else {
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=0 ) && ( pdebug & P_SCAN )) {
-				Serial.print(F("SCAN unknown:: "));
-				SerialStat(intr);
+				response = "SCAN unknown:: ";
+				mStat(intr, response);
+				mPrint(response);
 			}
-#endif
+#			endif //_MONITOR
 			_state=S_SCAN;
 			//_event=1;												// XXX 06/03 loop until interrupt
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
@@ -437,12 +444,13 @@ void stateMachine()
 			_rssi = rssi;											// Read the RSSI in the state variable
 
 			detTime = micros();
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=1 ) && ( pdebug & P_CAD )) {
-				Serial.print(F("CAD:: "));
-				SerialStat(intr);
+				response = "CAD:: ";
+				mStat(intr, response);
+				mPrint(response);
 			}
-#endif
+#			endif //_MONITOR
 			_state = S_RX;											// Set state to start receiving
 			
 		}// CDDETD
@@ -471,12 +479,11 @@ void stateMachine()
 				delayMicroseconds(RSSI_WAIT);
 				rssi = readRegister(REG_RSSI);						// Read the RSSI
 
-#if _DUSB>=1
-				if (( debug>=2 ) && ( pdebug & P_CAD )) {
-					Serial.print(F("S_CAD:: CDONE, SF="));
-					Serial.println(sf);
+#				if _MONITOR>=1
+				if (( debug>=3 ) && ( pdebug & P_CAD )) {
+					mPrint("S_CAD:: CDONE, SF=" + String(sf) );
 				}
-#endif
+#				endif //_MONIYOT
 			}
 
 			// If we reach the highest SF for the frequency plan,
@@ -493,12 +500,11 @@ void stateMachine()
 				sf = (sf_t) freqs[ifreq].upLo;
 				cadScanner();										// Which will reset SF to lowest SF
 
-#if _DUSB>=1		
-				if (( debug>=2 ) && ( pdebug & P_CAD )) {
-					Serial.print(F("CAD->SCAN:: "));
-					SerialStat(intr);
+#				if _MONITOR>=1		
+				if (( debug>=3 ) && ( pdebug & P_CAD )) {
+					mPrint("CAD->SCAN:: " + String(intr) );
 				}
-#endif
+#				endif //_MONITOR
 			}
 			doneTime = micros();									// We need CDDONE or other intr to reset timeout
 			
@@ -511,11 +517,11 @@ void stateMachine()
 		// coming on this frequency so we wait on CDECT.
 		//
 		else if (intr == 0x00) {
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=3 ) && ( pdebug & P_CAD )) {
-				Serial.println("Err CAD:: intr is 0x00");
+				mPrint ("CAD:: intr is 0x00");
 			}
-#endif
+#			endif //_MONITOR
 			_event=1;												// Stay in CAD _state until real interrupt
 		}
 		
@@ -523,12 +529,11 @@ void stateMachine()
 		// and restart scanning. If hop we even start at ifreq==1
 		//
 		else {
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=0) && ( pdebug & P_CAD )) { 
-				Serial.print(F("Err CAD: Unknown::")); 
-				SerialStat(intr);
+				mPrint("Err CAD: Unknown::" + String(intr) ); 
 			}
-#endif
+#			endif //_MONITOR
 			_state = S_SCAN;
 				sf = SF7;
 				cadScanner();										// Scan and set SF7
@@ -545,7 +550,7 @@ void stateMachine()
 	  // If we receive an RXDONE interrupt on dio0 with state==S_RX
 	  // 	So we should handle the received message
 	  // Else if it is RXTOUT interrupt
-	  //	So we handle this, and get modem out of standby
+	  //	Timeout, so we handle this interrupt, and get modem out of standby
 	  // Else
 	  //	Go back to SCAN
 	  //
@@ -553,20 +558,21 @@ void stateMachine()
 		
 		if (intr & IRQ_LORA_RXDONE_MASK) {
 		
-#if CRCCHECK==1
+#			if _CRCCHECK>=1
 			// We have to check for CRC error which will be visible AFTER RXDONE is set.
 			// CRC errors might indicate that the reception is not OK.
 			// Could be CRC error or message too large.
 			// CRC error checking requires DIO3
 			//
 			if (intr & IRQ_LORA_CRCERR_MASK) {
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug>=0 ) && ( pdebug & P_RX )) {
 					Serial.print(F("Rx CRC err: "));
 					SerialStat(intr);
 				}
-#endif
-				if (_cad) {
+#				endif //_MONITOR
+
+				if ((_cad) || (_hop)) {
 					sf = SF7;
 					_state = S_SCAN;
 					cadScanner();
@@ -585,16 +591,17 @@ void stateMachine()
 					IRQ_LORA_HEADER_MASK | 
 					IRQ_LORA_CRCERR_MASK ));
 
-				break;
-			}// RX-CRC
-#endif // CRCCHECK
+				break;													// Get out of loop
+			}// RX-CRC mask
+#			endif //_CRCCHECK
+
 			
 			// If we are here, no CRC error occurred, start timer
-#if _DUSB>=1
-			unsigned long ffTime = micros();	
-#endif			
+#			if _DUSB>=1 || _MONITOR>=1
+				unsigned long ffTime = micros();	
+#			endif			
 			// There should not be an error in the message
-			LoraUp.payLoad[0]= 0x00;									// Empty the message
+			LoraUp.payLoad[0]= 0x00;								// Empty the message
 
 			// If receive S_RX error, 
 			// - print Error message
@@ -602,35 +609,32 @@ void stateMachine()
 			// - Set _event=1 so that we loop until we have an interrupt
 			// - Reset the interrupts
 			// - break
+			// NOTE: receivePacket also increases .ok0 - .ok2 counter
+			
 			if((LoraUp.payLength = receivePkt(LoraUp.payLoad)) <= 0) {
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug>=1 ) && ( pdebug & P_RX )) {
-					Serial.print(F("sMachine:: Error S-RX: "));
-					Serial.print(F("payLength="));
-					Serial.print(LoraUp.payLength);
-					Serial.println();
+					response += "sMachine:: Error S-RX: payLenth=";
+					response += String(LoraUp.payLength);
+					mPrint(response);
 				}
-#endif
+#				endif //_MONITOR
 				_event=1;
 				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Reset the interrupt mask
-				//writeRegister(REG_IRQ_FLAGS, (uint8_t)(
-				//	IRQ_LORA_RXDONE_MASK | 
-				//	IRQ_LORA_RXTOUT_MASK | 
-				//	IRQ_LORA_HEADER_MASK | 
-				//	IRQ_LORA_CRCERR_MASK ));
 				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
 				
 				_state = S_SCAN;
 				break;
 			}
-#if _DUSB>=1
-			if (( debug>=1 ) && ( pdebug & P_RX )) {
-				Serial.print(F("R RXDONE in dT="));
-				Serial.print(ffTime - detTime);
-				Serial.print(F(": "));
-				SerialStat(intr);
-			}
-#endif
+			
+#			if _MONITOR>=1
+			if ((pdebug & P_RX) && (debug >= 2)) {
+				response  = "RXDONE:: dT=";
+				response += String(ffTime - detTime);
+				mStat(intr, response);
+				mPrint(response);
+			}
+#			endif //_MONITOR
 				
 			// Do all register processing in this section
 			uint8_t value = readRegister(REG_PKT_SNR_VALUE);		// 0x19; 
@@ -659,11 +663,11 @@ void stateMachine()
 			// If read was successful, read the package from the LoRa bus
 			//
 			if (receivePacket() <= 0) {								// read is not successful
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug>=0 ) && ( pdebug & P_RX )) {
-					Serial.println(F("sMach:: Error receivePacket"));
+					mPrint("sMach:: Error receivePacket");
 				}
-#endif
+#				endif //_MONITOR
 			}
 			
 			// Set the modem to receiving BEFORE going back to user space.
@@ -680,7 +684,7 @@ void stateMachine()
 			
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// Reset the interrupt mask
-			eventTime=micros();										//There was an event for receive
+			eventTime=micros();										// There was an event for receive
 			_event=0;
 		}// RXDONE
 		
@@ -704,12 +708,13 @@ void stateMachine()
 			//
 			if ((_cad) || (_hop)) {
 				// Set the state to CAD scanning
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug>=2 ) && ( pdebug & P_RX )) {
-					Serial.print(F("RXTOUT:: "));
-					SerialStat(intr);
+					response = "RXTOUT:: ";
+					mStat(intr, response);
+					mPrint(response);
 				}
-#endif
+#				endif //_MONITOR
 				sf = SF7;
 				cadScanner();										// Start the scanner after RXTOUT
 				_state = S_SCAN;									// New state is scan
@@ -732,12 +737,11 @@ void stateMachine()
 			// This interrupt means we received an header successfully
 			// which is normall an indication of RXDONE
 			//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_HEADER_MASK);
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=3 ) && ( pdebug & P_RX )) {
-				Serial.print(F("RX HEADER:: "));
-				SerialStat(intr);
+				mPrint("RX HEADER:: " + String(intr));
 			}
-#endif
+#			endif //_MONITOR
 			//_event=1;
 		}
 
@@ -746,24 +750,22 @@ void stateMachine()
 		// state there always comes a RXTOUT or RXDONE interrupt
 		//
 		else if (intr == 0x00) {
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=3) && ( pdebug & P_RX )) {
-				Serial.print(F("S_RX no INTR:: "));
-				SerialStat(intr);
+				mPrint("S_RX no INTR:: " + String(intr));
 			}
-#endif
+#			endif //_MONITOR
 		}
 		
 		// The interrupt received is not RXDONE, RXTOUT or HEADER
 		// therefore we wait. Make sure to clear the interrupt
 		// as HEADER interrupt comes just before RXDONE
 		else {							
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=0 ) && ( pdebug & P_RX )) {
-				Serial.print(F("R S_RX:: no RXDONE, RXTOUT, HEADER:: "));
-				SerialStat(intr);
+				mPrint("R S_RX:: no RXDONE, RXTOUT, HEADER:: " + String(intr));
 			}
-#endif
+#			endif //_MONITOR
 			//writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 );
 			//writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
 		}// int not RXDONE or RXTOUT
@@ -784,11 +786,11 @@ void stateMachine()
 		// then there will nog be a TXDONE but probably another CDDONE/CDDETD before
 		// we have a timeout in the main program (Keep Alive)
 		if (intr == 0x00) {
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=2 ) && ( pdebug & P_TX )) {
-				Serial.println(F("TX:: 0x00"));
+				mPrint("TX:: 0x00");
 			}
-#endif
+#			endif //_MONITOR
 			_event=1;
 			_state=S_TXDONE;
 		}
@@ -814,12 +816,11 @@ void stateMachine()
 		);
 		// After filling the buffer we only react on TXDONE interrupt
 		
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug>=1 ) && ( pdebug & P_TX )) { 
-			Serial.print(F("T TX done:: ")); 
-			SerialStat(intr);
+			mPrint("TX done:: " + String(intr) ); 
 		}
-#endif
+#		endif //_MONITOR
 		// More or less start at the "case TXDONE:" below 
 		_state=S_TXDONE;
 		_event=1;													// Or remove the break below
@@ -838,15 +839,22 @@ void stateMachine()
 	  case S_TXDONE:
 		if (intr & IRQ_LORA_TXDONE_MASK) {
 
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=0 ) && ( pdebug & P_TX )) {
-				Serial.print(F("T TXDONE:: rcvd="));
-				Serial.print(micros());
-				Serial.print(F(", diff="));
-				Serial.println(micros()-LoraDown.tmst);
-				if (debug>=2) Serial.flush();
+				response =  "T TXDONE:: rcvd=" + String(micros());
+				response += ", diff=" + String(micros()-LoraDown.tmst);
+				mPrint(response);
 			}
-#endif
+#			endif
+
+#			if _MONITOR>=2
+			if (pdebug & P_TX) {
+				response  = "T TXDONE:: rcvd=" + micros();
+				response += ", diff=" + String(micros()-LoraDown.tmst);
+				mPrint(response);
+			}
+#			endif
+
 			// After transmission reset to receiver
 			if ((_cad) || (_hop)) {									// XXX 26/02
 				// Set the state to CAD scanning
@@ -862,21 +870,22 @@ void stateMachine()
 			_event=0;
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset interrupt flags
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=1 ) && ( pdebug & P_TX )) {
-				Serial.println(F("T TXDONE:: done OK"));
+				mPrint("T TXDONE:: done OK");
 			}
-#endif
+#			endif //_MONITOR
 		}
 		
 		// If a soft _event==0 interrupt and no transmission finished:
 		else if ( intr != 0 ) {
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=0 ) && ( pdebug & P_TX )) {
-				Serial.print(F("T TXDONE:: unknown int:"));
-				SerialStat(intr);
-			}
-#endif
+				response =  "TXDONE:: unknown int:";
+				mStat(intr, response);
+				mPrint(response);
+			} //_MONITOR
+#			endif
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset interrupt flags
 			_event=0;
@@ -891,19 +900,18 @@ void stateMachine()
 			// within 7 seconds according to spec, of here is a problem.
 			if ( sendTime > micros() ) sendTime = 0;				// This could be omitted for usigned ints
 			if (( _state == S_TXDONE ) && (( micros() - sendTime) > 7000000 )) {
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if (( debug>=1 ) && ( pdebug & P_TX )) {
-					Serial.println(F("T TXDONE:: reset TX"));
-					Serial.flush();
+					mPrint("TXDONE:: reset TX");
 				}
-#endif
+#				endif //_MONITOR
 				startReceiver();
 			}
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=3 ) && ( pdebug & P_TX )) {
-				Serial.println(F("T TXDONE:: No Interrupt"));
+				mPrint("T TXDONE:: No Interrupt");
 			}
-#endif
+#			endif //_MONITOR
 		}
 	
 
@@ -915,19 +923,20 @@ void stateMachine()
 	  // If such a thing happens, we should re-init the interface and 
 	  // make sure that we pick up next interrupt
 	  default:
-#if _DUSB>=1
-		if (( debug>=0) && ( pdebug & P_PRE )) { 
-			Serial.print("ERR state="); 
-			Serial.println(_state);	
+#		if _MONITOR>=1
+		if (( debug>=0) && ( pdebug & P_PRE )) {
+			mPrint("ERR state=" + String(_state));	
 		}
-#endif
+#		endif //_MONITOR
+
 		if ((_cad) || (_hop)) {
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (debug>=0) {
-				Serial.println(F("default:: Unknown _state "));
-				SerialStat(intr);
+				response = "default:: Unknown _state ";
+				mStat(intr, response);
+				mPrint(response);
 			}
-#endif
+#			endif //_MONITOR
 			_state = S_SCAN;
 			sf = SF7;
 			cadScanner();											// Restart the state machine

+ 4 - 4
ESP-sc-gway/_tcpTTN.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -35,7 +35,7 @@
 
 #if defined(_TTNROUTER)
 #if defined(_UDPROUTER)
-#error "Error: Please undefine _UDPROUTER if you like to use _TTNROUTER"
+#	error "Error: Please undefine _UDPROUTER if you like to use _TTNROUTER"
 #endif
 
 // The following functions ae defined in this modue:
@@ -49,7 +49,7 @@
 // Add gateway code of functions here
 
 void connectTtn() {
-#error "Error: Please define and use _UDPROUTER instead of _TTNROUTER"
+#	error "Error: Please define and use _UDPROUTER instead of _TTNROUTER"
 }
 
 int readTtn(int Packetsize) {

+ 76 - 79
ESP-sc-gway/_txRx.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -38,7 +38,7 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	// Received package with Meta Data (for example):
 	// codr	: "4/5"
 	// data	: "Kuc5CSwJ7/a5JgPHrP29X9K6kf/Vs5kU6g=="	// for example
-	// freq	: 868.1 									// 868100000
+	// freq	: 868.1 									// 868100000 default
 	// ipol	: true/false
 	// modu : "LORA"
 	// powe	: 14										// Set by default
@@ -64,28 +64,22 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	char * bufPtr = (char *) (buf);
 	buf[length] = 0;
 	
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (( debug>=2) && (pdebug & P_TX)) {
-		Serial.println((char *)buf);
-		Serial.print(F("<"));
-		Serial.flush();
+		mPrint("sendPacket:: " + String((char *)buf) + "< ");
 	}
-#endif
+#	endif //_MONITOR
+
 	// Use JSON to decode the string after the first 4 bytes.
 	// The data for the node is in the "data" field. This function destroys original buffer
 	auto error = deserializeJson(jsonBuffer, bufPtr);
 		
 	if (error) {
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug>=1) && (pdebug & P_TX)) {
-			Serial.print (F("T sendPacket:: ERROR Json Decode"));
-			if (debug>=2) {
-				Serial.print(':');
-				Serial.println(bufPtr);
-			}
-			Serial.flush();
+			mPrint("T sendPacket:: ERROR Json Decode: " + String(bufPtr) );
 		}
-#endif
+#		endif //_MONITOR
 		return(-1);
 	}
 	yield();
@@ -112,21 +106,18 @@ int sendPacket(uint8_t *buf, uint8_t length)
 	//}
 
 	if ( data != NULL ) {
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug>=2 ) && ( pdebug & P_TX )) { 
-			Serial.print(F("T data: ")); 
-			Serial.println((char *) data);
-			if (debug>=2) Serial.flush();
+			mPrint("sendPacket:: data=" + String(data)); 
 		}
-#endif
+#		endif //_MONITOR
 	}
 	else {												// There is data!
-#if _DUSB>=1
-		if ((debug>0) && ( pdebug & P_TX )) {
-			Serial.println(F("T sendPacket:: ERROR: data is NULL"));
-			if (debug>=2) Serial.flush();
+#		if _MONITOR>=1
+		if ((debug>=0) && ( pdebug & P_TX )) {
+			mPrint("sendPacket:: ERROR: data is NULL");
 		}
-#endif
+#		endif //_MONITOR
 		return(-1);
 	}
 
@@ -141,49 +132,48 @@ int sendPacket(uint8_t *buf, uint8_t length)
 
 // _STRICT_1CH determines how we will react on downstream messages.
 //
-// If STRICT==1, we will answer (in the RX1 timeslot) on the frequency we receive on.
+// If _STRICT==1, we will answer (in the RX1 timeslot) on the frequency we receive on.
+// We will anser in RX2 in rthe time set by _RX2_SF.
 // This way, we can better communicate as a single gateway machine
+// Otherwise we will answer in RX with RF==12 and use special answer frequency
 //
 #if _STRICT_1CH == 1
 	// RX1 is requested frequency
-	// RX2 is SF12
+	// RX2 is SF _RX2_SF probably SF9
 	// If possible use RX1 timeslot as this is our frequency.
 	// Do not use RX2 or JOIN2 as they contain other frequencies
 	
 	// Wait time RX1
 	if ((w>1000000) && (w<3000000)) { 
 		LoraDown.tmst-=1000000; 
+		LoraDown.sfTx= sfi;									// Take care, TX sf not to be mixed with SCAN
 	}
 	// RX2. Is tmst correction necessary
 	else if ((w>6000000) && (w<7000000)) { 
-		LoraDown.tmst-=500000; 
+		LoraDown.tmst-=500000; 								// Corrrect the Timestamp
+		LoraDown.sfTx= _RX2_SF;								// Use the RX2 downstream SF (may be dedicated to TTN)
 	}
 	LoraDown.powe	= 14;									// On all freqs except 869.5MHz power is limited
-	LoraDown.sfTx	= sfi;									// Take care, TX sf not to be mixed with SCAN
-	LoraDown.fff	= freqs[ifreq].dwnFreq;					// Use the corresponsing Down frequency
-	
+	LoraDown.fff	= freqs[ifreq].dwnFreq;					// Use the corresponding Down frequency
+
 #else
-// If _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
+// Elif _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
 // And since the Gateway is a single channel gateway, and its nodes are probably
 // single channel too. They will not listen to that frequency at all.
 // Pleae note that this parameter is more for nodes (that cannot change freqs)
 // than for gateways.
 //
 	LoraDown.powe = powe;
-
 	// convert double frequency (MHz) into uint32_t frequency in Hz.
 	LoraDown.fff = (uint32_t) ((uint32_t)((ff+0.000035)*1000)) * 1000;
-#endif
+#endif //_STRICT_1CH
 	
 	LoraDown.payLoad = payLoad;				
 
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (( debug>=1 ) && ( pdebug & P_TX)) {
 	
-		Serial.print(F("T LoraDown tmst="));
-		Serial.print(LoraDown.tmst);
-		//Serial.print(F(", w="));
-		//Serial.print(w);
+		mPrint("T LoraDown tmst=" + String(LoraDown.tmst));
 		
 		if ( debug>=2 ) {
 			Serial.print(F(" Request:: "));
@@ -201,21 +191,21 @@ int sendPacket(uint8_t *buf, uint8_t length)
 			Serial.print(F(" codr="));		Serial.println(codr);
 
 			Serial.print(F(" ipol="));		Serial.println(ipol);
+			Serial.println();
 		}
-		Serial.println();
 	}
-#endif
+#	endif // _MONITOR
 
 	if (LoraDown.payLength != psize) {
-#if _DUSB>=1
+#		if _MONITOR>=1
 		Serial.print(F("sendPacket:: WARNING payLength: "));
 		Serial.print(LoraDown.payLength);
 		Serial.print(F(", psize="));
 		Serial.println(psize);
 		if (debug>=2) Serial.flush();
-#endif
+#		endif //_MONITOR
 	}
-#if _DUSB>=1
+#	if _MONITOR>=1
 	else if (( debug >= 2 ) && ( pdebug & P_TX )) {
 		Serial.print(F("T Payload="));
 		for (i=0; i<LoraDown.payLength; i++) {
@@ -224,7 +214,7 @@ int sendPacket(uint8_t *buf, uint8_t length)
 		}
 		Serial.println();
 	}
-#endif
+#	endif //_MONITOR
 
 	// Update downstream statistics
 	statc.msg_down++;
@@ -234,19 +224,24 @@ int sendPacket(uint8_t *buf, uint8_t length)
 		case 2: statc.msg_down_2++; break;
 	}
 
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (( debug>=2 ) && ( pdebug & P_TX )) {
-		Serial.println(F("T sendPacket:: fini OK"));
-		Serial.flush();
+		mPrint("T sendPacket:: fini OK");
 	}
-#endif // _DUSB
+#	endif //_MONITOR
 
 	// 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>=1) && ( pdebug & P_TX)) {
+		mPrint("sendPacket:: STRICT=" + String(_STRICT_1CH) );
+	}
+#	endif //_MONITOR
+	
 	return 1;
-}//sendPacket
+}//sendPacket DOWN
 
 
 
@@ -259,12 +254,11 @@ int sendPacket(uint8_t *buf, uint8_t length)
 // parameters:
 // 	tmst: Timestamp to include in the upstream message
 // 	buff_up: The buffer that is generated for upstream
-// 	message: The payload message to include in the the buff_up
-//	messageLength: The number of bytes received by the LoRa transceiver
+//	LoraUP: Structure describing the message received from device
 // 	internal: Boolean value to indicate whether the local sensor is processed
 //
 // returns:
-//	buff_index
+//	buff_index:
 // ----------------------------------------------------------------------------
 int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool internal) 
 {
@@ -338,10 +332,12 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 	statr[0].ch= ifreq;
 	statr[0].prssi = prssi - rssicorr;
 	statr[0].sf = LoraUp.sf;
-#if RSSI==1
-	statr[0].rssi = _rssi - rssicorr;
-#endif // RSII
-#if _DUSB>=2
+	
+#	if RSSI==1
+		statr[0].rssi = _rssi - rssicorr;
+#	endif // RSII
+
+#	if _DUSB>=2
 	if (debug>=0) {
 		if ((message[4] != 0x26) || (message[1]==0x99)) {
 			Serial.print(F("addr="));
@@ -353,7 +349,7 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 			Serial.println();
 		}
 	}
-#endif //DUSB
+#	endif //DUSB
 	statr[0].node = ( message[1]<<24 | message[2]<<16 | message[3]<<8 | message[4] );
 
 #if _STATISTICS >= 2
@@ -373,7 +369,7 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 
 #if _STATISTICS >= 3
 	if (statr[0].ch == 0) {
-		statc.msg_ttl_0++;
+		statc.msg_ttl_0++;								// Increase #message received channel 0
 		switch (statr[0].sf) {
 			case SF7:  statc.sf7_0++;  break;
 			case SF8:  statc.sf8_0++;  break;
@@ -472,14 +468,12 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 	// 	message Length is multiple of 4!
 	// Encode message with messageLength into b64
 	int encodedLen = base64_enc_len(messageLength);		// max 341
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if ((debug>=1) && (encodedLen>255) && ( pdebug & P_RADIO )) {
-		Serial.print(F("R buildPacket:: b64 err, len="));
-		Serial.println(encodedLen);
-		if (debug>=2) Serial.flush();
+		mPrint("R buildPacket:: b64 err, len=" + String(encodedLen));
 		return(-1);
 	}
-#endif // _DUSB
+#	endif // _MONITOR
 	base64_encode(b64, (char *) message, messageLength);// max 341
 	// start composing datagram with the header 
 	uint8_t token_h = (uint8_t)rand(); 					// random token
@@ -513,11 +507,13 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 	buff_up[buff_index] = '{';
 	++buff_index;
 	j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "\"tmst\":%u", tmst);
-#if _DUSB>=1
+	
+#	if _MONITOR>=1
 	if ((j<0) && ( debug>=1 ) && ( pdebug & P_RADIO )) {
-		Serial.println(F("buildPacket:: Error "));
+		mPrint("buildPacket:: Error ");
 	}
-#endif
+#	endif //_MONITOR
+
 	buff_index += j;
 	ftoa((double)freqs[ifreq].upFreq / 1000000, cfreq, 6);					// XXX This can be done better
 	
@@ -605,14 +601,11 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 	addSeen(listSeen, statr[0] );
 #endif
 	
-#if _DUSB>=1
-	if (( debug>=2 ) && ( pdebug & P_RX )) {
-		Serial.print(F("R RXPK:: "));
-		Serial.println((char *)(buff_up + 12));			// debug: display JSON payload
-		Serial.print(F("R RXPK:: package length="));
-		Serial.println(buff_index);
+#	if _MONITOR>=1
+	if (( debug>=2 ) && ( pdebug & P_RX )) {			// debug: display JSON payload
+		mPrint("RXPK:: "+String((char *)(buff_up + 12))+"R RXPK:: package length="+String(buff_index));		
 	}
-#endif
+#	endif
 	return(buff_index);
 }// buildPacket
 
@@ -629,7 +622,11 @@ int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool inte
 // - returns the length of string returned in buff_up
 // - returns -1 or -2 when no message arrived, depending connection.
 //
-// This is the "highlevel" function called by loop()
+// This is the "highlevel" read function called by loop(). The receive function 
+// is started in the _stateMachine.ini file after CDONE event by interrupt 
+// functions.
+// However, the actual read from the buffer (filled by interrupt) is done 
+// by this function in the main loop() program.
 // ----------------------------------------------------------------------------
 int receivePacket()
 {
@@ -735,11 +732,11 @@ int receivePacket()
 				}
 #endif //DUSB
 			}
-#if _DUSB>=1
+#			if _MONITOR>=1
 			else if (( debug>=2 ) && ( pdebug & P_RX )) {
-					Serial.println(F("receivePacket:: No Index"));
+					mPrint("receivePacket:: No Index");
 			}
-#endif //DUSB
+#			endif //DUSB
 #endif // _LOCALSERVER
 
 			// Reset the message area

+ 97 - 104
ESP-sc-gway/_udpSemtech.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -49,28 +49,33 @@ bool connectUdp()
 
 	bool ret = false;
 	unsigned int localPort = _LOCUDPPORT;			// To listen to return messages from WiFi
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (debug>=1) {
-		Serial.print(F("Local UDP port="));
-		Serial.println(localPort);
+		mPrint("Local UDP port=" + String(localPort));
 	}
-#endif	
+#	endif //_MONITOR
+
 	if (Udp.begin(localPort) == 1) {
-#if _DUSB>=1
-		if (debug>=1) Serial.println(F("Connection successful"));
-#endif
+#		if _MONITOR>=1
+		if (debug>=1) {
+			mPrint("UDP Connection successful");
+		}
+#		endif //_MONITOR
 		ret = true;
 	}
 	else{
-#if _DUSB>=1
-		if (debug>=1) Serial.println("Connection failed");
-#endif
+#		if _MONITOR>=1
+		if (debug>=0) {
+			mPrint("Connection failed");
+		}
+#		endif //_MONITOR
 	}
 	return(ret);
 }// connectUdp
 
 
 // ----------------------------------------------------------------------------
+// DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN 
 // readUdp()
 // Read DOWN a package from UDP socket, can come from any server
 // Messages are received when server responds to gateway requests from LoRa nodes 
@@ -95,35 +100,32 @@ int readUdp(int packetSize)
 	uint8_t buff[32]; 						// General buffer to use for UDP, set to 64
 	uint8_t buff_down[RX_BUFF_SIZE];		// Buffer for downstream
 
-//	if ((WiFi.status() != WL_CONNECTED) &&& (WlanConnect(10) < 0)) {
 	if (WlanConnect(10) < 0) {
-#if _DUSB>=1
-			Serial.print(F("readUdp: ERROR connecting to WLAN"));
-			if (debug>=2) Serial.flush();
-#endif
-			Udp.flush();
-			yield();
-			return(-1);
+#		if _MONITOR>=1
+			mPrint("readUdp: ERROR connecting to WLAN");
+#		endif //_MONITOR
+		Udp.flush();
+		yield();
+		return(-1);
 	}
 
 	yield();
 	
 	if (packetSize > RX_BUFF_SIZE) {
-#if _DUSB>=1
-		Serial.print(F("readUdp:: ERROR package of size: "));
-		Serial.println(packetSize);
-#endif
+#		if _MONITOR>=1
+			mPrint("readUdp:: ERROR package of size: " + String(packetSize));
+#		endif //_MONITOR
 		Udp.flush();
 		return(-1);
 	}
   
-	// We assume here that we know the originator of the message
+	// We assume here that we know the originator of the message.
 	// In practice however this can be any sender!
 	if (Udp.read(buff_down, packetSize) < packetSize) {
-#if _DUSB>=1
-		Serial.println(F("A readUdp:: Reading less chars"));
+#		if _MONITOR>=1
+			mPrint("A readUdp:: Reading less chars");
+#		endif //_MONITOR
 		return(-1);
-#endif
 	}
 
 	// Remote Address should be known
@@ -134,11 +136,11 @@ int readUdp(int packetSize)
 
 	if (remotePortNo == 123) {
 		// This is an NTP message arriving
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if ( debug>=0 ) {
-			Serial.println(F("A readUdp:: NTP msg rcvd"));
+			mPrint("A readUdp:: NTP msg rcvd");
 		}
-#endif
+#		endif //_MONITOR
 		gwayConfig.ntpErr++;
 		gwayConfig.ntpErrTime = now();
 		return(0);
@@ -151,52 +153,48 @@ int readUdp(int packetSize)
 		token = buff_down[2]*256 + buff_down[1];
 		ident = buff_down[3];
 
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if ((debug>1) && (pdebug & P_MAIN)) {
-			Serial.print(F("M readUdp:: message waiting="));
-			Serial.print(ident);
-			Serial.println();
+			mPrint("M readUdp:: message waiting="+String(ident));
 		}
-#endif
+#		endif //_MONITOR
+
 		// now parse the message type from the server (if any)
 		switch (ident) {
 
-		// This message is used by the gateway to send sensor data to the
-		// server. As this function is used for downstream only, this option
+		// This message is used by the gateway to send sensor data to the server. 
+		// As this function is used for downstream only, this option
 		// will never be selected but is included as a reference only
 		case PKT_PUSH_DATA: // 0x00 UP
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (debug >=1) {
-				Serial.print(F("PKT_PUSH_DATA:: size ")); Serial.print(packetSize);
-				Serial.print(F(" From ")); Serial.print(remoteIpNo);
-				Serial.print(F(", port ")); Serial.print(remotePortNo);
-				Serial.print(F(", data: "));
-				for (int i=0; i<packetSize; i++) {
-					Serial.print(buff_down[i],HEX);
-					Serial.print(':');
-				}
-				Serial.println();
-				if (debug>=2) Serial.flush();
+				mPrint("PKT_PUSH_DATA:: size "+String(packetSize)+" From "+String(remoteIpNo.toString()));
+
+//				Serial.print(F(", port ")); Serial.print(remotePortNo);
+//				Serial.print(F(", data: "));
+//				for (int i=0; i<packetSize; i++) {
+//					Serial.print(buff_down[i],HEX);
+//					Serial.print(':');
+//				}
+//				Serial.println();
+//				if (debug>=2) Serial.flush();
 			}
-#endif
+#		endif //_MONITOR
 		break;
 	
 		// This message is sent by the server to acknowledge receipt of a
 		// (sensor) message sent with the code above.
 		case PKT_PUSH_ACK:	// 0x01 DOWN
-#if _DUSB>=1
+#if _MONITOR>=1
 			if (( debug>=2) && (pdebug & P_MAIN )) {
-				Serial.print(F("M PKT_PUSH_ACK:: size ")); 
-				Serial.print(packetSize);
-				Serial.print(F(" From ")); 
-				Serial.print(remoteIpNo);
-				Serial.print(F(", port ")); 
-				Serial.print(remotePortNo);
-				Serial.print(F(", token: "));
-				Serial.println(token, HEX);
-				Serial.println();
+				mPrint("M PKT_PUSH_ACK:: size="+String(packetSize)+" From "+String(remoteIpNo.toString())); 
+//				Serial.print(F(", port ")); 
+//				Serial.print(remotePortNo);
+//				Serial.print(F(", token: "));
+//				Serial.println(token, HEX);
+//				Serial.println();
 			}
-#endif
+#endif //_MONITOR
 		break;
 	
 		case PKT_PULL_DATA:	// 0x02 UP
@@ -209,11 +207,11 @@ int readUdp(int packetSize)
 		// This message type is used to confirm OTAA message to the node
 		// XXX This message format may also be used for other downstream communication
 		case PKT_PULL_RESP:	// 0x03 DOWN
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-				Serial.println(F("M readUdp:: PKT_PULL_RESP received"));
+				mPrint("readUdp:: PKT_PULL_RESP received");
 			}
-#endif
+#			endif //_MONITOR
 //			lastTmst = micros();					// Store the tmst this package was received
 			
 			// Send to the LoRa Node first (timing) and then do reporting to Serial
@@ -221,11 +219,11 @@ int readUdp(int packetSize)
 			sendTime = micros();					// record when we started sending the message
 			
 			if (sendPacket(data, packetSize-4) < 0) {
-#if _DUSB>=1
+#				if _MONITOR>=1
 				if ( debug>=0 ) {
-					Serial.println(F("A readUdp:: Error: PKT_PULL_RESP sendPacket failed"));
+					mPrint("A readUdp:: ERROR: PKT_PULL_RESP sendPacket failed");
 				}
-#endif
+#				endif //_MONITOR
 				return(-1);
 			}
 
@@ -244,11 +242,11 @@ int readUdp(int packetSize)
 			buff[10]=MAC_array[4];
 			buff[11]=MAC_array[5];
 			buff[12]=0;
-#if _DUSB>=1
+#			if _MONITOR>=1
 			if (( debug >= 2 ) && ( pdebug & P_MAIN )) {
-				Serial.println(F("M readUdp:: TX buff filled"));
+				mPrint("M readUdp:: TX buff filled");
 			}
-#endif
+#			endif //_MONITOR
 			// Only send the PKT_PULL_ACK to the UDP socket that just sent the data!!!
 			Udp.beginPacket(remoteIpNo, remotePortNo);
 			if (Udp.write((unsigned char *)buff, 12) != 12) {
@@ -315,18 +313,16 @@ int readUdp(int packetSize)
 #else
 
 #endif
-#if _DUSB>=1
-			Serial.print(F(", ERROR ident not recognized="));
-			Serial.println(ident);
-#endif
+#			if _MONITOR>=1
+				mPrint(", ERROR ident not recognized="+String(ident));
+#			endif //_MONITOR
 		break;
 		}
-#if _DUSB>=2
-		if (debug>=1) {
-			Serial.print(F("readUdp:: returning=")); 
-			Serial.println(packetSize);
+#		if _MONITOR>=2
+		if (debug>=2) {
+			mPrint("readUdp:: returning=" + String(packetSize)); 
 		}
-#endif
+#		endif //_MONITOR
 		// For downstream messages
 		return packetSize;
 	}
@@ -351,12 +347,11 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
 
 	// Check whether we are conected to Wifi and the internet
 	if (WlanConnect(3) < 0) {
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-			Serial.print(F("M sendUdp: ERROR connecting to WiFi"));
-			Serial.flush();
+			mPrint("sendUdp: ERROR connecting to WiFi");
 		}
-#endif
+#		endif //_MONITOR
 		Udp.flush();
 		yield();
 		return(0);
@@ -365,29 +360,29 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
 	yield();
 
 	//send the update
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (( debug>=3 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("M WiFi connected"));
+		mPrint("M WiFi connected");
 	}
-#endif	
+#	endif //_MONITOR
+
 	if (!Udp.beginPacket(server, (int) port)) {
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.println(F("M sendUdp:: Error Udp.beginPacket"));
+			mPrint("M sendUdp:: Error Udp.beginPacket");
 		}
-#endif
+#		endif //_MONITOR
 		return(0);
 	}
 	
 	yield();
-	
 
 	if (Udp.write((unsigned char *)msg, length) != length) {
-#if _DUSB>=1
+#		if _MONITOR>=1
 		if (( debug<=1 ) && ( pdebug & P_MAIN )) {
-			Serial.println(F("M sendUdp:: Error write"));
+			mPrint("M sendUdp:: Error write");
 		}
-#endif
+#		endif //_MONITOR
 		Udp.endPacket();						// Close UDP
 		return(0);								// Return error
 	}
@@ -395,12 +390,11 @@ int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
 	yield();
 	
 	if (!Udp.endPacket()) {
-#if _DUSB>=1
+#	if _MONITOR>=1
 		if (debug>=1) {
-			Serial.println(F("sendUdp:: Error Udp.endPacket"));
-			Serial.flush();
+			mPrint("sendUdp:: Error Udp.endPacket");
 		}
-#endif
+#	endif //_MONITOR
 		return(0);
 	}
 	return(1);
@@ -455,13 +449,12 @@ void pullData() {
 	yield();
 #endif
 
-#if _DUSB>=1
+#	if _MONITOR>=1
 	if (pullPtr != pullDataReq) {
-		Serial.println(F("pullPtr != pullDatReq"));
-		Serial.flush();
+		mPrint("pullPtr != pullDatReq");
 	}
+#	endif //_MONITOR
 
-#endif
 #ifdef _THINGSERVER
 	sendUdp(thingServer, _THINGPORT, pullDataReq, pullIndex);
 #endif
@@ -551,9 +544,9 @@ void sendstat() {
 	}
 #endif	
 	if (stat_index > STATUS_SIZE) {
-#if _DUSB>=1
-		Serial.println(F("A sendstat:: ERROR buffer too big"));
-#endif
+#		if _MONITOR>=1
+			mPrint("A sendstat:: ERROR buffer too big");
+#		endif //_MONITOR
 		return;
 	}
 	

+ 131 - 16
ESP-sc-gway/_utils.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -19,12 +19,130 @@
 // ========================================================================================
 
 
-// ==================== STRING STRING STRING ==================================
+// ==================== STRING STRING STRING ==============================================
+
+
+// ----------------------------------------------------------------------------------------
+// Print to the monitor console.
+// This function is used all over the gateway code as a substitue for USB debug code.
+// It allows webserver users to view printed/debugging code.
+//
+// Parameters:
+//	txt: The text to be printed.
+// return:
+//	<None>
+// ----------------------------------------------------------------------------------------
+
+static void mPrint(String txt) 
+{
+	
+#	if DUSB>=1
+		Serial.println(F(txt));
+		if (debug>=2) Serial.flush();
+#	endif //_DUSB
+
+#	if _MONITOR>=1
+	time_t tt = now();
+	
+	for (int i=_MONITOR; i>0; i--) {		// Do only for values present....
+		monitor[i]= monitor[i-1];
+	}
+	
+	monitor[0].txt  = String(day(tt))	+ "-";
+	monitor[0].txt += String(month(tt))	+ "-";
+	monitor[0].txt += String(year(tt))	+ " ";
+	
+	byte _hour   = hour(tt);
+	byte _minute = minute(tt);
+	byte _second = second(tt);
+
+	if (_hour   < 10) monitor[0].txt += "0"; monitor[0].txt += String( _hour )+ ":";
+	if (_minute < 10) monitor[0].txt += "0"; monitor[0].txt += String(_minute) + ":";
+	if (_second < 10) monitor[0].txt += "0"; monitor[0].txt += String(_second) + "- ";
+	
+	monitor[0].txt += String(txt);
+	
+#	endif //_MONITOR
+	return;
+}
+
 
 // ----------------------------------------------------------------------------
+// mStat
+// Print the statistics on Serial (USB) port and/or Monitor
+// Depending on setting of _DUSB and _MONITOR.
+// Note: This function does not initialise the response var, will only append.
+// Parameters:
+//	Interrupt:	8-bit
+//	Response:	String
+// Return:
+//	1: If successful
+//	0: No Success
+// ----------------------------------------------------------------------------
+
+int mStat(uint8_t intr, String & response) 
+{
+#if _MONITOR>=1
+
+	if (debug>=0) {
+	
+		response += "I=";
+
+		if (intr & IRQ_LORA_RXTOUT_MASK) response += String("RXTOUT ");		// 0x80
+		if (intr & IRQ_LORA_RXDONE_MASK) response += String("RXDONE ");		// 0x40
+		if (intr & IRQ_LORA_CRCERR_MASK) response += "CRCERR ";		// 0x20
+		if (intr & IRQ_LORA_HEADER_MASK) response += "HEADER ";		// 0x10
+		if (intr & IRQ_LORA_TXDONE_MASK) response += "TXDONE ";		// 0x08
+		if (intr & IRQ_LORA_CDDONE_MASK) response += String("CDDONE ");		// 0x04
+		if (intr & IRQ_LORA_FHSSCH_MASK) response += "FHSSCH ";		// 0x02
+		if (intr & IRQ_LORA_CDDETD_MASK) response += "CDDETD ";		// 0x01
+
+		if (intr == 0x00) response += "  --  ";
+			
+		response += ", F=" + String(ifreq);
+		response += ", SF=" + String(sf);
+		response += ", E=" + String(_event);
+			
+		response += ", S=";
+
+		switch (_state) {
+			case S_INIT:
+				response += "INIT ";
+			break;
+			case S_SCAN:
+				response += "SCAN ";
+			break;
+			case S_CAD:
+				response += "CAD  ";
+			break;
+			case S_RX:
+				response += String("RX   ");
+			break;
+			case S_TX:
+				response += "TX   ";
+			break;
+			case S_TXDONE:
+				response += "TXDONE";
+			break;
+			default:
+				response += " -- ";
+		}
+		response += ", eT=";
+		response += String( micros() - eventTime );
+		response += ", dT=";
+		response += String( micros() - doneTime );
+
+		//mPrint(response);							// Do actual printing
+	}
+#endif //_MONITOR
+	return(1);
+}
+
+
+// ----------------------------------------------------------------------------------------
 // Fill a HEXadecimal String  from a 4-byte char array
 //
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 static void printHEX(char * hexa, const char sep, String& response) 
 {
 	char m;
@@ -36,13 +154,13 @@ static void printHEX(char * hexa, const char sep, String& response)
 
 
 
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 // stringTime
 // Print the time t into the String reponse. t is of type time_t in seconds.
 // Only when RTC is present we print real time values
 // t contains number of seconds since system started that the event happened.
 // So a value of 100 would mean that the event took place 1 minute and 40 seconds ago
-// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
 static void stringTime(time_t t, String& response) {
 
 	if (t==0) { response += "--"; return; }
@@ -66,18 +184,15 @@ static void stringTime(time_t t, String& response) {
 		case 6: response += "Friday "; break;
 		case 7: response += "Saturday "; break;
 	}
-	response += String() + day(eTime) + "-";
-	response += String() + month(eTime) + "-";
-	response += String() + year(eTime) + " ";
-	
-	if (_hour < 10) response += "0";
-	response += String() + _hour + ":";
-	if (_minute < 10) response += "0";
-	response += String() + _minute + ":";
-	if (_second < 10) response += "0";
-	response += String() + _second;
+	response += String(day(eTime)) + "-";
+	response += String(month(eTime)) + "-";
+	response += String(year(eTime)) + " ";	
+	if (_hour < 10) response += "0";   response += String(_hour) + ":";
+	if (_minute < 10) response += "0"; response += String(_minute) + ":";
+	if (_second < 10) response += "0"; response += String(_second);
 }
 
+
 // ============== SERIAL SERIAL SERIAL ========================================
 
 // ----------------------------------------------------------------------------

+ 354 - 310
ESP-sc-gway/_wwwServer.ino

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by many people and making use of several libraries.
 //
@@ -122,20 +122,18 @@ boolean YesNo()
 void wwwFile(String fn) {
 
 	if (!SPIFFS.exists(fn)) {
-#if _DUSB>=1
-		Serial.print(F("wwwFile:: ERROR: file not found="));
-		Serial.println(fn);
-#endif
+#		if _MONITOR>=1
+			mPrint("wwwFile:: ERROR: SPIFFS file not found=");
+#		endif
 		return;
-	}
-#if _DUSB>=2
+	} // _MONITOR
+#	if _MONITOR>=2
 	else {
-		Serial.print(F("wwwFile:: File existist= "));
-		Serial.println(fn);
+		mPrint("wwwFile:: SPIFFS File existist= " + String(fn));
 	}
-#endif
+#	endif //_MONITOR
 
-#if _DUSB>=1
+#	if _MONITOR>=1
 	File f = SPIFFS.open(fn, "r");					// Open the file for reading
 		
 	int j;
@@ -153,7 +151,7 @@ void wwwFile(String fn) {
 	
 	f.close();
 
-#endif
+#	endif //_MONITOR
 	
 }
 
@@ -207,25 +205,6 @@ void buttonLog()
 //	server.sendContent(response);
 }
 
-// --------------------------------------------------------------------------------
-// BUTTONSEEN
-// List the listSeen array.
-// Read the logfiles and display info about nodes (last seend, SF used etc).
-// This is a button on the top of the USB GUI screen
-// --------------------------------------------------------------------------------
-void buttonSeen() 
-{
-	String fn = "";
-	int i = 0;
-	
-	printSeen(listSeen);
-#if _DUSB>=1
-	if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("buttonSeen:: printSeen called"));
-	}
-#endif	
-
-}
 
 // --------------------------------------------------------------------------------
 // Navigate webpage by buttons. This method has some advantages:
@@ -236,15 +215,20 @@ static void wwwButtons()
 {
 	String response = "";
 	String mode = (gwayConfig.expert ? "Basic Mode" : "Expert Mode");
+	String moni = (gwayConfig.monitor ? "Hide Monitor" : "Monitor ON");
+	String seen = (gwayConfig.seen ? "Seen OFF" : "Node last seen");
 
 	YesNo();												// Init the Yes/No function
 	buttonDocu();
 
 	response += "<input type=\"button\" value=\"Documentation\" onclick=\"showDocu()\" >";
+	response += "<a href=\"LOG\" download><button type=\"button\">Log Files</button></a>";
 	
 	response += "<a href=\"EXPERT\" download><button type=\"button\">" + mode + "</button></a>";
-	response += "<a href=\"SEEN\" download><button type=\"button\">Nodes Seen</button></a>";
-	response += "<a href=\"LOG\" download><button type=\"button\">Log Files</button></a>";
+#	if _MONITOR>=1
+	response += "<a href=\"MONITOR\" download><button type=\"button\">" +moni+ "</button></a>";
+#	endif
+	response += "<a href=\"SEEN\" download><button type=\"button\">" +seen+ "</button></a>";
 
 	server.sendContent(response);							// Send to the screen
 }
@@ -427,17 +411,19 @@ static void openWebPage()
 	//
 	server.setContentLength(CONTENT_LENGTH_UNKNOWN);
 	server.send(200, "text/html", "");
+	String tt=""; printIP((IPAddress)WiFi.localIP(),'.',tt);	// Time with separator
+	
 #if A_REFRESH==1
 	if (gwayConfig.refresh) {
 		response += String() + "<!DOCTYPE HTML><HTML><HEAD><meta http-equiv='refresh' content='"+_WWW_INTERVAL+";http://";
-		printIP((IPAddress)WiFi.localIP(),'.',response);
-		response += "'><TITLE>ESP8266 1ch Gateway</TITLE>";
+		response += tt;
+		response += "'><TITLE>1ch Gateway " + String(tt) + "</TITLE>";
 	}
 	else {
-		response += String() + "<!DOCTYPE HTML><HTML><HEAD><TITLE>ESP8266 1ch Gateway</TITLE>";
+		response += String("<!DOCTYPE HTML><HTML><HEAD><TITLE>1ch Gateway " + String(tt) + "</TITLE>");
 	}
 #else
-	response += String() + "<!DOCTYPE HTML><HTML><HEAD><TITLE>ESP8266 1ch Gateway</TITLE>";
+	response += String("<!DOCTYPE HTML><HTML><HEAD><TITLE>1ch Gateway " + String(tt) + "</TITLE>");
 #endif
 	response += "<META HTTP-EQUIV='CONTENT-TYPE' CONTENT='text/html; charset=UTF-8'>";
 	response += "<META NAME='AUTHOR' CONTENT='M. Westenberg (mw1554@hotmail.com)'>";
@@ -460,13 +446,10 @@ static void openWebPage()
 	uint8_t _hour   = hour(secs);
 	uint8_t _minute = minute(secs);
 	uint8_t _second = second(secs);
-	response += String() + days + "-";
-	if (_hour < 10) response += "0";
-	response += String() + _hour + ":";
-	if (_minute < 10) response += "0";
-	response += String() + _minute + ":";
-	if (_second < 10) response += "0";
-	response += String() + _second;
+	response += String(days) + "-";
+	if (_hour < 10) response += "0"; response += String(_hour) + ":";
+	if (_minute < 10) response += "0"; response += String(_minute) + ":";
+	if (_second < 10) response += "0"; 	response += String(_second);
 	
 	response +="<br>Current time    "; 					// CURRENT TIME
 	stringTime(now(), response);
@@ -534,7 +517,7 @@ static void gatewaySettings()
 		response += "AUTO</td>";
 	}
 	else {
-		response += String() + ifreq; 
+		response += String(ifreq); 
 		response +="</td>";
 		response +="<td class=\"cell\"><a href=\"FREQ=-1\"><button>-</button></a></td>";
 		response +="<td class=\"cell\"><a href=\"FREQ=1\"><button>+</button></a></td>";
@@ -553,23 +536,13 @@ static void gatewaySettings()
 
 	// Debugging options, only when _DUSB is set, otherwise no
 	// serial activity
-#if _DUSB>=1	
+#if _DUSB>=1 || _MONITOR>=1
 	response +="<tr><td class=\"cell\">Debug Level</td><td class=\"cell\" colspan=\"2\">"; 
 	response +=debug; 
 	response +="</td>";
 	response +="<td class=\"cell\"><a href=\"DEBUG=-1\"><button>-</button></a></td>";
 	response +="<td class=\"cell\"><a href=\"DEBUG=1\"><button>+</button></a></td>";
 	response +="</tr>";
-
-	// Time Correction
-	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>";
-	}
 	
 	// Debug Pattern
 	response +="<tr><td class=\"cell\">Debug pattern</td>"; 
@@ -664,6 +637,16 @@ 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>";
@@ -712,11 +695,11 @@ static void statisticsData()
 	response +="<h2>Package Statistics</h2>";
 	response +="<table class=\"config_table\">";
 	response +="<tr><th class=\"thead\">Counter</th>";
-#if _STATISTICS == 3
-	response +="<th class=\"thead\">C 0</th>";
-	response +="<th class=\"thead\">C 1</th>";
-	response +="<th class=\"thead\">C 2</th>";
-#endif
+#	if _STATISTICS == 3
+		response +="<th class=\"thead\">C 0</th>";
+		response +="<th class=\"thead\">C 1</th>";
+		response +="<th class=\"thead\">C 2</th>";
+#	endif //_STATISTICS==3
 	response +="<th class=\"thead\">Pkgs</th>";
 	response +="<th class=\"thead\">Pkgs/hr</th>";
 	response +="</tr>";
@@ -725,35 +708,35 @@ static void statisticsData()
 	// Table rows
 	//
 	response +="<tr><td class=\"cell\">Packages Downlink</td>";
-#if _STATISTICS == 3
+#	if _STATISTICS == 3
 		response +="<td class=\"cell\">" + String(statc.msg_down_0) + "</td>";
 		response +="<td class=\"cell\">" + String(statc.msg_down_1) + "</td>";
 		response +="<td class=\"cell\">" + String(statc.msg_down_2) + "</td>"; 
-#endif
+#	endif
 	response += "<td class=\"cell\">" + String(statc.msg_down) + "</td>";
 	response +="<td class=\"cell\"></td></tr>";
 		
 	response +="<tr><td class=\"cell\">Packages Uplink Total</td>";
-#if _STATISTICS == 3
+#	if	 _STATISTICS == 3
 		response +="<td class=\"cell\">" + String(statc.msg_ttl_0) + "</td>";
 		response +="<td class=\"cell\">" + String(statc.msg_ttl_1) + "</td>";
 		response +="<td class=\"cell\">" + String(statc.msg_ttl_2) + "</td>";
-#endif
-		response +="<td class=\"cell\">" + String(statc.msg_ttl) + "</td>";
-		response +="<td class=\"cell\">" + String((statc.msg_ttl*3600)/(now() - startTime)) + "</td></tr>";
+#	endif //_STATISTICS==3
+	response +="<td class=\"cell\">" + String(statc.msg_ttl) + "</td>";
+	response +="<td class=\"cell\">" + String((statc.msg_ttl*3600)/(now() - startTime)) + "</td></tr>";
 		
 	response +="<tr><td class=\"cell\">Packages Uplink OK </td>";
-#if _STATISTICS == 3
+#if	 _STATISTICS == 3
 		response +="<td class=\"cell\">" + String(statc.msg_ok_0) + "</td>";
 		response +="<td class=\"cell\">" + String(statc.msg_ok_1) + "</td>";
 		response +="<td class=\"cell\">" + String(statc.msg_ok_2) + "</td>";
-#endif
+#	endif //_STATISTICS==3
 	response +="<td class=\"cell\">" + String(statc.msg_ok) + "</td>";
 	response +="<td class=\"cell\"></td></tr>";
 		
 
 	// Provide a table with all the SF data including percentage of messsages
-#if _STATISTICS == 2
+	#if _STATISTICS == 2
 	response +="<tr><td class=\"cell\">SF7 rcvd</td>"; 
 		response +="<td class=\"cell\">"; response +=statc.sf7; 
 		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf7/statc.msg_ttl : 0)+" %"; 
@@ -778,8 +761,9 @@ static void statisticsData()
 		response +="<td class=\"cell\">"; response +=statc.sf12; 
 		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf12/statc.msg_ttl : 0)+" %"; 
 		response +="</td></tr>";
-#endif
-#if _STATISTICS == 3
+#	endif //_STATISTICS==2
+
+#	if _STATISTICS == 3
 	response +="<tr><td class=\"cell\">SF7 rcvd</td>";
 		response +="<td class=\"cell\">"; response +=statc.sf7_0; 
 		response +="<td class=\"cell\">"; response +=statc.sf7_1; 
@@ -827,7 +811,7 @@ static void statisticsData()
 		response +="<td class=\"cell\">"; response +=statc.sf12;		
 		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf12/statc.msg_ttl : 0)+" %"; 
 		response +="</td></tr>";
-#endif
+#	endif //_STATISTICS==3
 
 	response +="</table>";
 	server.sendContent(response);
@@ -913,9 +897,9 @@ static void messageHistory()
 				break;
 			case 3: // Value and we do not print unless also defined for LOCAL_SERVER
 			default:
-#if _DUSB>=1
-				Serial.println("Unknow value for gwayConfig.trusted");
-#endif			
+#				if _MONITOR>=1
+					mPrint("Unknow value for gwayConfig.trusted");
+#				endif	 //_MONITOR		
 				break;
 		}
 		
@@ -968,7 +952,7 @@ static void messageHistory()
 static void nodeHistory() 
 {
 #if _SEENMAX > 0
-	if (gwayConfig.expert) {
+	if (gwayConfig.seen) {
 		// First draw the headers
 		String response="";
 	
@@ -977,7 +961,7 @@ static void nodeHistory()
 		response += "<tr>";
 		response += "<th class=\"thead\" style=\"width: 220px;\">Time</th>";
 		response += "<th class=\"thead\">Node</th>";
-		response += "<th class=\"thead\">Count</th>";
+		response += "<th class=\"thead\">Pkgs</th>";
 //#if _LOCALSERVER==1
 //		response += "<th class=\"thead\">Data</th>";
 //#endif
@@ -1013,21 +997,19 @@ static void nodeHistory()
 					break;
 				case 3: // Value 3 and we do not print unless also defined for LOCAL_SERVER
 				default:
-#if _DUSB>=1
-					Serial.println("Unknow value for gwayConfig.trusted");
-#endif
+#					if _MONITOR>=1
+						mPrint("Unknow value for gwayConfig.trusted");
+#					endif //_MONITOR
 					break;
 			}	
-#else // _TRUSTED_NODES
+#else
 			printHEX((char *)(& (listSeen[i].idSeen)),' ',response);
 #endif // _TRUSTED_NODES
 			
 			response += "</td>";
 			
 			response += String() + "<td class=\"cell\">" + listSeen[i].cntSeen + "</td>";			// Counter		
-
 			response += String() + "<td class=\"cell\">" + listSeen[i].chnSeen + "</td>";								// Channel
-			
 			response += String() + "<td class=\"cell\">" + listSeen[i].sfSeen + "</td>";			// SF
 			
 			server.sendContent(response);
@@ -1038,39 +1020,222 @@ static void nodeHistory()
 } // nodeHistory()
 
 
+
 // --------------------------------------------------------------------------------
-// SEND WEB PAGE() 
-// Call the webserver and send the standard content and the content that is 
-// passed by the parameter. Each time a variable is changed, this function is 
-// called to display the webpage again/
-//
-// NOTE: This is the only place where yield() or delay() calls are used.
+// MONITOR DATA
+// This function will print monitor data for the gateway based on the settings in
+// _MONITOR in file configGway.h
+// Only when the _MONITOR is positive then the function will be executed. 
+// If less then nothing will be displayed.
+// XXX We have to make the function such that when printed, the webpage refreshes.
+// --------------------------------------------------------------------------------
+int monitorData() 
+{
+#	if _MONITOR>=1
+	if (gwayConfig.monitor) {
+		String response="";
+		response +="<h2>Monitoring Console</h2>";
+	
+		response +="<table class=\"config_table\">";
+		response +="<tr>";
+		response +="<th class=\"thead\">Monitor Console</th>";
+		response +="</tr>";
+		
+
+		for (int i=0; i<_MONITOR; i++) {
+			if (monitor[i].txt == "") {
+				break;
+			}
+			// DISPLAY line
+			response +="<tr><td class=\"cell\">" ;
+			response += String(monitor[i].txt);
+			response += "</td></tr>";
+		}
+		response +="</table>";
+		server.sendContent(response);
+	}
+#	endif
+}
+
+
+// --------------------------------------------------------------------------------
+// WIFI CONFIG
+// wifiConfig() displays the most important Wifi parameters gathered
 //
 // --------------------------------------------------------------------------------
-void sendWebPage(const char *cmd, const char *arg)
+static void wifiConfig()
 {
-	openWebPage(); yield();						// Do the initial website setup
+	if (gwayConfig.expert) {
+		String response="";
+		response +="<h2>WiFi Config</h2>";
+
+		response +="<table class=\"config_table\">";
+
+		response +="<tr><th class=\"thead\">Parameter</th><th class=\"thead\">Value</th></tr>";
 	
-	wwwButtons();								// Display buttons such as Documentation, Mode, Logfiles
+		response +="<tr><td class=\"cell\">WiFi host</td><td class=\"cell\">"; 
+#if ESP32_ARCH==1
+		response +=WiFi.getHostname(); response+="</tr>";
+#else
+		response +=wifi_station_get_hostname(); response+="</tr>";
+#endif
+
+		response +="<tr><td class=\"cell\">WiFi SSID</td><td class=\"cell\">"; 
+		response +=WiFi.SSID(); response+="</tr>";
 	
-	setVariables(cmd,arg); yield();				// Read Webserver commands from line
+		response +="<tr><td class=\"cell\">IP Address</td><td class=\"cell\">"; 
+		printIP((IPAddress)WiFi.localIP(),'.',response); 
+		response +="</tr>";
+		response +="<tr><td class=\"cell\">IP Gateway</td><td class=\"cell\">"; 
+		printIP((IPAddress)WiFi.gatewayIP(),'.',response); 
+		response +="</tr>";
+		response +="<tr><td class=\"cell\">NTP Server</td><td class=\"cell\">"; response+=NTP_TIMESERVER; response+="</tr>";
+		response +="<tr><td class=\"cell\">LoRa Router</td><td class=\"cell\">"; response+=_TTNSERVER; response+="</tr>";
+		response +="<tr><td class=\"cell\">LoRa Router IP</td><td class=\"cell\">"; 
+		printIP((IPAddress)ttnServer,'.',response); 
+		response +="</tr>";
+#ifdef _THINGSERVER
+		response +="<tr><td class=\"cell\">LoRa Router 2</td><td class=\"cell\">"; response+=_THINGSERVER; 
+		response += String() + ":" + _THINGPORT + "</tr>";
+		response +="<tr><td class=\"cell\">LoRa Router 2 IP</td><td class=\"cell\">"; 
+		printIP((IPAddress)thingServer,'.',response);
+		response +="</tr>";
+#endif
 
-	statisticsData(); yield();		 			// Node statistics
-	messageHistory(); yield();					// Display the sensor history, message statistics
-	nodeHistory(); yield();						// Display the lastSeen array
 
-	gatewaySettings(); yield();					// Display web configuration
-	wifiConfig(); yield();						// WiFi specific parameters
+		response +="</table>";
+
+		server.sendContent(response);
+	} // gwayConfig.expert
+} // wifiConfig
+
+
+// --------------------------------------------------------------------------------
+// H2 systemStatus
+// systemStatus is additional and only available in the expert mode.
+// It provides a number of system specific data such as heap size etc.
+// --------------------------------------------------------------------------------
+static void systemStatus()
+{
+	if (gwayConfig.expert) {
+		String response="";
+		response +="<h2>System Status</h2>";
 	
-	systemStatus(); yield();					// System statistics such as heap etc.
-	interruptData(); yield();					// Display interrupts only when debug >= 2
+		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 +="</tr>";
 	
-	websiteFooter(); yield();
+		response +="<tr><td style=\"border: 1px solid black; width:120px;\">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);
+		if (MAC_array[2]< 0x10) response +='0'; response +=String(MAC_array[2],HEX);
+		response +="FFFF"; 
+		if (MAC_array[3]< 0x10) response +='0'; response +=String(MAC_array[3],HEX);
+		if (MAC_array[4]< 0x10) response +='0'; response +=String(MAC_array[4],HEX);
+		if (MAC_array[5]< 0x10) response +='0'; response +=String(MAC_array[5],HEX);
+		response+="</tr>";
 	
 
-	
-	server.client().stop();
-}
+		response +="<tr><td class=\"cell\">Free heap</td><td class=\"cell\">"; response+=ESP.getFreeHeap(); response+="</tr>";
+// XXX We Shoudl 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
+		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
+
+		response +="</table>";
+		server.sendContent(response);
+	} // gwayConfig.expert
+} // systemStatus
+
+
+// --------------------------------------------------------------------------------
+// H2 System State and Interrupt
+// Display interrupt data, but only for debug >= 2
+//
+// --------------------------------------------------------------------------------
+static void interruptData()
+{
+	if (gwayConfig.expert) {
+		uint8_t flags = readRegister(REG_IRQ_FLAGS);
+		uint8_t mask = readRegister(REG_IRQ_FLAGS_MASK);
+		String response="";
+		
+		response +="<h2>System State and Interrupt</h2>";
+		
+		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 +="</tr>";
+		
+		response +="<tr><td class=\"cell\">_state</td>";
+		response +="<td class=\"cell\">";
+		switch (_state) {							// See loraModem.h
+			case S_INIT: response +="INIT"; break;
+			case S_SCAN: response +="SCAN"; break;
+			case S_CAD: response +="CAD"; break;
+			case S_RX: response +="RX"; break;
+			case S_TX: response +="TX"; break;
+			default: response +="unknown"; break;
+		}
+		response +="</td></tr>";
+		
+		response +="<tr><td class=\"cell\">_STRICT_1CH</td>";
+		response +="<td class=\"cell\">" ;
+		response += String() + _STRICT_1CH;
+		response +="</td></tr>";		
+
+		response +="<tr><td class=\"cell\">flags (8 bits)</td>";
+		response +="<td class=\"cell\">0x";
+		if (flags <16) response += "0";
+		response +=String(flags,HEX); response+="</td></tr>";
+
+		
+		response +="<tr><td class=\"cell\">mask (8 bits)</td>";
+		response +="<td class=\"cell\">0x"; 
+		if (mask <16) response += "0";
+		response +=String(mask,HEX); response+="</td></tr>";
+		
+		response +="<tr><td class=\"cell\">Re-entrant cntr</td>";
+		response +="<td class=\"cell\">"; 
+		response += String() + gwayConfig.reents;
+		response +="</td></tr>";
+
+		response +="<tr><td class=\"cell\">ntp call cntr</td>";
+		response +="<td class=\"cell\">"; 
+		response += String() + gwayConfig.ntps;
+		response+="</td></tr>";
+		
+		response +="<tr><td class=\"cell\">ntpErr cntr</td>";
+		response +="<td class=\"cell\">"; 
+		response += String() + gwayConfig.ntpErr;
+		response +="</td>";
+		response +="<td colspan=\"2\" style=\"border: 1px solid black;\">";
+		stringTime(gwayConfig.ntpErrTime, response);
+		response +="</td>";
+		response +="</tr>";
+		
+		response +="</table>";
+		
+		server.sendContent(response);
+	}// if gwayConfig.expert
+} // interruptData
+
 
 
 // --------------------------------------------------------------------------------
@@ -1111,9 +1276,11 @@ void setupWWW()
 		initConfig(&gwayConfig);
 		writeConfig( CONFIGFILE, &gwayConfig);
 		writeSeen( _SEENFILE, listSeen);			// Write the last time record  is seen
-#if _DUSB>=1
-		Serial.println(F("DONE"));
-#endif
+#		if _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_GUI )) {
+			mPrint("Format DONE");
+		}
+#		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
@@ -1177,15 +1344,25 @@ void setupWWW()
 		gwayConfig.ntps = 0;					// Number of NTP calls
 #endif
 		gwayConfig.reents = 0;					// Re-entrance
-
 		writeGwayCfg(CONFIGFILE);
-#if _DUSB>=1
-		Serial.println(F("BOOT, config written"));
+#if _MONITOR>=1
+		if ((debug>=2) && (pdebug & P_MAIN)) {
+			mPrint("BOOT, config written");
+		}
 #endif
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
 
+	// Reboot the Gateway
+	// NOTE: There is no button for this code yet
+	server.on("/REBOOT", []() {
+		sendWebPage("",""); 					// Send the webPage string
+		server.sendHeader("Location", String("/"), true);
+		server.send ( 302, "text/plain", "");
+		ESP.restart();
+	});
+
 	server.on("/NEWSSID", []() {
 		sendWebPage("NEWSSID","");				// Send the webPage string
 		server.sendHeader("Location", String("/"), true);
@@ -1193,46 +1370,50 @@ void setupWWW()
 	});
 
 	// Set debug parameter
-	server.on("/DEBUG=-1", []() {				// Set debug level 0-2						
+	server.on("/DEBUG=-1", []() {				// Set debug level 0-2. Note: +3 is same as -1					
 		debug = (debug+3)%4;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#if _DUSB>=1
-		Serial.println(F("DEBUG -1: config written"));
-#endif
+#		if _DUSB>=1 || _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_MAIN)) {
+			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);				// Save configuration to file
-#if _DUSB>=1
-		Serial.println(F("DEBUG +1: config written"));
-#endif
+#		if _DUSB>=1 || _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_MAIN)) {
+			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 0-2						
+	server.on("/PDEBUG=SCAN", []() {			// Set debug level 0x01						
 		pdebug ^= P_SCAN;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
-	server.on("/PDEBUG=CAD", []() {				// Set debug level 0-2						
+	server.on("/PDEBUG=CAD", []() {				// Set debug level 0x02						
 		pdebug ^= P_CAD;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
-	server.on("/PDEBUG=RX", []() {				// Set debug level 0-2						
+	server.on("/PDEBUG=RX", []() {				// Set debug level 0x04						
 		pdebug ^= P_RX;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
-	server.on("/PDEBUG=TX", []() {				// Set debug level 0-2						
+	server.on("/PDEBUG=TX", []() {				// Set debug level 0x08						
 		pdebug ^= P_TX;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
 		server.sendHeader("Location", String("/"), true);
@@ -1268,18 +1449,22 @@ void setupWWW()
 	server.on("/DELAY=1", []() {
 		gwayConfig.txDelay+=5000;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#if _DUSB>=1
-		Serial.println(F("DELAY +, config written"));
-#endif
+#		if _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_MAIN)) {
+			mPrint("DELAY +, config written");
+		}
+#		endif
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
 	server.on("/DELAY=-1", []() {
 		gwayConfig.txDelay-=5000;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#if _DUSB>=1
-		Serial.println(F("DELAY +, config written"));
-#endif
+#		if _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_MAIN)) {
+			mPrint("DELAY -, config written");
+		}
+#		endif
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
@@ -1288,9 +1473,9 @@ void setupWWW()
 	server.on("/TRUSTED=1", []() {
 	gwayConfig.trusted = (gwayConfig.trusted +1)%4;
 		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#if _DUSB>=2
-		Serial.println(F("TRUSTED +, config written"));
-#endif
+#		if _MONITOR>=2
+			mPrint("TRUSTED +, config written");
+#		endif //_MONITOR
 		server.sendHeader("Location", String("/"), true);
 		server.send ( 302, "text/plain", "");
 	});
@@ -1451,15 +1636,20 @@ void setupWWW()
 		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);
+		gwayConfig.monitor = bool(1 - (int) gwayConfig.monitor) ;
+		server.send ( 302, "text/plain", "");
+	});
+#endif
 	
 	// Display the SEEN statistics
 	server.on("/SEEN", []() {
 		server.sendHeader("Location", String("/"), true);
-#if _DUSB>=1
-		Serial.println(F("SEEN button"));
-		printSeen(listSeen);
-#endif
-		buttonSeen();
+		gwayConfig.seen = bool(1 - (int) gwayConfig.seen) ;
 		server.send ( 302, "text/plain", "");
 	});
 
@@ -1479,191 +1669,45 @@ void setupWWW()
 	// Maybe not all information should be put on the screen since it
 	// may take too much time to serve all information before a next
 	// package interrupt arrives at the gateway
-	
-	Serial.print(F("WWW Server started on port "));
-	Serial.println(A_SERVERPORT);
+#	if _DUSB>=1
+		Serial.print(F("WWW Server started on port "));
+		Serial.println(A_SERVERPORT);
+#	endif //_DUSB
+
 	return;
 } // setupWWW
 
-
-
 // --------------------------------------------------------------------------------
-// WIFI CONFIG
-// wifiConfig() displays the most important Wifi parameters gathered
+// SEND WEB PAGE() 
+// Call the webserver and send the standard content and the content that is 
+// passed by the parameter. Each time a variable is changed, this function is 
+// called to display the webpage again/
+//
+// NOTE: This is the only place where yield() or delay() calls are used.
 //
 // --------------------------------------------------------------------------------
-static void wifiConfig()
+void sendWebPage(const char *cmd, const char *arg)
 {
-	if (gwayConfig.expert) {
-		String response="";
-		response +="<h2>WiFi Config</h2>";
-
-		response +="<table class=\"config_table\">";
-
-		response +="<tr><th class=\"thead\">Parameter</th><th class=\"thead\">Value</th></tr>";
+	openWebPage(); yield();						// Do the initial website setup
 	
-		response +="<tr><td class=\"cell\">WiFi host</td><td class=\"cell\">"; 
-#if ESP32_ARCH==1
-		response +=WiFi.getHostname(); response+="</tr>";
-#else
-		response +=wifi_station_get_hostname(); response+="</tr>";
-#endif
-
-		response +="<tr><td class=\"cell\">WiFi SSID</td><td class=\"cell\">"; 
-		response +=WiFi.SSID(); response+="</tr>";
+	wwwButtons();								// Display buttons such as Documentation, Mode, Logfiles
 	
-		response +="<tr><td class=\"cell\">IP Address</td><td class=\"cell\">"; 
-		printIP((IPAddress)WiFi.localIP(),'.',response); 
-		response +="</tr>";
-		response +="<tr><td class=\"cell\">IP Gateway</td><td class=\"cell\">"; 
-		printIP((IPAddress)WiFi.gatewayIP(),'.',response); 
-		response +="</tr>";
-		response +="<tr><td class=\"cell\">NTP Server</td><td class=\"cell\">"; response+=NTP_TIMESERVER; response+="</tr>";
-		response +="<tr><td class=\"cell\">LoRa Router</td><td class=\"cell\">"; response+=_TTNSERVER; response+="</tr>";
-		response +="<tr><td class=\"cell\">LoRa Router IP</td><td class=\"cell\">"; 
-		printIP((IPAddress)ttnServer,'.',response); 
-		response +="</tr>";
-#ifdef _THINGSERVER
-		response +="<tr><td class=\"cell\">LoRa Router 2</td><td class=\"cell\">"; response+=_THINGSERVER; 
-		response += String() + ":" + _THINGPORT + "</tr>";
-		response +="<tr><td class=\"cell\">LoRa Router 2 IP</td><td class=\"cell\">"; 
-		printIP((IPAddress)thingServer,'.',response);
-		response +="</tr>";
-#endif
-
-
-		response +="</table>";
-
-		server.sendContent(response);
-	} // gwayConfig.expert
-} // wifiConfig
-
+	setVariables(cmd,arg); yield();				// Read Webserver commands from line
 
-// --------------------------------------------------------------------------------
-// H2 systemStatus
-// systemStatus is additional and only available in the expert mode.
-// It provides a number of system specific data such as heap size etc.
-// --------------------------------------------------------------------------------
-static void systemStatus()
-{
-	if (gwayConfig.expert) {
-		String response="";
-		response +="<h2>System Status</h2>";
-	
-		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 +="</tr>";
-	
-		response +="<tr><td style=\"border: 1px solid black; width:120px;\">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);
-		if (MAC_array[2]< 0x10) response +='0'; response +=String(MAC_array[2],HEX);
-		response +="FFFF"; 
-		if (MAC_array[3]< 0x10) response +='0'; response +=String(MAC_array[3],HEX);
-		if (MAC_array[4]< 0x10) response +='0'; response +=String(MAC_array[4],HEX);
-		if (MAC_array[5]< 0x10) response +='0'; response +=String(MAC_array[5],HEX);
-		response+="</tr>";
+	statisticsData(); yield();		 			// Node statistics
+	messageHistory(); yield();					// Display the sensor history, message statistics
+	nodeHistory(); yield();						// Display the lastSeen array
+	monitorData(); yield();						// Console
 	
+	gatewaySettings(); yield();					// Display web configuration
+	wifiConfig(); yield();						// WiFi specific parameters
+	systemStatus(); yield();					// System statistics such as heap etc.
+	interruptData(); yield();					// Display interrupts only when debug >= 2
 
-		response +="<tr><td class=\"cell\">Free heap</td><td class=\"cell\">"; response+=ESP.getFreeHeap(); response+="</tr>";
-// XXX We Shoudl 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
-		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
-
-		response +="</table>";
-		server.sendContent(response);
-	} // gwayConfig.expert
-} // systemStatus
-
-
-// --------------------------------------------------------------------------------
-// H2 System State and Interrupt
-// Display interrupt data, but only for debug >= 2
-//
-// --------------------------------------------------------------------------------
-static void interruptData()
-{
-	if (gwayConfig.expert) {
-		uint8_t flags = readRegister(REG_IRQ_FLAGS);
-		uint8_t mask = readRegister(REG_IRQ_FLAGS_MASK);
-		String response="";
-		
-		response +="<h2>System State and Interrupt</h2>";
-		
-		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 +="</tr>";
-		
-		response +="<tr><td class=\"cell\">_state</td>";
-		response +="<td class=\"cell\">";
-		switch (_state) {							// See loraModem.h
-			case S_INIT: response +="INIT"; break;
-			case S_SCAN: response +="SCAN"; break;
-			case S_CAD: response +="CAD"; break;
-			case S_RX: response +="RX"; break;
-			case S_TX: response +="TX"; break;
-			default: response +="unknown"; break;
-		}
-		response +="</td></tr>";
-		
-		response +="<tr><td class=\"cell\">_STRICT_1CH</td>";
-		response +="<td class=\"cell\">" ;
-		response += String() + _STRICT_1CH;
-		response +="</td></tr>";		
-
-		response +="<tr><td class=\"cell\">flags (8 bits)</td>";
-		response +="<td class=\"cell\">0x";
-		if (flags <16) response += "0";
-		response +=String(flags,HEX); response+="</td></tr>";
-
-		
-		response +="<tr><td class=\"cell\">mask (8 bits)</td>";
-		response +="<td class=\"cell\">0x"; 
-		if (mask <16) response += "0";
-		response +=String(mask,HEX); response+="</td></tr>";
-		
-		response +="<tr><td class=\"cell\">Re-entrant cntr</td>";
-		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.reents;
-		response +="</td></tr>";
-
-		response +="<tr><td class=\"cell\">ntp call cntr</td>";
-		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.ntps;
-		response+="</td></tr>";
-		
-		response +="<tr><td class=\"cell\">ntpErr cntr</td>";
-		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.ntpErr;
-		response +="</td>";
-		response +="<td colspan=\"2\" style=\"border: 1px solid black;\">";
-		stringTime(gwayConfig.ntpErrTime, response);
-		response +="</td>";
-		response +="</tr>";
-		
-		response +="</table>";
-		
-		server.sendContent(response);
-	}// if gwayConfig.expert
-} // interruptData
+	websiteFooter(); yield();
+	
+	server.client().stop();
+}
 
 
 // --------------------------------------------------------------------------------

+ 66 - 73
ESP-sc-gway/configGway.h

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4 E EU868
-// Date: 2019-11-29
+// Version 6.1.5 E EU868
+// Date: 2019-12-20
 //
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway and many others.
 // Contibutions of Dorijan Morelj and Andreas Spies for OLED support.
@@ -20,7 +20,7 @@
 // too much code compiled and loaded on your ESP device.
 //
 // NOTE: 
-// If version if vor ESP32 Heltec board, compile with ESP32 setting and board 
+// If version is for ESP32 Heltec board, compile with ESP32 setting and board 
 // "ESP32 Dev Module" or "Heltec WiFi Lora 32"
 // 
 // For ESP8266 Wemos: compile with "Wemos R1 D1" and choose
@@ -30,31 +30,46 @@
 // ========================================================================================
 
 // Specify the correct version and date of your gateway here.
-// Normally it is provided with teh GitHub version
-#define VERSION "V.6.1.4.E.EU868; 191129a"
+// Normally it is provided with the GitHub version
+#define VERSION "V.6.1.5.E.EU868; 191220g"
 
-// This value of DEBUG determines whether some parts of code get compiled.
-// Also this is the initial value of debug parameter. 
-// The value can be changed using the admin webserver
-// For operational use, set initial DEBUG vaulue 0
-#define DEBUG 1
+
+// Define whether we should do a formatting of SPIFFS when starting the gateway
+// This is usually a good idea if the webserver is interrupted halfway a writing
+// operation. Also to be used when software is upgraded
+// Normally, value 0 is a good default and should not be changed.
+#define _SPIFF_FORMAT 0
+
+
+// Define the CLASS mode of the gateway
+// A: Baseline Class
+// B: Beacon/Battery Class
+// C: Continuous Listen Class
+#define _CLASS "A"
 
 
 // Debug message will be put on Serial is this one is set.
-// If set to 0, no USB Serial prints are done
-// Set to 1 it will prinr all user level messages (with correct debug set)
+// If set to 0, no printing to USB devices is done.
+// Set to 1 it will print all user level messages (with correct debug set)
 // If set to 2 it will also print interrupt messages (not recommended)
 #define _DUSB 1
 
 
-// Define whether we should do a formatting of SPIFFS when starting the gateway
-// This is usually a good idea if the webserver is interrupted halfway a writing
-// operation. Also to be used when software is upgraded
-// Normally, value 0 is a good default.
-#define _SPIFF_FORMAT 0
+// Define the monitor screen. When it is greater than 0 then logging is displayed in
+// the special screen at the GUI.
+// If _DUSB is also set to 1 then most messages will also be copied to USB devices.
+#define _MONITOR 20
 
 
-// Define the frequency band the gateway will listen on. Valid options are:
+// Gather statistics on sensor and Wifi status
+// 0= No statistics
+// 1= Keep track of messages statistics, number determined by MAX_STAT
+// 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
+
+
+// Define the frequency band the gateway will listen on. Valid options are
 // EU863_870	Europe 
 // US902_928	North America
 // AU925_928	Australia
@@ -63,9 +78,8 @@
 // CN779-787	(Not Used!)
 // EU433		Europe
 // AS923		(Not Used)
-// See https://www.thethingsnetwork.org/docs/lorawan/frequency-plans.html
 // You can find the definitions in "loraModem.h" and frequencies in
-
+// See https://www.thethingsnetwork.org/docs/lorawan/frequency-plans.html
 #define EU863_870 1
  
  
@@ -96,6 +110,11 @@
 // device and also connect enable dio1 to detect this state. 
 #define _CAD 1
 
+// CRCCHECK
+// Defines whether we should check on the CRC of RXDONE messages (see stateMachine.ino)
+// This should prevent us from getting a lot os stranges messgages of unknown nodes.
+// Note: DIO3 must be connected for this to work (Heltec and later Wemos gateways). 
+#define _CRCCHECK 1
 
 // Definitions for the admin webserver.
 // A_SERVER determines whether or not the admin webpage is included in the sketch.
@@ -120,34 +139,26 @@
 //	1: HALLARD
 //	2: COMRESULT pin out
 //	3: ESP32 Wemos pin out
-//	4: ESP32 TTGO pinning (should work for 433 and OLED too).
-//	5: ESP32 TTGO EU868/EU433 MHz with OLED
-//	6: Other, define your own in loraModem.h
+//	4: ESP32 TTGO pin out (should work for Heltec, 433 and OLED too).
+//	5: Other, define your own in loraModem.h (does not include GPS Code)
 #define _PIN_OUT 4
 
-// Gather statistics on sensor and Wifi status
-// 0= No statistics
-// 1= Keep track of messages statistics, number determined by MAX_STAT
-// 2= Option 1 + Keep track of messages received PER each SF (default)
-// 3= See Option 2, but with extra channel info (Do not use when no Hopping is selected)
-#define _STATISTICS 3
-
-
-
 
 // Single channel gateways if they behave strict should only use one frequency 
-// channel and one spreading factor. However, the TTN backend replies on RX2 
-// timeslot for spreading factors SF9-SF12. 
-// Also, the server will respond with SF12 in the RX2 timeslot.
+// channel and one, or in case _CAD all, spreading factors. 
+// The TTN backend replies on RX1 timeslot for spreading factors SF9-SF12. 
 // If the 1ch gateway is working in and for nodes that ONLY transmit and receive on the set
 // and agreed frequency and spreading factor. make sure to set STRICT to 1.
 // In this case, the frequency and spreading factor for downlink messages is adapted by this
 // gateway
 // NOTE: If your node has only one frequency enabled and one SF, you must set this to 1
-//		in order to receive downlink messages
+//		in order to receive downlink messages. This is the default mode.
 // NOTE: In all other cases, value 0 works for most gateways with CAD enabled
 #define _STRICT_1CH 1
-
+//
+// Also, normally the server will respond with SF12 in the RX2 timeslot.
+// For TTN, thr RX2 timeslot is SF9, and we should use that one for TTN
+#define _RX2_SF 9
 
 // Allows configuration through WifiManager AP setup. Must be 0 or 1					
 #define _WIFIMANAGER 0
@@ -213,7 +224,7 @@
 
 
 // This defines whether or not we would use the gateway as 
-// as sort of backend system which decodes
+// as sort of backend system for local sensors which decodes
 // 1: _LOCALSERVER is used
 // 0: Do not use _LOCALSERVER 
 #define _LOCALSERVER 1						// See server definitions for decodes
@@ -221,11 +232,11 @@
 
 // Gateway Ident definitions. Where is the gateway located?
 #define _DESCRIPTION "ESP Gateway"			// Name of the gateway
-#define _EMAIL "your@email.com"		// Owner
+#define _EMAIL "mw12554@hotmail.com"		// Owner
 #define _PLATFORM "ESP8266"
-#define _LAT 52.0
-#define _LON 5.0
-#define _ALT 1								// Altitude
+#define _LAT 52.237367
+#define _LON 5.978654
+#define _ALT 14								// Altitude
 
 // ntp
 // Please add daylight saving time to NTP_TIMEZONES when desired
@@ -236,8 +247,8 @@
 
 
 // lora sensor code definitions
-// Defines whether the gateway will also report sensor/status value on MQTT
-// such as GPS, battery or temperature.
+// Defines whether the gateway will also report sensor/status value on MQTT 
+// (such as battery and GPS)
 // after all, a gateway can be a node to the system as well. Some sensors like GPS can be
 // sent to the backend as a parameter, some (like humidity for example) can only be sent
 // as a regular sensor value.
@@ -246,14 +257,13 @@
 #define _CHECK_MIC 0
 
 
-
 // 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)
-// 2: Same as 1, but is nodes NOT in the nodes list below they are NOT shown.
-// NOTE: This list is dynamic!
+// 2: Same as 1, but is nodes NOT in the nodes list below they are NOT shown
+// NOTE: We probably will make this list dynamic!
 #define _TRUSTED_NODES 1
 #define _TRUSTED_DECODE 1
 
@@ -266,8 +276,8 @@
 // ========================================================================
 
 
-// Maximum number of statistics records gathered. 20 is a good maximum (memory intensive)
-// For ESP32 maybe 30 could be used as well
+// 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 MAX_STAT 20
 
 
@@ -276,11 +286,12 @@
 //	- node Number, or known node name
 //	- Last seen 'seconds since 1/1/1970'
 //	- SF seen (8-bit integer with SF per bit)
-// The initial version _NUMMAX stores max this many nodes, please 
-// "define _SEENMAX 0" when not used
-#define _SEENMAX 25
+// The initial version _NUMMAX stores max this many nodes, please make
+// _SEENMAX==0 when not used
+#define _SEENMAX 20
 #define _SEENFILE "/gwayNum.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		
@@ -293,30 +304,12 @@
 
 
 // Serial Port speed
-#define _BAUDRATE 115200					// Works for debug messages to serial momitor
+#define _BAUDRATE 115200						// Works for debug messages to serial momitor
 
 
 // MQTT definitions, these settings should be standard for TTN
 // and need no changing
 #define _TTNSERVER "router.eu.thethings.network"
-#define _TTNPORT 1700						// Standard port for TTN
+#define _TTNPORT 1700							// Standard port for TTN
 
 
-// If you have a second back-end server defined such as Semtech or loriot.io
-// your can define _THINGPORT and _THINGSERVER with your own value.
-// If not, make sure that you do not define these, which will save CPU time
-// Port is UDP port in this program
-//
-// Default for testing: Switched off
-#define _THINGSERVER "your,webserver.org"		// Server URL of the LoRa-udp.js handler
-#define _THINGPORT 1700						// Port 1700 is old compatibility
-
-
-
-// For asserting and testing the following defines are used.
-//
-#if !defined(CFG_noassert)
-#define ASSERT(cond) if(!(cond)) gway_failed(__FILE__, __LINE__)
-#else
-#define ASSERT(cond) /**/
-#endif

+ 36 - 15
ESP-sc-gway/configNode.h

@@ -1,7 +1,7 @@
 // sensor.h; 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-25
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // and many other contributors.
@@ -25,9 +25,9 @@
 // substitute the node info below.
 #if GATEWAYNODE==1
 
-#define _DEVADDR { 0x33, 0x33, 0x33, 0x33 }
-#define _APPSKEY { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
-#define _NWKSKEY { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 }
+#define _DEVADDR { 0xAA, 0xAA, 0xAA, 0xAA }
+#define _APPSKEY { 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB }
+#define _NWKSKEY { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }
 #define _SENSOR_INTERVAL 300
 // For ESP32 based T_BEAM/TTGO boards these two are normally included
 // If included make value 1, else if not, make them 0
@@ -55,13 +55,10 @@ struct wpas {
 //
 wpas wpa[] = {
 	{ "" , "" },							// Reserved for WiFi Manager
-	{ "YourSSID", "YourPassword" },
-	{ "Livebox-yyy", "xxxxxxxxxxxx"}
+	{ "yourSSID", "yourPassword" },
+	{ "Your2SSID", "your2Password" }
 };
 
-
-
-
 #if _TRUSTED_NODES >= 1
 struct nodex {
 	uint32_t id;				// This is the LoRa ID (coded in 4 bytes uint32_t
@@ -70,6 +67,8 @@ struct nodex {
 
 // Add all your named and trusted nodes to this list
 nodex nodes[] = {
+	{ 0x260116BD , "lora-34 PIR node" },						// F=0
+	{ 0x26011152 , "lora-35 temp+humi node" },					// F=0
 	{ 0x2601148C , "lora-36 test node"  },						// F=0
 	{ 0x00000000 , "lora-00 well known sensor" }				// F=0
 };
@@ -98,13 +97,35 @@ struct codex  {
 // Definition of all nodes that we want to decode locally on the gateway.
 //
 codex decodes[] = {
-	{ 0x2601148C , "lora-36", 	// F=0
-		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
-		{ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } 
+	{ 0xAAAAAAAA , "lora-EE", 	// F=0
+		{ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB },
+		{ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC } 
+	},
+	{ 0xBBBBBBBB , "lora-FF", 	// F=0
+		{ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB },
+		{ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC } 
 	},
 	{ 0x00000000 , "lora-00",	// F=0
 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
-		{ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } 
-	}				
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+	}					
 };
 #endif //_LOCALSERVER
+
+// If you have a second back-end server defined such as Semtech or loriot.io
+// your can define _THINGPORT and _THINGSERVER with your own value.
+// If not, make sure that you do not define these, which will save CPU time
+// Port is UDP port in this program
+//
+// Default for testing: Switched off
+#define _THINGSERVER "your.extra.server"		// Server URL of the LoRa-udp.js handler
+#define _THINGPORT 1700						// Port 1700 is old compatibility
+
+
+// For asserting and testing the following defines are used.
+//
+#if !defined(CFG_noassert)
+#define ASSERT(cond) if(!(cond)) gway_failed(__FILE__, __LINE__)
+#else
+#define ASSERT(cond) /**/
+#endif

+ 11 - 4
ESP-sc-gway/loraFiles.h

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many others.
@@ -70,7 +70,7 @@ struct espGwayConfig {
 	uint8_t sf;					// range from SF7 to SF12
 	uint8_t debug;				// range 0 to 4
 	uint8_t pdebug;				// pattern debug, 
-	uint8_t trusted;				// pattern debug, 
+	uint8_t trusted;			// pattern debug, 
 
 
 	
@@ -78,7 +78,9 @@ struct espGwayConfig {
 	bool hop;					// Is HOP enabled (Note: default be disabled)
 	bool isNode;				// Is gateway node enabled
 	bool refresh;				// Is WWW browser refresh enabled
+	bool seen;
 	bool expert;
+	bool monitor;
 	
 	String ssid;				// SSID of the last connected WiFi Network
 	String pass;				// Password of WiFi network
@@ -109,6 +111,7 @@ struct espGwayConfig {
 #define nSF12	0x40
 #define nFSK	0x80
 
+// define the Seen functon as when we have seen seen last time nodes last time
 struct nodeSeen {
 	unsigned long timSeen;
 	uint32_t idSeen;
@@ -118,4 +121,8 @@ struct nodeSeen {
 };
 struct nodeSeen listSeen[_SEENMAX];
 
-
+// define the loggin structure used for printout of error and warning messages
+struct moniLine {
+	String txt;
+};
+struct moniLine monitor[_MONITOR];

+ 7 - 35
ESP-sc-gway/loraModem.h

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 //	and many other contributors.
@@ -47,15 +47,15 @@
 // How long will it take when hopping before a CDONE or CDETD value
 // is present and can be measured.
 //
-#define EVENT_WAIT 15000						// XXX 180520 was 25 milliseconds before CDDETD timeout
-#define DONE_WAIT 1950							// 2000 microseconds (1/500) sec between CDDONE events
+#define EVENT_WAIT	15000						// XXX 180520 was 25 milliseconds before CDDETD timeout
+#define DONE_WAIT	1950						// 2000 microseconds (1/500) sec between CDDONE events
 
 
 // SPI setting. 8MHz seems to be the max
 #define SPISPEED 8000000						// Set to 8 * 10E6
 
 // Frequencies
-// Set center frequency. If in doubt, choose the first one, comment all others
+// Set center frequency. If in doubt, choose the first one, comment out all others
 // Each "real" gateway should support the first 3 frequencies according to LoRa spec.
 // NOTE: This means you have to specify at least 3 frequencies here for the single
 //	channel gateway to work. 
@@ -162,7 +162,7 @@ vector freqs [] = {
 #else
 int freqs [] = {
 	// Print an Error, Not supported
-#error "Sorry, but your frequency plan is not supported"
+#	error "Sorry, but your frequency plan is not supported"
 };
 #endif
 
@@ -260,34 +260,6 @@ struct pins {
 #define GPS_TX 12
 #endif // _GPS
 
-#elif _PIN_OUT==5
-// ----------------------------------------------------------------------------
-// For ESP32/TTGO based board for EU32 with 0.9" OLED
-// NOTE: This board should be same as general type TTGO (nr 4)
-// but for the moment we include this as a separate item
-//
-// SCK  == GPIO5/ PIN5
-// SS   == GPIO18/PIN18 CS
-// MISO == GPIO19/ PIN19
-// MOSI == GPIO27/ PIN27
-// RST  == GPIO14/ PIN14
-struct pins {
-	uint8_t dio0=26;		// GPIO26 / Dio0 used for one frequency and one SF
-	uint8_t dio1=33;		// GPIO26 / Used for CAD, may or not be shared with DIO0
-	uint8_t dio2=32;		// GPIO26 / Used for frequency hopping, don't care
-	uint8_t ss=18;			// GPIO18 / Dx. Select pin connected to GPIO18
-	uint8_t rst=14;			// GPIO0 / D3. Reset pin not used	
-} pins;
-#define SCK 5				// Check
-#define MISO 19				// Check
-#define MOSI 27				// Check
-#define RST 14				// Check
-#define SS 18
-
-#if _GPS==1
-#define GPS_RX 15
-#define GPS_TX 12
-#endif // _GPS
 
 #else
 // ----------------------------------------------------------------------------
@@ -388,7 +360,7 @@ struct LoraBuffer {
 } LoraDown;
 
 // Up buffer (from Lora sensor to UDP)
-//
+// This struct contains all data of the buffer received from devices to gateway
 
 struct LoraUp {
 	uint8_t		payLoad[128];

+ 2 - 2
ESP-sc-gway/oLED.h

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP8266
 // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.4
-// Date: 2019-11-29
+// Version 6.1.5
+// Date: 2019-12-20
 //
 // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
 // and many others.

+ 19 - 6
README.md

@@ -1,7 +1,7 @@
 # Single Channel LoRaWAN Gateway
 
-Version 6.1.4, 
-Data: November 29, 2019  
+Version 6.1.5, 
+Data: December 20, 2019  
 Author: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 
@@ -160,14 +160,27 @@ When setting _DUSB to 0 all output by Serial is disabled
 
  \#define _DUSB 1
 
+### Selecting Class mode of operation
 
-### Debug
+Define the class of operation that is supported by the gateway. 
+Class A is supported and contains the basic operation for battery sensors. 
 
-The user can set the initial value of the DEBUG parameter. 
-Setting this parameter will also detemine some settings of the webserver.
+Class B contains the beacon/battery mode of operation. The Gateway will send ou a beacon to the 
+connected sensors which enables them to synchronize downlink messagaging.
 
- \#define DEBUG 1
+Class C (Continuous) mode of operation contains support for devices that are probably NOT battery 
+operated and will listen to the network at all times. As a result the latency of these devices 
+is also shorter than for class A devices.
+Class C devices are not dependent on battery power and will extend the receive windows
+until the next transmission window. In fact, only transmissions will make the device abort 
+listening as long as this tranmission lasts. 
+Class C devices cannot do Class B operation.
 
+ \#define _CLASS "A"
+ 
+ All devices will start as class A devices, and may decide to "upgrade" to class B or C.
+Also the gateway may or may not support Class B, which is a superset of class A.
+ NOTE: Only class A is supported
  
 ### Selecting you standard pin-out
 

+ 9 - 6
TODO.md

@@ -1,6 +1,6 @@
 # Single Channel LoRaWAN Gateway
 
-Last Updated: November 25, 2019	  
+Last Updated: November 29, 2019	  
 Author: M. Westenberg (mw12554@hotmail.com)  
 Copyright: M. Westenberg (mw12554@hotmail.com)  
 
@@ -16,13 +16,16 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
 
 # ToDo Functions
 
-Features not in release 6.1.4
+Features not in release 6.1.5
 
-- Support FSK
-- Support for eu433 frequencies
-- Testing and timing of downlink functions (quiet area)
-- Get HOP functions to work on three frequencies
 
+- Frequency: Support for eu433 frequencies
+- Testing and timing of downlink functions (I need a quiet area)
+- Get HOP frequency functions to work on three frequencies
+- Security: Enable passwords for GUI access and WiFi upload (may not be necessary for normal home router use)
+- Enable remote updating through GUI
+- Support FSK (May not be necessary)
+- Support for other Mode A and B of LoRa devices