Browse Source

Version 6.2.7; Initial Version

platenspeler 4 years ago
parent
commit
04e5d76ac7
15 changed files with 971 additions and 644 deletions
  1. 5 0
      CHANGELOG.md
  2. 67 84
      platformio.ini
  3. 23 12
      src/ESP-sc-gway.ino
  4. 95 72
      src/_loraFiles.ino
  5. 153 136
      src/_loraModem.ino
  6. 2 2
      src/_repeater.ino
  7. 34 10
      src/_sensor.ino
  8. 148 97
      src/_stateMachine.ino
  9. 68 43
      src/_txRx.ino
  10. 158 111
      src/_udpSemtech.ino
  11. 79 29
      src/_utils.ino
  12. 68 15
      src/_wwwServer.ino
  13. 7 7
      src/configGway.h
  14. 2 0
      src/loraFiles.h
  15. 62 26
      src/loraModem.h

+ 5 - 0
CHANGELOG.md

@@ -16,6 +16,11 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
 
 # Release Notes
 
+Features  release 6.2.7 (October 30, 2020)
+- Further repair timing
+- Make interrupt handling simplier
+- improve website of gateway, making data dynamic
+
 Features release 6.2.6 (September 08, 2020)
 - Better timing for downstream
 - Other display of statistics

+ 67 - 84
platformio.ini

@@ -17,7 +17,6 @@ board_build.f_cpu = 80000000L
 build_flags =
   -D _PIN_OUT=1
   -D _WIFIMANAGER=0
-;  -D _SPIFFS_FORMAT=1
   -D _CHANNEL=0
   -D _REPEATER=0
   -D _OLED=0
@@ -32,23 +31,7 @@ board_build.flash_mode = qio
 upload_speed = 115200
 upload_port = 192.168.2.21
 
-[env:Gateway_22]
-platform = espressif8266
-board = d1_mini
-board_build.mcu = esp8266
-board_build.f_cpu = 80000000L
-build_flags =
-  -D _WIFIMANAGER=0
-  -D _OLED=1
-  -D _DUSB=1
-  -D _PROFILER=1
-framework = arduino
-upload_protocol = espota
-board_build.flash_mode = qio
-upload_speed = 115200
-upload_port = 192.168.2.22
-
-;[env:Gateway_30]
+;[env:Gateway_22]
 ;platform = espressif8266
 ;board = d1_mini
 ;board_build.mcu = esp8266
@@ -56,16 +39,54 @@ upload_port = 192.168.2.22
 ;build_flags =
 ;  -D _PIN_OUT=1
 ;  -D _WIFIMANAGER=0
-;  -D _SPIFFS_FORMAT=0
-;  -D _OLED=0
+;  -D _CHANNEL=0
+;  -D _OLED=1
 ;  -D _DUSB=1
 ;  -D _PROFILER=1
-;  -D _STAT_LOG=0
 ;framework = arduino
 ;upload_protocol = espota
 ;board_build.flash_mode = qio
 ;upload_speed = 115200
-;upload_port = 192.168.2.30
+;upload_port = 192.168.2.22
+
+[env:Gateway_30]
+platform = espressif8266
+board = d1_mini
+board_build.mcu = esp8266
+board_build.f_cpu = 80000000L
+build_flags =
+  -D _PIN_OUT=1
+  -D _WIFIMANAGER=0
+  -D _SPIFFS_FORMAT=0
+  -D _OLED=0
+  -D _DUSB=1
+  -D _PROFILER=1
+  -D _STRICT_1CH=2
+  -D _STAT_LOG=0
+framework = arduino
+upload_protocol = espota
+board_build.flash_mode = qio
+upload_speed = 115200
+upload_port = 192.168.2.30
+
+[env:Gateway_38]
+platform = espressif32
+board = heltec_wifi_lora_32
+framework = arduino
+build_flags =
+  -D _WIFIMANAGER=0
+  -D _SPIFFS_FORMAT=0
+  -D _OLED=1
+  -D _DUSB=1
+  -D _PROFILER=1
+;  -D _JSONENCODE=1
+  -D _STRICT_1CH=2
+  -D _MAXSEEN=10
+  -D _STAT_LOG=0
+upload_protocol = espota
+board_build.flash_mode = qio
+upload_speed = 115200
+upload_port = 192.168.2.38
 
 ;[env:Gateway_HC8]
 ;platform = espressif8266
@@ -103,41 +124,27 @@ upload_port = 192.168.2.22
 ;upload_speed = 115200
 ;upload_port = 192.168.2.72
 
-[env:Gateway_38]
-platform = espressif32
-board = heltec_wifi_lora_32
-framework = arduino
-build_flags =
-  -D _WIFIMANAGER=0
-  -D _SPIFFS_FORMAT=0
-  -D _OLED=1
-  -D _DUSB=1
-  -D _PROFILER=1
-;  -D _JSONENCODE=1
-  -D _MAXSEEN=10
-  -D _STAT_LOG=0
-upload_protocol = espota
-board_build.flash_mode = qio
-upload_speed = 115200
-upload_port = 192.168.2.38
-
 ; Nr. 54 has WIFIMANAGER sometimes set
 ; Also the Gateway is a T-Beam sensor for temperature and GPS (_GATEWAYNODE=1)
-;[env:Gateway_59]
+;[env:Gateway_73]
 ;platform = espressif32
 ;board = heltec_wifi_lora_32
 ;build_flags =
 ;  -D _WIFIMANAGER=0
 ;  -D _SPIFFS_FORMAT=0
-;  -D _DUSB=0
+;  -D _DUSB=1
 ;  -D _OLED=0
 ;  -D _GATEWAYNODE=1
 ;  -D _PROFILER=1
+;;  -D _JSONENCODE=1
+;  -D _STRICT_1CH=2
+;  -D _MAXSEEN=10
+;  -D _STAT_LOG=0
 ;framework = arduino
 ;upload_protocol = espota
 ;board_build.flash_mode = qio
 ;upload_speed = 115200
-;upload_port = 192.168.2.59
+;upload_port = 192.168.2.73
 
 ;[env:Gateway_23]
 ;platform = espressif8266
@@ -239,23 +246,23 @@ upload_port = 192.168.2.38
 ;upload_speed = 115200
 ;upload_port = 192.168.2.31
 
-[env:Gateway_152]
-platform = espressif32
-board = heltec_wifi_lora_32
-framework = arduino
-build_flags =
-  -D _WIFIMANAGER=0
-  -D _OLED=1
-  -D _DUSB=1
-  -D _PROFILER=1
-  -D _SPIFFS_FORMAT=1
-  -D _STAT_LOG=0
-;  -D _JSONENCODE=1
-;  -D _MAXSEEN=20
-upload_protocol = espota
-board_build.flash_mode = qio
-upload_speed = 115200
-upload_port = 192.168.2.152
+;[env:Gateway_152]
+;platform = espressif32
+;board = heltec_wifi_lora_32
+;framework = arduino
+;build_flags =
+;  -D _WIFIMANAGER=0
+;  -D _OLED=1
+;  -D _DUSB=1
+;  -D _PROFILER=1
+;  -D _SPIFFS_FORMAT=1
+;  -D _STAT_LOG=0
+;;  -D _JSONENCODE=1
+;;  -D _MAXSEEN=20
+;upload_protocol = espota
+;board_build.flash_mode = qio
+;upload_speed = 115200
+;upload_port = 192.168.2.152
 
 ;[env:Gateway_174]
 ;platform = espressif32
@@ -274,27 +281,3 @@ upload_port = 192.168.2.152
 ;board_build.flash_mode = qio
 ;upload_speed = 115200
 ;upload_port = 192.168.2.174
-
-[env:Gateway_36]
-platform = espressif8266
-board = d1_mini
-board_build.mcu = esp8266
-board_build.f_cpu = 80000000L
-build_flags =
-  -D _PIN_OUT=1
-  -D _WIFIMANAGER=0
-  -D _SPIFFS_FORMAT=0
-  -D _CHANNEL=0
-  -D _REPEATER=0
-  -D _OLED=0
-  -D _DUSB=1
-  -D _PROFILER=1
-  -D _STAT_LOG=1
-  -D _STRICT_1CH=2
-  ;-D _MONITOR=1
-  -D _MAXSEEN=10
-framework = arduino
-upload_protocol = espota
-board_build.flash_mode = qio
-upload_speed = 115200
-upload_port = 192.168.1.36

+ 23 - 12
src/ESP-sc-gway.ino

@@ -70,7 +70,7 @@ extern "C" {
 #	include "lwip/dns.h"
 }
 
-#if (_GATEWAYNODE==1) || (_LOCALSERVER==1)
+#if (_GATEWAYNODE==1) || (_LOCALSERVER>=1)
 #	include "AES-128_V10.h"
 #endif
 
@@ -142,7 +142,7 @@ uint8_t pdebug= P_MAIN ;									// Initially only MAIN and GUI
 
 using namespace std;
 byte 		currentMode = 0x81;
-bool		sx1272 = true;									// Actually we use sx1276/RFM95
+bool		sx1272 = false;									// Actually we use sx1276/RFM95
 uint8_t		MAC_array[6];
 
 // ----------------------------------------------------------------------------
@@ -151,6 +151,9 @@ uint8_t		MAC_array[6];
 //
 // ----------------------------------------------------------------------------
 
+
+uint8_t protocol	= PROTOCOL_VERSION;
+
 // Set spreading factor (SF7 - SF12)
 sf_t sf 			= _SPREADING;							// Initial value of SF					
 
@@ -212,6 +215,12 @@ uint16_t iSens=0;
 // 
 int16_t mutexSPI = 1;
 
+uint8_t buff[64]; 											// Buffer to use for sx1276, set to 64 characters
+uint8_t buff_down[TX_BUFF_SIZE];							// Buffer for downstream
+IPAddress remoteIpNo;
+unsigned int remotePortNo;
+
+
 // ----------------------------------------------------------------------------
 // FORWARD DECLARATIONS
 // These forward declarations are done since other .ino fils are linked by the
@@ -239,7 +248,7 @@ static void stringTime(time_t t, String & response);					// _utils.ino
 
 int initMonitor(struct moniLine *monitor);								// _loraFiles.ino
 void initConfig(struct espGwayConfig *c);								// _loraFiles.ino
-int writeSeen(const char *fn, struct nodeSeen *listSeen);				// _loraFiles.ino
+int printSeen(const char *fn, struct nodeSeen *listSeen);				// _loraFiles.ino
 int readGwayCfg(const char *fn, struct espGwayConfig *c);				// _loraFiles.ino
 
 void init_oLED();														// _oLED.ino
@@ -490,7 +499,7 @@ void setup() {
 		printHexDigit(MAC_array[5], response);
 
 		response += ", Listening at SF" + String(sf) + " on ";
-		response += String((double)freqs[gwayConfig.ch].upFreq/1000000) + " MHz.";
+		response += String(freqs[gwayConfig.ch].upFreq) + " Hz.";
 		mPrint(response);
 	}
 #	endif //_MONITOR
@@ -498,7 +507,7 @@ void setup() {
 	// ---------- TIME -------------------------------------
 	msg_lLED("GET TIME",".");
 	ntpServer = resolveHost(NTP_TIMESERVER, 15);
-	if (ntpServer.toString() == "0:0:0:0")	{					// MMM Experimental
+	if (ntpServer.toString() == "0:0:0:0")	{					// Experimental
 #		if _MONITOR>=1
 			mPrint("setup:: NTP Server not found, found="+ntpServer.toString());
 #		endif
@@ -620,7 +629,7 @@ void setup() {
 	}
 
 	writeConfig(_CONFIGFILE, &gwayConfig);					// Write config
-	writeSeen(_SEENFILE, listSeen);							// Write the last time record  is seen
+	printSeen(_SEENFILE, listSeen);							// Write the last time record  is seen
 
 	// activate Oled display
 #	if _OLED>=1
@@ -628,6 +637,9 @@ void setup() {
 		addr_oLED();
 #	endif //_OLED
 
+	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Allow all
+	writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);		// Reset all interrupt flags
+
 	mPrint(" --- Setup() ended, Starting loop() ---");
 
 }//setup
@@ -666,7 +678,7 @@ void loop ()
 		return;												// Exit loop if no WLAN connected
 	} //WlanConnect()
 
-	yield();												// MMM 200403 to make sure UDP buf filled
+	yield();												// 200403 to make sure UDP buf filled
 
 	// So if we are connected 
 	// Receive UDP PUSH_ACK messages from server. (*2, par. 3.3)
@@ -742,8 +754,7 @@ void loop ()
 			_state = S_RX;
 			rxLoraModem();
 		}
-		writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
-		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);		// Reset all interrupt flags
+
 		msgTime = nowSeconds;
 	}
 
@@ -775,6 +786,7 @@ void loop ()
 
 
 	// stat PUSH_DATA message (*2, par. 4)
+	// Down send to server
 	//	
     if ((nowSeconds - statTime) >= _STAT_INTERVAL) {		// Wake up every xx seconds
 		yield();											// on 26/12/2017
@@ -824,7 +836,6 @@ void loop ()
 
 		yield();
         pullData();											// Send PULL_DATA message to server
-		//startReceiver();
 		pullTime = nowSeconds;
 		
 #		if _MONITOR>=1
@@ -838,7 +849,7 @@ void loop ()
 
 
 	// send RESET_DATA message (*2, par. 4)
-	//
+	// 				MMM Do we need this as standard?
 	// This message will also restart the server which taken approx. 3 ms.
 	nowSeconds = now();
     if ((nowSeconds - rstTime) >= _RST_INTERVAL) {			// Wake up every xx seconds
@@ -886,7 +897,7 @@ void loop ()
 
 #	if _MAXSEEN>=1
 		if ((nowSeconds - fileTime) >= _FILE_INTERVAL) {
-			writeSeen(_SEENFILE, listSeen);
+			printSeen(_SEENFILE, listSeen);
 			fileTime = nowSeconds;
 		}
 #	endif //_MAXSEEN

+ 95 - 72
src/_loraFiles.ino

@@ -92,11 +92,13 @@ void initConfig(struct espGwayConfig *c)
 	// Declarations that are dependent on the init settings
 	// The structure definitions below make it possible to dynamically size and resize the
 	// information in the GUI
-	free(statr); delay(10);
+	free(statr); 
+	delay(5);
+
 	statr = (struct stat_t *) malloc((*c).maxStat * sizeof(struct stat_t));
 	for (int i=0; i<(*c).maxStat; i++) {
-		//statr[i].data=0;
-		statr[i].time=0;						// Time since 1970 in seconds		
+		statr[i].time=0;						// Time since 1970 in seconds
+		statr[i].upDown=0;						// Init for Down traffic
 		statr[i].node=0;						// 4-byte DEVaddr (the only one known to gateway)
 		statr[i].ch=0;							// Channel index to freqs array
 		statr[i].sf=0;							// Init Spreading Factor
@@ -104,7 +106,7 @@ void initConfig(struct espGwayConfig *c)
 
 	free(listSeen); delay(50);
 	listSeen = (struct nodeSeen *) malloc((*c).maxSeen * sizeof(struct nodeSeen));
-	for (int i=0; i<(*c).maxSeen; i+=1) {
+	for (int i=0; i<(*c).maxSeen; i +=1 ) {
 		listSeen[i].idSeen=0;
 	}
 
@@ -132,11 +134,11 @@ int readGwayCfg(const char *fn, struct espGwayConfig *c)
 
 #	if _GATEWAYNODE==1
 		if (gwayConfig.fcnt != (uint8_t) 0) {
-			frameCount = gwayConfig.fcnt+10;
+			frameCount = gwayConfig.fcnt+10;			// Assume he is only 10 off
 		}
 #	endif
 
-	writeGwayCfg(_CONFIGFILE, &gwayConfig );				// And writeback the configuration, not to miss a boot
+	writeGwayCfg(_CONFIGFILE, &gwayConfig );			// And writeback the configuration, not to miss a boot
 
 	return 1;
 	
@@ -199,49 +201,49 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 			id_print(id, val);
 			(*c).monitor = (bool) val.toInt();
 		}
-		else if (id == "CH") { 									// Frequency Channel
-			id_print(id,val); 
-			(*c).ch = (uint8_t) val.toInt();
-		}
-		else if (id == "SF") { 									// Spreading Factor
+		else if (id == "BOOTS") {								// BOOTS setting
 			id_print(id, val);
-			(*c).sf = (uint8_t) val.toInt();
+			(*c).boots = (uint16_t) val.toInt();
 		}
-		else if (id == "FCNT") {								// Frame Counter
+		else if (id == "CAD") {									// CAD setting
 			id_print(id, val);
-			(*c).fcnt = (uint16_t) val.toInt();
+			(*c).cad = (bool) val.toInt();
+		}
+		else if (id == "CH") { 									// Frequency Channel
+			id_print(id,val); 
+			(*c).ch = (uint8_t) val.toInt();
 		}
 		else if (id == "DEBUG") {								// Debug Level
 			id_print(id, val);
 			(*c).debug = (uint8_t) val.toInt();
 		}
-		else if (id == "PDEBUG") {								// pDebug Pattern
+		else if (id == "DELAY") {								// DELAY setting
 			id_print(id, val);
-			(*c).pdebug = (uint8_t) val.toInt();
+			(*c).txDelay = (int32_t) val.toInt();
 		}
-		else if (id == "CAD") {									// CAD setting
+		else if (id == "EXPERT") {								// EXPERT button setting
 			id_print(id, val);
-			(*c).cad = (bool) val.toInt();
+			(*c).expert = (bool) val.toInt();
 		}
-		else if (id == "HOP") {									// HOP setting
+		else if (id == "FCNT") {								// Frame Counter
 			id_print(id, val);
-			(*c).hop = (bool) val.toInt();
+			(*c).fcnt = (uint16_t) val.toInt();
 		}
-		else if (id == "BOOTS") {								// BOOTS setting
+		else if (id == "FILENO") {								// FILENO setting
 			id_print(id, val);
-			(*c).boots = (uint16_t) val.toInt();
+			(*c).logFileNo = (uint16_t) val.toInt();
 		}
-		else if (id == "RESETS") {								// RESET setting
+		else if (id == "FILEREC") {								// FILEREC setting
 			id_print(id, val);
-			(*c).resets = (uint16_t) val.toInt();
+			(*c).logFileRec = (uint16_t) val.toInt();
 		}
-		else if (id == "WIFIS") {								// WIFIS setting
+		else if (id == "FORMAT") {								// FORMAT setting
 			id_print(id, val);
-			(*c).wifis = (uint16_t) val.toInt();
+			(*c).formatCntr= (int8_t) val.toInt();
 		}
-		else if (id == "VIEWS") {								// VIEWS setting
+		else if (id == "HOP") {									// HOP setting
 			id_print(id, val);
-			(*c).views = (uint16_t) val.toInt();
+			(*c).hop = (bool) val.toInt();
 		}
 		else if (id == "NODE") {								// NODE setting
 			id_print(id, val);
@@ -255,17 +257,13 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 			id_print(id, val);
 			(*c).reents = (uint16_t) val.toInt();
 		}
-		else if (id == "NTPERR") {								// NTPERR setting
-			id_print(id, val);
-			(*c).ntpErr = (uint16_t) val.toInt();
-		}
-		else if (id == "WAITERR") {								// WAITERR setting
+		else if (id == "RESETS") {								// RESET setting
 			id_print(id, val);
-			(*c).waitErr = (uint16_t) val.toInt();
+			(*c).resets = (uint16_t) val.toInt();
 		}
-		else if (id == "WAITOK") {								// WAITOK setting
+		else if (id == "NTPERR") {								// NTPERR setting
 			id_print(id, val);
-			(*c).waitOk = (uint16_t) val.toInt();
+			(*c).ntpErr = (uint16_t) val.toInt();
 		}
 		else if (id == "NTPETIM") {								// NTPERR setting
 			id_print(id, val);
@@ -275,33 +273,41 @@ int readConfig(const char *fn, struct espGwayConfig *c)
 			id_print(id, val);
 			(*c).ntps = (uint16_t) val.toInt();
 		}
-		else if (id == "FILENO") {								// FILENO setting
-			id_print(id, val);
-			(*c).logFileNo = (uint16_t) val.toInt();
-		}
-		else if (id == "FILEREC") {								// FILEREC setting
-			id_print(id, val);
-			(*c).logFileRec = (uint16_t) val.toInt();
-		}
-		else if (id == "EXPERT") {								// EXPERT button setting
+		else if (id == "PDEBUG") {								// pDebug Pattern
 			id_print(id, val);
-			(*c).expert = (bool) val.toInt();
+			(*c).pdebug = (uint8_t) val.toInt();
 		}
 		else if (id == "SEEN") {								// SEEN button setting
 			id_print(id, val);
 			(*c).seen = (bool) val.toInt();
 		}
-		else if (id == "DELAY") {								// DELAY setting
+		else if (id == "SF") { 									// Spreading Factor
 			id_print(id, val);
-			(*c).txDelay = (int32_t) val.toInt();
+			(*c).sf = (uint8_t) val.toInt();
+		}
+		else if (id == "SHOWDATA") { 							// Show data of node Factor
+			id_print(id, val);
+			(*c).showdata = (uint8_t) val.toInt();
 		}
 		else if (id == "TRUSTED") {								// TRUSTED setting
 			id_print(id, val);
 			(*c).trusted= (int8_t) val.toInt();
 		}
-		else if (id == "FORMAT") {								// TRUSTED setting
+		else if (id == "VIEWS") {								// VIEWS setting
 			id_print(id, val);
-			(*c).formatCntr= (int8_t) val.toInt();
+			(*c).views = (uint16_t) val.toInt();
+		}
+		else if (id == "WAITERR") {								// WAITERR setting
+			id_print(id, val);
+			(*c).waitErr = (uint16_t) val.toInt();
+		}
+		else if (id == "WAITOK") {								// WAITOK setting
+			id_print(id, val);
+			(*c).waitOk = (uint16_t) val.toInt();
+		}
+		else if (id == "WIFIS") {								// WIFIS setting
+			id_print(id, val);
+			(*c).wifis = (uint16_t) val.toInt();
 		}
 		else {
 #			if _MONITOR>=1
@@ -384,6 +390,7 @@ int writeConfig(const char *fn, struct espGwayConfig *c)
 	f.print("FILENO");	f.print('='); f.print((*c).logFileNo);	f.print('\n');
 	f.print("FORMAT");	f.print('='); f.print((*c).formatCntr); f.print('\n');
 	f.print("DELAY");	f.print('='); f.print((*c).txDelay); 	f.print('\n');
+	f.print("SHOWDATA");f.print('='); f.print((*c).showdata); 	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');
@@ -470,7 +477,7 @@ int addLog(const unsigned char * line, int cnt)
 #	if _MONITOR>=1
 	if ((debug>=2) && (pdebug & P_RX)) {
 		char s[256];
-		i+=12;									// First 12 chars are non printable
+		i += 12;								// First 12 chars are non printable
 		sprintf(s, "addLog:: fileno=%d, rec=%d : %s",gwayConfig.logFileNo,gwayConfig.logFileRec,&line[i]);
 		mPrint(s);
 	}
@@ -514,6 +521,7 @@ int initSeen(struct nodeSeen *listSeen)
 #if _MAXSEEN>=1
 	for (int i=0; i< gwayConfig.maxSeen; i++) {
 		listSeen[i].idSeen=0;
+		listSeen[i].upDown=0;
 		listSeen[i].sfSeen=0;
 		listSeen[i].cntSeen=0;
 		listSeen[i].chnSeen=0;
@@ -528,7 +536,7 @@ int initSeen(struct nodeSeen *listSeen)
 
 // ----------------------------------------------------------------------------
 // readSeen
-// This function read the information stored by writeSeen from the file.
+// This function read the information stored by printSeen from the file.
 // The file is read as String() values and converted to int after.
 // Parameters:
 //	fn:			Filename
@@ -571,6 +579,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 			break;
 		}
 		val=f.readStringUntil('\t'); listSeen[i].timSeen = (time_t) val.toInt();
+		val=f.readStringUntil('\t'); listSeen[i].upDown = (uint8_t) val.toInt();
 		val=f.readStringUntil('\t'); listSeen[i].idSeen = (int64_t) val.toInt();
 		val=f.readStringUntil('\t'); listSeen[i].cntSeen = (uint32_t) val.toInt();
 		val=f.readStringUntil('\t'); listSeen[i].chnSeen = (uint8_t) val.toInt();
@@ -581,6 +590,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 		}
 
 #		if _MONITOR>=1
+
 		if ((debug>=2) && (pdebug & P_MAIN)) {
 				mPrint(" readSeen:: idSeen ="+String(listSeen[i].idSeen,HEX)+", i="+String(i));
 		}
@@ -598,7 +608,7 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 
 
 // ----------------------------------------------------------------------------
-// writeSeen
+// printSeen
 // Once every few messages, update the SPIFFS file and write the array.
 // Parameters:
 // - fn contains the filename to write
@@ -606,13 +616,13 @@ int readSeen(const char *fn, struct nodeSeen *listSeen)
 // Return values:
 // - return 1 on success
 // ----------------------------------------------------------------------------
-int writeSeen(const char *fn, struct nodeSeen *listSeen)
+int printSeen(const char *fn, struct nodeSeen *listSeen)
 {
 #if _MAXSEEN>=1
 	int i;
 	if (!SPIFFS.exists(fn)) {
 #		if _MONITOR>=1
-			mPrint("WARNING:: writeSeen, file not exists="+String(fn));
+			mPrint("WARNING:: printSeen, file not exists="+String(fn));
 #		endif //_MONITOR
 		//initSeen(listSeen);		// XXX make all initial declarations here if config vars need to have a value
 	}
@@ -620,7 +630,7 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen)
 	File f = SPIFFS.open(fn, "w");
 	if (!f) {
 #		if _MONITOR>=1
-			mPrint("writeSeen:: ERROR open file="+String(fn)+" for writing");
+			mPrint("printSeen:: ERROR open file="+String(fn)+" for writing");
 #		endif //_MONITOR
 		return(-1);
 	}
@@ -628,13 +638,24 @@ int writeSeen(const char *fn, struct nodeSeen *listSeen)
 
 	for (i=0; i<iSeen; i++) {							// For all records indexed
 		if ((int32_t)listSeen[i].idSeen == 0) break;
+		
 		f.print((time_t)listSeen[i].timSeen);	f.print('\t');
+		f.print((uint8_t)listSeen[i].upDown);	f.print('\t');
 		f.print((int32_t)listSeen[i].idSeen);	f.print('\t'); // Typecast to avoid errors in unsigned conversion!
 		f.print((uint32_t)listSeen[i].cntSeen);	f.print('\t');
 		f.print((uint8_t)listSeen[i].chnSeen);	f.print('\t');
-		f.print((uint8_t)listSeen[i].sfSeen);	f.print('\n');			
+		f.print((uint8_t)listSeen[i].sfSeen);	f.print('\n');
+
+		// MMM
+#		if _MONITOR>=1
+		if ((debug >= 2) && (pdebug & P_TX)) {
+			if (listSeen[i].upDown == 1) {
+				mPrint("printSeen:: ERROR f.print, upDown="+String(listSeen[i].upDown)+", i="+String(i) );
+			}
+		}
+#		endif //_MONITOR
 	}
-	
+
 	f.close();
 #endif //_MAXSEEN
 	return(1);
@@ -666,14 +687,16 @@ int addSeen(struct nodeSeen *listSeen, struct stat_t stat)
 
 		// If the record node is equal, we found the record already.
 		// So increment cntSeen
-		if (listSeen[i].idSeen==stat.node) {
-		
-			listSeen[i].timSeen = (time_t)stat.time;
+		if ((listSeen[i].idSeen==stat.node)	&&
+			(listSeen[i].upDown==stat.upDown))
+		{
+			//listSeen[i].upDown	= stat.upDown;		// Not necessary, is the same
+			//listSeen[i].idSeen	= stat.node;		// Not necessary, is the same
+			listSeen[i].timSeen		= (time_t)stat.time;
+			listSeen[i].chnSeen		= stat.ch;
+			listSeen[i].sfSeen		= stat.sf;			// The SF argument
 			listSeen[i].cntSeen++;					// Not included on function para
-			//listSeen[i].idSeen = stat.node;		// Not necessary, is the same
-			listSeen[i].chnSeen = stat.ch;
-			listSeen[i].sfSeen = stat.sf;			// The SF argument
-//			writeSeen(_SEENFILE, listSeen);
+//			printSeen(_SEENFILE, listSeen);
 			
 #			if _MONITOR>=2
 			if ((debug>=3) && (pdebug & P_MAIN)) {
@@ -687,17 +710,17 @@ int addSeen(struct nodeSeen *listSeen, struct stat_t stat)
 
 	// else: We did not find the current record so make a new listSeen entry
 	if ((i>=iSeen) && (i<gwayConfig.maxSeen)) {
-		mPrint("addSeen:: Adding node i="+String(i) );
-		listSeen[i].idSeen = stat.node;
-		listSeen[i].chnSeen = stat.ch;
-		listSeen[i].sfSeen = stat.sf;				// The SF argument
-		listSeen[i].timSeen = (time_t)stat.time;	// Timestamp correctly
-		listSeen[i].cntSeen = 1;					// We see this for the first time	
+		listSeen[i].upDown	= stat.upDown;
+		listSeen[i].idSeen	= stat.node;
+		listSeen[i].chnSeen	= stat.ch;
+		listSeen[i].sfSeen	= stat.sf;				// The SF argument
+		listSeen[i].timSeen	= (time_t)stat.time;	// Timestamp correctly
+		listSeen[i].cntSeen	= 1;					// We see this for the first time	
 		iSeen++;
 	}
 
 #	if _MONITOR>=1
-	if ((debug>=1) && (pdebug & P_MAIN)) {
+	if ((debug>=2) && (pdebug & P_MAIN)) {
 		String response= "  addSeen:: i=";
 		response += i;
 		response += ", tim=";

+ 153 - 136
src/_loraModem.ino

@@ -111,14 +111,13 @@ SPISettings readSettings(SPISPEED, MSBFIRST, SPI_MODE0);
 
 uint8_t readRegister(uint8_t addr)
 {
-
 	SPI.beginTransaction(readSettings);				
     digitalWrite(pins.ss, LOW);					// Select Receiver
-	SPI.transfer(addr & 0x7F);					// First address bit 0x00 is read
-	uint8_t res = (uint8_t) SPI.transfer(0x00);
+	SPI.transfer(addr & 0x7F);					// First address bit means read
+	uint8_t res = (uint8_t) SPI.transfer(0x00); // Read address
     digitalWrite(pins.ss, HIGH);				// Unselect Receiver
 	SPI.endTransaction();
-    return((uint8_t) res);
+    return((uint8_t) res) & 0xFF;
 }
 
 
@@ -161,17 +160,18 @@ void writeRegister(uint8_t addr, uint8_t value)
 
 void writeBuffer(uint8_t addr, uint8_t *buf, uint8_t len)
 {
-	//noInterrupts();							// XXX
+	//noInterrupts();								// MMM
 
 	SPI.beginTransaction(writeSettings);
-	digitalWrite(pins.ss, LOW);					// Select Receiver
+	digitalWrite(pins.ss, LOW);					// put SPI slave on
 
 	SPI.transfer((addr | 0x80) & 0xFF);			// write buffer address
 	for (uint8_t i=0; i<len; i++) {				// write all bytes of buffer
 		SPI.transfer(buf[i] & 0xFF);
 	}
 
-    digitalWrite(pins.ss, HIGH);				// Unselect Receiver
+    digitalWrite(pins.ss, HIGH);				// Unselect SPI slave
+	
 	SPI.endTransaction();
 
 	//interrupts();
@@ -207,7 +207,7 @@ void setRate(uint8_t sf, uint8_t crc)
 
 	// Set rate based on Spreading Factor etc
     if (sx1272) {
-		mc1= 0x0A;						// SX1276_MC1_BW_250 0x80 | SX1276_MC1_CR_4_5 0x02 (MMM define BW)
+		mc1= 0x0A;							// SX1276_MC1_BW_250 0x80 | SX1276_MC1_CR_4_5 0x02 (MMM define BW)
 		mc2= ((sf<<4) | crc) % 0xFF;
 		// SX1276_MC1_BW_250 0x80 | SX1276_MC1_CR_4_5 0x02 | SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
         if (sf == SF11 || sf == SF12) { 
@@ -217,22 +217,19 @@ void setRate(uint8_t sf, uint8_t crc)
 	
 	// For sx1276 chips is the CRC is either ON for receive or OFF for transmit
 	else {
-		
-		//if (sf==SF8) {
-		//	mc1= 0x78;					// SX1276_MC1_BW_125==0x70 | SX1276_MC1_CR_4_8==0x08
-		//}
-		//else {
-			mc1= 0x72;					// SX1276_MC1_BW_125==0x70 | SX1276_MC1_CR_4_5==0x02 (4/5)
-										// MMM Read this from the freq table
-		//
-		mc2= ((sf<<4) | crc) & 0xFF;	// crc is 0x00 or 0x04==SX1276_MC2_RX_PAYLOAD_CRCON
-		mc3= 0x04;						// 0x04; SX1276_MC3_AGCAUTO
-        if (sf == SF11 || sf == SF12) { mc3|= 0x08; }		// 0x08 | 0x04
+
+		mc1= 0x72;							// SX1276_MC1_BW_125==0x70 | SX1276_MC1_CR_4_5==0x02 (4/5)
+
+		mc2= ((sf<<4) | crc) & 0xFF;		// crc is 0x00 or 0x04==SX1276_MC2_RX_PAYLOAD_CRCON
+		//mc3= 0x04;						// 0x04; SX1276_MC3_AGCAUTO
+        if (sf == SF11 || sf == SF12) { 
+			mc3|= 0x08; 					// 0x08 | 0x04
+		}
     }
-	
+
 	// Implicit Header (IH), for CLASS B beacons (&& SF6)
 	//if (getIh(LMIC.rps)) {
-    //   mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;
+    //   mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;		// SF6, Not Supported
     //    writeRegister(REG_PAYLOAD_LENGTH, getIh(LMIC.rps)); // required length
     //}
 	
@@ -243,7 +240,8 @@ void setRate(uint8_t sf, uint8_t crc)
 	// Symbol timeout settings
     if (sf == SF10 || sf == SF11 || sf == SF12) {
         writeRegister(REG_SYMB_TIMEOUT_LSB, (uint8_t) 0x05);
-    } else {
+    } 
+	else {
         writeRegister(REG_SYMB_TIMEOUT_LSB, (uint8_t) 0x08);
     }
 	return;
@@ -259,30 +257,39 @@ void setRate(uint8_t sf, uint8_t crc)
 void  setFreq(uint32_t freq)
 {
     // set frequency
-    uint64_t frf = ((uint64_t)freq << 19) / 32000000;
-    writeRegister(REG_FRF_MSB, (uint8_t)(frf>>16) );
-    writeRegister(REG_FRF_MID, (uint8_t)(frf>> 8) );
-    writeRegister(REG_FRF_LSB, (uint8_t)(frf>> 0) );
-	
+    uint32_t frf = (((uint64_t)freq << 19) / 32000000) & 0xFFFFFFFF;
+	//uint32_t frf = (((uint64_t)(freq << 8)) / 15265) & 0xFFFFFFFF;
+
+    writeRegister(REG_FRF_MSB, ((uint8_t)(frf>>16)) & 0xFF );
+    writeRegister(REG_FRF_MID, ((uint8_t)(frf>> 8)) & 0xFF );
+    writeRegister(REG_FRF_LSB, ((uint8_t)(frf>> 0)) & 0xFF );
 	return;
 }
 
 
 // ----------------------------------------------------------------------------------------
-//	Set Power for our gateway
+//	Set Power for our gateway	
+// Note: Power settings for CFG_sx1272 are different
 // ----------------------------------------------------------------------------------------
-void setPow(uint8_t powe)
+void setPow(uint8_t pow)
 {
-	if (powe > 15) powe = 15;
-	else if (powe < 2) powe = 2;
-	
-	ASSERT((powe>=2)&&(powe<=15));
-	
-	uint8_t pac = (0x80 | (powe & 0xF)) & 0xFF;
-	writeRegister(REG_PAC, (uint8_t)pac);								// set 0x09 to pac
-	
-	// Note: Power settings for CFG_sx1272 are different
+	uint8_t pac = 0x00;
 	
+	if (pow > 17) {	
+		pac = 0x8F;
+	}
+	else if (pow < 2) {
+		pac = 2;
+	}
+	else if (pow<=12) {
+		pac=0x20+pow+3;
+	}
+	else {
+		//pac = 0x40 | pow;
+		pac=0x80+pow-2;
+	}
+	ASSERT(((pac&0x0F)>=2) &&((pac&0x0F)<=20));
+	writeRegister(REG_PAC, (uint8_t) pac);								// set register 0x09 to pac
 	return;
 }
 
@@ -299,10 +306,11 @@ void opmode(uint8_t mode)
 #		ifdef CFG_sx1276_radio
 		//mode |= 0x08;   											// TBD: sx1276 high freq
 #		endif
-		writeRegister(REG_OPMODE, (uint8_t) mode);
+		writeRegister(REG_OPMODE, 0xFF & (uint8_t) mode );
 	}
 	else {
-		writeRegister(REG_OPMODE, (uint8_t)((readRegister(REG_OPMODE) & ~OPMODE_MASK) | mode));
+		// If in OPMODE_LORA, leave it is (0x80)
+		writeRegister(REG_OPMODE, 0xFF & (uint8_t)((readRegister(REG_OPMODE) & 0x80) | mode));
 	}
 }
 
@@ -339,7 +347,7 @@ void hop()
 	writeRegister(REG_MAX_PAYLOAD_LENGTH,MAX_PAYLOAD_LENGTH);	// set 0x23 to 0x80==128 bytes
 	writeRegister(REG_PAYLOAD_LENGTH,PAYLOAD_LENGTH);			// 0x22, 0x40==64Byte long
 	
-	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_RX_BASE_AD));	// set reg 0x0D to 0x0F
+	writeRegister(REG_FIFO_ADDR_PTR,(uint8_t)readRegister(REG_FIFO_RX_BASE_AD));	// set reg 0x0D to reg 0x0F(==0x00)
 	writeRegister(REG_HOP_PERIOD,0x00);							// reg 0x24, set to 0x00
 
 	// 5. Config PA Ramp up time								// set reg 0x0A  
@@ -366,7 +374,8 @@ void hop()
 #	endif //_MONITOR
 	// Remember the last time we hop
 	hopTime = micros();									// At what time did we hop
-}
+	
+} //hop
 	
 
 // ------------------------------------- UP -----------------------------------------------
@@ -408,7 +417,7 @@ uint8_t receivePkt(uint8_t *payload)
     statc.msg_ttl++;													// Receive statistics counter
 
     uint8_t irqflags = readRegister(REG_IRQ_FLAGS);						// 0x12; read back flags											
-	uint8_t crcUsed = readRegister(REG_HOP_CHANNEL);					// Is CRC used? (Register 0x1C)
+	uint8_t crcUsed  = readRegister(REG_HOP_CHANNEL);					// Is CRC used? (Register 0x1C)
 	if (crcUsed & 0x40) {
 #		if _DUSB>=1
 		if (( debug>=2) && (pdebug & P_RX )) {
@@ -416,7 +425,7 @@ uint8_t receivePkt(uint8_t *payload)
 		}
 #		endif //_DUSB
 	}
-	
+
     //  Check for payload IRQ_LORA_CRCERR_MASK=0x20 set
     if (irqflags & IRQ_LORA_CRCERR_MASK)								// Is CRC error?
     {
@@ -429,7 +438,7 @@ uint8_t receivePkt(uint8_t *payload)
 #		endif //_MONITOR
 		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
@@ -444,7 +453,7 @@ uint8_t receivePkt(uint8_t *payload)
         writeRegister(REG_IRQ_FLAGS, (uint8_t)(IRQ_LORA_HEADER_MASK  | IRQ_LORA_RXDONE_MASK));	// 0x12; clear HEADER (== 0x10) flag
         return 0;
     }
-	
+
 	// If there are no error messages, read the buffer from the FIFO
 	// This means "Set FifoAddrPtr to FifoRxBaseAddr"
 	else {
@@ -456,16 +465,16 @@ uint8_t receivePkt(uint8_t *payload)
 		}
 
 		if (readRegister(REG_FIFO_RX_CURRENT_ADDR) != readRegister(REG_FIFO_RX_BASE_AD)) {
-#		if _MONITOR>=1
+#			if _MONITOR>=1
 			if ((debug>=1) && (pdebug & P_RADIO)) {
 				mPrint("RX BASE <" + String(readRegister(REG_FIFO_RX_BASE_AD)) + "> != RX CURRENT <" + String(readRegister(REG_FIFO_RX_CURRENT_ADDR)) + ">"	);
 			}
 #			endif //_MONITOR
 		}
-		
+
         //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
+		uint8_t currentAddr   = readRegister(REG_FIFO_RX_BASE_AD);		// 0x0F
+        uint8_t receivedCount = readRegister(REG_RX_BYTES_NB);			// 0x13; How many bytes were read
 #		if _MONITOR>=1
 			if ((debug>=1) && (currentAddr > 64)) {						// More than 64 read?
 				mPrint("rxPkt:: ERROR Rx addr>64"+String(currentAddr));
@@ -487,17 +496,15 @@ uint8_t receivePkt(uint8_t *payload)
             payload[i] = readRegister(REG_FIFO);						// 0x00, FIFO will auto shift register
         }
 
-		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);					// Reset ALL interrupts
-		
 		// As long as _MONITOR is enabled, and P_RX debug messages are selected,
 		// the received packet is displayed on the output.
-#		if _MONITOR>=1
+#	if _MONITOR>=1
 		if ((debug>=1) && (pdebug & P_RX)) {
-		
+
 			String response = "^ receivePkt:: rxPkt: t=";
 			stringTime(now(), response);
 			response += ", f=" + String(gwayConfig.ch) + ", sf=" + String(sf);
-			
+
 			response += ", a=";
 			uint8_t DevAddr [4];
 					DevAddr[0] = payload[4];
@@ -505,14 +512,14 @@ uint8_t receivePkt(uint8_t *payload)
 					DevAddr[2] = payload[2];
 					DevAddr[3] = payload[1];
 			printHex((IPAddress)DevAddr, ':', response);
-			
+
 			response += ", flags=" + String(irqflags,HEX);
 			response += ", addr=" + String(currentAddr);
 			response += ", len=" + String(receivedCount);
 
 			// If debug level 1 is specified, we display the content of the message as well
 			// We need to decode the message as well will it make any sense
-#			if _TRUSTED_DECODE>=2
+#			if _LOCALSERVER>=1
 			if (debug>=1)  {							// Must be 1 for operational use
 
 				int index;								// The index of the codex struct to decode
@@ -527,23 +534,30 @@ uint8_t receivePkt(uint8_t *payload)
 				}	
 
 				// ------------------------------
-				
+
 				Serial.print(F(", data="));
 
 				for (int i=0; i<receivedCount; i++) { 			// Copy array
-					data[i] = payload[i]; 
+					data[i]= payload[i]; 
 				}
 
-				uint16_t frameCount=payload[7]*256 + payload[6];
-				
-				// The message received has a length, but data starts at byte 9, and stops 4 bytes
-				// before the end since those are MIC bytes
-				uint8_t CodeLength = encodePacket((uint8_t *)(data + 9), receivedCount-9-4, (uint16_t)frameCount, DevAddr, decodes[index].appKey, 0);
+				uint16_t frameCount= payload[7]*256 + payload[6];
+
+				// The message received has a length, but data starts at byte 9, 
+				// and stops 4 bytes before the end since those are MIC bytes
+				uint8_t CodeLength= encodePacket(
+					(uint8_t *)(data + 9),
+					receivedCount-9-4,
+					(uint16_t)frameCount,
+					DevAddr,
+					decodes[index].appKey,
+					0
+				);
 
 				Serial.print(F("- NEW fc="));
 				Serial.print(frameCount);
 				Serial.print(F(", addr="));
-				
+
 				for (int i=0; i<4; i++) {
 					if (DevAddr[i]<=0xF) {
 						Serial.print('0');
@@ -551,15 +565,13 @@ uint8_t receivePkt(uint8_t *payload)
 					Serial.print(DevAddr[i], HEX);
 					Serial.print(' ');
 				}
-				
 				Serial.print(F(", len="));
 				Serial.print(CodeLength);
-
 			}
-#			endif //_TRUSTED_DECODE
+#			endif //_LOCALSERVER
 
 			mPrint(response);							// Print response for Serial or mPrint
-			
+
 			// ONLY on USB
 			Serial.print(F(", paylength="));
 			Serial.print(receivedCount);
@@ -571,10 +583,12 @@ uint8_t receivePkt(uint8_t *payload)
 			}
 			Serial.println();
 		}
-#		endif //_MONITOR
+#	endif //_MONITOR
+
 		return(receivedCount);
     }
 
+	// Reset all relevant interrupts
 	writeRegister(REG_IRQ_FLAGS, (uint8_t) (
 		IRQ_LORA_RXDONE_MASK | 
 		IRQ_LORA_RXTOUT_MASK |
@@ -582,7 +596,7 @@ uint8_t receivePkt(uint8_t *payload)
 		IRQ_LORA_CRCERR_MASK));							// 0x12; Clear RxDone IRQ_LORA_RXDONE_MASK
 
 	return 0;
-	
+
 } //receivePkt UP
 	
 	
@@ -604,20 +618,27 @@ bool sendPkt(uint8_t *payLoad, uint8_t payLength)
 {
 #	if _MONITOR>=1
 	if (payLength>=128) {
-		if (debug>=2) {
+		if ((debug>=2) && (pdebug & P_TX)) {
 			mPrint("V sendPkt:: len="+String(payLength));
 		}
 		return false;
 	}
 #	endif //_MONITOR
 
+	payLoad[payLength] = 0x00;											// terminate buffer
+	
 	// MMM?
 	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;											// terminate buffer
+	writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) payLength);				// 0x22	
+
 	writeBuffer(REG_FIFO, (uint8_t *) payLoad, payLength);
-	
+
+#	if _MONITOR>=1
+	if ((debug >=1) && (pdebug & P_TX)) {
+		mPrint("sendPkt:: payLength="+String(payLength)+", REG_FIFO=0x"+String(readRegister(REG_FIFO),HEX) );
+	}
+#	endif
+
 	return true;
 } // sendPkt()
 
@@ -658,14 +679,14 @@ int loraWait(struct LoraDown *LoraDown)
 		return(1);
 	}
 	
-	int32_t delayTmst = (int32_t)(LoraDown->tmst - micros()) + gwayConfig.txDelay;
+	int32_t delayTmst = (int32_t)(LoraDown->tmst - micros()) -1000 + gwayConfig.txDelay;
 												// delayTmst based on txDelay and spreading factor
 	
-	if ((delayTmst > 8000000) || (delayTmst < 0)) {		// Delay is  > 8 secs or less than 0
+	if ((delayTmst > 8000000) || (delayTmst < -1000)) {		// Delay is  > 8 secs or less than 0
 #		if _MONITOR>=1
 		if (delayTmst > 8000000) {
 			String response= "v loraWait:: ERROR: ";
-			printDwn(LoraDown,response);
+			printDwn(LoraDown, response);
 			mPrint(response);
 		}
 		else {
@@ -712,8 +733,8 @@ int loraWait(struct LoraDown *LoraDown)
 //	6. config Power
 //	7. RegLoRaSyncWord LORA_MAC_PREAMBLE
 //	8. write REG dio mapping (dio0)
-//	9. write REG IRQ flags
-// 10. write REG IRQ mask
+//	9. write REG IRQ mask
+// 10. write REG IRQ flags
 // 11. write REG LoRa Fifo Base Address
 // 12. write REG LoRa Fifo Addr Ptr
 // 13. write REG LoRa Payload Length
@@ -729,81 +750,74 @@ void txLoraModem(struct LoraDown *LoraDown)
 	_state = S_TX;
 		
 	// 1. Select LoRa modem from sleep mode
-	//opmode(OPMODE_SLEEP);
-	//opmode(OPMODE_LORA);									// set register 0x01 to 0x80
+	//opmode(OPMODE_SLEEP);											// set 0x01
+	//opmode(OPMODE_LORA);											// set 0x01 to 0x80
 	
 	// Assert the value of the current mode
 	ASSERT((readRegister(REG_OPMODE) & OPMODE_LORA) != 0);
 	
 	// 2. enter standby mode (required for FIFO loading))
-	opmode(OPMODE_STANDBY);									// set 0x01 to 0x01
+	opmode(OPMODE_STANDBY);											// set 0x01 to 0x01
 	
 	// 3. Init spreading factor and other Modem setting
 	setRate(LoraDown->sf, LoraDown->crc);
 	
 	// Frequency hopping
-	//writeRegister(REG_HOP_PERIOD, (uint8_t) 0x00);		// set 0x24 to 0x00 only for receivers
+	//writeRegister(REG_HOP_PERIOD, (uint8_t) 0x00);				// set 0x24 to 0x00 only for receivers
 	
 	// 4. Init Frequency, config channel
 	setFreq(LoraDown->freq);
 
+	writeRegister(REG_SYNC_WORD, (uint8_t) 0x34);					// set 0x39 to 0x34==LORA_MAC_PREAMBLE
+	writeRegister(REG_PREAMBLE_LSB, (uint8_t) LoraDown->prea & 0xFF);
+	writeRegister(REG_PARAMP, (readRegister(REG_PARAMP) & 0xF0) | 0x08); // set 0x0A  ramp-up time 50 uSec
+	writeRegister(REG_PADAC_SX1276,  0x84); 						// set 0x4D (PADAC) to 0x84
+	writeRegister(REG_DET_TRESH, 0x0A);								// Detection Treshhold
+	writeRegister(REG_LNA, (uint8_t) LNA_MAX_GAIN);  				// set reg 0x0C to 0x23
+	
 	// 6. Set power level, REG_PAC
 	setPow(LoraDown->powe);
 	
 	// 7. prevent node to node communication
-	writeRegister(REG_INVERTIQ, readRegister(REG_INVERTIQ) | (uint8_t)(LoraDown->iiq));	// 0x33, (0x27 up or |0x40 down)
+	//writeRegister(REG_INVERTIQ, readRegister(REG_INVERTIQ) | (uint8_t)(LoraDown->iiq));	// set 0x33, (0x27 up or |0x40 down)
+	writeRegister(REG_INVERTIQ, readRegister(REG_INVERTIQ) | (uint8_t)(LoraDown->iiq)); // set 0x33 to (0x27 (reserved) | 0x40) for downstream
 	
 	// 8. set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP (or less for 1ch gateway)
     writeRegister(REG_DIO_MAPPING_1, (uint8_t)(
 		MAP_DIO0_LORA_TXDONE | 
 		MAP_DIO1_LORA_NOP | 
 		MAP_DIO2_LORA_NOP |
-		MAP_DIO3_LORA_NOP));								// was MAP_DIO3_LORA_CRC
-	
-	// 9. clear all radio IRQ flags
-    writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
-	
-	// 10. mask all IRQs but TxDone
+		MAP_DIO3_LORA_NOP));										// was MAP_DIO3_LORA_CRC
+
+	// 9. mask all IRQs but TxDone
     writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~IRQ_LORA_TXDONE_MASK);
 	
-	// txLora
-	opmode(OPMODE_FSTX);													// set reg 0x01 to 0x02 (actual value becomes 0x82)
-	
-	// 11, 12, 13, 14. write the buffer to the FiFo
-	sendPkt(LoraDown->payLoad, LoraDown->size);
-	
+	// 10. clear all radio IRQ flags
+    writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
+	//writeRegister(REG_IRQ_FLAGS, (uint8_t) IRQ_LORA_TXDONE_MASK);	// set reg 0x12 to 0x08, clear TXDONE
+
+	// FSTX setting
+	opmode(OPMODE_FSTX);											// set reg 0x01 to 0x02 (actual value becomes 0x82)
+	delay(1);														// MMM
+
 	//Set the base addres of the transmit buffer in FIFO
 	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_TX_BASE_AD));	// set 0x0D to 0x0F (contains 0x80);	
-	
+
 	//For TX we have to set the PAYLOAD_LENGTH
-	writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) LoraDown->size);			// set reg 0x22 to  0x40==64Byte long
-	
+	writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) LoraDown->size);	// set reg 0x22 to  0x40==64Byte long
+
 	//For TX we have to set the MAX_PAYLOAD_LENGTH
 	writeRegister(REG_MAX_PAYLOAD_LENGTH, (uint8_t) MAX_PAYLOAD_LENGTH);	// set reg 0x22, max 0x40==64Byte long
+
+	// 11, 12, 13, 14. write the buffer to the FiFo
+	sendPkt(LoraDown->payLoad, LoraDown->size);
 	
-	// Reset the IRQ register
-	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);						// Clear the mask
-//	writeRegister(REG_IRQ_FLAGS, (uint8_t) IRQ_LORA_TXDONE_MASK);			// set reg 0x12 to 0x08, clear TXDONE
-	writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);							// set reg 0x12 to 0xFF, clear TXDONE and others
-	
-	// 16. Initiate actual transmission of FiFo
-	opmode(OPMODE_TX);														// set reg 0x01 to 0x03 (actual value becomes 0x83)
+	// 16. Initiate actual transmission of FiFo, after opmode TX it switches to standby mode
+	delay(5);														// MMM works
+	opmode(OPMODE_TX);												// set reg 0x01 to 0x03 (actual value becomes 0x83)
 
 	// After message transmitted the sender switches to STANDBY state, and issues TXDONE
 
-#	if _MONITOR>=1
-	if ((debug>=1) && (pdebug & P_TX)) {
-		String response = "v txLoraModem:: end=";
-		printDwn(LoraDown, response);
-		response += ", size=" + String(LoraDown->size);
-		response += ", data=";
-		for(int i=0; i<LoraDown->size; i++) {
-			response += String(LoraDown->payLoad[i],HEX) + " ";
-		}
-		mPrint(response);
-	}
-#	endif //_MONITOR
-
 }// txLoraModem
 
 
@@ -858,9 +872,9 @@ void rxLoraModem()
 	
 	// 5. Accept no interrupts except RXDONE, RXTOUT en RXCRC
 	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~(
-		IRQ_LORA_RXDONE_MASK | 
-		IRQ_LORA_RXTOUT_MASK | 
-		IRQ_LORA_HEADER_MASK | 
+		IRQ_LORA_RXDONE_MASK |
+		IRQ_LORA_RXTOUT_MASK |
+		IRQ_LORA_HEADER_MASK |
 		IRQ_LORA_CRCERR_MASK));
 
 	// set frequency hopping
@@ -1011,20 +1025,23 @@ void initLoraModem()
 
 	// 5. Set chip type/version
     uint8_t version = readRegister(REG_VERSION);				// read reg 0x34 the LoRa chip version id
-    if (version == 0x22) {										// sx1272==0x22
-#		if _DUSB>=2
-			Serial.println(F("WARNING:: SX1272 detected"));
+	if (version == 0x12) {									// sx1276==0x12
+#		if _DUSB>=1
+           if ((debug>=2) && (pdebug & P_MAIN)) {
+			Serial.println(F("SX1276 starting"));
+		}
+#		endif
+		sx1272= false;
+	}
+    else if (version == 0x22) {										// sx1272==0x22
+#		if _DUSB>=1
+            if ((debug>=1) && (pdebug & P_MAIN)) {
+				Serial.println(F("WARNING:: SX1272 detected"));
+			}
 #		endif
-        sx1272 = true;
+        sx1272= true;
     } 
 	
-	else if (version == 0x12) {									// sx1276==0x12
-#			if _DUSB>=2
-            if (debug >=1) 
-				Serial.println(F("SX1276 starting"));
-#			endif
-            sx1272 = false;
-	}
 	else {
 		// Normally this means that we connected the wrong type of board and
 		// therefore specified the wrong type of wiring/pins to the software
@@ -1066,7 +1083,7 @@ void initLoraModem()
 	// Set 0x4D PADAC for SX1276 ; XXX register is 0x5a for sx1272
 	//Semtech rev. 5, Aug 2016, para 
 	writeRegister(REG_PADAC_SX1276,  0x84); 					// set reg 0x4D (PADAC) to 0x84
-	//writeRegister(REG_PADAC, readRegister(REG_PADAC) | 0x4);
+	//writeRegister(REG_PADAC_SX1276, readRegister(REG_PADAC_SX1276) | 0x4);
 
 	// Set treshold according to sx1276 specs
 	writeRegister(REG_DET_TRESH, 0x0A);

+ 2 - 2
src/_repeater.ino

@@ -53,9 +53,9 @@ int repeatLora(struct LoraUp * LUP) {
 	LDWN->freq 		= freqs[(gwayConfig.ch-1)%3].dwnFreq;
 	LDWN->size		= LUP->size;
 	LDWN->sf		= LUP->sf;
-	LDWN->powe		= 15;								// Default for normal frequencies
+	LDWN->powe		= 14;								// Default for normal frequencies
 	LDWN->crc		= 1;
-	LDWN->iiq		= 0x27;								// 0x40 when true or 0x27 when ipol false
+	LDWN->iiq		= 0x27;								// 0x40 when ipol true or 0x27 when false
 	LDWN->imme		= false;
 
 	//strncpy((char *)((* LDWN).payLoad), (char *)((* LUP).payLoad), (int)((* LUP).size));

+ 34 - 10
src/_sensor.ino

@@ -442,7 +442,7 @@ void checkMic(uint8_t *buf, uint8_t len, uint8_t *key)
 	uint8_t NwkSKey[16] = _NWKSKEY;
 
 #	if _MONITOR>=1
-	if (debug>=2) {
+	if ((debug>=2) && (pdebug & P_RX)) {
 		String response = "";
 		for (int i=0; i<len; i++) { 
 			printHexDigit(buf[i], response); 
@@ -460,7 +460,7 @@ void checkMic(uint8_t *buf, uint8_t len, uint8_t *key)
 	uint16_t FrameCount = ( cBuf[7] * 256 ) + cBuf[6];
 	len += micPacket(cBuf, len, FrameCount, NwkSKey, 0);
 	
-	if (debug>=2) {
+	if ((debug>=2) && (pdebug & P_RX)) {
 		String response = "";
 
 		for (int i=0; i<len; i++) { 
@@ -503,7 +503,7 @@ int sensorPacket() {
 
 	uint8_t buff_up[512];								// Declare buffer here to avoid exceptions
 	uint8_t message[64]={ 0 };							// Payload, init to 0
-	uint8_t mlength = 0;
+	//uint8_t mlength = 0;
 	uint8_t NwkSKey[16] = _NWKSKEY;
 	uint8_t AppSKey[16] = _APPSKEY;
 	uint8_t DevAddr[4]  = _DEVADDR;
@@ -529,7 +529,7 @@ int sensorPacket() {
 	
 	// -------------------------------
 	// FHDR consists of 4 bytes addr, 1 byte Fctrl, 2 byte FCnt, 0-15 byte FOpts
-	// We support ABP addresses only for Gateways
+	// We support ABP addresses only for Gateway sensors
 	LUP.payLoad[1] = DevAddr[3];						// Last byte[3] of address
 	LUP.payLoad[2] = DevAddr[2];
 	LUP.payLoad[3] = DevAddr[1];
@@ -566,7 +566,13 @@ int sensorPacket() {
 #endif	//_DUSB
 	
 	// we have to include the AES functions at this stage in order to generate LoRa Payload.
-	uint8_t CodeLength = encodePacket((uint8_t *)(LUP.payLoad + LUP.size), PayLength, (uint16_t)frameCount, DevAddr, AppSKey, 0);
+	uint8_t CodeLength = encodePacket(
+		(uint8_t *)(LUP.payLoad + LUP.size), 
+		PayLength, (uint16_t)frameCount, 
+		DevAddr, 
+		AppSKey, 
+		0
+	);
 
 #if _DUSB>=1
 	if ((debug>=2) && (pdebug & P_RADIO)) {
@@ -645,7 +651,15 @@ int sensorPacket() {
 	// If all is right, we should after decoding (which is the same as encoding) get
 	// the original message back again.
 	if ((debug>=2) && (pdebug & P_RADIO)) {
-		CodeLength = encodePacket((uint8_t *)(LUP.payLoad + 9), PayLength, (uint16_t)frameCount-1, DevAddr, AppSKey, 0);
+		CodeLength = encodePacket(
+			(uint8_t *)(LUP.payLoad + 9), 
+			PayLength, 
+			(uint16_t)frameCount-1, 
+			DevAddr, 
+			AppSKey, 
+			0
+		);
+		
 		Serial.print(F("rev: "));
 		for (int i=0; i<CodeLength; i++) {
 			Serial.print(LUP.payLoad[i],HEX);
@@ -678,7 +692,7 @@ int sensorPacket() {
 #endif //_GATEWAYNODE==1
 
 
-#if (_GATEWAYNODE==1) || (_LOCALSERVER==1)
+#if (_GATEWAYNODE==1) || (_LOCALSERVER>=1)
 // ----------------------------------------------------------------------------
 // ENCODEPACKET
 // In Sensor mode, we have to encode the user payload before sending.
@@ -702,6 +716,14 @@ int sensorPacket() {
 //  but not part of this code.
 //
 // cmac = aes128_encrypt(K, Block_A[i])
+//
+// Parameters:
+//	Data:		Data to encoide
+//	DataLength:	Length of the data field
+//	FrameCount:	xx
+//	DevAddr:	Device ID
+//	AppSKey:	Device specific
+//	Direction:	Uplink==0, e.g. receivePakt(), semsorPacket(),
 // ----------------------------------------------------------------------------
 uint8_t encodePacket(uint8_t *Data, uint8_t DataLength, uint16_t FrameCount, uint8_t *DevAddr, uint8_t *AppSKey, uint8_t Direction)
 {
@@ -709,9 +731,11 @@ uint8_t encodePacket(uint8_t *Data, uint8_t DataLength, uint16_t FrameCount, uin
 #if _MONITOR>=1
 	if ((debug>=2) && (pdebug & P_MAIN)) {
 		String response="encodePacket:: DevAddr=";
-		for (int i=0; i<4; i++ ) { response+=(String(DevAddr[i],HEX)+(' ')); }
-		response+=", encodePacket:: AppSKey=";
-		for (int i=0; i<16; i++ ) { response+=(String(AppSKey[i],HEX)+(' ')); }
+		for (int i=0; i<4; i++ ) { response += (String(DevAddr[i],HEX)+(' ')); }
+		response += ", fcnt=" + String(FrameCount);
+		response += ", encodePacket:: AppSKey=";
+		for (int i=0; i<16; i++ ) { response += (String(AppSKey[i],HEX)+(' ')); }
+		response += ", direction=" + String(Direction);
 		mPrint(response);
 	}
 #endif //_MONITOR

+ 148 - 97
src/_stateMachine.ino

@@ -16,7 +16,6 @@
 // This file contains the state machine code enabling to receive
 // and transmit packages/messages.
 // ============================================================================================
-//
 
 
 // --------------------------------------------------------------------------------------------
@@ -77,7 +76,7 @@ void stateMachine()
 	uint8_t intr  = flags & ( ~ mask );							// Only react on non masked interrupts
 	uint8_t rssi;
 	_event=0;													// Reset the interrupt detector	
-	
+
 #	if _MONITOR>=1
 	if (intr != flags) {
 		String response = "stateMachine:: Error: flags="+String(flags,HEX)+", ";
@@ -99,14 +98,13 @@ void stateMachine()
 		if ((_state == S_SCAN) || (_state == S_CAD)) {
 
 			_event=0;
-		
+
 			uint32_t eventWait = EVENT_WAIT;
 			switch (_state) {
 				case S_INIT:	eventWait = 0; break;
 				// Next two are most important
 				case S_SCAN:	eventWait = EVENT_WAIT * 1; break;
 				case S_CAD:		eventWait = EVENT_WAIT * 1; break;
-				
 				case S_RX:		eventWait = EVENT_WAIT * 8; break;
 				case S_TX:		eventWait = EVENT_WAIT * 1; break;
 				case S_TXDONE:	eventWait = EVENT_WAIT * 4; break;
@@ -118,7 +116,7 @@ void stateMachine()
 						mPrint(response);
 #					endif //_MONITOR
 			}
-			
+
 			// doneWait is the time that we received CDDONE interrupt
 			// So we init the wait time for RXDONE based on the current SF.
 			// As for highter CF it takes longer to receive symbols
@@ -184,8 +182,8 @@ void stateMachine()
 				doneTime=micros();								// reset the timer on timeout
 				return;
 			}
-			
-		
+
+
 			// If we are here, NO timeout has occurred 
 			// So we need to return to the main State Machine
 			// as there was NO interrupt
@@ -201,19 +199,19 @@ void stateMachine()
 			}
 #			endif //_MONITOR
 		} // if SCAN or CAD
-		
+
 		// else, S_RX of S_TX for example
 		else {
 			//
 		} // else S_RX or S_TX, TXDONE
-		
+
 		yield();										// if hopping is enabled
-		
+
 	}// intr==0 && gwayConfig.hop
 
-	
 
-	// ========================================================================================
+
+	// ==========================================================================================
 	// This is the actual state machine of the gateway
 	// and its next actions are depending on the state we are in.
 	// For hop situations we do not get interrupts, so we have to
@@ -233,11 +231,11 @@ void stateMachine()
 #		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
+		writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 );			// Accept ALL interrupts
 		_event=0;
 	  break;
 
-	  
+
 	  // ----------------------------------------------------------------------------------------
 	  // In S_SCAN we measure a high RSSI this means that there (probably) is a message
 	  // coming in at that freq. But not necessarily on the current SF.
@@ -259,7 +257,7 @@ void stateMachine()
 				MAP_DIO1_LORA_RXTOUT | 
 				MAP_DIO2_LORA_NOP | 
 				MAP_DIO3_LORA_CRC));
-			
+
 			// Since new state is S_RX, accept no interrupts except RXDONE or RXTOUT
 			// HEADER and CRCERR
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~(
@@ -267,19 +265,19 @@ void stateMachine()
 				IRQ_LORA_RXTOUT_MASK | 
 				IRQ_LORA_HEADER_MASK | 
 				IRQ_LORA_CRCERR_MASK));
-			
+
 			// Starting with version 5.0.1 the waittime is dependent on the SF
 			// So for SF12 we wait longer (2^7 == 128 uSec) and for SF7 4 uSec.
 			//delayMicroseconds( (0x01 << ((uint8_t)sf - 5 )) );
 			//if (gwayConfig.cad) 									// XXX 180520 make sure we start reading asap in hop
 			//	delayMicroseconds( RSSI_WAIT );						// Wait some microseconds less
-			
+
 			rssi = readRegister(REG_RSSI);							// Read the RSSI
 			_rssi = rssi;											// Read the RSSI in the state variable
 
 			_event=0;												// Make 0, as soon as we have an interrupt
 			detTime=micros();										// mark time that preamble detected
-			
+
 #			if _MONITOR>=1
 			if ((debug>=1) && (pdebug & P_PRE)) {
 				String response = "SCAN:: ";
@@ -329,7 +327,7 @@ void stateMachine()
 				_state = S_CAD;										// promote to next level
 				_event=0;
 			}
-			
+
 			// If the RSSI is not big enough we skip the CDDONE
 			// and go back to scanning
 			else {
@@ -351,7 +349,7 @@ void stateMachine()
 			doneTime = micros();									// Need CDDONE or other intr to reset timeout			
 
 		}//SCAN CDDONE 
-		
+
 		// So if we are here then we are in S_SCAN and the interrupt is not
 		// CDDECT or CDDONE. it is probably soft interrupt _event==1
 		// So if gwayConfig.hop we change the frequency and restart the
@@ -371,7 +369,7 @@ void stateMachine()
 		{
 			_event=0;												// XXX 26/12/2017 !!! NEED
 		}
-		
+
 		// Unkown Interrupt, so we have an error
 		//
 		else {
@@ -387,10 +385,10 @@ void stateMachine()
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
 		}
-		
+
 	  break; // S_SCAN
 
-	  
+
 	  // ----------------------------------------------------------------------------------------
 	  // S_CAD: In CAD mode we scan every SF for high RSSI until we have a DETECT.
 	  // Reason is the we received a CADDONE interrupt so we know a message is received
@@ -416,28 +414,28 @@ void stateMachine()
 				MAP_DIO1_LORA_RXTOUT | 
 				MAP_DIO2_LORA_NOP |
 				MAP_DIO3_LORA_CRC ));
-			
+
 			// Accept no interrupts except RXDONE or RXTOUT
 			_event=0;								
-			
+
 			// if CDECT, make state S_RX so we wait for RXDONE intr
-			
+
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~(
 				IRQ_LORA_RXDONE_MASK | 
 				IRQ_LORA_RXTOUT_MASK |
 				IRQ_LORA_HEADER_MASK |
 				IRQ_LORA_CRCERR_MASK ));
-				
+
 			// Reset all interrupts as soon as possible
 			// But listen ONLY to RXDONE and RXTOUT interrupts 
 			//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_CDDETD_MASK | IRQ_LORA_RXDONE_MASK);
 
 			// If we want to reset CRC, HEADER and RXTOUT flags as well
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );			// XXX 180326, reset all CAD Detect interrupt flags
-			
+
 			//_state = S_RX;										// XXX 180521 Set state to start receiving
 			opmode(OPMODE_RX_SINGLE);								// set reg 0x01 to 0x06, initiate READ
-			
+
 			delayMicroseconds( RSSI_WAIT );							// Wait some microseconds less
 			//delayMicroseconds( (0x01 << ((uint8_t)sf - 5 )) );
 			rssi = readRegister(REG_RSSI);							// Read the RSSI
@@ -452,9 +450,9 @@ void stateMachine()
 			}
 #			endif //_MONITOR
 			_state = S_RX;											// Set state to start receiving
-			
+
 		}// CDDETD
-		
+
 		// Intr == CADDONE
 		// So we scan this SF and if not high enough ... next
 		//
@@ -464,18 +462,12 @@ void stateMachine()
 			// We expect on other SF get CDDETD
 			//
 			if (((uint8_t)sf) < freqs[gwayConfig.ch].upHi) {
-			
+
 				sf = (sf_t)((uint8_t)sf+1);							// Increment sf
 				setRate(sf, 0x04);									// Set SF with CRC==on
-				
-				// reset interrupt flags for CAD Done
-				_event=0;											// XXX 180324, when increasing SF loop, ws 0x00
-				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Reset the interrupt mask
-				//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_CDDONE_MASK | IRQ_LORA_CDDETD_MASK);
-				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );		// This will prevent the CDDETD from being read
 
 				opmode(OPMODE_CAD);									// Scanning mode
-				
+
 				delayMicroseconds(RSSI_WAIT);
 				rssi = readRegister(REG_RSSI);						// Read the RSSI
 
@@ -483,6 +475,13 @@ void stateMachine()
 				if ((debug>=3) && (pdebug & P_CAD)) {
 					mPrint("S_CAD:: CDONE, SF=" + String(sf) );
 				}
+
+				// reset interrupt flags for CAD Done
+				_event=0;											// XXX 180324, when increasing SF loop, ws 0x00
+				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Accept all
+				//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_CDDONE_MASK | IRQ_LORA_CDDETD_MASK);
+				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );		// Clear all
+
 #				endif //_MONITOR
 			}
 
@@ -495,7 +494,7 @@ void stateMachine()
 				_event=1;											// reset soft intr, to state machine again
 				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Reset the interrupt mask
 				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );		// or IRQ_LORA_CDDONE_MASK
-				
+
 				_state = S_SCAN;									// As soon as we reach SF12 do something
 				sf = (sf_t) freqs[gwayConfig.ch].upLo;
 				cadScanner();										// Which will reset SF to lowest SF
@@ -507,7 +506,7 @@ void stateMachine()
 #				endif //_MONITOR
 			}
 			doneTime = micros();									// We need CDDONE or other intr to reset timeout
-			
+
 		} //CAD CDDONE
 
 		// if this interrupt is not CDECT or CDDONE then probably is 0x00
@@ -524,7 +523,7 @@ void stateMachine()
 #			endif //_MONITOR
 			//_event=1;												// Stay in CAD _state until real interrupt
 		}
-		
+
 		// else we do not recognize the interrupt. We print an error
 		// and restart scanning. If hop we start at gwayConfig.ch==0
 		//
@@ -555,9 +554,9 @@ void stateMachine()
 	  //	Go back to SCAN
 	  //
 	  case S_RX:
-		
+
 		if (intr & IRQ_LORA_RXDONE_MASK) {
-		
+
 #			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.
@@ -585,7 +584,7 @@ void stateMachine()
 				// Reset interrupts
 				_event=0;												// CRC error
 				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);		// Reset the interrupt mask
-				writeRegister(REG_IRQ_FLAGS, (uint8_t)(
+				writeRegister(REG_IRQ_FLAGS, (uint8_t) (
 					IRQ_LORA_RXDONE_MASK | 
 					IRQ_LORA_RXTOUT_MASK | 
 					IRQ_LORA_HEADER_MASK | 
@@ -595,12 +594,11 @@ void stateMachine()
 			}// RX-CRC mask
 #			endif //_CRCCHECK
 
-			
 			// If we are here, no CRC error occurred, start timer
 #			if _DUSB>=1 || _MONITOR>=1
 				uint32_t rxDoneTime = micros();	
 #			endif	
-		
+
 			// There should not be an error in the message
 			LoraUp.payLoad[0]= 0x00;								// Empty the message
 
@@ -611,7 +609,7 @@ void stateMachine()
 			// - Reset the interrupts
 			// - break
 			// NOTE: receivePacket also increases .ok0 - .ok2 counter
-			
+
 			if((LoraUp.size = receivePkt(LoraUp.payLoad)) <= 0) {
 #				if _MONITOR>=1
 				if ((debug>=0) && (pdebug & P_RX)) {
@@ -623,11 +621,11 @@ void stateMachine()
 				_event=1;
 				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Reset the interrupt mask
 				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
-				
+
 				_state = S_SCAN;
 				break;
 			}
-			
+
 #			if _MONITOR>=1
 			if ((debug >=2) && (pdebug & P_RX)) {
 				String response  = "RXDONE:: dT=";
@@ -636,7 +634,7 @@ void stateMachine()
 				mPrint(response);
 			}
 #			endif //_MONITOR
-				
+
 			// Do all register processing in this section
 			uint8_t value = readRegister(REG_PKT_SNR_VALUE);		// 0x19; 
 			if ( value & 0x80 ) {									// The SNR sign bit is 1
@@ -651,14 +649,14 @@ void stateMachine()
 
 			// Packet RSSI
 			LoraUp.prssi = readRegister(REG_PKT_RSSI);				// read register 0x1A, packet rssi
-    
+
 			// Correction of RSSI value based on chip used.	
 			if (sx1272) {											// Is it a sx1272 radio?
 				LoraUp.rssicorr = 139;
 			} else {												// Probably SX1276 or RFM95
 				LoraUp.rssicorr = 157;
 			}
-				
+
 			LoraUp.sf = readRegister(REG_MODEM_CONFIG2) >> 4;
 
 			// If read was successful, read the package from the LoRa bus
@@ -682,13 +680,13 @@ void stateMachine()
 				_state = S_RX;
 				rxLoraModem();
 			}
-			
+
 			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
 			_event=0;
 		}// RXDONE
-		
+
 		// RXOUT: 
 		// We did receive message receive timeout
 		// This is the most common event in hop mode, possibly due to the fact
@@ -697,13 +695,13 @@ void stateMachine()
 		// immediately without delay.
 		//
 		else if (intr & IRQ_LORA_RXTOUT_MASK) {
-			
+
 			// Make sure we reset all interrupts
 			// and get back to scanning
 			_event=0;												// Is set by interrupt handlers
 			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 );
 			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset all interrupts
-			
+
 			// If RXTOUT we put the modem in cad state and reset to SF7
 			// If a timeout occurs here we reset the cadscanner
 			//
@@ -719,21 +717,20 @@ void stateMachine()
 				sf = SF7;
 				cadScanner();										// Start the scanner after RXTOUT
 				_state = S_SCAN;									// New state is scan
-
 			}
-			
+
 			// If not in cad mode we are in single channel single sf mode.
 			//
 			else {
 				_state = S_RX;										// Receive when interrupted
 				rxLoraModem();
 			}
-			
+
 			eventTime=micros();										//There was an event for receive
 			doneTime = micros();									// We need CDDONE or other intr to reset timeout
-			
+
 		}// RXTOUT
-		
+
 		else if (intr & IRQ_LORA_HEADER_MASK) {
 			// This interrupt means we received an header successfully
 			// which is normall an indication of RXDONE
@@ -757,7 +754,7 @@ void stateMachine()
 			}
 #			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
@@ -770,10 +767,10 @@ void stateMachine()
 			//writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00 );
 			//writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
 		}// int not RXDONE or RXTOUT
-		
+
 	  break; // S_RX
 
-	  
+
 	  // ----------------------------------------------------------------------------------------
 	  // Start the transmission of a message in state S-TX (DOWN)
 	  // This is not an interrupt state, we use this state to start transmission
@@ -795,25 +792,6 @@ void stateMachine()
 			_event= 1;
 		}
 
-#		if _MONITOR>=1
-		//if ((debug>=1) && (pdebug & P_MAIN)) {
-		//	mPrint("TX stateMachine:: calling loraWait");
-		//}
-#		endif
-
-		//loraWait(&LoraDown);
-	
-		// Set state to transmit
-		// Clear interrupt flags and masks
-		//writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
-		//writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);				// reset interrupt flags
-		
-	  	// Initiate the transmission of the buffer (in User space)
-		// We react on ALL interrupts if we are in TX state.
-		//txLoraModem(&LoraDown);
-		
-		// After filling the buffer we only react on TXDONE interrupt
-		// So, more or less start at the "case TXDONE:" below 
 		_state=S_TXDONE;
 		_event=1;													// Or remove the break below
 
@@ -827,7 +805,7 @@ void stateMachine()
 
 	  break; // S_TX
 
-	  
+
 	  // ----------------------------------------------------------------------------------------
 	  // After the transmission is completed by the hardware, 
 	  // the interrupt TXDONE is raised telling us that the tranmission
@@ -856,7 +834,7 @@ void stateMachine()
 #			endif //_MONITOR
 
 			// After transmission reset to receiver
-			if ((gwayConfig.cad) || (gwayConfig.hop)) {									// XXX 26/02
+			if ((gwayConfig.cad) || (gwayConfig.hop)) {				// XXX 26/02
 				// Set the state to CAD scanning
 				_state = S_SCAN;
 				sf = SF7;
@@ -866,17 +844,70 @@ void stateMachine()
 				_state = S_RX;
 				rxLoraModem();		
 			}
-			
+
 			_event=0;
-			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
-			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset interrupt flags
+
+			if (protocol == 1) {							// Got from the downstream message
+#				if _MONITOR>=1
+				if ((debug>=2) && (pdebug & P_TX)) {
+					mPrint("^ TX_ACK:: readUdp: protocol version 1");
+				}
+#				endif
+				break;										// return
+			}
+
+#			if _MONITOR>=1
+			if ((debug>=2) && (pdebug & P_TX)) {
+				mPrint("^ TX_ACK:: readUDP: protocol version 2+");
+			}
+#			endif //_MONITOR
+
+			// UP: Now respond with an TX_ACK
+			// Byte 3 is 0x05; see para 5.2.6 of spec
+			buff[0]= buff_down[0];							// As read from the Network Server
+			buff[1]= buff_down[1];							// Token 1, copied from downstream
+			buff[2]= buff_down[2];							// Token 2
+			buff[3]= TX_ACK;								// ident == 0x05;
+			buff[4]= 0;										// Not error means "\0"
+			// If it is an error, please look at para 6.1.2
+
+			yield();
+
+			// Only send the PULL_ACK to the UDP socket that just sent the data!!!
+			Udp.beginPacket(remoteIpNo, remotePortNo);
+
+			// XXX We should format the message before sending up with UDP
+
+			if (Udp.write((unsigned char *)buff, 12) != 12) {
+#				if _MONITOR>=1
+				if (debug>=0) {
+					mPrint("^ readUdp:: ERROR: PULL_ACK write");
+				}
+#				endif //_MONITOR
+			}
+			else {
+#				if _MONITOR>=1
+				if ((debug>=2) && (pdebug & P_TX)) {
+					mPrint("^ readUdp:: TX_ACK: micros="+String(micros()));
+				}
+#				endif //_MONITOR
+			}
+
+			if (!Udp.endPacket()) {
+#				if _MONITOR>=1
+				if ((debug>=0) && (pdebug & P_TX)) {
+					mPrint("^ readUdp:: PULL_ACK: ERROR Udp.endPacket");
+				}
+#				endif //_MONITOR
+			}
+			yield();
 		}
-		
+
 		// If a soft _event==0 interrupt and no transmission finished:
 		else if ( intr != 0 ) {
 #			if _MONITOR>=1
 			if ((debug>=0) && (pdebug & P_TX)) {
-				String response =  "TXDONE:: Error unknown intr=";
+				String response =  "TXDONE:: ERROR unknown intr=";
 				mStat(intr, response);
 				mPrint(response);
 			} //_MONITOR
@@ -886,24 +917,44 @@ void stateMachine()
 			_event=0;
 			_state=S_SCAN;
 		}
-		
+
 		// intr == 0
+		// TX_DONE interrupt is not received in time
 		else {
 
 			// Increase timer. If timer exceeds certain value (7 seconds!), reset
 			// After sending a message with S_TX, we have to receive a TXDONE interrupt
-			// 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 )) {
+			// within 7 seconds according to spec, or there is a problem.
+			if ( sendTime > micros() ) {
+				sendTime = 0;				// This could be omitted for usigned ints
 #				if _MONITOR>=1
 				if ((debug>=1) && (pdebug & P_TX)) {
-					mPrint("TXDONE:: reset TX");
+					mPrint("v Warning:: intr=0 received, sendTime=0");
+				}
+#				endif //_MONITOR
+			}
+			if (( _state == S_TXDONE ) && (( micros() - sendTime) > 8000000 )) {
+#				if _MONITOR>=1
+				if ((debug>=1) && (pdebug & P_TX)) {
+					mPrint("v Warning:: TXDONE not received, reset receiver");
 				}
 #				endif //_MONITOR
 				startReceiver();
 			}
 		}
-	
+
+		// ONLY NOW WE START TO MONITOR THE PULL_RESP MESSAGE.
+#		if _MONITOR>=1
+		if ((debug>=1) && (pdebug & P_TX)) {
+			//uint8_t * data = buff_down + 4;
+			//data[packetSize-4] = 0;
+			//mPrint("v TXDONE:: PULL_RESP: size="+String(packetSize)+", data="+String((char *)data)); 
+		}
+#		endif //_MONITOR
+
+		// The interrupts should be set by the _loramodem.ino functions
+		//writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);		// receive all
+		//writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);				// reset interrupt flags
 
 	  break; // S_TXDONE	  
 

+ 68 - 43
src/_txRx.ino

@@ -31,8 +31,14 @@
 // The LoraDown.tmst contains the timestamp that the tranmission should finish (Node start reading).
 //
 // Parameters:
-//	char * buf			Total buffer including first 4 bytes
+//	char * buf			Total buffer including first 4 bytes that need skip
 //	uint8_t len;		Length of the buf unsigned 0-255 bytes, including first four bytes
+//
+//	buf[0]	Version number (==PROTOCOL_VERSION)
+//	buf[1]	Token LSB: If Protocol version==0, make 0. If version==1 arbitrary?
+//	buf[2]	Token MSB
+//	buf[3]	PULL_RESP: ident = 0x03
+//
 // Return:
 //	Int = 1 when success
 // ----------------------------------------------------------------------------
@@ -52,8 +58,9 @@ int sendPacket(uint8_t *buf, uint8_t len)
 	// datr	: "SF7BW125"
 	// imme : false										// Immediately transfer
 	// fdev	: FSK frequency deviation (unsigned integer, in Hz) // NOT USED
-	// prea	:
-	// ncrc	:
+	// prea	: 8
+	// ncrc	: 
+	
 	// time Y: Mandatory time
 
 	// 12-byte header;
@@ -110,7 +117,6 @@ int sendPacket(uint8_t *buf, uint8_t len)
 	const char * modu	= root["txpk"]["modu"];
 	const char * time	= root["txpk"]["time"];			// Time is a string in UTC
 	
-	//LoraDown.modu		= modu;
 	LoraDown.modu		= (char *) modu;				// =="LORA"
 	LoraDown.codr		= (char *) codr;				// e.g. "4/5"
 	
@@ -120,7 +126,7 @@ int sendPacket(uint8_t *buf, uint8_t len)
 	LoraDown.prea		= root["txpk"]["prea"];
 	LoraDown.ncrc		= root["txpk"]["ncrc"];			// Cancel CRC for outgoing packets
 	LoraDown.rfch		= root["txpk"]["rfch"];			// ==0X00 first antenna
-	LoraDown.iiq 		= (LoraDown.ipol==true ? 0x40: 0x27);		// if ipol==true 0x40 else 0x27
+	LoraDown.iiq 		= (LoraDown.ipol==true ? (0x67 | 0x27): 0x27);
 	LoraDown.crc		= 0x00;							// switch CRC off for TX
 
 	LoraDown.sf 		= atoi(datr+2);					// Convert "SF9BW125" or what is received from gateway to number
@@ -131,16 +137,16 @@ int sendPacket(uint8_t *buf, uint8_t len)
 	base64_decode((char *) payLoad, (char *) data, strlen(data));	// Fill payload w decoded message
 	LoraDown.payLoad	= payLoad;
 
-//	MMM Print some text
-	LoraDown.prea 		= 8;									// Change one time
-	mPrint("time="+String(time)+", ipol="+String(LoraDown.ipol)+", codr="+String(codr)+", prea="+String(LoraDown.prea) );
+	//	preamble definition
+	if (LoraDown.prea == 0) LoraDown.prea = 0x0A;		// Change one time, maybe better use 0x0A or so
+//MMM	mPrint("v sendPacket:: time="+String(time)+", ipol="+String(LoraDown.ipol)+", codr="+String(codr)+", prea="+String(LoraDown.prea) );
 	
 	// Compute wait time in microseconds
 	//int32_t w = (int32_t) (LoraDown.tmst - micros());	// Wait Time compute
 
 	if (data != NULL) {
 #		if _MONITOR>=1
-		if ((debug>=1) && (pdebug & P_TX)) { 
+		if ((debug>=2) && (pdebug & P_TX)) { 
 			mPrint("v sendPacket:: LoraDown.size="+String(LoraDown.size)+", psize="+String(psize)+", strlen(data)="+String(strlen(data))+", data=" + String(data)); 
 		}
 #		endif //_MONITOR
@@ -157,7 +163,7 @@ int sendPacket(uint8_t *buf, uint8_t len)
 // _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.
-// We will anser in RX2 in the Spreading Factor set by _RX2_SF (set in configGway.h)
+// We will answer in RX2 in the Spreading Factor set by _RX2_SF (set in configGway.h)
 // This way, we can better communicate as a single gateway machine
 //
 #if _STRICT_1CH == 1
@@ -166,28 +172,53 @@ int sendPacket(uint8_t *buf, uint8_t len)
 	// If possible use RX1 timeslot as this is our frequency.
 	// Do not use RX2 or JOIN2 as they contain other frequencies (aka 868.5 MHz)
 
-	if (LoraDown.powe>15) LoraDown.powe=15;				// On all freqs except 869.5MHz power is limited
-	LoraDown.freq	= ((double)freqs[gwayConfig.ch].dwnFreq)/1000000;		// Use the requestor Down frequency (always)
+	if (LoraDown.powe>14) LoraDown.powe=14;				// On all freqs except 869.5MHz power is limited
+	//LoraDown.freq	= ((double)freqs[gwayConfig.ch].dwnFreq)/1000000;		// Use the requestor Down frequency (always)
+	const uint32_t ff = (uint32_t) (freqs[gwayConfig.ch].dwnFreq);
+	LoraDown.freq = (uint32_t)(ff & 0xFFFFFFFF);
+	
+	Serial.print("v MMM _STRICT_1CH==1 done, freq=");
+	Serial.print(LoraDown.freq);
+	Serial.print(", HEX=");
+	uint32_t effe = LoraDown.freq;
+	Serial.print((effe >> 24) & 0xFF);	Serial.print(" ");	// 0x00
+	Serial.print((effe >> 16) & 0xFF);	Serial.print(" ");	// MSB
+	Serial.print((effe >>  8) & 0xFF);	Serial.print(" ");	// MID
+	Serial.print((effe >>  0) & 0xFF);	Serial.print(" ");	// LSB
+	Serial.println();
 
 #elif _STRICT_1CH == 2
-// Semi:: We transmit only on ONE channel but the sensor end-node listens to
-// the special channel too.
-//	So, not change to SF (arranged by server)or frequency, as long as it is CH.
+	// Semi:: We transmit only on ONE channel but the sensor end-node listens to
+	// the special channel too.
+	// So, not change to SF (arranged by server) or frequency, as long as it is CH.
 
-	LoraDown.freq = (double)root["txpk"]["freq"];
+	uint32_t fff	= (uint32_t)(root["txpk"]["freq"].as<double>() * 1000000);
+	
+	if (abs(freqs[gwayConfig.ch].dwnFreq - fff) < 100000) {
+		LoraDown.freq = (uint32_t) (freqs[gwayConfig.ch].dwnFreq) & 0xFFFFFFFF ;
+	}
+	else {
+		LoraDown.freq = fff & 0xFFFFFFFF;
+	}
+
+	Serial.print("v _STRICT_1CH==2, freq=");
+	Serial.print(LoraDown.freq);
+	Serial.println();
 
 #else
-// elif _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
+// elif _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on 
+//	the freq it is sended in RX1 and on SF9/869.5MHz for RX2
 // 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)
+// Please note that this parameter is more for nodes (that cannot change freqs)
 // than for gateways.
 // We will probably answer in RX with RF==12 and use special answer frequency
 //
 	LoraDown.powe	= root["txpk"]["powe"];				// The server determines the power
-	const float ff	= root["txpk"]["freq"];				// eg 869.525
+	const float ff	= root["txpk"]["freq"];				// eg 868.1 (RX1) or 869.525 (RX2)
 	// convert double frequency (MHz) into uint32_t frequency in Hz.
-	LoraDown.freq = (uint32_t) ((uint32_t)((ff+0.000035)*1000)) * 1000;		// MMM Not correct
+	//LoraDown.freq = (uint32_t) ((uint32_t)((ff+0.000015)*1000)) * 1000;		// MMM Not correct
+	LoraDown.freq = (uint32_t) freqs[gwayConfig.ch].dwnFreq;
 
 #endif //_STRICT_1CH
 
@@ -202,9 +233,8 @@ int sendPacket(uint8_t *buf, uint8_t len)
 	}
 
 #	if _MONITOR>=1
-
 	else if ((debug >= 2) && (pdebug & P_TX)) {	
-		Serial.print(F("T Payload="));
+		Serial.print(F("v Payload="));
 		for (i=0; i<LoraDown.size; i++) {
 			Serial.print(LoraDown.payLoad[i],HEX); 
 			Serial.print(':'); 
@@ -280,14 +310,15 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	}
 
 #if _STATISTICS >= 1
+	// push down all members of statr and make a new statr[0] member.
 	// Receive statistics, move old statistics down 1 position
 	// and fill the new top line with the latest received sensor values.
 	// This works fine for the sensor, EXCEPT when we decode data for _LOCALSERVER
 	//
-	for (int m=( gwayConfig.maxStat -1); m>0; m--) statr[m]=statr[m-1];
+	for (int m=( gwayConfig.maxStat -1); m>0; m--) statr[m]= statr[m-1];
 	
 	// From now on we can fill statr[0] with sensor data
-#if _LOCALSERVER==1
+#if _LOCALSERVER>=1
 	statr[0].datal=0;
 	int index;
 	if ((index = inDecodes((char *)(LoraUp->payLoad+1))) >=0 ) {
@@ -316,17 +347,16 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	}
 #endif //_LOCALSERVER
 
-	statr[0].time = now();								// Not a real timestamp. but the current time
-	statr[0].ch =	gwayConfig.ch;
-	statr[0].prssi = prssi - rssicorr;
-	statr[0].sf =	LoraUp->sf;
-	
+	statr[0].time	= now();							// Not a real timestamp. but the current time
+	statr[0].ch		=	gwayConfig.ch;					// Lora Channel
+	statr[0].prssi	= prssi - rssicorr;
+	statr[0].sf		=	LoraUp->sf;						// spreading factor
+	statr[0].upDown = 0;								// Uplink
+	statr[0].node	= ( message[1]<<24 | message[2]<<16 | message[3]<<8 | message[4] );	
 #	if RSSI==1
-		statr[0].rssi = _rssi - rssicorr;
+	statr[0].rssi	= _rssi - rssicorr;
 #	endif // RSII
 
-	statr[0].node = ( message[1]<<24 | message[2]<<16 | message[3]<<8 | message[4] );
-
 #if _STATISTICS >= 2
 	// Fill in the statistics that we will also need for the GUI.
 	// So 
@@ -340,8 +370,6 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	}
 #endif //_STATISTICS >= 2
 
-
-
 #if _STATISTICS >= 3
 	if (statr[0].ch == 0) {
 		statc.msg_ttl_0++;								// Increase #message received channel 0
@@ -519,8 +547,8 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 
 
 #else 
-//_JSONENCODE undefined, this is default
-// -------------------------------------
+// _JSONENCODE undefined, this is default
+// ---------------------------------------
 	ftoa((double)freqs[gwayConfig.ch].upFreq / 1000000, cfreq, 6);		// XXX This can be done better
 	if ((LoraUp->sf<6) || (LoraUp->sf>12)) { 							// Lora datarate & bandwidth SF6-SF12, 16-19 useful chars */
 		LoraUp->sf=7;
@@ -565,10 +593,6 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	buff_up[buff_index+2] = '}'; 
 	buff_index += 3;
 	
-	//buff_up[buff_index]   = '}';
-	//buff_up[buff_index+1] = '}'; 
-	//buff_index += 2;									// Decrease of we need no ]
-	
 	buff_up[buff_index] = 0; 							// add string terminator, for safety
 
 	// When we have the node address and the SF, fill the listSeen array
@@ -590,6 +614,7 @@ int buildPacket(uint8_t *buff_up, struct LoraUp *LoraUp, bool internal)
 	}
 #	endif
 
+	//rstTime = now();								// 200930 MMM
 	return(buff_index);
 	
 }// buildPacket()
@@ -652,8 +677,8 @@ int receivePacket()
 			}
 #			endif //_TTNSERVER
 
-			yield();
-			Udp.flush();								// MMM 200419
+			yield();									// make sure the kernekl sends message to server asap
+			Udp.flush();								// 200419 empty the buffer
 
 #			ifdef _PROFILER
 			if ((debug>=1) && (pdebug & P_RX)) {
@@ -672,7 +697,7 @@ int receivePacket()
 			}
 #			endif //_THINGSERVER
 
-#if _LOCALSERVER==1
+#if _LOCALSERVER>=1
 			// Or special case, we do not use a local server to receive
 			// and decode the server. We use buildPacket() to call decode
 			// and use statr[0] information to store decoded message

+ 158 - 111
src/_udpSemtech.ino

@@ -97,8 +97,6 @@ bool connectUdp()
 // ----------------------------------------------------------------------------
 int readUdp(int packetSize)
 { 
-	uint8_t buff[64]; 						// General buffer to use for UDP, set to 64 characters
-	uint8_t buff_down[TX_BUFF_SIZE];		// Buffer for downstream
 
 	// Make sure we are connected over WiFI
 	if (WlanConnect(10) < 0) {
@@ -129,11 +127,11 @@ int readUdp(int packetSize)
 	yield();								// MMM 200406
 
 	// Remote Address should be known
-	IPAddress remoteIpNo = Udp.remoteIP();
+	remoteIpNo = Udp.remoteIP();
 
 	// Remote port is either of the remote TTN server or from NTP server (=123)
+	remotePortNo = Udp.remotePort();
 	
-	unsigned int remotePortNo = Udp.remotePort();
 	if (remotePortNo == 123) {				// NTP message arriving, not expected
 		// This is an NTP message arriving
 #		if _MONITOR>=1
@@ -143,7 +141,7 @@ int readUdp(int packetSize)
 #		endif //_MONITOR
 		gwayConfig.ntpErr++;
 		gwayConfig.ntpErrTime = now();
-		Udp.flush();						// MMM 200326 Clear buffer when time response arrives (error)
+		Udp.flush();						// 200326 Clear buffer when time response arrives (error)
 		return(0);
 	}
 	
@@ -152,11 +150,11 @@ int readUdp(int packetSize)
 	else {
 		// First 4 butes are very important, rest is data
 		// Especially the 2 token bytes should be watched.
-		uint8_t *data = (uint8_t *) ((uint8_t *)buff_down + 4);
-		uint8_t protocol= buff_down[0];
+		protocol= buff_down[0];
 		uint16_t token= buff_down[2]*256 + buff_down[1];			// LSB first [1], MSB [2] comes after
 		uint8_t ident= buff_down[3];
-
+		// uint8_t *data = (uint8_t *) ((uint8_t *)buff_down + 4);
+		
 #		if _MONITOR>=1
 		if ((debug>=3) && (pdebug & P_TX)) {
 			mPrint("v readUdp:: message ident="+String(ident));
@@ -177,7 +175,7 @@ int readUdp(int packetSize)
 		//	Byte 4-11:	Gateway EUI
 		//	Byte 12-n:	JSON data
 		//
-		case PUSH_DATA: 								// 0x00 UP
+		case PUSH_DATA: 								// 0x00 UP, never activated
 #			if _MONITOR>=1
 			if ((debug>=1) && (pdebug & P_RX)) {
 				mPrint("v PUSH_DATA:: size "+String(packetSize)+" From "+String(remoteIpNo.toString()));
@@ -195,9 +193,9 @@ int readUdp(int packetSize)
 		//	byte 1+2:	Token copied from requestor
 		//	byte 3:		ident = 0x01, ack PUSH_ACK
 		//
-		case PUSH_ACK:								// 0x01 DOWN
+		case PUSH_ACK:									// 0x01 DOWN
 #			if _MONITOR>=1
-			if ((debug>=1) && (pdebug & P_TX)) {
+			if ((debug>=2) && (pdebug & P_TX)) {
 				char res[128];				
 				sprintf(res, "v PUSH_ACK:: token=%u, size=%u, IP=%d.%d.%d.%d, port=%d, protocol=%u ", 
 					(buff_down[2]*256+buff_down[1]),
@@ -212,8 +210,8 @@ int readUdp(int packetSize)
 		break;
 
 
-		// PULL DATA message (Up)
-		// This is a request/UP message and will not be executed by this function.
+		// PULL DATA message (Up)						// UP, never activated
+		// This is a request/UP message and is never executed by this function.
 		// We have it here as a description only. 
 		//	Para 5.2.3, Semtech Gateway to Server Interface document
 		//
@@ -222,17 +220,17 @@ int readUdp(int packetSize)
 		// Byte 3		PULL_DATA ident == 0x02
 		// Byte 4-11	Gateway EUI
 		//
-		case PULL_DATA:								// 0x02 UP
+		case PULL_DATA:									// 0x02 UP
 #			if _MONITOR>=1
 			if ((debug>=1) && (pdebug & P_RX)) {
 				mPrint("v PULL_DATA");
 			}
 #			endif //_MONITOR
-			Udp.flush();								// MMM 200419 Added
+			Udp.flush();								// 200419 Added, probably never executed
 		break;
 
 
-		// PULL_ACK message (Down)
+		// PULL_ACK message (Down)						// Called to confirm receipt of pull-data
 		// This is the (immediate!) response to PULL_DATA message
 		// Para 5.2.4, Semtech Gateway to Server Interface document
 		// With this ACK, the server confirms the gateway that the route is open
@@ -246,7 +244,7 @@ int readUdp(int packetSize)
 		//
 		case PULL_ACK:									// 0x04 DOWN
 #			if _MONITOR>=1
-			if ((debug>=1) && (pdebug & P_TX)) {
+			if ((debug>=2) && (pdebug & P_TX)) {
 				char res[128];				
 				sprintf(res, "v PULL_ACK:: token=%u, size=%u, IP=%d.%d.%d.%d, port=%d, protocol=%u ", 
 					(buff_down[2]*256+buff_down[1]),
@@ -259,7 +257,7 @@ int readUdp(int packetSize)
 #			endif //_MONITOR
 			
 			yield();				
-			Udp.flush();								// MMM 200419
+			Udp.flush();								// 200419
 			// No response is needed
 		break;
 
@@ -267,14 +265,15 @@ int readUdp(int packetSize)
 		// PULL_RESP (Down)
 		// This message type is used to confirm OTAA message to the node,
 		// but this message format will also be used for other downstream communication
-		// It's length shall not exceed 1000 Octets. This is:
+		// It's length shall not exceed 1000 Octets. (TTN 51 octets) 
+		// This is:
 		//	RECEIVE_DELAY1		1 s 
 		//	RECEIVE_DELAY2		2 s (is RECEIVE_DELAY1+1)
 		//	JOIN_ACCEPT_DELAY1	5 s
 		//	JOIN_ACCEPT_DELAY2	6 s
 		//
 		// buff_down[0]:		Version number (==PROTOCOL_VERSION)
-		// buff_down[1-2]:		Token: If Protocol version==0, make 0. If version==2 arbitrary?
+		// buff_down[1-2]:		Token: If Protocol version==0, make 0. If version==1 arbitrary?
 		// buff_down[3]:		PULL_RESP: ident = 0x03
 		// buff_down[4-n]:		payLoad data
 		//
@@ -307,10 +306,10 @@ int readUdp(int packetSize)
 #			endif//_PROFILER
 
 			// Send to the LoRa Node first (timing) and then do reporting to _Monitor
-			_state=S_TX;
+			//_state=S_TX;
 			sendTime = micros();						// record when we started sending the message
-// XXX
-			// Send the package DOWN to the sensor
+
+			// Prepare to send the package DOWN to the sensor
 			// We just read the packet from the Network Server and it is formatted
 			// as described in the specs. This function fills LoraDown struct.
 			if (sendPacket(buff_down, packetSize) < 0) {
@@ -328,77 +327,176 @@ int readUdp(int packetSize)
 			// another package receiving/sending
 
 			if (loraWait(&LoraDown) == 0) {
-				_state=S_CAD;							// Maybe call TXDONE and wait 1 sec
+				_state=S_CAD;										// Maybe call TXDONE and wait 1 sec
 				_event=1;
 				break;
 			}
-
-			// Clear interrupt flags and masks
-			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);			// MMM 200407 Reset
-			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);				// reset interrupt flags
 			
 			// Initiate the transmission of the buffer
 			// (We normally react on ALL interrupts if we are in TX state)
-			txLoraModem(&LoraDown);										// Calling sendPkt() in turn
+			txLoraModem(&LoraDown);									// Calling sendPkt() in turn
 
+			// Copy the lastSeen data down
+			for (int m=( gwayConfig.maxStat -1); m>0; m--) statr[m]= statr[m-1];
+			
+			// If transmission is finished, print statistics
 #			if _MONITOR>=1
-			if ((debug>=2) && (pdebug & P_TX)) {
-				uint8_t flags = readRegister(REG_IRQ_FLAGS);
-				uint8_t mask  = readRegister(REG_IRQ_FLAGS_MASK);
-				uint8_t intr  = flags & ( ~ mask );
-
 
-				String response = "v readUdp:: PULL_RESP from IP="+String(remoteIpNo.toString())
-					+", micros=" + String(micros())
-					+", wait=";
-				if (sendTime < micros()) {
-					response += String(micros() - sendTime) ;
+				//DecodePayload: para 4.3.1 of Lora 1.1 Spec
+				// MHDR
+				//	1 byte			Payload[0]
+				// FHDR
+				// 	4 byte Dev Addr Payload[1-4]
+				// 	1 byte FCtrl  	Payload[5]
+				// 	2 bytes FCnt	Payload[6-7]				
+				// 		= Optional 0 to 15 bytes Options
+				// FPort
+				//	1 bytes, 0x00	Payload[8]
+				// ------------
+				// +=9 BYTES HEADER
+				//
+				// FRMPayload
+				//	N bytes			(Payload )
+				//
+				// 4 bytes MIC trailer
+				
+#			  if _LOCALSERVER>=2				
+				uint8_t DevAddr[4];
+				uint16_t frameCount;
+				int index;
+				
+				if ((index = inDecodes((char *)(LoraDown.payLoad+1))) >=0 ) {
+#	ifdef _FCNT
+					frameCount= LoraDown.fcnt;
+#	else
+					frameCount= LoraDown.payLoad[7]*256 + LoraDown.payLoad[6];
+#	endif
+					// Only if _LOCALSERVER >= 2 for downstream
+					strncpy ((char *)statr[0].data, (char *)LoraDown.payLoad,  LoraDown.size);
+
+					DevAddr[0]= LoraDown.payLoad[4];
+					DevAddr[1]= LoraDown.payLoad[3];
+					DevAddr[2]= LoraDown.payLoad[2];
+					DevAddr[3]= LoraDown.payLoad[1];
+
+					statr[0].datal = encodePacket((uint8_t *)(statr[0].data + 9), 
+						LoraDown.size -9 -4, 
+						(uint16_t)frameCount, 
+						DevAddr, 
+						decodes[index].appKey, 
+						1
+					);													// Down
 				}
 				else {
-					response += "-" + String(sendTime - micros()) ;
-				};
-
+#					if _MONITOR >= 1				
+						//
+#					endif //_MONITOR
+				}
+#			  elif _LOCALSERVER==1
+				// If we should not print data for downlink
+				statr[0].datal = 0;
+#			  endif //_LOCALSERVER
+			
+			// If _MONITOR set print the statistics
+			if ((debug>=1) && (pdebug & P_TX)) {
 
-				response+=", stat:: ";
-				mStat(intr, response);
-				mPrint(response); 
+				String response ="v txLoraModem hi:: ";
+				printDwn(&LoraDown, response);
+				mPrint(response);
 
+				response = "v txLoraModem reg:: ";
+				printRegs(&LoraDown, response);
+				mPrint(response);
+			
+				delay(1);
+				response = "v txLoraModem lo:: ";
+
+#				if _LOCALSERVER>=2
+
+					if (statr[0].datal>24) {
+						response+= ", statr[0].datal=" + String(statr[0].datal);
+						statr[0].datal=24;
+					}
+					
+					response+= "coded=<";
+					
+					if (statr[0].datal < 0) {
+						mPrint("ERROR datal=0");
+						statr[0].datal=0;
+					}
+					for (int i=0; i<statr[0].datal; i++) {
+						response += String(statr[0].data[i],HEX) + " ";
+					}
+					response += ">";
+					
+					response += ", addr=";
+					printHex((IPAddress)DevAddr, ':', response);
+					
+					response+= ", fcnt=" + String(frameCount);
+#				endif //_LOCALSERVER
+
+				response += ", size=" + String(LoraDown.size);
+				response += ", load=<";
+				for(int i=0; i<LoraDown.size; i++) {
+					response += String(LoraDown.payLoad[i],HEX) + " ";
+				}
+				response += ">";				
+				mPrint(response);
 			}
+
 #			endif //_MONITOR
 
+			statr[0].time	= now();
+			statr[0].ch		= gwayConfig.ch;
+			statr[0].sf		= LoraDown.sf;
+			statr[0].upDown	= 1;							// Down
+			statr[0].node	= ( 
+					LoraDown.payLoad[1]<<24 | 
+					LoraDown.payLoad[2]<<16 | 
+					LoraDown.payLoad[3]<<8 | 
+					LoraDown.payLoad[4] 
+			);
+
+			addSeen(listSeen, statr[0]);
+			
+#			if RSSI==1
+				statr[0].rssi	= _rssi - rssicorr;
+#			endif // RSSI
+
+			//statr[0].datal	= 3;
+			//statr[0].data[0]	= 0x86;
+			//statr[0].data[1]	= 0xC4;
+			//statr[0].data[2]	= 0x0A;
+			//statr[0].data[3]	= 0x00;
+			//strncpy((char *)statr[0].data, "Down", 4);	// MMMM
+
 			// After filling the buffer we only react on TXDONE interrupt
 			// So, more or less start at the "case TXDONE:"  
 			_state=S_TXDONE;
 			_event=1;										// Or remove the break below
 
-//			Udp.flush();									// MMM 200509 flush UDP buffer
-
-			// No break!! so next secton will be executed
+			yield();										// MMM 200925
 
-#			ifdef _PROFILER
-			// measure the total time for transmissioon here
-			if ((debug>=2) && (pdebug & P_TX)) {
-				mPrint("v PULL_RESP:: finit: micros="+String(micros() ));
-			}
-#			endif //_PROFILER
+		break;
 
 
-		// TX_ACK (Up)
-		// This is the response to the PULL_RESP message by the sensor device (above)
+		// TX_ACK (Up)										// Never activated by this function
+		// This is the response to the PULL_RESP message by the sensor device
 		// it is sent by the gateway UP to the server to confirm the PULL_RESP message.
 		//	byte 0:		Protocol version (0x01 or 0x02)
 		//	byte 1+2:	Token number of UP sender
 		//	byte 3:		Message ID TX_ACK == 0x05
 		//	byte 4-n:	Optional Error Data, {"errno":xxxx}
 		//
-		case TX_ACK:									// Message id: 0x05 UP
+		case TX_ACK:										// Message id: 0x05 UP
 
 			if (protocol == 1) {							// Got from the downstream message
 #				if _MONITOR>=1
 				if ((debug>=1) && (pdebug & P_TX)) {
 					mPrint("^ TX_ACK:: readUdp: protocol version 1");
-					//data = buff_down + 4;
-					//data[packetSize-4] = 0;
+//					uint8_t *data;
+//					data = buff_down + 4;
+//					data[packetSize-4] = 0;
 				}
 #				endif
 				break;										// return
@@ -409,60 +507,9 @@ int readUdp(int packetSize)
 				mPrint("^ TX_ACK:: readUDP: protocol version 2+");
 			}
 #			endif //_MONITOR
-
-
-			// UP: Now respond with an TX_ACK
-			// Byte 3 is 0x05; see para 5.2.6 of spec
-			buff[0]= buff_down[0];							// As read from the Network Server
-			buff[1]= buff_down[1];							// Token 1, copied from downstream
-			buff[2]= buff_down[2];							// Token 2
-			buff[3]= TX_ACK;								// ident == 0x05;
-			buff[4]= 0;										// Not error means "\0"
-			// If it is an error, please look at para 6.1.2
-
-			yield();
-
-			// Only send the PULL_ACK to the UDP socket that just sent the data!!!
-			Udp.beginPacket(remoteIpNo, remotePortNo);
-			
-			// XXX We should format the message before sending up with UDP
-			
-			if (Udp.write((unsigned char *)buff, 12) != 12) {
-#				if _MONITOR>=1
-				if (debug>=0) {
-					mPrint("^ readUdp:: ERROR: PULL_ACK write");
-				}
-#				endif //_MONITOR
-			}
-			else {
-#				if _MONITOR>=1
-				if ((debug>=2) && (pdebug & P_TX)) {
-					mPrint("^ readUdp:: TX_ACK: micros="+String(micros()));
-				}
-#				endif //_MONITOR
-			}
-
-			if (!Udp.endPacket()) {
-#				if _MONITOR>=1
-				if ((debug>=0) && (pdebug & P_TX)) {
-					mPrint("^ readUdp:: PULL_ACK: ERROR Udp.endPacket");
-				}
-#				endif //_MONITOR
-			}
-			
-			yield();
-
-			// ONLY NOW WE START TO MONITOR THE PULL_RESP MESSAGE.
-#			if _MONITOR>=1
-			if ((debug>=1) && (pdebug & P_TX)) {
-				data = buff_down + 4;
-				data[packetSize-4] = 0;
-				mPrint("v readUdp:: PULL_RESP: size="+String(packetSize)+", data="+String((char *)data)); 
-			}
-#			endif //_MONITOR
-
 		break;
 
+
 		default:
 #			if _GATEWAYMGT==1
 				// For simplicity, we send the first 4 bytes too

+ 79 - 29
src/_utils.ino

@@ -18,7 +18,9 @@
 
 
 
-// ==================== STRING STRING STRING ==============================================
+
+
+// ======================= STRING STRING STRING ===========================================
 
 // --------------------------------------------------------------------------------
 // PRINT INT
@@ -31,13 +33,65 @@
 // --------------------------------------------------------------------------------
 void printInt (uint32_t i, String & response)
 {
-	response+=(String(i/1000000) + "." + String(i%1000000));
+	response +=(String(i/1000000) + "." + String(i%1000000));
+}
+
+
+// --------------------------------------------------------------------------------
+// PRINT REGS
+//  Print the register settings
+// --------------------------------------------------------------------------------
+#define printReg(x) {int i=readRegister(x); if(i<=0x0F) Serial.print('0'); Serial.println(i,HEX);}
+
+void printRegs(struct LoraDown *LoraDown, String & response)
+{
+	response += "v FIFO (0x00)=0x" + String(readRegister(REG_FIFO),HEX);
+	response += "v OPMODE (0x01)=0x" + String(readRegister(REG_OPMODE),HEX);
+	
+#	if _DUSB>=1
+	if (debug>=1) {
+		Serial.print("v FIFO                 (0x00)\t=0x"); printReg(REG_FIFO);
+		Serial.print("v OPMODE               (0x01)\t=0x"); printReg(REG_OPMODE);
+		Serial.print("v FRF                  (0x06)\t=0x"); printReg(REG_FRF_MSB); 
+			Serial.print(' '); printReg(REG_FRF_MID); 
+			Serial.print(' '); printReg(REG_FRF_LSB);
+		Serial.print("v PAC                  (0x09)\t=0x"); printReg(REG_PAC);
+		Serial.print("v PARAMP               (0x0A)\t=0x"); printReg(REG_PARAMP);
+		Serial.print("v REG_OCP              (0x0B)\t=0x"); printReg(REG_OCP);
+		Serial.print("v LNA                  (0x0C)\t=0x"); printReg(REG_LNA);
+		Serial.print("v FIFO_ADDR_PTR        (0x0D)\t=0x"); printReg(REG_FIFO_ADDR_PTR);
+		Serial.print("v FIFO_TX_BASE_AD      (0x0E)\t=0x"); printReg(REG_FIFO_TX_BASE_AD);
+		Serial.print("v FIFO_RX_BASE_AD      (0x0F)\t=0x"); printReg(REG_FIFO_RX_BASE_AD);
+
+		Serial.print("v FIFO_RX_CURRENT_ADDR (0x10)\t=0x"); printReg(REG_FIFO_RX_CURRENT_ADDR);
+		Serial.print("v IRQ_FLAGS_MASK       (0x11)\t=0x"); printReg(REG_IRQ_FLAGS_MASK);
+		Serial.print("v IRQ_FLAGS            (0x12)\t=0x"); printReg(REG_IRQ_FLAGS);
+		Serial.print("v MODEM_CONFIG1        (0x1D)\t=0x"); printReg(REG_MODEM_CONFIG1);
+		Serial.print("v MODEM_CONFIG2        (0x1E)\t=0x"); printReg(REG_MODEM_CONFIG2);
+		Serial.print("v MODEM_CONFIG3        (0x26)\t=0x"); printReg(REG_MODEM_CONFIG3);
+
+		Serial.print("v PREAMBLE_MSB         (0x20)\t=0x"); printReg(REG_PREAMBLE_MSB);
+		Serial.print("v PREAMBLE_LSB         (0x21)\t=0x"); printReg(REG_PREAMBLE_LSB);		
+		Serial.print("v PAYLOAD_LENGTH       (0x22)\t="); Serial.println(readRegister(REG_PAYLOAD_LENGTH));
+		Serial.print("v MAX_PAYLOAD_LENGTH   (0x23)\t="); Serial.println(readRegister(REG_MAX_PAYLOAD_LENGTH));
+		Serial.print("v HOP_PERIOD           (0x24)\t="); Serial.println(readRegister(REG_HOP_PERIOD));
+		Serial.print("v FIFO_RX_BYTE_ADDR_PTR(0x25)\t=0x"); printReg(REG_FIFO_RX_BYTE_ADDR_PTR);
+
+		Serial.println("");
+	}
+#	endif // _DUSB
+
+
+	return;
 }
 
+
+
 // --------------------------------------------------------------------------------
 // PRINT Down
-// In a uniform way, this function prints the timstamp, the current time and the 
-// time the function must wait to execute. It will print all Downstream data
+// In a uniform way, this function prints the LoraDown structure.
+// This includes the timstamp, the current time and the time the function 
+// must wait to execute. It will print all Downstream data
 // Parameters:
 //
 // Returns:
@@ -52,23 +106,16 @@ void printDwn(struct LoraDown *LoraDown, String & response)
 	response += ", tmst=";	printInt(i, response);
 
 	response += ", wait=";
-	if (i>m) {
+	if (i>m) {										// Positive numbers
 		response += String(i-m);
 	}
-	else {
+	else {											// Negative numbers contain (number)
 		response += "(";
 		response += String(m-i);
 		response += ")";
 	}
 
-	//inval	=int(LoraDown->freq);
-	//response += ", freq="	+String(intval) +".";
-	//fraqval	=int((LoraDown->freq-intval)*10000);
-	//response += String(fraqval);
-
-	char cfreq[12] = {0};
-	ftoa(LoraDown->freq, cfreq, 3);
-	response += ", freq="	+String(cfreq);
+	response += ", freq="	+String(LoraDown->freq);
 	response += ", sf="		+String(LoraDown->sf);
 	response += ", bw="		+String(LoraDown->bw);
 	response += ", powe="	+String(LoraDown->powe);
@@ -90,8 +137,9 @@ void printDwn(struct LoraDown *LoraDown, String & response)
 	printHex((IPAddress)DevAddr, ':', response);
 
 	yield();
+
 	return;
-}
+} // printDwn
 
 
 // --------------------------------------------------------------------------------
@@ -107,10 +155,10 @@ void printDwn(struct LoraDown *LoraDown, String & response)
 // --------------------------------------------------------------------------------
 void printIP(IPAddress ipa, const char sep, String & response)
 {
-	response+=(String)ipa[0]; response+=sep;
-	response+=(String)ipa[1]; response+=sep;
-	response+=(String)ipa[2]; response+=sep;
-	response+=(String)ipa[3];
+	response += (String)ipa[0]; response += sep;
+	response += (String)ipa[1]; response += sep;
+	response += (String)ipa[2]; response += sep;
+	response += (String)ipa[3];
 }
 
 // ----------------------------------------------------------------------------------------
@@ -127,10 +175,10 @@ void printHex(uint32_t hexa, const char sep, String & response)
 
 	uint8_t * h = (uint8_t *)(& hexa);
 
-	if (h[0]<016) response+='0'; response += String(h[0], HEX);  response+=sep;
-	if (h[1]<016) response+='0'; response += String(h[1], HEX);  response+=sep;
-	if (h[2]<016) response+='0'; response += String(h[2], HEX);  response+=sep;
-	if (h[3]<016) response+='0'; response += String(h[3], HEX);  response+=sep;
+	if (h[0]<016) response += '0'; response += String(h[0], HEX);  response+=sep;
+	if (h[1]<016) response += '0'; response += String(h[1], HEX);  response+=sep;
+	if (h[2]<016) response += '0'; response += String(h[2], HEX);  response+=sep;
+	if (h[3]<016) response += '0'; response += String(h[3], HEX);  response+=sep;
 }
 
 // ----------------------------------------------------------------------------
@@ -227,6 +275,9 @@ int mStat(uint8_t intr, String & response)
 			
 		response += ", S=";
 		switch (_state) {
+			case S_TXDONE:
+				response += "TXDONE";
+			break;
 			case S_INIT:
 				response += "INIT ";
 			break;
@@ -242,9 +293,6 @@ int mStat(uint8_t intr, String & response)
 			case S_TX:
 				response += "TX   ";
 			break;
-			case S_TXDONE:
-				response += "TXDONE";
-			break;
 			default:
 				response += " -- ";
 		}
@@ -523,7 +571,7 @@ int SerialName(uint32_t a, String & response)
 } //SerialName
 
 
-#if _LOCALSERVER==1
+#if _LOCALSERVER>=1
 // ----------------------------------------------------------------------------
 // inDecodes(id)
 // Find the id in Decodes array, and return the index of the item
@@ -543,7 +591,9 @@ int inDecodes(char * id) {
 	}
 	return(-1);
 }
-#endif
+#endif //_LOCALSERVER
+
+
 
 
 
@@ -566,7 +616,7 @@ void die(String s)
 	if (debug>=2) Serial.flush();
 #	endif //_DUSB
 
-	delay(50);			
+	delay(50);
 	abort();												// Within a second
 }
 

+ 68 - 15
src/_wwwServer.ino

@@ -554,7 +554,7 @@ static void gatewaySettings()
 	response +="<td class=\"cell\"><a href=\"TRUSTED=-1\"><button>-</button></a></td>";
 	response +="<td class=\"cell\"><a href=\"TRUSTED=1\"><button>+</button></a></td>";
 	response +="</tr>";
-#endif
+#endif //_TRUSTED_NODES
 
 	// Debugging options, only when _DUSB or _MONITOR is set, otherwise no
 	// serial or minotoring activity
@@ -633,6 +633,20 @@ static void gatewaySettings()
 	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"DUSB=1\"><button>ON</button></a></td>";
 	response +="</tr>";
 
+#if _LOCALSERVER>=1
+	// Show Node Data
+	bg = " background-color: ";
+	bg += ( (gwayConfig.showdata == 1) ? "LightGreen" : "orange" );
+	response +="<tr><td class=\"cell\">Show Node Data</td>";
+	response +="<td class=\"cell\" colspan=\"2\" style=\"border: 1px solid black; " + bg + "\">";
+	response += ( (gwayConfig.showdata == true) ? "ON" : "OFF" );
+	response +="</td>";
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SHOWDATA=0\"><button>OFF</button></a></td>";
+	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SHOWDATA=1\"><button>ON</button></a></td>";
+	response +="</tr>";
+
+#endif //_LOCALSERVER
+
 	/// WWW Refresh
 #if _REFRESH==1
 	bg = " background-color: ";
@@ -664,9 +678,10 @@ static void gatewaySettings()
 #endif
 
 #if _REPEATER>=0
+	// Show repeater setting
 	bg = " background-color: ";
 	bg += ( _REPEATER==1 ? "LightGreen" : "orange" );
-	response +="<tr><td class=\"cell\">REPEATER</td>";
+	response +="<tr><td class=\"cell\">Repeater</td>";
 	response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
 	response += ( _REPEATER==1 ? "ON" : "OFF" );
 	//response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REPT=0\"><button>OFF</button></a></td>";
@@ -883,19 +898,24 @@ static void messageHistory()
 	response += "<table class=\"config_table\">";
 	response += "<tr>";
 	response += "<th class=\"thead\">Time</th>";
+	response += "<th class=\"thead\" style=\"width: 20px;\">Up/Dwn</th>";
 	response += "<th class=\"thead\">Node</th>";
-#if _LOCALSERVER==1
-	response += "<th class=\"thead\">Data</th>";
-#endif
+#if _LOCALSERVER>=1
+	if (gwayConfig.showdata) {
+		response += "<th class=\"thead\">Data</th>";
+	}
+#endif //_LOCALSERVER
 	response += "<th class=\"thead\" style=\"width: 20px;\">C</th>";
 	response += "<th class=\"thead\">Freq</th>";
 	response += "<th class=\"thead\" style=\"width: 40px;\">SF</th>";
 	response += "<th class=\"thead\" style=\"width: 50px;\">pRSSI</th>";
 #if RSSI==1
-	if (debug > 1) {
+	if (debug => 1) {
 		response += "<th class=\"thead\" style=\"width: 50px;\">RSSI</th>";
 	}
 #endif
+
+	// Print of Heads is ober.Now print all the rows
 	response += "</tr>";
 	server.sendContent(response);
 
@@ -903,12 +923,16 @@ static void messageHistory()
 	for (int i=0; i< gwayConfig.maxStat; i++) {								// For every Node in the list
 		if (statr[i].sf == 0) break;
 		
-		response = "";
+		response = "" + String();
 		
-		response += String() + "<tr><td class=\"cell\">";					// Tmst
-		stringTime((statr[i].time), response);								// XXX Change tmst not to be millis() dependent
+		response += "<tr><td class=\"cell\">";								// Tmst
+		stringTime(statr[i].time, response);								// XXX Change tmst not to be millis() dependent
 		response += "</td>";
-		
+
+		response += String() + "<td class=\"cell\">"; 						// Up or Downlink
+		response += String(statr[i].upDown ? "v" : "^");
+		response += "</td>";
+
 		response += String() + "<td class=\"cell\">"; 						// Node
 		
 #ifdef  _TRUSTED_NODES														// DO nothing with TRUSTED NODES
@@ -940,14 +964,17 @@ static void messageHistory()
 
 		response += "</td>";
 		
-#if _LOCALSERVER==1
+#if _LOCALSERVER>=1
+	if (gwayConfig.showdata) {
 		response += String() + "<td class=\"cell\">";						// Data
+		if (statr[i].datal>24) statr[i].datal=24;							
 		for (int j=0; j<statr[i].datal; j++) {
 			if (statr[i].data[j] <0x10) response+= "0";
 			response += String(statr[i].data[j],HEX) + " ";
 		}
 		response += "</td>";
-#endif
+	}
+#endif //_LOCALSERVER
 
 
 		response += String() + "<td class=\"cell\">" + statr[i].ch + "</td>";
@@ -990,7 +1017,8 @@ static void nodeHistory()
 		response += "<h2>Node Last Seen History</h2>";
 		response += "<table class=\"config_table\">";
 		response += "<tr>";
-		response += "<th class=\"thead\" style=\"width: 220px;\">Time</th>";
+		response += "<th class=\"thead\" style=\"width: 215px;\">Time</th>";
+		response += "<th class=\"thead\" style=\"width: 20px;\">Up/Dwn</th>";
 		response += "<th class=\"thead\">Node</th>";
 		response += "<th class=\"thead\">Pkgs</th>";
 		response += "<th class=\"thead\" style=\"width: 20px;\">C</th>";
@@ -1002,6 +1030,7 @@ static void nodeHistory()
 		// Now start the contents
 		
 		for (int i=0; i<gwayConfig.maxSeen; i++) {
+		
 			if (listSeen[i].idSeen == 0)
 			{
 #				if _MONITOR>=1
@@ -1016,9 +1045,18 @@ static void nodeHistory()
 			response += String("<tr><td class=\"cell\">");						// Tmst
 			stringTime((listSeen[i].timSeen), response);
 			response += "</td>";
+			
+			response += String("<td class=\"cell\">");							// upDown
+			switch (listSeen[i].upDown) 
+			{
+				case 0: response += String("^"); break;
+				case 1: response += String("v"); break;
+				default: mPrint("wwwServer.ino:: ERROR upDown");
+			}
+			response += "</td>";
 		
 			response += String() + "<td class=\"cell\">"; 						// Node
-#			ifdef  _TRUSTED_NODES												// DO nothing with TRUSTED NODES
+#			ifdef  _TRUSTED_NODES												// Do nothing with TRUSTED NODES
 				switch (gwayConfig.trusted) {
 					case 0: 	
 						printHex(listSeen[i].idSeen,' ',response);
@@ -1441,7 +1479,7 @@ void setupWWW()
 		initConfig(&gwayConfig);					// Well known values
 		gwayConfig.formatCntr++;
 		writeConfig(_CONFIGFILE, &gwayConfig);
-		writeSeen( _SEENFILE, listSeen);			// Write the last time record  is Seen
+		printSeen( _SEENFILE, listSeen);			// Write the last time record  is Seen
 #		if _MONITOR>=1
 		if ((debug>=1) && (pdebug & P_MAIN )) {
 			mPrint("www:: manual Format DONE");
@@ -1743,6 +1781,21 @@ void setupWWW()
 		server.sendHeader("Location", String("/"), true);
 		server.send( 302, "text/plain", "");
 	});
+
+	// SHOWDATA, write node trusted value 
+	server.on("/SHOWDATA=1", []() {					// WWW page Serial Print ON
+		gwayConfig.showdata =1;
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
+	});
+	server.on("/SHOWDATA=0", []() {					// WWW page Serial Print OFF
+		gwayConfig.showdata =0;
+		writeGwayCfg(_CONFIGFILE, &gwayConfig );	// Save configuration to file
+		server.sendHeader("Location", String("/"), true);
+		server.send( 302, "text/plain", "");
+	});
+
 	
 	// Switch off/on the HOP functions
 	server.on("/HOP=1", []() {

+ 7 - 7
src/configGway.h

@@ -1,7 +1,7 @@
 // 1-channel LoRa Gateway for ESP32 and ESP8266
 // Copyright (c) Maarten Westenberg 2016-2020 
 
-#define VERSION "V.6.2.6.EU868; PlatformIO 200908 d"
+#define VERSION "V.6.2.7.EU868; PlatformIO 201030 d"
 
 //
 // Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway and many others.
@@ -114,7 +114,7 @@
 // and to one spreading factor only.
 // This parameters contains the default value of SF, the actual version can be set with
 // the webserver and it will be stored in SPIFF
-// NOTE: The frequency is set in the loraModem.h file and is default 868.100000 MHz.
+// NOTE: The frequency is set in the loraModem.h file and is default 868100000 Hz.
 #if !defined _SPREADING
 #	define _SPREADING SF9
 #endif
@@ -254,10 +254,11 @@
 
 // This defines whether or not we would use the gateway as 
 // as sort of backend decoding system for local sensors which decodes (such as TTGO T-Beam)
-// 1: _LOCALSERVER is used
-// 0: Do not use _LOCALSERVER 
+// 0: Do not use _LOCALSERVER
+// 1: _LOCALSERVER is used for received messages
+// 2: Also transmittes messages are encoded
 #if !defined _LOCALSERVER
-#	define _LOCALSERVER 0					// See server definitions for decodes
+#	define _LOCALSERVER 1					// See server definitions for decodes
 #endif
 
 
@@ -290,7 +291,6 @@
 // 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
 
 
 // ========================================================================
@@ -339,7 +339,7 @@
 #define _WWW_INTERVAL 60					// Number of seconds before we refresh the WWW page
 #define _FILE_INTERVAL 30					// Number of timer (in secs) before writing to files
 #define _MSG_INTERVAL 31					// Message timeout timer in seconds
-#define _RST_INTERVAL 97					// Reset interval in seconds, total chip reset
+#define _RST_INTERVAL 125					// Reset interval in seconds, total chip reset
 
 
 // Define the correct radio type that you are using

+ 2 - 0
src/loraFiles.h

@@ -92,6 +92,7 @@ struct espGwayConfig {
 	bool seen;
 	bool expert;
 	bool monitor;
+	bool showdata;				// If set, code and deconde know data
 	bool dusbStat;				// Status of _DUSB
 	
 } gwayConfig;
@@ -121,6 +122,7 @@ struct espGwayConfig {
 // define the Seen functon as when we have seen seen nodes last time
 struct nodeSeen {
 	time_t timSeen;
+	uint8_t	upDown;
 	uint32_t idSeen;
 	uint32_t cntSeen;
 	uint8_t chnSeen;

+ 62 - 26
src/loraModem.h

@@ -59,12 +59,12 @@
 //	channel gateway to work according to spec. 
 struct vector {
 	// Upstream messages
-	uint32_t upFreq;							// 4 bytes
+	uint32_t upFreq;							// 4 bytes unsigned int32 Frequency
 	uint16_t upBW;								// 2 bytes
 	uint8_t  upLo;								// 1 bytes
 	uint8_t  upHi;								// 1 bytes
 	// Downstream messages
-	uint32_t dwnFreq;							// 4 bytes Unsigned ubt Frequency
+	uint32_t dwnFreq;							// 4 bytes unsigned int32 Frequency
 	uint16_t dwnBW;								// 2 bytes BW Specification
 	uint8_t  dwnLo;								// 1 bytes Spreading Factor
 	uint8_t  dwnHi;								// 1 bytes
@@ -298,11 +298,12 @@ struct stat_t {
 	uint8_t ch;								// Channel index to freqs array
 	uint8_t sf;
 #if RSSI==1
-	int8_t		rssi;						// XXX Can be < -128
+	int8_t	rssi;						// XXX Can be < -128
 #endif
-	int8_t		prssi;						// XXX Can be < -128
-#if _LOCALSERVER==1
-	uint8_t data[23];						// For memory purposes, only 23 chars
+	int8_t	prssi;						// XXX Can be < -128
+	uint8_t upDown;							// 0==up, 1==down
+#if _LOCALSERVER>=1
+	uint8_t data[24];						// For memory purposes, only 24 chars
 	uint8_t datal;							// Length of decoded message 1 char
 #endif
 } stat_t;
@@ -376,27 +377,33 @@ struct LoraDown {
 	uint32_t	tmst;						// Timestamp (will ignore time)
 	uint32_t	tmms;						// Timestamp according to GPS (sync required)
 	uint32_t	time;
-	double_t	freq;						// Frequency
+	uint32_t	freq;						// Frequency
+	
+	uint16_t	fcnt;						// Framecount of the requesting LoraUp message
+
 	uint8_t		size;
-	//			chan = <NOT USED>
+	uint8_t		chan;						// = <NOT USED>
+	uint8_t		sf;							// through datr
+	uint8_t		bw;							// through datr
+	
 	bool		ipol;
 	uint8_t		powe;						// transmit power, normally 14, except when using special channel
 	uint8_t		crc;
 	uint8_t		iiq;						// message inverted or not for node-node communiction
 	uint8_t		imme;						// Immediate transfer execution
-	uint8_t		sf;							// through datr
-	uint8_t		bw;							// through datr
 	uint8_t		ncrc;						// no CRC check
 	uint8_t		prea;						// preamble
-	uint8_t		rfch;						// Concentrator "RF chain" used for TX (unsigned integer)
+	uint8_t		rfch;						// Antenna "RF chain" used for TX (unsigned integer)
+
 	char *		modu;						//	"LORA" os "FSCK"
 	char *		datr;						// = "SF12BW125", contains both .sf and .bw parts
 	char *		codr;
-	
 
-	
 	uint8_t	* 	payLoad;
 } LoraDown;
+
+
+
 // Up buffer (from Lora sensor to UDP)
 // This struct contains all data of the buffer received from devices to gateway
 
@@ -404,15 +411,17 @@ struct LoraUp {
 	uint32_t	tmst;						// Timestamp of message
 	uint32_t	tmms;						// <not used at the moment>
 	uint32_t	time;						// <not used at the moment>
-	double_t	freq;						// frequency used in HZ
+	uint32_t	freq;						// MMM frequency used in HZ
 	uint8_t		size;						// Length of the message Payload
 	uint8_t		chan;						// Channel "IF" used for RX
 	uint8_t		sf;							// Spreading Factor
-	//			modu not used
-	//			datr = "SF12BW125", contains both .sf and .bw parts
+
 	int32_t		snr;
 	int16_t		prssi; 
 	int16_t		rssicorr;
+
+	char *		modu;						//	"LORA" os "FSCK"
+
 	uint8_t		payLoad[128];
 } LoraUp;
 
@@ -427,21 +436,30 @@ struct LoraUp {
 
 #define REG_FIFO                    0x00		// rw FIFO address
 #define REG_OPMODE                  0x01		// Operation Mode Register (Page 108)
-												// Register 2 to 5 are unused for LoRa
+// 0x02	 reserved
+// 0x03
+// 0x04
+// 0x05											// Register 2 to 5 are unused for LoRa
 #define REG_FRF_MSB					0x06
 #define REG_FRF_MID					0x07
 #define REG_FRF_LSB					0x08
 #define REG_PAC                     0x09
 #define REG_PARAMP                  0x0A
+#define REG_OCP						0x0B		// 200927 Not used yet
 #define REG_LNA                     0x0C
 #define REG_FIFO_ADDR_PTR           0x0D		// rw SPI interface address pointer in FIFO data buffer
 #define REG_FIFO_TX_BASE_AD         0x0E		// rw write base address in FIFO data buffer for TX modulator
 #define REG_FIFO_RX_BASE_AD         0x0F		// rw read base address in FIFO data buffer for RX demodulator (0x00)
 
-#define REG_FIFO_RX_CURRENT_ADDR    0x10		// r  Address of last packet received
-#define REG_IRQ_FLAGS_MASK          0x11
-#define REG_IRQ_FLAGS               0x12
-#define REG_RX_NB_BYTES             0x13
+#define REG_FIFO_RX_CURRENT_ADDR	0x10		// r  Address of last packet received
+#define REG_IRQ_FLAGS_MASK			0x11
+#define REG_IRQ_FLAGS				0x12
+#define REG_RX_BYTES_NB				0x13
+// 0x14
+// 0x15
+// 0x16
+// 0x17
+// 0x18
 #define REG_PKT_SNR_VALUE			0x19
 #define REG_PKT_RSSI				0x1A		// latest package
 #define REG_RSSI					0x1B		// Current RSSI, section 6.4, or  5.5.5
@@ -450,14 +468,32 @@ struct LoraUp {
 #define REG_MODEM_CONFIG2           0x1E		// LoRa: Modem PHY config 2
 #define REG_SYMB_TIMEOUT_LSB  		0x1F
 
+#define REG_PREAMBLE_MSB			0x20
+#define REG_PREAMBLE_LSB			0x21		// MMM 200930: set to 0x08
 #define REG_PAYLOAD_LENGTH          0x22
 #define REG_MAX_PAYLOAD_LENGTH 		0x23
 #define REG_HOP_PERIOD              0x24
-#define REG_MODEM_CONFIG3           0x26		// Modem PHY config 3
+#define REG_FIFO_RX_BYTE_ADDR_PTR	0x25		// 200927 Not used yet
+#define REG_MODEM_CONFIG3           0x26		// Modem PHY config 3, bit 2 AgcAutoOn and 3 LowDataRateOptimize used
+#define REG_PPM_CORRECTION			0x27
+#define REG_FREQ_ERROR_MSB			0x28 (r)
+#define REG_FREQ_ERROR_MID			0x29 (r)
+#define REG_FREQ_ERROR_LSB			0x2A (r)
+// 0x2B reserved
 #define REG_RSSI_WIDEBAND			0x2C
-
-#define REG_INVERTIQ				0x33
+// 0x2D reserved
+// 0x2E reserved
+// 0x2F reserved
+
+// 0x30 reserved
+#define REG_DETECT_OPTIMIZE			0x31
+// 0x32 reserved
+#define REG_INVERTIQ				0x33		// 0x27 for normal and 0x40 for inverted IIQ
+// 0x34 reserved
+// 0x35 reserved
+// 0x36 reserved
 #define REG_DET_TRESH				0x37		// SF6
+// 0x38 reserved
 #define REG_SYNC_WORD				0x39
 #define REG_TEMP					0x3C
 
@@ -480,7 +516,7 @@ struct LoraUp {
 
 // ----------------------------------------
 // LMIC Constants for radio registers
-#define OPMODE_LORA      			0x80
+#define OPMODE_LORA      			0x80		// bit 6 is AccessSharing Reg. Bits 4 and 5 are 0x00
 #define OPMODE_MASK      			0x0F		// Select LSB 8 bits 0, ignore LoRa bit for example
 
 #define OPMODE_LOWFREQ				0x08		// Should be - for 868.1 MHZ operation
@@ -583,7 +619,7 @@ struct LoraUp {
 
 // ----------------------------------------
 // Definitions for UDP message arriving from server
-#define PROTOCOL_VERSION			0x02
+#define PROTOCOL_VERSION			0x01
 
 #define PUSH_DATA					0x00
 #define PUSH_ACK					0x01