platenspeler 5 роки тому
батько
коміт
36cff9229c

+ 0 - 239
CHANGELOG.md

@@ -1,239 +0,0 @@
-# Single Channel LoRaWAN Gateway
-
-Version 6.0.1, October 20, 2019	  
-Author: M. Westenberg (mw12554@hotmail.com)  
-Copyright: M. Westenberg (mw12554@hotmail.com)  
-
-All rights reserved. This program and the accompanying materials are made available under the terms 
-of the MIT License which accompanies this distribution, and is available at
-https://opensource.org/licenses/mit-license.php  
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-Maintained by Maarten Westenberg (mw12554@hotmail.com)
-
-
-
-# Release Notes
-
-Make ready for Publishing (October 20, 2019)
--Edit all files and make ready for publising to Github
-
-New features in version 5.3.4 (March 25, 2019)
-- Make use of the latest Arduino IDE available version 1.8.21
-- Added new iteams to the statc function so that it now has all the Package Statistics. Fieds are such as: mesg_ttl, msg_ttl_0 etc. Removed reference to the old counters.
-- Changed Json version in the IDE to ArduinoJSON 6 in _txRx.ino
-- Larger message history for ESP32 based on free heap
-
-New features in version 5.3.3 (August 25, 2018)
-- Bug Fixing SPIFFS Format in GUI
-- Included a confirm dialog in RESET, BOOT and STATISTICS buttons for user to confirm
-- Repaired WlanConnect issues
-- Improved Downlink function. Work for SF8-SF10. Does not work reliable for SF7, SF11, SF12
-- Provided documentation button o top of page
-- Added expert mode button in GUI (Wifi, System and Interrupt data is only shown in expert mode)
-- bug fixes and documentation
-
-New features in version 5.3.2 (July 07, 2018)
-- Support for local decoding of sensor messages received by the gateway. 
-	Use #define _LOCALSERVER 1, to enable this functionality. Also specify for each node that you want
-	to inspect the messages from the NwkSKey and AppSKey in the sensor.h file.
-	NOTE: the heap of the ESP32 is much larger than of the ESP8266. SO please be careful not to add too many 
-		features to the "old" gateway modules
-- As a result reworked the sensor functions and changes such as adding/changing DevAddrm NwkSKEY 
-	and AppSKey parameters to several functions
-- Several in-line documentaton enhancements and typos were fixed
-
-New features in version 5.3.1 (June 30, 2018)
-- Included support for T-Beam board including on board GPS sensor (_sensor.ino). #define GATEWAYNODE 1 will
-	turn the gateway into a node as well. Remember to set the address etc in ESP-sc-gway.h.
-- First version to explore possibilities of 433 MHz LoRa frequencies. 
-	Included frequency setting in the ESP-sc-gway.h file
-- Changes to the WiFi inplementation. The gateway does now store the SSID and password.
-- 
-
-New features in version 5.3.0 (June 20, 2018)
-- Connect to both public and private routers
-
-
-New features in version 5.2.1 (June 6, 2018)
-- Repair the downlink functions
-- Repair sersor functions
-- Bufgixes
-
-New features in version 5.2.0 (May 30, 2018)
-- Enable support for ESP32 from TTGO, several code changes where ESP32 differs from ESP8266. 
-OLED is supported but NOT tested. Some hardware specific reporting functions of the WebGUI do not work yet.
-- Include new ESP32WebServer library for support of ESP32
-- Made pin configuration definitions in Gateway.h file, and support in loraModem.h and .ino files.
-
-New features in version 5.1.1 (May 17, 2018)
-- The LOG button in the GUI now opens a txt .CSV file in the browser with loggin details.
-- Improved debugging in WebGUI, not only based on debug level but also on part of the software we want to debug.
-- Clean up of StateMachine
-- Enable filesystem formatting from the GUI
-
-New features in version 5.1.0 (May 03, 2018)
-- Improved debuggin in WebGUI, not only based on debug level but also on part of the software we want to debug.
-- Clean up of StateMachine
-
-New features in version 5.0.9 (Apr 08, 2018)
-- In statistics overview the option is added to specify names for known nodes (in ESP-sc-gateway.h file)
-- Keep track of the amount of messages per channel (only 3 channels supported).
-- Use the SPIFFS filesystem to provide log statistics of messages. Use the GUI and on the top select log. 
-The log data is displayed in the USB Serial area (for the moment).
-- Remove a lot of the debug==1 and debug==2 messages as they are not useful.
-
-New features in version 5.0.8 (Mar 26, 2018)
-- Simplified State machine and removed unnecessary code
-- Changed the WiFi Disconnect code (bug in SDK). When WiFi.begin() is executed, 
-  the previous accesspoint is not deleted. But the ESP8266 does also not connect 
-  to it anymore. The workaround restarts the WiFi completely.
-- Repair the bug causing the Channel setting to switch back to channel 0 when the RFM95 modem is reset 
-  (after upstream message)
-- Introduced the _utils.ino with Serial line utilities
-- Documentation Changes
-- Small bug fixes
-- Removal of unused global variables
-
-New features in version 5.0.7 (Feb 12, 2018)
-- On low debug value (0) we show the time in the rx status message on 
-- WlanConnect function updated
-
-New features in version 5.0.7 (Feb 24, 2018)
-- Changed WlaConnect function to not hang and give more debug info
-- Made the change to display correct MAC address info
-
-New features in version 5.0.6 (Feb 11, 2018)
-- All timer functions that show lists on website etc are now based on now() en NTP, 
-the realtime functions needed for LoRa messages are still based on micros() or millis()
-- Change some USB debug messages
-- Added to the documentation of the README.md
-
-New Features in version 5.0.5 (Feb 2, 2018)
-- Change timer functions to now() and secons instead of millis() as the latter one overflows once 
-every 50 days.
-- Add more debug information
-- Simplified and enhanced the State Machine function
-
-New features in version 5.0.4 (January 1, 2018)
-- Cleanup of the State machine
-- Separate file for oLED work, support for 1.3" SH3006 chips based oLED.
-- Still not supported: Multi Frequency works, but with loss of #packages, 
-  and some packages are recognizeg at the wrong frequency (but since they are so close that could happen).
-- In-line documenattion cleaned up
-
-New features in version 5.0.1 (November 18, 2017)
-- Changed the state machine to run in user space only
-- No Watchdog Resets anymore
-- For each SF, percentage of such packages received of total packages
-- OTAA and downlink work (again) although not always
-- Nober of packages per hour displayed in webserver
-- All Serial communication only when DUSB==1 is defined at compile time
-
-New features in version 4.0.9 (August 11, 2017)
-
-- This release contains updates for memory leaks in several Gateway files
-- Also changes in OLED functions
-
-New features in version 4.0.8 (August 05, 2017)
-
-- This release updates for memory leaks in NTP routines (see ESP-sc-gway.h file for NTP_INTR
-- OLED support contributed by Dorijan Morelj (based on Adreas Spies' release)
-
-New features in version 4.0.7 (July 22, 2017)
-
-- This release contains merely updates to memory leaks and patches to avoid chip resets etc.
-- The webinterface allows the user to see more parameters and has buttons to set/reset these parameters.
-- By setting debug >=2, the webinterface will display more information.
-- The gateway allows OTA (Over the Air) update. Please have an Apple "Bonjour" somewhere on your network 
-(included in iTunes) and you will see the network port in the "Port" section of your IDE.
-
-New features in version 4.0.4 (June 24, 2017):
-
-- Review of the _wwwServer.ino file. Repaired some of the bugs causing crashes of the webserver.
-- Updated the README.md file with more cofniguration information
-
-New features in version 4.0.3 (June 22, 2017):
-
-- Added CMAC functions so that the sensor functions work as expected over TTN
-- Webserver prints a page in chunks now, so that memory usage is lower and more heap is left over for variables
-- Webserver does refresh every 60 seconds
-- Implemented suggested change of M. for answer to PKT_PULL_RESP
-- Updated README.md to correctly displa all headers
-- Several small bug fixes
-
-New features in version 4.0.0 (January 26, 2017)):
-
-- Implement both CAD (Channel Activity Detection) and HOP functions (HOP being experimental)
-- Message history visible in web interface
-- Repaired the WWW server memory leak (due to String assignments)
-- Still works on one interrupt line (GPIO15), or can be configured to work with 2 interrupt lines for dio0 and dio1
-  for two or more interrupt lines (better performance for automatic SF setting?)
-- Webserver with debug level 3 and level 4 (for interrupt testing).
-  dynamic setting thorugh the web interface. Level 3 and 4 will show more info
-  on sf, rssi, interrupt flags etc.
-- Tested on Arduino IDE 1.18.0
-- See http://things4u.github.io for documentation
-
-New features in version 3.3.0 (January 1, 2017)):
-
-- Redesign of the Webserver interface
-- Use of the SPIFFS filesystem to store SSID, Frequency, Spreading Factor and Framecounter to survice reboots and resets of the ESP8266
-- Possibility to set the Spreading Factor dynamically throug the web interface
-- Possibility to set the Frequency in the web interface
-- Reset the Framecounter in te webinterface
-
-New features in version 3.2.2 (December 29, 2016)):
-
-- Repair the situation where WIFIMANAGER was set to 0 in the ESP-sc-gway.h file. The sketch would not compile which is now repaired
-- The compiler would issue a set of warnings related to the ssid and passw setting in the ESP-sc-gway.h file. Compiler was complaining (and it should) because char* were statically initialised and modified in the code.
-
-New features in version 3.2.1 (December 20, 2016)):
-
-- Repair the status messages to the server. All seconds, minutes, hours etc. are now reported in 2 digits. The year is reported in 4 digits.
-
-New features in version 3.2.0 (December 08, 2016)):
-
-- Several bugfixes
-
-New features in version 3.1 (September 29, 2016)):
-
-- In the ESP-sc-gway.h it is possible to set the gateway as sensor node as well. Just set the DevAddr and AppSKey in the _sensor.ino file and be able to forward any sensor or other values to the server as if they were coming from a LoRa node.
-- If the #define _STRICT_1CH is set (to 1) then the system will be able to send downlink messages to LoRa nodes that are strict 1-channel devices (all frequencies but frequency 0 are disabled and Spreading Factor (SF) is fixed to one value).
-- Code clean-up. The code has been made smaller in the area of loraWait() functions and where the radio is initiated for receiving of transmitting messages.
-- Several small bug fixes
-- Licensing, the license has been changed to MIT
-
-New features in version 3.0 (September 27, 2016):
-
-- WiFiManager support
-- Limited SPIFF (filesystem) support for persistent data storage
-- Added functions to webserver. Webserver port now 80 by default (!)
-
-Other
-
-- Supports ABP nodes (TeensyLC and Arduino Pro-mini)
-- Supports OTAA functions on TeensyLC and Arduino Pro-Mini (not all of them) for SF7 and SF8.
-- Supports SF7, SF8. SF7 is tested for downstream communication
-- Listens on configurable frequency and spreading factor
-- Send status updates to server (keepalive)
-- PULL_DATA messages to server
-- It can forward messages to two servers at the same time (and read from them as well)
-- DNS support for server lookup
-- NTP Support for time sync with internet time servers
-- Webserver support (default port 8080)
-- .h header file for configuration
-
-Not (yet) supported:
-
-- SF7BW250 modulation
-- FSK modulation
-- RX2 timeframe messages at frequency 869,525 MHz are not (yet) supported.
-- SF9-SF12 downlink messaging available but needs more testing
-
-
-# License
-
-The source files of the gateway sketch in this repository is made available under the MIT
-license. The libraries included in this repository are included for convenience only and all have their own license, and are not part of the ESP 1ch gateway code.

+ 0 - 316
ESP-sc-gway/ESP-sc-gway.h

@@ -1,316 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0 E EU868
-// Date: 2019-10-20
-//
-// Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway and many others.
-// Contibutions of Dorijan Morelj and Andreas Spies for OLED support.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains a number of compile-time settings that can be set on (=1) or off (=0)
-// The disadvantage of compile time is minor compared to the memory gain of not having
-// too much code compiled and loaded on your ESP8266.
-//
-// ----------------------------------------------------------------------------------------
-
-// NOTE: Compile with ESP32 setting and board "ESP32 Dev Module" or "Heltec WiFi Lora 32"
-#define VERSION "V.6.1.0.E.EU868; 191020a"
-
-// This value of DEBUG determines whether some parts of code get compiled.
-// Also this is the initial value of debug parameter. 
-// The value can be changed using the admin webserver
-// For operational use, set initial DEBUG vaulue 0
-#define DEBUG 1
-
-
-// Debug message will be put on Serial is this one is set.
-// If set to 0, not USB Serial prints are done
-// Set to 1 it will prinr all user level messages (with correct debug set)
-// If set to 2 it will also print interrupt messages (not recommended)
-#define DUSB 1
-
-
-// Define whether we should do a formatting of SPIFFS when starting the gateway
-// This is usually a good idea if the webserver is interrupted halfway a writing
-// operation. Also to be used when software is upgraded
-// Normally, value 0 is a good default.
-#define _SPIFF_FORMAT 0
-
-
-// Define the frequency band the gateway will listen on. Valid options are
-// EU863_870 (Europe), US902_928 (North America) & AU925_928 (Australia), CN470_510 (China).
-// See https://www.thethingsnetwork.org/docs/lorawan/frequency-plans.html
-#define EU863_870 1
- 
- 
-// Define whether to use the old Semtech gateway API, which is still supported by TTN,
-// but is more lightweight than the new TTN tcp based protocol.
-// NOTE: Only one of the two should be defined!
-//
-#define _UDPROUTER 1
-//#define _TTNROUTER 1
-
-
-// The spreading factor is the most important parameter to set for a single channel
-// gateway. It specifies the speed/datarate in which the gateway and node communicate.
-// As the name says, in principle the single channel gateway listens to one channel/frequency
-// 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.
-#define _SPREADING SF9
-
-
-// Channel Activity Detection
-// This function will scan for valid LoRa headers and determine the Spreading 
-// factor accordingly. If set to 1 we will use this function which means the 
-// 1-channel gateway will become even more versatile. If set to 0 we will use the
-// continuous listen mode.
-// Using this function means that we HAVE to use more dio pins on the RFM95/sx1276
-// device and also connect enable dio1 to detect this state. 
-#define _CAD 1
-
-
-// Definitions for the admin webserver.
-// A_SERVER determines whether or not the admin webpage is included in the sketch.
-// Normally, leave it in!
-#define A_SERVER 1				// Define local WebServer only if this define is set
-#define A_REFRESH 1				// Allow the webserver refresh or not?
-#define A_SERVERPORT 80			// Local webserver port (normally 80)
-#define A_MAXBUFSIZE 192		// Must be larger than 128, but small enough to work
-
-
-// Definitions for over the air updates. At the moment we support OTA with IDE
-// Make sure that tou have installed Python version 2.7 and have Bonjour in your network.
-// Bonjour is included in iTunes (which is free) and OTA is recommended to install 
-// the firmware on your router witout having to be really close to the gateway and 
-// connect with USB.
-#define A_OTA 1
-
-
-// We support a few pin-out configurations out-of-the-box: HALLARD, COMPRESULT and TTGO ESP32.
-// If you use one of these two, just set the parameter to the right value.
-// If your pin definitions are different, update the loraModem.h file to reflect these settings.
-//	1: HALLARD
-//	2: COMRESULT pin out
-//	3: ESP32 Wemos pin out
-//	4: ESP32 TTGO pinning (should work for 433 and OLED too).
-//	5: ESP32 TTGO EU433 MHz with OLED
-//	6: Other, define your own in loraModem.h
-#define _PIN_OUT 4
-
-// Gather statistics on sensor and Wifi status
-// 0= No statistics
-// 1= Keep track of messages statistics, number determined by MAX_STAT
-// 2= Option 1 + Keep track of messages received PER each SF (default)
-// 3= See Option 2, but with extra channel info (Do not use when no Hopping is selected)
-#define STATISTICS 3
-
-
-// Maximum number of statistics records gathered. 20 is a good maximum (memory intensive)
-// For ESP32 maybe 30 could be used as well
-#define MAX_STAT 20
-
-
-// Single channel gateways if they behave strict should only use one frequency 
-// channel and one spreading factor. However, the TTN backend replies on RX2 
-// timeslot for spreading factors SF9-SF12. 
-// Also, the server will respond with SF12 in the RX2 timeslot.
-// If the 1ch gateway is working in and for nodes that ONLY transmit and receive on the set
-// and agreed frequency and spreading factor. make sure to set STRICT to 1.
-// In this case, the frequency and spreading factor for downlink messages is adapted by this
-// gateway
-// NOTE: If your node has only one frequency enabled and one SF, you must set this to 1
-//		in order to receive downlink messages
-// NOTE: In all other cases, value 0 works for most gateways with CAD enabled
-#define _STRICT_1CH 1
-
-
-// Allows configuration through WifiManager AP setup. Must be 0 or 1					
-#define WIFIMANAGER 0
-
-
-// Define the name of the accesspoint if the gateway is in accesspoint mode (is
-// getting WiFi SSID and password using WiFiManager)
-#define AP_NAME "ESP8266-Gway-Things4U"
-#define AP_PASSWD "ttnAutoPw"
-
-
-// This section defines whether we use the gateway as a repeater
-// For his, we use another output channle as the channel (default==0) we are 
-// receiving the messages on.
-#define _REPEATER 0
-
-
-// Will we use Mutex or not?
-// +SPI is input for SPI, SPO is output for SPI
-#define MUTEX 0
-
-
-// Define if OLED Display is connected to I2C bus. Note that defining an OLED display does not
-// impact performance very much, certainly if no OLED is connected. Wrong OLED will not show
-// sensible results on display
-// OLED==0; No OLED display connected
-// OLED==1; 0.9 Oled Screen based on SSD1306
-// OLED==2;	1"3 Oled screens for Wemos, 128x64 SH1106
-#define OLED 1
-
-
-// Define whether we want to manage the gateway over UDP (next to management 
-// thru webinterface).
-// This will allow us to send messages over the UDP connection to manage the gateway 
-// and its parameters. Sometimes the gateway is not accesible from remote, 
-// in this case we would allow it to use the SERVER UDP connection to receive 
-// messages as well.
-// NOTE: Be aware that these messages are NOT LoRa and NOT LoRa Gateway spec compliant.
-//	However that should not interfere with regular gateway operation but instead offer 
-//	functions to set/reset certain parameters from remote.
-#define GATEWAYMGT 0
-
-
-// Do extensive loggin
-// Use the ESP8266 SPIFS filesystem to do extensive logging.
-// We must take care that the filesystem never(!) is full, and for that purpose we
-// rather have new records/line of statistics than very old.
-// Of course we must store enough records to make the filesystem work
-#define STAT_LOG 1
-
-
-// Name of he configfile in SPIFFs	filesystem
-// In this file we store the configuration and other relevant info that should
-// survive a reboot of the gateway		
-#define CONFIGFILE "/gwayConfig.txt"
-
-// Set the Server Settings (IMPORTANT)
-#define _LOCUDPPORT 1700					// UDP port of gateway! Often 1700 or 1701 is used for upstream comms
-
-// Timing
-#define _MSG_INTERVAL 15					// Reset timer in seconds
-#define _PULL_INTERVAL 55					// PULL_DATA messages to server to get downstream in milliseconds
-#define _STAT_INTERVAL 120					// Send a 'stat' message to server
-#define _NTP_INTERVAL 3600					// How often do we want time NTP synchronization
-#define _WWW_INTERVAL	60					// Number of seconds before we refresh the WWW page
-
-
-// MQTT definitions, these settings should be standard for TTN
-// and need not changing
-#define _TTNSERVER "router.eu.thethings.network"
-#define _TTNPORT 1700						// Standard port for TTN
-
-
-// If you have a second back-end server defined such as Semtech or loriot.io
-// your can define _THINGPORT and _THINGSERVER with your own value.
-// If not, make sure that you do not define these, which will save CPU time
-// Port is UDP port in this program
-//
-// Default for testing: Switched off
-#define _THINGSERVER "westenberg.org"		// Server URL of the LoRa-udp.js handler
-//#define _THINGPORT 57084					// dash.westenberg.org:8057
-//#define _THINGSERVER "capgemini.thethings.industries"		// Server URL of the LoRa-udp.js handler
-#define _THINGPORT 1700						// Port 1700 is old compatibility
-
-
-// This defines whether or not we would use the gateway as 
-// as sort of backend system which decodes
-// 1: _LOCALSERVER is used
-// 0: Do not use _LOCALSERVER 
-#define _LOCALSERVER 1						// See server definitions for decodes
-
-
-// Gateway Ident definitions
-#define _DESCRIPTION "ESP Gateway"			// Name of the gateway
-#define _EMAIL "mw12554@hotmail.com"		// Owner
-#define _PLATFORM "ESP8266"
-#define _LAT 52.237367
-#define _LON 5.978654
-#define _ALT 14								// Altitude
-
-// ntp
-// Please add daylight saving time to NTP_TIMEZONES when desired
-#define NTP_TIMESERVER "nl.pool.ntp.org"	// Country and region specific
-#define NTP_TIMEZONES	2					// How far is our Timezone from UTC (excl daylight saving/summer time)
-#define SECS_IN_HOUR	3600
-#define NTP_INTR 0							// Do NTP processing with interrupts or in loop();
-
-
-// lora sensor code definitions
-// Defines whether the gateway will also report sensor/status value on MQTT
-// after all, a gateway can be a node to the system as well. Some sensors like GPS can be
-// sent to the backend as a parameter, some (like humidity for example) can only be sent
-// as a regular sensor value.
-// Set its LoRa address and key below in this file, See spec. para 4.3.2
-#define GATEWAYNODE 0
-#define _CHECK_MIC 0
-
-#if GATEWAYNODE==1
-#define _DEVADDR { 0x22, 0x22, 0x22, 0x22 }
-#define _APPSKEY { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
-#define _NWKSKEY { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 }
-#define _SENSOR_INTERVAL 300
-// For ESP32 based T_BEAM/TTGO boards these two are normally included
-// If included make value 1, else if not, make them 0
-#define _GPS 1
-#define _BATTERY 1
-#endif
-
-
-// Define the correct radio type that you are using
-#define CFG_sx1276_radio		
-//#define CFG_sx1272_radio
-
-
-// Serial Port speed
-#define _BAUDRATE 115200					// Works for debug messages to serial momitor
-
-
-// We can put the gateway in such a mode that it will (only) recognize
-// nodes that are put in a list of trusted nodes 
-// Values:
-// 0: Do not use names for trusted Nodes
-// 1: Use the nodes as a translation table for hex codes to names (in TLN)
-// 2: Same as 1, but is nodes NOT in the nodes list below they are NOT
-//		forwarded or counted! (not yet fully implemented)
-#define _TRUSTED_NODES 1
-#define _TRUSTED_DECODE 1
-
-
-// Wifi definitions
-// WPA is an array with SSID and password records. Set WPA size to number of entries in array
-// When using the WiFiManager, we will overwrite the first entry with the 
-// accesspoint we last connected to with WifiManager
-// NOTE: Structure needs at least one (empty) entry.
-//		So WPASIZE must be >= 1
-struct wpas {
-	char login[32];							// Maximum Buffer Size (and allocated memory)
-	char passw[64];
-};
-
-
-// Please fill in at least ONE SSID and password from your own WiFI network
-// below. This is needed to get the gateway working
-// Note: DO NOT use the first and the last line of the stucture, these should be empty strings and
-//	the first line in te struct is reserved for WifiManager.
-//
-wpas wpa[] = {
-	{ "" , "" },							// Reserved for WiFi Manager
-	{ "your SSID 1", "your PASS 1" },
-	{ "your SSID 2", "your PASS 2" },
-	{ "your SSID n", "your PASS n"}
-};
-
-
-// For asserting and testing the following defines are used.
-//
-#if !defined(CFG_noassert)
-#define ASSERT(cond) if(!(cond)) gway_failed(__FILE__, __LINE__)
-#else
-#define ASSERT(cond) /**/
-#endif

+ 0 - 908
ESP-sc-gway/ESP-sc-gway.ino

@@ -1,908 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// Based on work done by Thomas Telkamp for Raspberry PI 1-ch gateway and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// The protocols and specifications used for this 1ch gateway: 
-// 1. LoRA Specification version V1.0 and V1.1 for Gateway-Node communication
-//	
-// 2. Semtech Basic communication protocol between Lora gateway and server version 3.0.0
-//	https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT
-//
-// Notes: 
-// - Once call gethostbyname() to get IP for services, after that only use IP
-//	 addresses (too many gethost name makes the ESP unstable)
-// - Only call yield() in main stream (not for background NTP sync). 
-//
-// ----------------------------------------------------------------------------------------
-
-#include "ESP-sc-gway.h"									// This file contains configuration of GWay
-
-#if defined (ARDUINO_ARCH_ESP32) || defined(ESP32)
-#define ESP32_ARCH 1
-#endif
-
-#include <Esp.h>											// ESP8266 specific IDE functions
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <cstdlib>
-#include <sys/time.h>
-#include <cstring>
-#include <string>											// C++ specific string functions
-
-#include <SPI.h>											// For the RFM95 bus
-#include <TimeLib.h>										// http://playground.arduino.cc/code/time
-#include <DNSServer.h>										// Local DNSserver
-#include <ArduinoJson.h>
-#include <FS.h>												// ESP8266 Specific
-#include <WiFiUdp.h>
-#include <pins_arduino.h>
-#include <gBase64.h>										// https://github.com/adamvr/arduino-base64 (changed the name)
-
-// Local include files
-#include "loraModem.h"
-#include "loraFiles.h"
-#include "sensor.h"
-#include "oLED.h"
-
-extern "C" {
-#include "lwip/err.h"
-#include "lwip/dns.h"
-}
-
-#if WIFIMANAGER==1
-#include <WiFiManager.h>									// Library for ESP WiFi config through an AP
-#endif
-
-#if (GATEWAYNODE==1) || (_LOCALSERVER==1)
-#include "AES-128_V10.h"
-#endif
-
-
-// ----------- Specific ESP32 stuff --------------
-#if ESP32_ARCH==1											// IF ESP32
-
-#include "WiFi.h"
-#include <ESPmDNS.h>
-#include <SPIFFS.h>
-#if A_SERVER==1
-#include <ESP32WebServer.h>									// Dedicated Webserver for ESP32
-#include <Streaming.h>          							// http://arduiniana.org/libraries/streaming/
-#endif
-#if A_OTA==1
-#include <ESP32httpUpdate.h>								// Not yet available
-#include <ArduinoOTA.h>
-#endif//OTA
-
-// ----------- Specific ESP8266 stuff --------------
-#else
-
-#include <ESP8266WiFi.h>									// Which is specific for ESP8266
-#include <ESP8266mDNS.h>
-extern "C" {
-#include "user_interface.h"
-#include "c_types.h"
-}
-#if A_SERVER==1
-#include <ESP8266WebServer.h>
-#include <Streaming.h>          							// http://arduiniana.org/libraries/streaming/
-#endif //A_SERVER
-#if A_OTA==1
-#include <ESP8266httpUpdate.h>
-#include <ArduinoOTA.h>
-#endif//OTA
-
-#endif//ESP_ARCH
-
-// ----------- Declaration of vars --------------
-uint8_t debug=1;											// Debug level! 0 is no msgs, 1 normal, 2 extensive
-uint8_t pdebug=0xFF;										// Allow all atterns (departments)
-
-#if GATEWAYNODE==1
-#if _GPS==1
-#include <TinyGPS++.h>
-TinyGPSPlus gps;
-HardwareSerial Serial1(1);
-#endif
-#endif
-
-// You can switch webserver off if not necessary but probably better to leave it in.
-#if A_SERVER==1
-#if ESP32_ARCH==1
-	ESP32WebServer server(A_SERVERPORT);
-#else
-	ESP8266WebServer server(A_SERVERPORT);
-#endif
-#endif
-
-using namespace std;
-
-byte currentMode = 0x81;
-
-bool sx1272 = true;											// Actually we use sx1276/RFM95
-
-uint8_t	 ifreq = 0;											// Channel Index
-//unsigned long freq = 0;
-
-
-
-uint8_t MAC_array[6];
-
-// ----------------------------------------------------------------------------
-//
-// Configure these values only if necessary!
-//
-// ----------------------------------------------------------------------------
-
-// Set spreading factor (SF7 - SF12)
-sf_t sf 			= _SPREADING;
-sf_t sfi 			= _SPREADING;								// Initial value of SF
-
-// Set location, description and other configuration parameters
-// Defined in ESP-sc_gway.h
-//
-float lat			= _LAT;									// Configuration specific info...
-float lon			= _LON;
-int   alt			= _ALT;
-char platform[24]	= _PLATFORM; 							// platform definition
-char email[40]		= _EMAIL;    							// used for contact email
-char description[64]= _DESCRIPTION;							// used for free form description 
-
-// define servers
-
-IPAddress ntpServer;										// IP address of NTP_TIMESERVER
-IPAddress ttnServer;										// IP Address of thethingsnetwork server
-IPAddress thingServer;
-
-WiFiUDP Udp;
-
-time_t startTime = 0;										// The time in seconds since 1970 that the server started
-															// be aware that UTP time has to succeed for meaningful values.
-															// We use this variable since millis() is reset every 50 days...
-uint32_t eventTime = 0;										// Timing of _event to change value (or not).
-uint32_t sendTime = 0;										// Time that the last message transmitted
-uint32_t doneTime = 0;										// Time to expire when CDDONE takes too long
-uint32_t statTime = 0;										// last time we sent a stat message to server
-uint32_t pulltime = 0;										// last time we sent a pull_data request to server
-//uint32_t lastTmst = 0;									// Last activity Timer
-
-#if A_SERVER==1
-uint32_t wwwtime = 0;
-#endif
-#if NTP_INTR==0
-uint32_t ntptimer = 0;
-#endif
-
-#define TX_BUFF_SIZE  1024									// Upstream buffer to send to MQTT
-#define RX_BUFF_SIZE  1024									// Downstream received from MQTT
-#define STATUS_SIZE	  512									// Should(!) be enough based on the static text .. was 1024
-
-#if GATEWAYNODE==1
-uint16_t frameCount=0;										// We write this to SPIFF file
-#endif
-
-// volatile bool inSPI This initial value of mutex is to be free,
-// which means that its value is 1 (!)
-// 
-int mutexSPI = 1;
-
-// ----------------------------------------------------------------------------
-// FORWARD DECLARATIONS
-// These forward declarations are done since other .ino fils are linked by the
-// compiler/linker AFTER the main ESP-sc-gway.ino file. 
-// And espcecially when calling functions with ICACHE_RAM_ATTR the complier 
-// does not want this.
-// Solution can also be to specify less STRICT compile options in Makefile
-// ----------------------------------------------------------------------------
-
-void ICACHE_RAM_ATTR Interrupt_0();
-void ICACHE_RAM_ATTR Interrupt_1();
-
-int sendPacket(uint8_t *buf, uint8_t length);				// _txRx.ino forward
-
-void setupWWW();											// _wwwServer.ino forward
-static void printIP(IPAddress ipa, const char sep, String& response);	// _wwwServer.ino
-
-void SerialTime();											// _utils.ino forward
-
-
-void init_oLED();											// oLED.ino
-void acti_oLED();
-void addr_oLED();
-
-void setupOta(char *hostname);								// _otaServer.ino
-
-void initLoraModem();										// _loraModem.ino
-void rxLoraModem();											// _loraModem.ino
-void writeRegister(uint8_t addr, uint8_t value);			// _loraModem.ino
-void cadScanner();											// _loraModem.ino
-
-void stateMachine();										// _stateMachine.ino
-
-void SerialStat(uint8_t intr);								// _utils.ino
-
-#if MUTEX==1
-// Forward declarations
-void ICACHE_FLASH_ATTR CreateMutux(int *mutex);
-bool ICACHE_FLASH_ATTR GetMutex(int *mutex);
-void ICACHE_FLASH_ATTR ReleaseMutex(int *mutex);
-#endif
-
-// ----------------------------------------------------------------------------
-// DIE is not use actively in the source code anymore.
-// It is replaced by a Serial.print command so we know that we have a problem
-// somewhere.
-// There are at least 3 other ways to restart the ESP. Pick one if you want.
-// ----------------------------------------------------------------------------
-void die(const char *s)
-{
-	Serial.println(s);
-	if (debug>=2) Serial.flush();
-
-	delay(50);
-	// system_restart();									// SDK function
-	// ESP.reset();				
-	abort();												// Within a second
-}
-
-// ----------------------------------------------------------------------------
-// gway_failed is a function called by ASSERT in ESP-sc-gway.h
-//
-// ----------------------------------------------------------------------------
-void gway_failed(const char *file, uint16_t line) {
-	Serial.print(F("Program failed in file: "));
-	Serial.print(file);
-	Serial.print(F(", line: "));
-	Serial.println(line);
-	if (debug>=2) Serial.flush();
-}
-
-
-
-// ----------------------------------------------------------------------------
-// Convert a float to string for printing
-// Parameters:
-//	f is float value to convert
-//	p is precision in decimal digits
-//	val is character array for results
-// ----------------------------------------------------------------------------
-void ftoa(float f, char *val, int p) {
-	int j=1;
-	int ival, fval;
-	char b[7] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	
-	for (int i=0; i< p; i++) { j= j*10; }
-
-	ival = (int) f;											// Make integer part
-	fval = (int) ((f- ival)*j);								// Make fraction. Has same sign as integer part
-	if (fval<0) fval = -fval;								// So if it is negative make fraction positive again.
-															// sprintf does NOT fit in memory
-	if ((f<0) && (ival == 0)) strcat(val, "-");
-	strcat(val,itoa(ival,b,10));							// Copy integer part first, base 10, null terminated
-	strcat(val,".");										// Copy decimal point
-	
-	itoa(fval,b,10);										// Copy fraction part base 10
-	for (int i=0; i<(p-strlen(b)); i++) {
-		strcat(val,"0");									// first number of 0 of faction?
-	}
-	
-	// Fraction can be anything from 0 to 10^p , so can have less digits
-	strcat(val,b);
-}
-
-// ============================================================================
-// NTP TIME functions
-
-// ----------------------------------------------------------------------------
-// Send the request packet to the NTP server.
-//
-// ----------------------------------------------------------------------------
-int sendNtpRequest(IPAddress timeServerIP) {
-	const int NTP_PACKET_SIZE = 48;							// Fixed size of NTP record
-	byte packetBuffer[NTP_PACKET_SIZE];
-
-	memset(packetBuffer, 0, NTP_PACKET_SIZE);				// Zeroise the buffer.
-	
-	packetBuffer[0]  = 0b11100011;   						// LI, Version, Mode
-	packetBuffer[1]  = 0;									// Stratum, or type of clock
-	packetBuffer[2]  = 6;									// Polling Interval
-	packetBuffer[3]  = 0xEC;								// Peer Clock Precision
-	// 8 bytes of zero for Root Delay & Root Dispersion
-	packetBuffer[12] = 49;
-	packetBuffer[13] = 0x4E;
-	packetBuffer[14] = 49;
-	packetBuffer[15] = 52;	
-
-	
-	if (!sendUdp( (IPAddress) timeServerIP, (int) 123, packetBuffer, NTP_PACKET_SIZE)) {
-		gwayConfig.ntpErr++;
-		gwayConfig.ntpErrTime = now();
-		return(0);	
-	}
-	return(1);
-}
-
-
-// ----------------------------------------------------------------------------
-// Get the NTP time from one of the time servers
-// Note: As this function is called from SyncINterval in the background
-//	make sure we have no blocking calls in this function
-// ----------------------------------------------------------------------------
-time_t getNtpTime()
-{
-	gwayConfig.ntps++;
-	
-    if (!sendNtpRequest(ntpServer))							// Send the request for new time
-	{
-		if (( debug>=0 ) && ( pdebug & P_MAIN ))
-			Serial.println(F("M sendNtpRequest failed"));
-		return(0);
-	}
-	
-	const int NTP_PACKET_SIZE = 48;							// Fixed size of NTP record
-	byte packetBuffer[NTP_PACKET_SIZE];
-	memset(packetBuffer, 0, NTP_PACKET_SIZE);				// Set buffer cntents to zero
-
-    uint32_t beginWait = millis();
-	delay(10);
-    while (millis() - beginWait < 1500) 
-	{
-		int size = Udp.parsePacket();
-		if ( size >= NTP_PACKET_SIZE ) {
-		
-			if (Udp.read(packetBuffer, NTP_PACKET_SIZE) < NTP_PACKET_SIZE) {
-				break;
-			}
-			else {
-				// Extract seconds portion.
-				unsigned long secs;
-				secs  = packetBuffer[40] << 24;
-				secs |= packetBuffer[41] << 16;
-				secs |= packetBuffer[42] <<  8;
-				secs |= packetBuffer[43];
-				// UTC is 1 TimeZone correction when no daylight saving time
-				return(secs - 2208988800UL + NTP_TIMEZONES * SECS_IN_HOUR);
-			}
-			Udp.flush();	
-		}
-		delay(100);											// Wait 100 millisecs, allow kernel to act when necessary
-    }
-
-	Udp.flush();
-	
-	// If we are here, we could not read the time from internet
-	// So increase the counter
-	gwayConfig.ntpErr++;
-	gwayConfig.ntpErrTime = now();
-#if DUSB>=1
-	if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("M getNtpTime:: read failed"));
-	}
-#endif
-	return(0); 												// return 0 if unable to get the time
-}
-
-// ----------------------------------------------------------------------------
-// Set up regular synchronization of NTP server and the local time.
-// ----------------------------------------------------------------------------
-#if NTP_INTR==1
-void setupTime() {
-  setSyncProvider(getNtpTime);
-  setSyncInterval(_NTP_INTERVAL);
-}
-#endif
-
-
-
-// ============================================================================
-// MAIN PROGRAM CODE (SETUP AND LOOP)
-
-
-// ----------------------------------------------------------------------------
-// Setup code (one time)
-// _state is S_INIT
-// ----------------------------------------------------------------------------
-void setup() {
-
-	char MAC_char[19];										// XXX Unbelievable
-	MAC_char[18] = 0;
-
-	Serial.begin(_BAUDRATE);								// As fast as possible for bus
-	delay(100);	
-
-#if _GPS==1
-	// Pins are define in LoRaModem.h together with other pins
-	Serial1.begin(9600, SERIAL_8N1, GPS_TX, GPS_RX);// PIN 12-TX 15-RX
-#endif
-
-#ifdef ESP32
-#if DUSB>=1
-	Serial.print(F("ESP32 defined, freq="));
-	Serial.print(freqs[0].upFreq);
-	Serial.println();
-#endif
-#endif
-#ifdef ARDUINO_ARCH_ESP32
-#if DUSB>=1
-	Serial.println(F("ARDUINO_ARCH_ESP32 defined"));
-#endif
-#endif
-
-
-#if DUSB>=1
-	Serial.flush();
-
-	delay(500);
-
-	if (SPIFFS.begin()) {
-		Serial.println(F("SPIFFS init success"));
-	}
-	else {
-	}
-#endif	
-#if _SPIFF_FORMAT>=1
-#if DUSB>=1
-	if (( debug >= 0 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("M Format Filesystem ... "));
-	}
-#endif
-	SPIFFS.format();										// Normally disabled. Enable only when SPIFFS corrupt
-#if DUSB>=1
-	if (( debug >= 0 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("Done"));
-	}
-#endif
-#endif
-
-	Serial.print(F("Assert="));
-#if defined CFG_noassert
-	Serial.println(F("No Asserts"));
-#else
-	Serial.println(F("Do Asserts"));
-#endif
-
-#if OLED>=1
-	init_oLED();											// Display "STARTING" on OLED
-#endif
-
-	delay(500);
-	yield();
-#if DUSB>=1	
-	if (debug>=1) {
-		Serial.print(F("debug=")); 
-		Serial.println(debug);
-		yield();
-	}
-#endif
-
-	WiFi.mode(WIFI_STA);
-	WiFi.setAutoConnect(true);
-	//WiFi.begin();
-	
-	WlanReadWpa();											// Read the last Wifi settings from SPIFFS into memory
-
-	WiFi.macAddress(MAC_array);
-	
-    sprintf(MAC_char,"%02x:%02x:%02x:%02x:%02x:%02x",
-		MAC_array[0],MAC_array[1],MAC_array[2],MAC_array[3],MAC_array[4],MAC_array[5]);
-	Serial.print("MAC: ");
-    Serial.print(MAC_char);
-	Serial.print(F(", len="));
-	Serial.println(strlen(MAC_char));
-
-	// We start by connecting to a WiFi network, set hostname
-	char hostname[12];
-
-	// Setup WiFi UDP connection. Give it some time and retry x times..
-	while (WlanConnect(0) <= 0) {
-		Serial.print(F("Error Wifi network connect "));
-		Serial.println();
-		yield();
-	}	
-	
-	// After there is a WiFi router connection, we can also set the hostname.
-#if ESP32_ARCH==1
-	sprintf(hostname, "%s%02x%02x%02x", "esp32-", MAC_array[3], MAC_array[4], MAC_array[5]);
-	WiFi.setHostname( hostname );
-#else
-	sprintf(hostname, "%s%02x%02x%02x", "esp8266-", MAC_array[3], MAC_array[4], MAC_array[5]);
-	wifi_station_set_hostname( hostname );
-#endif	
-
-	
-	Serial.print(F("Host "));
-#if ESP32_ARCH==1
-	Serial.print(WiFi.getHostname());
-#else
-	Serial.print(wifi_station_get_hostname());
-#endif
-	Serial.print(F(" WiFi Connected to "));
-	Serial.print(WiFi.SSID());
-	Serial.print(F(" on IP="));
-	Serial.print(WiFi.localIP());
-	Serial.println();
-	delay(200);
-	
-	// If we are here we are connected to WLAN
-	
-#if defined(_UDPROUTER)
-	// So now test the UDP function
-	if (!connectUdp()) {
-		Serial.println(F("Error connectUdp"));
-	}
-#elif defined(_TTNROUTER)
-	if (!connectTtn()) {
-		Serial.println(F("Error connectTtn"));
-	}
-#else
-	Serial.print(F("Setup:: No UDP or TCP Connection defined"));
-	
-#endif
-	delay(200);
-	
-	// Pins are defined and set in loraModem.h
-    pinMode(pins.ss, OUTPUT);
-	pinMode(pins.rst, OUTPUT);
-    pinMode(pins.dio0, INPUT);								// This pin is interrupt
-	pinMode(pins.dio1, INPUT);								// This pin is interrupt
-	//pinMode(pins.dio2, INPUT);
-
-	// Init the SPI pins
-#if ESP32_ARCH==1
-	SPI.begin(SCK, MISO, MOSI, SS);
-#else
-	SPI.begin();
-#endif
-
-	delay(500);
-	
-	// We choose the Gateway ID to be the Ethernet Address of our Gateway card
-    // display results of getting hardware address
-	//
-
-    Serial.print("Gateway ID: ");
-	printHexDigit(MAC_array[0]);
-    printHexDigit(MAC_array[1]);
-    printHexDigit(MAC_array[2]);
-	printHexDigit(0xFF);
-	printHexDigit(0xFF);
-    printHexDigit(MAC_array[3]);
-    printHexDigit(MAC_array[4]);
-    printHexDigit(MAC_array[5]);
-
-    Serial.print(", Listening at SF");
-	Serial.print(sf);
-	Serial.print(" on ");
-	Serial.print((double)freqs[ifreq].upFreq/1000000);
-	Serial.println(" MHz.");
-
-	if (!WiFi.hostByName(NTP_TIMESERVER, ntpServer))		// Get IP address of Timeserver
-	{
-		die("Setup:: ERROR hostByName NTP");
-	};
-	delay(100);
-#ifdef _TTNSERVER
-	if (!WiFi.hostByName(_TTNSERVER, ttnServer))			// Use DNS to get server IP once
-	{
-		die("Setup:: ERROR hostByName TTN");
-	};
-	delay(100);
-#endif
-#ifdef _THINGSERVER
-	if (!WiFi.hostByName(_THINGSERVER, thingServer))
-	{
-		die("Setup:: ERROR hostByName THING");
-	}
-	delay(100);
-#endif
-
-	// The Over the Air updates are supported when we have a WiFi connection.
-	// The NTP time setting does not have to be precise for this function to work.
-#if A_OTA==1
-	setupOta(hostname);										// Uses wwwServer 
-#endif
-
-	// Set the NTP Time
-	// As long as the time has not been set we try to set the time.
-#if NTP_INTR==1
-	setupTime();											// Set NTP time host and interval
-#else
-	// If not using the standard libraries, do a manual setting
-	// of the time. This method works more reliable than the 
-	// interrupt driven method.
-	
-	//setTime((time_t)getNtpTime());
-	while (timeStatus() == timeNotSet) {
-#if DUSB>=1
-		if (( debug>=0 ) && ( pdebug & P_MAIN )) 
-			Serial.println(F("M setupTime:: Time not set (yet)"));
-#endif
-		delay(500);
-		time_t newTime;
-		newTime = (time_t)getNtpTime();
-		if (newTime != 0) setTime(newTime);
-	}
-	// When we are here we succeeded in getting the time
-	startTime = now();										// Time in seconds
-#if DUSB>=1
-	Serial.print("Time: "); printTime();
-	Serial.println();
-#endif
-	writeGwayCfg(CONFIGFILE );
-#if DUSB>=1
-	Serial.println(F("Gateway configuration saved"));
-#endif
-#endif //NTP_INTR
-
-#if A_SERVER==1	
-	// Setup the webserver
-	setupWWW();
-#endif
-
-	delay(100);												// Wait after setup
-	
-	// Setup and initialise LoRa state machine of _loramModem.ino
-	_state = S_INIT;
-	initLoraModem();
-	
-	if (_cad) {
-		_state = S_SCAN;
-		sf = SF7;
-		cadScanner();										// Always start at SF7
-	}
-	else { 
-		_state = S_RX;
-		rxLoraModem();
-	}
-	LoraUp.payLoad[0]= 0;
-	LoraUp.payLength = 0;									// Init the length to 0
-
-	// init interrupt handlers, which are shared for GPIO15 / D8, 
-	// we switch on HIGH interrupts
-	if (pins.dio0 == pins.dio1) {
-		//SPI.usingInterrupt(digitalPinToInterrupt(pins.dio0));
-		attachInterrupt(pins.dio0, Interrupt_0, RISING);	// Share interrupts
-	}
-	// Or in the traditional Comresult case
-	else {
-		//SPI.usingInterrupt(digitalPinToInterrupt(pins.dio0));
-		//SPI.usingInterrupt(digitalPinToInterrupt(pins.dio1));
-		attachInterrupt(pins.dio0, Interrupt_0, RISING);	// Separate interrupts
-		attachInterrupt(pins.dio1, Interrupt_1, RISING);	// Separate interrupts		
-	}
-	
-	writeConfig( CONFIGFILE, &gwayConfig);					// Write config
-
-	// activate OLED display
-#if OLED>=1
-	acti_oLED();
-	addr_oLED();
-#endif
-
-	Serial.println(F("--------------------------------------"));
-}//setup
-
-
-
-// ----------------------------------------------------------------------------
-// LOOP
-// This is the main program that is executed time and time again.
-// We need to give way to the backend WiFi processing that 
-// takes place somewhere in the ESP8266 firmware and therefore
-// we include yield() statements at important points.
-//
-// Note: If we spend too much time in user processing functions
-// and the backend system cannot do its housekeeping, the watchdog
-// function will be executed which means effectively that the 
-// program crashes.
-// We use yield() a lot to avoid ANY watch dog activity of the program.
-//
-// NOTE2: For ESP make sure not to do large array declarations in loop();
-// ----------------------------------------------------------------------------
-void loop ()
-{
-	uint32_t uSeconds;										// micro seconds
-	int packetSize;
-	uint32_t nowSeconds = now();
-	
-	// check for event value, which means that an interrupt has arrived.
-	// In this case we handle the interrupt ( e.g. message received)
-	// in userspace in loop().
-	//
-	stateMachine();											// do the state machine
-	
-	// After a quiet period, make sure we reinit the modem and state machine.
-	// The interval is in seconds (about 15 seconds) as this re-init
-	// is a heavy operation. 
-	// SO it will kick in if there are not many messages for the gateway.
-	// Note: Be careful that it does not happen too often in normal operation.
-	//
-	if ( ((nowSeconds - statr[0].tmst) > _MSG_INTERVAL ) &&
-		(msgTime <= statr[0].tmst) ) 
-	{
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.print("M REINIT:: ");
-			Serial.print( _MSG_INTERVAL );
-			Serial.print(F(" "));
-			SerialStat(0);
-		}
-#endif
-
-		// startReceiver() ??
-		if ((_cad) || (_hop)) {
-			_state = S_SCAN;
-			sf = SF7;
-			cadScanner();
-		}
-		else {
-			_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;
-	}
-
-#if A_SERVER==1
-	// Handle the Web server part of this sketch. Mainly used for administration 
-	// and monitoring of the node. This function is important so it is called at the
-	// start of the loop() function.
-	yield();
-	server.handleClient();
-#endif
-
-#if A_OTA==1
-	// Perform Over the Air (OTA) update if enabled and requested by user.
-	// It is important to put this function early in loop() as it is
-	// not called frequently but it should always run when called.
-	//
-	yield();
-	ArduinoOTA.handle();
-#endif
-
-	// If event is set, we know that we have a (soft) interrupt.
-	// After all necessary web/OTA services are scanned, we will
-	// reloop here for timing purposes. 
-	// Do as less yield() as possible.
-	// XXX 180326
-	if (_event == 1) {
-		return;
-	}
-	else yield();
-
-	
-	// If we are not connected, try to connect.
-	// We will not read Udp in this loop cycle then
-	if (WlanConnect(1) < 0) {
-#if DUSB>=1
-		if (( debug >= 0 ) && ( pdebug & P_MAIN ))
-			Serial.println(F("M ERROR reconnect WLAN"));
-#endif
-		yield();
-		return;												// Exit loop if no WLAN connected
-	}
-	
-	// So if we are connected 
-	// Receive UDP PUSH_ACK messages from server. (*2, par. 3.3)
-	// This is important since the TTN broker will return confirmation
-	// messages on UDP for every message sent by the gateway. So we have to consume them.
-	// As we do not know when the server will respond, we test in every loop.
-	//
-	else {
-		while( (packetSize = Udp.parsePacket()) > 0) {
-#if DUSB>=2
-			Serial.println(F("loop:: readUdp calling"));
-#endif
-			// DOWNSTREAM
-			// Packet may be PKT_PUSH_ACK (0x01), PKT_PULL_ACK (0x03) or PKT_PULL_RESP (0x04)
-			// This command is found in byte 4 (buffer[3])
-			if (readUdp(packetSize) <= 0) {
-#if DUSB>=1
-				if (( debug>0 ) && ( pdebug & P_MAIN ))
-					Serial.println(F("M readUdp error"));
-#endif
-				break;
-			}
-			// Now we know we succesfully received message from host
-			else {
-				//_event=1;									// Could be done double if more messages received
-			}
-		}
-	}
-	
-	yield();					// XXX 26/12/2017
-
-	// stat PUSH_DATA message (*2, par. 4)
-	//	
-
-    if ((nowSeconds - statTime) >= _STAT_INTERVAL) {		// Wake up every xx seconds
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.print(F("M STAT:: ..."));
-			Serial.flush();
-		}
-#endif
-        sendstat();											// Show the status message and send to server
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.println(F(" done"));
-			if (debug>=2) Serial.flush();
-		}
-#endif	
-
-		// If the gateway behaves like a node, we do from time to time
-		// send a node message to the backend server.
-		// The Gateway node emessage has nothing to do with the STAT_INTERVAL
-		// message but we schedule it in the same frequency.
-		//
-#if GATEWAYNODE==1
-		if (gwayConfig.isNode) {
-			// Give way to internal some Admin if necessary
-			yield();
-			
-			// If the 1ch gateway is a sensor itself, send the sensor values
-			// could be battery but also other status info or sensor info
-		
-			if (sensorPacket() < 0) {
-#if DUSB>=1
-				Serial.println(F("sensorPacket: Error"));
-#endif
-			}
-		}
-#endif
-		statTime = nowSeconds;
-    }
-	
-	yield();
-
-	
-	// send PULL_DATA message (*2, par. 4)
-	//
-	nowSeconds = now();
-    if ((nowSeconds - pulltime) >= _PULL_INTERVAL) {		// Wake up every xx seconds
-#if DUSB>=1
-		if (( debug>=2) && ( pdebug & P_MAIN )) {
-			Serial.println(F("M PULL"));
-			if (debug>=1) Serial.flush();
-		}
-#endif
-        pullData();											// Send PULL_DATA message to server
-		startReceiver();
-	
-		pulltime = nowSeconds;
-    }
-
-	
-	// If we do our own NTP handling (advisable)
-	// We do not use the timer interrupt but use the timing
-	// of the loop() itself which is better for SPI
-#if NTP_INTR==0
-	// Set the time in a manual way. Do not use setSyncProvider
-	// as this function may collide with SPI and other interrupts
-	yield();												// 26/12/2017
-	nowSeconds = now();
-	if (nowSeconds - ntptimer >= _NTP_INTERVAL) {
-		yield();
-		time_t newTime;
-		newTime = (time_t)getNtpTime();
-		if (newTime != 0) setTime(newTime);
-		ntptimer = nowSeconds;
-	}
-#endif
-	
-
-}//loop

+ 0 - 21
ESP-sc-gway/LICENSE.md

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg (mw12554@hotmail.com)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 0 - 21
ESP-sc-gway/LICENSE.txt

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2016-2019 Maarten Westenberg
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 0 - 372
ESP-sc-gway/_WiFi.ino

@@ -1,372 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the LoRa filesystem specific code
-
-// ----------------------------------------------------------------------------
-// WLANSTATUS prints the status of the Wlan.
-// The status of the Wlan "connection" can change if we have no relation
-// with the well known router anymore. Normally this relation is preserved
-// but sometimes we have to reconfirm to the router again and we get the same
-// address too.
-// So, if the router is still in range we can "survive" with the same address
-// and we may have to renew the "connection" from time to time.
-// But when we loose the SSID connection, we may have to look for another router.
-//
-// Parameters: <none>
-// Return value: Returns 1 when still WL_CONNETED, otherwise returns 0
-// ----------------------------------------------------------------------------
-int WlanStatus() {
-
-	switch (WiFi.status()) {
-		case WL_CONNECTED:
-#if DUSB>=1
-			if ( debug>=0 ) {
-				Serial.print(F("A WlanStatus:: CONNECTED to "));				// 3
-				Serial.println(WiFi.SSID());
-			}
-#endif
-			WiFi.setAutoReconnect(true);				// Reconenct to this AP if DISCONNECTED
-			return(1);
-			break;
-
-		// In case we get disconnected from the AP we loose the IP address.
-		// The ESP is configured to reconnect to the last router in memory.
-		case WL_DISCONNECTED:
-#if DUSB>=1
-			if ( debug>=0 ) {
-				Serial.print(F("A WlanStatus:: DISCONNECTED, IP="));			// 6
-				Serial.println(WiFi.localIP());
-			}
-#endif
-			//while (! WiFi.isConnected() ) {
-				// Wait
-				delay(1);
-			//}
-			return(0);
-			break;
-
-		// When still pocessing
-		case WL_IDLE_STATUS:
-#if DUSB>=1
-			if ( debug>=0 ) {
-				Serial.println(F("A WlanStatus:: IDLE"));					// 0
-			}
-#endif
-			break;
-		
-		// This code is generated as soonas the AP is out of range
-		// Whene detected, the program will search for a better AP in range
-		case WL_NO_SSID_AVAIL:
-#if DUSB>=1
-			if ( debug>=0 )
-				Serial.println(F("WlanStatus:: NO SSID"));					// 1
-#endif
-			break;
-			
-		case WL_CONNECT_FAILED:
-#if DUSB>=1
-			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: FAILED"));					// 4
-#endif
-			break;
-			
-		// Never seen this code
-		case WL_SCAN_COMPLETED:
-#if DUSB>=1
-			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: SCAN COMPLETE"));			// 2
-#endif
-			break;
-			
-		// Never seen this code
-		case WL_CONNECTION_LOST:
-#if DUSB>=1
-			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: LOST"));					// 5
-#endif
-			break;
-			
-		// This code is generated for example when WiFi.begin() has not been called
-		// before accessing WiFi functions
-		case WL_NO_SHIELD:
-#if DUSB>=1
-			if ( debug>=0 )
-				Serial.println(F("A WlanStatus:: WL_NO_SHIELD"));				// 
-#endif
-			break;
-			
-		default:
-#if DUSB>=1
-			if ( debug>=0 ) {
-				Serial.print(F("A WlanStatus Error:: code="));
-				Serial.println(WiFi.status());								// 255 means ERROR
-			}
-#endif
-			break;
-	}
-	return(-1);
-	
-} // WlanStatus
-
-// ----------------------------------------------------------------------------
-// config.txt is a text file that contains lines(!) with WPA configuration items
-// Each line contains an KEY vaue pair describing the gateway configuration
-//
-// ----------------------------------------------------------------------------
-int WlanReadWpa() {
-	
-	readConfig( CONFIGFILE, &gwayConfig);
-
-	if (gwayConfig.sf != (uint8_t) 0) sf = (sf_t) gwayConfig.sf;
-	ifreq = gwayConfig.ch;
-	debug = gwayConfig.debug;
-	pdebug = gwayConfig.pdebug;
-	_cad = gwayConfig.cad;
-	_hop = gwayConfig.hop;
-	gwayConfig.boots++;							// Every boot of the system we increase the reset
-	
-#if GATEWAYNODE==1
-	if (gwayConfig.fcnt != (uint8_t) 0) frameCount = gwayConfig.fcnt+10;
-#endif
-	
-#if WIFIMANAGER==1
-	String ssid=gwayConfig.ssid;
-	String pass=gwayConfig.pass;
-
-	char ssidBuf[ssid.length()+1];
-	ssid.toCharArray(ssidBuf,ssid.length()+1);
-	char passBuf[pass.length()+1];
-	pass.toCharArray(passBuf,pass.length()+1);
-	Serial.print(F("WlanReadWpa: ")); Serial.print(ssidBuf); Serial.print(F(", ")); Serial.println(passBuf);
-	
-	strcpy(wpa[0].login, ssidBuf);				// XXX changed from wpa[0][0] = ssidBuf
-	strcpy(wpa[0].passw, passBuf);
-	
-	Serial.print(F("WlanReadWpa: <")); 
-	Serial.print(wpa[0].login); 				// XXX
-	Serial.print(F(">, <")); 
-	Serial.print(wpa[0].passw);
-	Serial.println(F(">"));
-#endif
-
-}
-
-
-// ----------------------------------------------------------------------------
-// Print the WPA data of last WiFiManager to the config file
-// ----------------------------------------------------------------------------
-#if WIFIMANAGER==1
-int WlanWriteWpa( char* ssid, char *pass) {
-
-#if DUSB>=1
-	if (( debug >=0 ) && ( pdebug & P_MAIN )) {
-		Serial.print(F("M WlanWriteWpa:: ssid=")); 
-		Serial.print(ssid);
-		Serial.print(F(", pass=")); 
-		Serial.print(pass); 
-		Serial.println();
-	}
-#endif
-	// Version 3.3 use of config file
-	String s((char *) ssid);
-	gwayConfig.ssid = s;
-	
-	String p((char *) pass);
-	gwayConfig.pass = p;
-
-#if GATEWAYNODE==1	
-	gwayConfig.fcnt = frameCount;
-#endif
-	gwayConfig.ch = ifreq;
-	gwayConfig.sf = sf;
-	gwayConfig.cad = _cad;
-	gwayConfig.hop = _hop;
-	
-	writeConfig( CONFIGFILE, &gwayConfig);
-	return 1;
-}
-#endif
-
-
-
-// ----------------------------------------------------------------------------
-// Function to join the Wifi Network
-//	It is a matter of returning to the main loop() asap and make sure in next loop
-//	the reconnect is done first thing. By default the system will reconnect to the
-// samen SSID as it was connected to before.
-// Parameters:
-//		int maxTry: Number of retries we do:
-//		0: Used during Setup first CONNECT
-//		1: Try once and if unsuccessful return(1);
-//		x: Try x times
-//
-//  Returns:
-//		On failure: Return -1
-//		On connect: return 1
-//		On Disconnect state: return 0
-//
-//  XXX After a few retries, the ESP8266 should be reset. Note: Switching between 
-//	two SSID's does the trick. Rettrying the same SSID does not.
-//	Workaround is found below: Let the ESP8266 forget the SSID
-//
-//  NOTE: The Serial works only on debug setting and not on pdebug. This is 
-//	because WiFi problems would make webserver (which works on WiFi) useless.
-// ----------------------------------------------------------------------------
-int WlanConnect(int maxTry) {
-  
-#if WIFIMANAGER==1
-	WiFiManager wifiManager;
-#endif
-
-	unsigned char agains = 0;
-	unsigned char wpa_index = (WIFIMANAGER >0 ? 0 : 1);		// Skip over first record for WiFiManager
-
-	// The initial setup() call is done with parameter 0
-	// We clear the WiFi memory and start with previous AP.
-	//
-	if (maxTry==0) {
-		Serial.println(F("WlanConnect:: Init para 0"));
-		WiFi.persistent(false);
-		WiFi.mode(WIFI_OFF);   // this is a temporary line, to be removed after SDK update to 1.5.4
-		if (gwayConfig.ssid.length() >0) {
-			WiFi.begin(gwayConfig.ssid.c_str(), gwayConfig.pass.c_str());
-			delay(100);
-		}
-	}
-	
-	// So try to connect to WLAN as long as we are not connected.
-	// The try parameters tells us how many times we try before giving up
-	// Value 0 is reserved for setup() first time connect
-	int i=0;
-
-	while ( (WiFi.status() != WL_CONNECTED) && ( i<= maxTry ) )
-	{
-
-		// We try every SSID in wpa array until success
-		for (int j=wpa_index; (j< (sizeof(wpa)/sizeof(wpa[0]))) && (WiFi.status() != WL_CONNECTED ); j++)
-		{
-			// Start with well-known access points in the list
-			char *ssid		= wpa[j].login;
-			char *password	= wpa[j].passw;
-#if DUSB>=1
-			if (debug>=0)  {
-				Serial.print(i);
-				Serial.print(':');
-				Serial.print(j); 
-				Serial.print(':');
-				Serial.print(sizeof(wpa)/sizeof(wpa[0]));
-				Serial.print(F(". WiFi connect SSID=")); 
-				Serial.print(ssid);
-				if ( debug>=1 ) {
-					Serial.print(F(", pass="));
-					Serial.print(password);
-				}
-				Serial.println();
-			}
-#endif		
-			// Count the number of times we call WiFi.begin
-			gwayConfig.wifis++;
-
-
-
-			WiFi.mode(WIFI_STA);
-			delay(1000);
-			WiFi.begin(ssid, password);
-			delay(8000);
-			
-			// Check the connection status again, return values
-			// 1 = CONNECTED
-			// 0 = DISCONNECTED (will reconnect)
-			// -1 = No SSID or other cause			
-			int stat = WlanStatus();
-			if ( stat == 1) {
-				writeGwayCfg(CONFIGFILE);					// XXX Write configuration to SPIFFS
-				return(1);
-			}
-		
-			// We increase the time for connect but try the same SSID
-			// We try for 10 times
-			agains=1;
-			while (((WiFi.status()) != WL_CONNECTED) && (agains < 10)) {
-				agains++;
-				delay(agains*500);
-#if DUSB>=1
-				if ( debug>=0 ) {
-					Serial.print(".");
-				}
-#endif
-			}
-#if DUSB>=1
-			Serial.println();
-#endif		
-			//if ( WiFi.status() == WL_DISCONNECTED) return(0);				// XXX 180811 removed
-
-
-			// Make sure that we can connect to different AP's than 1
-			// this is a patch. Normally we connect to previous one.
-			WiFi.persistent(false);
-			WiFi.mode(WIFI_OFF);   // this is a temporary line, to be removed after SDK update to 1.5.4
-
-		} //for next WPA defined AP
-	  
-		i++;			// Number of times we try to connect
-	} //while
-
-	
-	// If we are not connected to a well known AP
-	// we can invoike WIFIMANAGER or else return unsuccessful.
-	if (WiFi.status() != WL_CONNECTED) {
-#if WIFIMANAGER==1
-#if DUSB>=1
-		Serial.println(F("Starting Access Point Mode"));
-		Serial.print(F("Connect Wifi to accesspoint: "));
-		Serial.print(AP_NAME);
-		Serial.print(F(" and connect to IP: 192.168.4.1"));
-		Serial.println();
-#endif
-		wifiManager.autoConnect(AP_NAME, AP_PASSWD );
-		//wifiManager.startConfigPortal(AP_NAME, AP_PASSWD );
-		// At this point, there IS a Wifi Access Point found and connected
-		// We must connect to the local SPIFFS storage to store the access point
-		//String s = WiFi.SSID();
-		//char ssidBuf[s.length()+1];
-		//s.toCharArray(ssidBuf,s.length()+1);
-		// Now look for the password
-		struct station_config sta_conf;
-		wifi_station_get_config(&sta_conf);
-
-		//WlanWriteWpa(ssidBuf, (char *)sta_conf.password);
-		WlanWriteWpa((char *)sta_conf.ssid, (char *)sta_conf.password);
-#else
-#if DUSB>=1
-		if (debug>=0) {
-			Serial.println(F("WlanConnect:: Not connected after all"));
-			Serial.print(F("WLAN retry="));
-			Serial.print(i);
-			Serial.print(F(" , stat="));
-			Serial.print(WiFi.status() );						// Status. 3 is WL_CONNECTED
-			Serial.println();
-		}
-#endif// DUSB
-		return(-1);
-#endif
-	}
-
-	yield();
-	return(1);
-}

+ 0 - 84
ESP-sc-gway/_gatewayMgt.ino

@@ -1,84 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg 
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-// and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg
-//
-// This file contains the functions to do management over UDP
-// We could make use of the LoRa message function for the Gateway sensor
-// itself. However the functions defined in this file are not sensor
-// functions and activating them through the LoRa interface would add
-// no value and make the code more complex.
-//
-// So advantage: Simple, and does not mess with TTN setup.
-//
-// Disadvantage of course is that you need to setup you own small backend
-// function to exchange messages with the gateway, as TTN won't do this.
-//
-// XXX But, if necessary we can always add this later.
-
-#if GATEWAYMGT==1
-
-#if !defined _THINGPORT
-#error "The management functions needs _THINGPORT defined (and not over _TTNPORT)"
-#endif
-
-
-
-// ----------------------------------------------------------------------------
-// This function gateway_mgt is called in the UDP Receive function after
-// all well-known LoRa Gateway messages are scanned.
-//
-// As part of this function, we will listen for another set of messages
-// that is defined in loraModem.h.
-// All opCodes start with 0x1y for at leaving opcodes 0x00 to 0x0F to the
-// pure Gateway protocol
-//
-// Incoming mesage format:
-//	buf[0]-buf[2], These are 0x00 or dont care
-//	buf[3], contains opcode
-//	buf[4]-buf[7], contains parameter max. 4 bytes.
-//
-// Upstream Message format:
-//
-// ----------------------------------------------------------------------------
-void gateway_mgt(uint8_t size, uint8_t *buff) {
-
-	uint8_t opcode = buff[3];
-	
-	switch (opcode) {
-		case MGT_RESET:
-			Serial.println(F("gateway_mgt:: RESET"));
-			// No further parameters, just reset the GWay
-			setup();								// Call the sketch setup function
-			// Send Ack to server
-			
-		break;
-		case MGT_SET_SF:
-			Serial.println(F("gateway_mgt:: SET SF"));
-			// byte [4] contains desired SF code (7 for SF7 and 12 for SF12)
-		break;
-		case MGT_SET_FREQ:
-			Serial.println(F("gateway_mgt:: SET FREQ"));
-			// Byte [4] contains index of Frequency
-		break;
-		default:
-			Serial.print(F("gateway_mgt:: Unknown UDP code=")); 
-			Serial.println(opcode);
-			return;
-		break;
-	}
-}
-
-#endif //GATEWAYMGT==1

+ 0 - 428
ESP-sc-gway/_loraFiles.ino

@@ -1,428 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0		
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the LoRa filesystem specific code
-
-
-// ============================================================================
-// LORA SPIFFS FILESYSTEM FUNCTIONS
-//
-// The LoRa supporting functions are in the section below
-
-// ----------------------------------------------------------------------------
-// Supporting function to readConfig
-// ----------------------------------------------------------------------------
-void id_print (String id, String val) {
-#if DUSB>=1
-	if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-		Serial.print(id);
-		Serial.print(F("=\t"));
-		Serial.println(val);
-	}
-#endif
-}
-
-// ----------------------------------------------------------------------------
-// INITCONFIG; Init the gateway configuration file
-// Espcecially when calling SPIFFS.format() the gateway is left in an init
-// which is not very well defined. This function will init some of the settings
-// to well known settings.
-// ----------------------------------------------------------------------------
-int initConfig(struct espGwayConfig *c) {
-	(*c).ch = 0;
-	(*c).sf = _SPREADING;
-	(*c).debug = 1;
-	(*c).pdebug = P_GUI;
-	(*c).cad = _CAD;
-	(*c).hop = false;
-	(*c).expert = false;
-}
-
-
-// ----------------------------------------------------------------------------
-// Read the gateway configuration file
-// ----------------------------------------------------------------------------
-int readConfig(const char *fn, struct espGwayConfig *c) {
-
-	int tries = 0;
-#if DUSB>=1
-	Serial.println(F("readConfig:: Starting "));
-#endif
-	if (!SPIFFS.exists(fn)) {
-#if DUSB>=1
-		if (( debug>=0 ) && ( pdebug & P_MAIN ))
-		Serial.print(F("M ERR:: readConfig, file="));
-		Serial.print(fn);
-		Serial.println(F(" does not exist .. Formatting"));
-#endif
-		SPIFFS.format();
-		initConfig(c);
-		return(-1);
-	}
-
-	File f = SPIFFS.open(fn, "r");
-	if (!f) {
-		Serial.println(F("ERROR:: SPIFFS open failed"));
-		return(-1);
-	}
-
-	while (f.available()) {
-		
-#if DUSB>=1
-		if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-			Serial.print('.');
-		}
-#endif
-		// If we wait for more than 10 times, reformat the filesystem
-		// We do this so that the system will be responsive (over OTA for example).
-		//
-		if (tries >= 10) {
-			f.close();
-#if DUSB>=1
-			if (( debug>=0 ) && ( pdebug & P_MAIN ))
-				Serial.println(F("Formatting"));
-#endif
-			SPIFFS.format();
-			initConfig(c);
-			f = SPIFFS.open(fn, "r");
-			tries = 0;
-		}
-		
-		String id =f.readStringUntil('=');						// C++ thing
-		String val=f.readStringUntil('\n');
-		
-		if (id == "SSID") {										// WiFi SSID
-			id_print(id, val);
-			(*c).ssid = val;									// val contains ssid, we do NO check
-		}
-		else if (id == "PASS") { 								// WiFi Password
-			id_print(id, val); 
-			(*c).pass = val;
-		}
-		else if (id == "CH") { 									// Frequency Channel
-			id_print(id,val); 
-			(*c).ch = (uint32_t) val.toInt();
-		}
-		else if (id == "SF") { 									// Spreading Factor
-			id_print(id, val);
-			(*c).sf = (uint32_t) val.toInt();
-		}
-		else if (id == "FCNT") {								// Frame Counter
-			id_print(id, val);
-			(*c).fcnt = (uint32_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
-			Serial.print(F("PDEBUG=")); Serial.println(val);
-			(*c).pdebug = (uint8_t) val.toInt();
-		}
-		else if (id == "CAD") {									// CAD setting
-			Serial.print(F("CAD=")); Serial.println(val);
-			(*c).cad = (uint8_t) val.toInt();
-		}
-		else if (id == "HOP") {									// HOP setting
-			Serial.print(F("HOP=")); Serial.println(val);
-			(*c).hop = (uint8_t) val.toInt();
-		}
-		else if (id == "BOOTS") {								// BOOTS setting
-			id_print(id, val);
-			(*c).boots = (uint8_t) val.toInt();
-		}
-		else if (id == "RESETS") {								// RESET setting
-			id_print(id, val);
-			(*c).resets = (uint8_t) val.toInt();
-		}
-		else if (id == "WIFIS") {								// WIFIS setting
-			id_print(id, val);
-			(*c).wifis = (uint8_t) val.toInt();
-		}
-		else if (id == "VIEWS") {								// VIEWS setting
-			id_print(id, val);
-			(*c).views = (uint8_t) val.toInt();
-		}
-		else if (id == "NODE") {								// NODE setting
-			id_print(id, val);
-			(*c).isNode = (uint8_t) val.toInt();
-		}
-		else if (id == "REFR") {								// REFR setting
-			id_print(id, val);
-			(*c).refresh = (uint8_t) val.toInt();
-		}
-		else if (id == "REENTS") {								// REENTS setting
-			id_print(id, val);
-			(*c).reents = (uint8_t) val.toInt();
-		}
-		else if (id == "NTPERR") {								// NTPERR setting
-			id_print(id, val);
-			(*c).ntpErr = (uint8_t) val.toInt();
-		}
-		else if (id == "NTPETIM") {								// NTPERR setting
-			id_print(id, val);
-			(*c).ntpErrTime = (uint32_t) val.toInt();
-		}
-		else if (id == "NTPS") {								// NTPS setting
-			id_print(id, val);
-			(*c).ntps = (uint8_t) val.toInt();
-		}
-		else if (id == "FILENO") {								// log FILENO setting
-			id_print(id, val);
-			(*c).logFileNo = (uint8_t) val.toInt();
-		}
-		else if (id == "FILEREC") {								// FILEREC setting
-			id_print(id, val);
-			(*c).logFileRec = (uint16_t) val.toInt();
-		}
-		else if (id == "FILENUM") {								// FILEREC setting
-			id_print(id, val);
-			(*c).logFileNum = (uint16_t) val.toInt();
-		}
-		else if (id == "EXPERT") {								// FILEREC setting
-			id_print(id, val);
-			(*c).expert = (uint8_t) val.toInt();
-		}
-		else {
-			tries++;
-		}
-	}
-	f.close();
-#if DUSB>=1
-	if (debug>=0) {
-		Serial.println('#');
-	}
-#endif
-	Serial.println();
-	return(1);
-}
-
-// ----------------------------------------------------------------------------
-// Write the current gateway configuration to SPIFFS. First copy all the
-// separate data items to the gwayConfig structure
-//
-// ----------------------------------------------------------------------------
-int writeGwayCfg(const char *fn) {
-
-	gwayConfig.ssid = WiFi.SSID();
-	gwayConfig.pass = WiFi.psk();						// XXX We should find a way to store the password too
-	gwayConfig.ch = ifreq;								// Frequency Index
-	gwayConfig.sf = (uint8_t) sf;						// Spreading Factor
-	gwayConfig.debug = debug;
-	gwayConfig.pdebug = pdebug;
-	gwayConfig.cad = _cad;
-	gwayConfig.hop = _hop;
-#if GATEWAYNODE==1
-	gwayConfig.fcnt = frameCount;
-#endif
-	return(writeConfig(fn, &gwayConfig));
-}
-
-// ----------------------------------------------------------------------------
-// Write the configuration as found in the espGwayConfig structure
-// to SPIFFS
-// Parameters:
-//		fn; Filename
-//		c; struct config
-// Returns:
-//		1 when successful, -1 on error
-// ----------------------------------------------------------------------------
-int writeConfig(const char *fn, struct espGwayConfig *c) {
-
-	if (!SPIFFS.exists(fn)) {
-		Serial.print("WARNING:: writeConfig, file not exists, formatting ");
-		SPIFFS.format();
-		initConfig(c);		// XXX make all initial declarations here if config vars need to have a value
-		Serial.println(fn);
-	}
-	File f = SPIFFS.open(fn, "w");
-	if (!f) {
-		Serial.print("ERROR:: writeConfig, open file=");
-		Serial.print(fn);
-		Serial.println();
-		return(-1);
-	}
-
-	f.print("SSID"); f.print('='); f.print((*c).ssid); f.print('\n'); 
-	f.print("PASS"); f.print('='); f.print((*c).pass); f.print('\n');
-	f.print("CH"); f.print('='); f.print((*c).ch); f.print('\n');
-	f.print("SF");   f.print('='); f.print((*c).sf);   f.print('\n');
-	f.print("FCNT"); f.print('='); f.print((*c).fcnt); f.print('\n');
-	f.print("DEBUG"); f.print('='); f.print((*c).debug); f.print('\n');
-	f.print("PDEBUG"); f.print('='); f.print((*c).pdebug); f.print('\n');
-	f.print("CAD");  f.print('='); f.print((*c).cad); f.print('\n');
-	f.print("HOP");  f.print('='); f.print((*c).hop); f.print('\n');
-	f.print("NODE");  f.print('='); f.print((*c).isNode); f.print('\n');
-	f.print("BOOTS");  f.print('='); f.print((*c).boots); f.print('\n');
-	f.print("RESETS");  f.print('='); f.print((*c).resets); f.print('\n');
-	f.print("WIFIS");  f.print('='); f.print((*c).wifis); f.print('\n');
-	f.print("VIEWS");  f.print('='); f.print((*c).views); f.print('\n');
-	f.print("REFR");  f.print('='); f.print((*c).refresh); f.print('\n');
-	f.print("REENTS");  f.print('='); f.print((*c).reents); f.print('\n');
-	f.print("NTPETIM");  f.print('='); f.print((*c).ntpErrTime); f.print('\n');
-	f.print("NTPERR");  f.print('='); f.print((*c).ntpErr); f.print('\n');
-	f.print("NTPS");  f.print('='); f.print((*c).ntps); f.print('\n');
-	f.print("FILEREC");  f.print('='); f.print((*c).logFileRec); f.print('\n');
-	f.print("FILENO");  f.print('='); f.print((*c).logFileNo); f.print('\n');
-	f.print("FILENUM");  f.print('='); f.print((*c).logFileNum); f.print('\n');
-	f.print("EXPERT");  f.print('='); f.print((*c).expert); f.print('\n');
-	
-	f.close();
-	return(1);
-}
-
-// ----------------------------------------------------------------------------
-// Add a line with statistics to the log.
-//
-// We put the check in the function to protect against calling 
-// the function without STAT_LOG being proper defined
-// ToDo: Store the fileNo and the fileRec in the status file to save for 
-// restarts
-// Parameters:
-//		line; char array with characters to write to log
-//		cnt;
-// Returns:
-//		<none>
-// ----------------------------------------------------------------------------
-void addLog(const unsigned char * line, int cnt) 
-{
-#if STAT_LOG==1
-	char fn[16];
-	
-	if (gwayConfig.logFileRec > LOGFILEREC) {		// Have to make define for this
-		gwayConfig.logFileRec = 0;					// In new logFile start with record 0
-		gwayConfig.logFileNo++;						// Increase file ID
-		gwayConfig.logFileNum++;					// Increase number of log files
-	}
-	gwayConfig.logFileRec++;
-	
-	// If we have too many logfies, delete the oldest
-	//
-	if (gwayConfig.logFileNum > LOGFILEMAX){
-		sprintf(fn,"/log-%d", gwayConfig.logFileNo - LOGFILEMAX);
-#if DUSB>=1
-		if (( debug>=0 ) && ( pdebug & P_GUI )) {
-			Serial.print(F("G addLog:: Too many logfile, deleting="));
-			Serial.println(fn);
-		}
-#endif
-		SPIFFS.remove(fn);
-		gwayConfig.logFileNum--;
-	}
-	
-	// Make sure we have the right fileno
-	sprintf(fn,"/log-%d", gwayConfig.logFileNo); 
-	
-	// If there is no SPIFFS, Error
-	// Make sure to write the config record/line also
-	if (!SPIFFS.exists(fn)) {
-#if DUSB>=1
-		if (( debug >= 1 ) && ( pdebug & P_GUI )) {
-			Serial.print(F("G ERROR:: addLog:: file="));
-			Serial.print(fn);
-			Serial.print(F(" does not exist .. rec="));
-			Serial.print(gwayConfig.logFileRec);
-			Serial.println();
-		}
-#endif
-	}
-	
-	File f = SPIFFS.open(fn, "a");
-	if (!f) {
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_GUI )) {
-			Serial.println("G file open failed=");
-			Serial.println(fn);
-		}
-#endif
-		return;									// If file open failed, return
-	}
-	
-	int i;
-#if DUSB>=1
-	if (( debug>=1 ) && ( pdebug & P_GUI )) {
-		Serial.print(F("G addLog:: fileno="));
-		Serial.print(gwayConfig.logFileNo);
-		Serial.print(F(", rec="));
-		Serial.print(gwayConfig.logFileRec);
-
-		Serial.print(F(": "));
-
-		for (i=0; i< 12; i++) {				// The first 12 bytes contain non printable characters
-			Serial.print(line[i],HEX);
-			Serial.print(' ');
-		}
-		Serial.print((char *) &line[i]);	// The rest if the buffer contains ascii
-
-		Serial.println();
-	}
-#endif //DUSB
-
-
-	for (i=0; i< 12; i++) {					// The first 12 bytes contain non printable characters
-	//	f.print(line[i],HEX);
-		f.print('*');
-	}
-	f.write(&(line[i]), cnt-12);				// write/append the line to the file
-	f.print('\n');
-	f.close();								// Close the file after appending to it
-
-#endif //STAT_LOG
-}
-
-// ----------------------------------------------------------------------------
-// Print (all) logfiles
-//
-// ----------------------------------------------------------------------------
-void printLog()
-{
-	char fn[16];
-	int i=0;
-#if DUSB>=1
-	while (i< LOGFILEMAX ) {
-		sprintf(fn,"/log-%d", gwayConfig.logFileNo - i);
-		if (!SPIFFS.exists(fn)) break;		// break the loop
-
-		// Open the file for reading
-		File f = SPIFFS.open(fn, "r");
-		
-		int j;
-		for (j=0; j<LOGFILEREC; j++) {
-			
-			String s=f.readStringUntil('\n');
-			if (s.length() == 0) break;
-
-			Serial.println(s.substring(12));			// Skip the first 12 Gateway specific binary characters
-			yield();
-		}
-		i++;
-	}
-#endif
-} //printLog
-
-
-// ----------------------------------------------------------------------------
-// listDir
-//	List the directory and put it in
-// ----------------------------------------------------------------------------
-void listDir(char * dir) 
-{
-#if DUSB>=1
-	
-#endif
-}
-

+ 0 - 1153
ESP-sc-gway/_loraModem.ino

@@ -1,1153 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the LoRa modem specific code enabling to receive
-// and transmit packages/messages.
-// ========================================================================================
-//
-//
-// ----------------------------------------------------------------------------------------
-// Variable definitions
-//
-//
-// ----------------------------------------------------------------------------------------
-
-
-
-//
-// ========================================================================================
-// SPI AND INTERRUPTS
-// The RFM96/SX1276 communicates with the ESP8266 by means of interrupts 
-// and SPI interface. The SPI interface is bidirectional and allows both
-// parties to simultaneous write and read to registers.
-// Major drawback is that access is not protected for interrupt and non-
-// interrupt access. This means that when a program in loop() and a program
-// in interrupt do access the readRegister and writeRegister() function
-// at the same time that probably an error will occur.
-// Therefore it is best to either not use interrupts AT all (like LMIC)
-// or only use these functions in interrupts and to further processing
-// in the main loop() program.
-//
-// ========================================================================================
-
-
-// ----------------------------------------------------------------------------------------
-// Mutex definitions
-//
-// ----------------------------------------------------------------------------------------
-#if MUTEX==1
-	void CreateMutux(int *mutex) {
-		*mutex=1;
-	}
-
-#define LIB_MUTEX 1
-#if LIB_MUTEX==1
-	bool GetMutex(int *mutex) {
-		//noInterrupts();
-		if (*mutex==1) { 
-			*mutex=0; 
-			//interrupts(); 
-			return(true); 
-		}
-		//interrupts();
-		return(false);
-	}
-#else	
-	bool GetMutex(int *mutex) {
-
-	int iOld = 1, iNew = 0;
-
-	asm volatile (
-		"rsil a15, 1\n"    // read and set interrupt level to 1
-		"l32i %0, %1, 0\n" // load value of mutex
-		"bne %0, %2, 1f\n" // compare with iOld, branch if not equal
-		"s32i %3, %1, 0\n" // store iNew in mutex
-		"1:\n"             // branch target
-		"wsr.ps a15\n"     // restore program state
-		"rsync\n"
-		: "=&r" (iOld)
-		: "r" (mutex), "r" (iOld), "r" (iNew)
-		: "a15", "memory"
-	);
-	return (bool)iOld;
-}
-#endif
-
-	void ReleaseMutex(int *mutex) {
-		*mutex=1;
-	}
-	
-#endif //MUTEX==1
-
-// ----------------------------------------------------------------------------------------
-// Read one byte value, par addr is address
-// Returns the value of register(addr)
-// 
-// The SS (Chip select) pin is used to make sure the RFM95 is selected
-// The variable is for obvious reasons valid for read and write traffic at the
-// same time. Since both read and write mean that we write to the SPI interface.
-// Parameters:
-//	Address: SPI address to read from. Type uint8_t
-// Return:
-//	Value read from address
-// ----------------------------------------------------------------------------------------
-
-// define the SPI settings for reading messages
-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);
-	uint8_t res = (uint8_t) SPI.transfer(0x00);
-    digitalWrite(pins.ss, HIGH);				// Unselect Receiver
-	SPI.endTransaction();
-    return((uint8_t) res);
-}
-
-
-// ----------------------------------------------------------------------------
-// Write value to a register with address addr. 
-// Function writes one byte at a time.
-// Parameters:
-//	addr: SPI address to write to
-//	value: The value to write to address
-// Returns:
-//	<void>
-// ----------------------------------------------------------------------------
-
-// define the settings for SPI writing
-SPISettings writeSettings(SPISPEED, MSBFIRST, SPI_MODE0);
-
-void writeRegister(uint8_t addr, uint8_t value)
-{
-	SPI.beginTransaction(writeSettings);
-	digitalWrite(pins.ss, LOW);					// Select Receiver
-	
-	SPI.transfer((addr | 0x80) & 0xFF);
-	SPI.transfer(value & 0xFF);
-	
-    digitalWrite(pins.ss, HIGH);				// Unselect Receiver
-	
-	SPI.endTransaction();
-}
-
-
-// ----------------------------------------------------------------------------
-// Write a buffer to a register with address addr. 
-// Function writes one byte at a time.
-// Parameters:
-//	addr: SPI address to write to
-//	value: The value to write to address
-// Returns:
-//	<void>
-// ----------------------------------------------------------------------------
-
-void writeBuffer(uint8_t addr, uint8_t *buf, uint8_t len)
-{
-	//noInterrupts();							// XXX
-	
-	SPI.beginTransaction(writeSettings);
-	digitalWrite(pins.ss, LOW);					// Select Receiver
-	
-	SPI.transfer((addr | 0x80) & 0xFF);			// write buffer address
-	for (uint8_t i=0; i<len; i++) {
-		SPI.transfer(buf[i] & 0xFF);
-	}
-    digitalWrite(pins.ss, HIGH);				// Unselect Receiver
-	
-	SPI.endTransaction();
-}
-
-// ----------------------------------------------------------------------------
-//  setRate is setting rate and spreading factor and CRC etc. for transmission
-//  for example
-//		Modem Config 1 (MC1) == 0x72 for sx1276
-//		Modem Config 2 (MC2) == (CRC_ON) | (sf<<4)
-//		Modem Config 3 (MC3) == 0x04 | (optional SF11/12 LOW DATA OPTIMIZE 0x08)
-//		sf == SF7 default 0x07, (SF7<<4) == SX72_MC2_SF7
-//		bw == 125 == 0x70
-//		cr == CR4/5 == 0x02
-//		CRC_ON == 0x04
-//
-//	sf is SF7 to SF12
-//	crc is 0x00 (off) or 
-// ----------------------------------------------------------------------------
-
-void setRate(uint8_t sf, uint8_t crc) 
-{
-	uint8_t mc1=0, mc2=0, mc3=0;
-#if DUSB>=2
-	if ((sf<SF7) || (sf>SF12)) {
-		if (( debug>=1 ) && ( pdebug & P_RADIO )) {
-			Serial.print(F("setRate:: SF="));
-			Serial.println(sf);
-		}
-		return;
-	}
-#endif
-	// Set rate based on Spreading Factor etc
-    if (sx1272) {
-		mc1= 0x0A;				// SX1276_MC1_BW_250 0x80 | SX1276_MC1_CR_4_5 0x02
-		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) { 
-			mc1= 0x0B; 
-		}			        
-    }
-	
-	// For sx1276 chips is the CRC ON is 
-	else {
-		uint8_t bw = 0;				// bw setting is in freqs[ifreq].dwnBw
-		uint8_t cr = 0;				// cr settings dependent on SF setting
-		//switch (
-		
-		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
-		}
-		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;
-    //    writeRegister(REG_PAYLOAD_LENGTH, getIh(LMIC.rps)); // required length
-    //}
-	
-	writeRegister(REG_MODEM_CONFIG1, (uint8_t) mc1);
-	writeRegister(REG_MODEM_CONFIG2, (uint8_t) mc2);
-	writeRegister(REG_MODEM_CONFIG3, (uint8_t) mc3);
-	
-	// Symbol timeout settings
-    if (sf == SF10 || sf == SF11 || sf == SF12) {
-        writeRegister(REG_SYMB_TIMEOUT_LSB, (uint8_t) 0x05);
-    } else {
-        writeRegister(REG_SYMB_TIMEOUT_LSB, (uint8_t) 0x08);
-    }
-	return;
-}
-
-
-// ----------------------------------------------------------------------------
-// Set the frequency for our gateway
-// The function has no parameter other than the freq setting used in init.
-// Since we are using a 1ch gateway this value is set fixed.
-// ----------------------------------------------------------------------------
-
-void  setFreq(uint32_t freq)
-{
-    // 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) );
-	
-	return;
-}
-
-
-// ----------------------------------------------------------------------------
-//	Set Power for our gateway
-// ----------------------------------------------------------------------------
-void setPow(uint8_t powe)
-{
-	if (powe >= 16) powe = 15;
-	//if (powe >= 15) powe = 14;
-	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
-	
-	// XXX Power settings for CFG_sx1272 are different
-	
-	return;
-}
-
-
-// ----------------------------------------------------------------------------
-// Used to set the radio to LoRa mode (transmitter)
-// Please note that this mode can only be set in SLEEP mode and not in Standby.
-// Also there should be not need to re-init this mode is set in the setup() 
-// function.
-// For high freqs (>860 MHz) we need to & with 0x08 otherwise with 0x00
-// ----------------------------------------------------------------------------
-
-//void ICACHE_RAM_ATTR opmodeLora()
-//{
-//#ifdef CFG_sx1276_radio
-//       uint8_t u = OPMODE_LORA | 0x80;   					// TBD: sx1276 high freq 
-//#else // SX-1272
-//	    uint8_t u = OPMODE_LORA | 0x08;
-//#endif
-//    writeRegister(REG_OPMODE, (uint8_t) u);
-//}
-
-
-// ----------------------------------------------------------------------------
-// Set the opmode to a value as defined on top
-// Values are 0x00 to 0x07
-// The value is set for the lowest 3 bits, the other bits are as before.
-// ----------------------------------------------------------------------------
-void  opmode(uint8_t mode)
-{
-	if (mode == OPMODE_LORA) 
-		writeRegister(REG_OPMODE, (uint8_t) mode);
-	else
-		writeRegister(REG_OPMODE, (uint8_t)((readRegister(REG_OPMODE) & ~OPMODE_MASK) | mode));
-}
-
-// ----------------------------------------------------------------------------
-// Hop to next frequency as defined by NUM_HOPS
-// This function should only be used for receiver operation. The current
-// receiver frequency is determined by ifreq index like so: freqs[ifreq] 
-// ----------------------------------------------------------------------------
-void hop() {
-
-	// 1. Set radio to standby
-	opmode(OPMODE_STANDBY);
-		
-	// 3. Set frequency based on value in freq		
-	ifreq = (ifreq + 1) % NUM_HOPS ;							// Increment the freq round robin
-	setFreq(freqs[ifreq].upFreq);
-	
-	// 4. Set spreading Factor
-	sf = SF7;													// Starting the new frequency 
-	setRate(sf, 0x40);											// set the sf to SF7 
-		
-	// Low Noise Amplifier used in receiver
-	writeRegister(REG_LNA, (uint8_t) LNA_MAX_GAIN);  			// 0x0C, 0x23
-	
-	// 7. set sync word
-	writeRegister(REG_SYNC_WORD, (uint8_t) 0x34);				// set 0x39 to 0x34 LORA_MAC_PREAMBLE
-	
-	// prevent node to node communication
-	writeRegister(REG_INVERTIQ,0x27);							// 0x33, 0x27; to reset from TX
-	
-	// Max Payload length is dependent on 256 byte buffer. At startup TX starts at
-	// 0x80 and RX at 0x00. RX therefore maximized at 128 Bytes
-	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_HOP_PERIOD,0x00);							// reg 0x24, set to 0x00
-
-	// 5. Config PA Ramp up time								// set reg 0x0A  
-	writeRegister(REG_PARAMP, (readRegister(REG_PARAMP) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
-	
-	// Set 0x4D PADAC for SX1276 ; XXX register is 0x5a for sx1272
-	writeRegister(REG_PADAC_SX1276,  0x84); 					// set 0x4D (PADAC) to 0x84
-	//writeRegister(REG_PADAC, readRegister(REG_PADAC) | 0x4);
-	
-	// 8. Reset interrupt Mask, enable all interrupts
-	writeRegister(REG_IRQ_FLAGS_MASK, 0x00);
-		
-	// 9. clear all radio IRQ flags
-    writeRegister(REG_IRQ_FLAGS, 0xFF);
-	
-	// Be aware that micros() has increased significantly from calling 
-	// the hop function until printed below
-	//
-#if DUSB>=1
-	if (( debug>=2 ) && ( pdebug & P_RADIO )){
-			Serial.print(F("hop:: hopTime:: "));
-			Serial.print(micros() - hopTime);
-			Serial.print(F(", "));
-			SerialStat(0);
-	}
-#endif
-	// Remember the last time we hop
-	hopTime = micros();									// At what time did we hop
-}
-	
-
-// ----------------------------------------------------------------------------
-// This LoRa function reads a message from the LoRa transceiver
-// on Success: returns message length read when message correctly received
-// on Failure: it returns a negative value on error (CRC error for example).
-// UP function
-// This is the "lowlevel" receive function called by stateMachine()
-// dealing with the radio specific LoRa functions
-//
-// Parameters:
-//		Payload: uint8_t[] message. when message is read it is returned in payload.
-// Returns:
-//		Length of payload received
-//
-// 9 bytes header
-// followed by data N bytes
-// 4 bytes MIC end
-// ----------------------------------------------------------------------------
-uint8_t receivePkt(uint8_t *payload)
-{
-    uint8_t irqflags = readRegister(REG_IRQ_FLAGS);			// 0x12; read back flags
-
-    statc.msg_ttl++;											// Receive statistics counter
-
-	uint8_t crcUsed = readRegister(REG_HOP_CHANNEL);
-	if (crcUsed & 0x40) {
-#if DUSB>=1
-		if (( debug>=2) && (pdebug & P_RX )) {
-			Serial.println(F("R rxPkt:: CRC used"));
-		}
-#endif
-	}
-	
-    //  Check for payload IRQ_LORA_CRCERR_MASK=0x20 set
-    if (irqflags & IRQ_LORA_CRCERR_MASK)
-    {
-#if DUSB>=1
-        if (( debug>=0) && ( pdebug & P_RADIO )) {
-			Serial.print(F("rxPkt:: Err CRC, ="));
-			SerialTime();
-			Serial.println();
-		}
-#endif
-		return 0;
-    }
-	
-	// Is header OK?
-	// Please note that if we reset the HEADER interrupt in RX,
-	// that we would here conclude that there is no HEADER
-	else if ((irqflags & IRQ_LORA_HEADER_MASK) == false)
-    {
-#if DUSB>=1
-        if (( debug>=0) && ( pdebug & P_RADIO )) {
-			Serial.println(F("rxPkt:: Err HEADER"));
-		}
-#endif
-		// Reset VALID-HEADER flag 0x10
-        writeRegister(REG_IRQ_FLAGS, (uint8_t)(IRQ_LORA_HEADER_MASK  | IRQ_LORA_RXDONE_MASK));	// 0x12; clear HEADER (== 0x10) flag
-        return 0;
-    }
-	
-	// If there are no error messages, read the buffer from the FIFO
-	// This means "Set FifoAddrPtr to FifoRxBaseAddr"
-	else {
-        statc.msg_ok++;													// Receive OK statistics counter
-		switch(statr[0].ch) {
-			case 0: statc.msg_ok_0++; break;
-			case 1: statc.msg_ok_1++; break;
-			case 2: statc.msg_ok_2++; break;
-		}
-
-		if (readRegister(REG_FIFO_RX_CURRENT_ADDR) != readRegister(REG_FIFO_RX_BASE_AD)) {
-			if (( debug>=0 ) && ( pdebug & P_RADIO )) {
-				Serial.print(F("RX BASE <"));
-				Serial.print(readRegister(REG_FIFO_RX_BASE_AD));
-				Serial.print(F("> != RX CURRENT <"));
-				Serial.print(readRegister(REG_FIFO_RX_CURRENT_ADDR));
-				Serial.print(F(">"));
-				Serial.println();
-			}
-		}
-		
-        //uint8_t currentAddr = readRegister(REG_FIFO_RX_CURRENT_ADDR);	// 0x10
-		uint8_t currentAddr = readRegister(REG_FIFO_RX_BASE_AD);		// 0x0F
-        uint8_t receivedCount = readRegister(REG_RX_NB_BYTES);			// 0x13; How many bytes were read
-#if DUSB>=1
-		if ((debug>=0) && (currentAddr > 64)) {
-			Serial.print(F("rxPkt:: Rx addr>64"));
-			Serial.println(currentAddr);
-		}
-#endif
-        writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) currentAddr);		// 0x0D 
-
-		if (receivedCount > PAYLOAD_LENGTH) {
-#if DUSB>=1
-			if (( debug>=0 ) & ( pdebug & P_RADIO )) {
-				Serial.print(F("rxPkt:: receivedCount="));
-				Serial.println(receivedCount);
-			}
-#endif
-			receivedCount=PAYLOAD_LENGTH;
-		}
-
-        for(int i=0; i < receivedCount; i++)
-        {
-            payload[i] = readRegister(REG_FIFO);			// 0x00, FIFO will auto shift register
-        }
-
-		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);		// Reset ALL interrupts
-		
-		// A long as DUSB is enabled, and RX debug messages are selected,
-		//the received packet is displayed on the output.
-#if DUSB>=1
-		if (( debug>=0 ) && ( pdebug & P_RX )){
-		
-			Serial.print(F("rxPkt:: t="));
-			SerialTime();
-			
-			Serial.print(F(", f="));
-			Serial.print(ifreq);
-			Serial.print(F(", sf="));
-			Serial.print(sf);
-			Serial.print(F(", a="));
-			if (payload[4]<0x10) Serial.print('0'); Serial.print(payload[4], HEX);
-			if (payload[3]<0x10) Serial.print('0'); Serial.print(payload[3], HEX);
-			if (payload[2]<0x10) Serial.print('0'); Serial.print(payload[2], HEX);
-			if (payload[1]<0x10) Serial.print('0'); Serial.print(payload[1], HEX);
-			Serial.print(F(", flags="));
-			Serial.print(irqflags,HEX);
-			Serial.print(F(", addr="));
-			Serial.print(currentAddr);
-			Serial.print(F(", len="));
-			Serial.print(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 (debug>=1)  {							// Must be 1 for operational use
-#if _TRUSTED_DECODE==2
-				int index;								// The index of the codex struct to decode
-				String response="";
-
-				uint8_t data[receivedCount];
-				
-				uint8_t DevAddr [4];
-					DevAddr[0] = payload[4];
-					DevAddr[1] = payload[3];
-					DevAddr[2] = payload[2];
-					DevAddr[3] = payload[1];
-				
-				if ((index = inDecodes((char *)(payload+1))) >=0 ) {
-					Serial.print(F(", Ind="));
-					Serial.print(index);
-					//Serial.println();
-				}
-				else if (debug>=1) {
-					Serial.print(F(", No Index"));
-					Serial.println();
-					return(receivedCount);
-				}	
-
-				// ------------------------------
-				
-				Serial.print(F(", data="));
-				for (int i=0; i<receivedCount; i++) { data[i] = payload[i]; }		// Copy array
-				
-				//for (int i=0; i<receivedCount; i++) {
-				//	if (payload[i]<=0xF) Serial.print('0');
-				//	Serial.print(payload[i], HEX);
-				//	Serial.print(' ');
-				//}
-
-
-
-				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');
-					Serial.print(DevAddr[i], HEX);
-					Serial.print(' ');
-				}
-				
-				Serial.print(F(", len="));
-				Serial.print(CodeLength);
-				Serial.print(F(", data="));
-
-				for (int i=0; i<receivedCount; i++) {
-					if (data[i]<=0xF) Serial.print('0');
-					Serial.print(data[i], HEX);
-					Serial.print(' ');
-				}
-#endif // _TRUSTED_DECODE
-			}
-			
-			Serial.println();
-			
-			if (debug>=2) Serial.flush();
-		}
-#endif //DUSB
-		return(receivedCount);
-    }
-
-	writeRegister(REG_IRQ_FLAGS, (uint8_t) (
-		IRQ_LORA_RXDONE_MASK | 
-		IRQ_LORA_RXTOUT_MASK |
-		IRQ_LORA_HEADER_MASK | 
-		IRQ_LORA_CRCERR_MASK));							// 0x12; Clear RxDone IRQ_LORA_RXDONE_MASK
-    return 0;
-} //receivePkt
-	
-	
-	
-// ----------------------------------------------------------------------------
-// This DOWN function sends a payload to the LoRa node over the air
-// Radio must go back in standby mode as soon as the transmission is finished
-// 
-// NOTE:: writeRegister functions should not be used outside interrupts
-// ----------------------------------------------------------------------------
-bool sendPkt(uint8_t *payLoad, uint8_t payLength)
-{
-#if DUSB>=2
-	if (payLength>=128) {
-		if (debug>=1) {
-			Serial.print("sendPkt:: len=");
-			Serial.println(payLength);
-		}
-		return false;
-	}
-#endif
-	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_TX_BASE_AD));	// 0x0D, 0x0E
-	
-	writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) payLength);				// 0x22
-	payLoad[payLength] = 0x00;
-	writeBuffer(REG_FIFO, (uint8_t *) payLoad, payLength);
-	return true;
-}
-
-// ----------------------------------------------------------------------------
-// loraWait()
-// This function implements the wait protocol needed for downstream transmissions.
-// Note: Timing of downstream and JoinAccept messages is VERY critical.
-//
-// As the ESP8266 watchdog will not like us to wait more than a few hundred
-// milliseconds (or it will kick in) we have to implement a simple way to wait
-// time in case we have to wait seconds before sending messages (e.g. for OTAA 5 or 6 seconds)
-// Without it, the system is known to crash in half of the cases it has to wait for 
-// JOIN-ACCEPT messages to send.
-//
-// This function uses a combination of delay() statements and delayMicroseconds().
-// As we use delay() only when there is still enough time to wait and we use micros()
-// to make sure that delay() did not take too much time this works.
-// 
-// Parameter: uint32-t tmst gives the micros() value when transmission should start. (!!!)
-// Note: We assume LoraDown.sfTx contains the SF we will use for downstream message.
-// ----------------------------------------------------------------------------
-
-void loraWait(const uint32_t timestamp)
-{
-	uint32_t startMics = micros();						// Start of the loraWait function
-	uint32_t tmst = timestamp;
-// XXX
-	int32_t adjust=0;
-	switch (LoraDown.sfTx) {
-		case 7: adjust= 60000; break;					// Make time for SF7 longer 
-		case 8: break;									// Around 60ms
-		case 9: break;
-		case 10: break;
-		case 11: break;
-		case 12: break;
-		default:
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_TX )) {
-			Serial.print(F("T loraWait:: unknown SF="));
-			Serial.print(LoraDown.sfTx);
-		}
-#endif
-		break;
-	}
-	tmst = tmst + txDelay + adjust;						// tmst based on txDelay and spreading factor
-	uint32_t waitTime = tmst - micros();				// Or make waitTime an unsigned and change next statement
-	if (micros()>tmst) {								// to (waitTime<0)
-		Serial.println(F("loraWait:: Error wait time < 0"));
-		return;
-	}
-	
-	// For larger delay times we use delay() since that is for > 15ms
-	// This is the most efficient way
-	while (waitTime > 16000) {
-		delay(15);										// ms delay including yield, slightly shorter
-		waitTime= tmst - micros();
-	}
-	// The remaining wait time is less tan 15000 uSecs
-	// And we use delayMicroseconds() to wait
-	if (waitTime>0) delayMicroseconds(waitTime);
-
-#if DUSB>=1
-	else if ((waitTime+20) < 0) {
-		Serial.println(F("loraWait:: TOO LATE"));		// Never happens
-	}
-
-	if (( debug>=2 ) && ( pdebug & P_TX )) { 
-		Serial.print(F("T start: ")); 
-		Serial.print(startMics);
-		Serial.print(F(", tmst: "));					// tmst
-		Serial.print(tmst);
-		Serial.print(F(", end: "));						// This must be micros(), and equal to tmst
-		Serial.print(micros());
-		Serial.print(F(", waited: "));
-		Serial.print(tmst - startMics);
-		Serial.print(F(", delay="));
-		Serial.print(txDelay);
-		Serial.println();
-		if (debug>=2) Serial.flush();
-	}
-#endif
-}
-
-
-// ----------------------------------------------------------------------------
-// txLoraModem
-// Init the transmitter and transmit the buffer
-// After successful transmission (dio0==1) TxDone re-init the receiver
-//
-//	crc is set to 0x00 for TX
-//	iiq is set to 0x27 (or 0x40 based on ipol value in txpkt)
-//
-//	1. opmode Lora (only in Sleep mode)
-//	2. opmode StandBY
-//	3. Configure Modem
-//	4. Configure Channel
-//	5. write PA Ramp
-//	6. config Power
-//	7. RegLoRaSyncWord LORA_MAC_PREAMBLE
-//	8. write REG dio mapping (dio0)
-//	9. write REG IRQ flags
-// 10. write REG IRQ mask
-// 11. write REG LoRa Fifo Base Address
-// 12. write REG LoRa Fifo Addr Ptr
-// 13. write REG LoRa Payload Length
-// 14. Write buffer (byte by byte)
-// 15. Wait until the right time to transmit has arrived
-// 16. opmode TX
-// ----------------------------------------------------------------------------
-
-void txLoraModem(
-				uint8_t *payLoad, 		// Payload contents
-				uint8_t payLength, 		// Length of payload
-				uint32_t tmst, 			// Timestamp
-				uint8_t sfTx,			// Sending spreading factor
-				uint8_t powe, 			// power
-				uint32_t freq, 			// frequency
-				uint8_t crc, 			// Do we use CRC error checking
-				uint8_t iiq				// Interrupt
-				)
-{
-#if DUSB>=2
-	if (debug>=1) {
-		// Make sure that all serial stuff is done before continuing
-		Serial.print(F("txLoraModem::"));
-		Serial.print(F("  powe: ")); Serial.print(powe);
-		Serial.print(F(", freq: ")); Serial.print(freq);
-		Serial.print(F(", crc: ")); Serial.print(crc);
-		Serial.print(F(", iiq: 0X")); Serial.print(iiq,HEX);
-		Serial.println();
-		if (debug>=2) Serial.flush();
-	}
-#endif
-	_state = S_TX;
-		
-	// 1. Select LoRa modem from sleep mode
-	//opmode(OPMODE_LORA);									// set register 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
-	
-	// 3. Init spreading factor and other Modem setting
-	setRate(sfTx, crc);
-	
-	// Frequency hopping
-	//writeRegister(REG_HOP_PERIOD, (uint8_t) 0x00);		// set 0x24 to 0x00 only for receivers
-	
-	// 4. Init Frequency, config channel
-	setFreq(freq);
-
-	// 6. Set power level, REG_PAC
-	setPow(powe);
-	
-	// 7. prevent node to node communication
-	writeRegister(REG_INVERTIQ, (uint8_t) iiq);					// 0x33, (0x27 or 0x40)
-	
-	// 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_CRC));
-	
-	// 9. clear all radio IRQ flags
-    writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
-	
-	// 10. mask all IRQs but TxDone
-    writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~IRQ_LORA_TXDONE_MASK);
-	
-	// txLora
-	opmode(OPMODE_FSTX);									// set 0x01 to 0x02 (actual value becomes 0x82)
-	
-	// 11, 12, 13, 14. write the buffer to the FiFo
-	sendPkt(payLoad, payLength);
-
-	// 15. wait extra delay out. The delayMicroseconds timer is accurate until 16383 uSec.
-	loraWait(tmst);
-	
-	//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) payLength);		// set 0x22, max 0x40==64Byte long
-	
-	//For TX we have to set the MAX_PAYLOAD_LENGTH
-	writeRegister(REG_MAX_PAYLOAD_LENGTH, (uint8_t) MAX_PAYLOAD_LENGTH);	// set 0x22, max 0x40==64Byte long
-	
-	// 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 0x12 to 0x08, clear TXDONE
-	
-	// 16. Initiate actual transmission of FiFo
-	opmode(OPMODE_TX);											// set 0x01 to 0x03 (actual value becomes 0x83)
-	
-}// txLoraModem
-
-
-// ----------------------------------------------------------------------------
-// Setup the LoRa receiver on the connected transceiver.
-// - Determine the correct transceiver type (sx1272/RFM92 or sx1276/RFM95)
-// - Set the frequency to listen to (1-channel remember)
-// - Set Spreading Factor (standard SF7)
-// The reset RST pin might not be necessary for at least the RFM95 transceiver
-//
-// 1. Put the radio in LoRa mode
-// 2. Put modem in sleep or in standby
-// 3. Set Frequency
-// 4. Spreading Factor
-// 5. Set interrupt mask
-// 6. Clear all interrupt flags
-// 7. Set opmode to OPMODE_RX
-// 8. Set _state to S_RX
-// 9. Reset all interrupts
-// ----------------------------------------------------------------------------
-
-void rxLoraModem()
-{
-	// 1. Put system in LoRa mode
-	//opmode(OPMODE_LORA);										// Is already so
-	
-	// 2. Put the radio in sleep mode
-	opmode(OPMODE_STANDBY);										// CAD set 0x01 to 0x00
-	
-	// 3. Set frequency based on value in freq
-	setFreq(freqs[ifreq].upFreq);										// set to the right frequency
-
-	// 4. Set spreading Factor and CRC
-    setRate(sf, 0x04);
-	
-	// prevent node to node communication
-	writeRegister(REG_INVERTIQ, (uint8_t) 0x27);				// 0x33, 0x27; to reset from TX
-	
-	// Max Payload length is dependent on 256 byte buffer. 
-	// At startup TX starts at 0x80 and RX at 0x00. RX therefore maximized at 128 Bytes
-	//For TX we have to set the PAYLOAD_LENGTH
-    //writeRegister(REG_PAYLOAD_LENGTH, (uint8_t) PAYLOAD_LENGTH);	// set 0x22, 0x40==64Byte long
-
-	// Set CRC Protection or MAX payload protection
-	//writeRegister(REG_MAX_PAYLOAD_LENGTH, (uint8_t) MAX_PAYLOAD_LENGTH);	// set 0x23 to 0x80==128
-	
-	//Set the start address for the FiFO (Which should be 0)
-	writeRegister(REG_FIFO_ADDR_PTR, (uint8_t) readRegister(REG_FIFO_RX_BASE_AD));	// set 0x0D to 0x0F (contains 0x00);
-	
-	// Low Noise Amplifier used in receiver
-	writeRegister(REG_LNA, (uint8_t) LNA_MAX_GAIN);  						// 0x0C, 0x23
-	
-	// 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_CRCERR_MASK));
-
-	// set frequency hopping
-	if (_hop) {
-		//writeRegister(REG_HOP_PERIOD, 0x01);					// 0x24, 0x01 was 0xFF
-		writeRegister(REG_HOP_PERIOD,0x00);						// 0x24, 0x00 was 0xFF
-	}
-	else {
-		writeRegister(REG_HOP_PERIOD,0x00);						// 0x24, 0x00 was 0xFF
-	}
-	// Set RXDONE interrupt to dio0
-	writeRegister(REG_DIO_MAPPING_1, (uint8_t)(
-			MAP_DIO0_LORA_RXDONE | 
-			MAP_DIO1_LORA_RXTOUT |
-			MAP_DIO2_LORA_NOP |			
-			MAP_DIO3_LORA_CRC));
-
-	// Set the opmode to either single or continuous receive. The first is used when
-	// every message can come on a different SF, the second when we have fixed SF
-	if (_cad) {
-		// cad Scanner setup, set _state to S_RX
-		// Set Single Receive Mode, goes in STANDBY mode after receipt
-		_state= S_RX;
-		opmode(OPMODE_RX_SINGLE);								// 0x80 | 0x06 (listen one message)
-	}
-	else {
-		// Set Continous Receive Mode, useful if we stay on one SF
-		_state= S_RX;
-		if (_hop) Serial.println(F("rxLoraModem:: ERROR continuous receive in hop mode"));
-		opmode(OPMODE_RX);										// 0x80 | 0x05 (listen)
-	}
-	
-	// 9. clear all radio IRQ flags
-    writeRegister(REG_IRQ_FLAGS, 0xFF);
-	
-	return;
-}// rxLoraModem
-
-
-// ----------------------------------------------------------------------------
-// function cadScanner()
-//
-// CAD Scanner will scan on the given channel for a valid Symbol/Preamble signal.
-// So instead of receiving continuous on a given channel/sf combination
-// we will wait on the given channel and scan for a preamble. Once received
-// we will set the radio to the SF with best rssi (indicating reception on that sf).
-// The function sets the _state to S_SCAN
-// NOTE: DO not set the frequency here but use the frequency hopper
-// ----------------------------------------------------------------------------
-void cadScanner()
-{
-	// 1. Put system in LoRa mode (which destroys all other modes)
-	//opmode(OPMODE_LORA);
-	
-	// 2. Put the radio in sleep mode
-	opmode(OPMODE_STANDBY);										// Was old value
-	
-	// 3. Set frequency based on value in ifreq					// XXX New, might be needed when receiving down 
-	setFreq(freqs[ifreq].upFreq);								// set to the right frequency
-
-	// For every time we start the scanner, we set the SF to the begin value
-	//sf = SF7;													// XXX 180501 Not by default
-	
-	// 4. Set spreading Factor and CRC
-	setRate(sf, 0x04);
-	
-	// listen to LORA_MAC_PREAMBLE
-	writeRegister(REG_SYNC_WORD, (uint8_t) 0x34);				// set reg 0x39 to 0x34
-	
-	// Set the interrupts we want to listen to
-	writeRegister(REG_DIO_MAPPING_1, (uint8_t)(
-		MAP_DIO0_LORA_CADDONE | 
-		MAP_DIO1_LORA_CADDETECT | 
-		MAP_DIO2_LORA_NOP | 
-		MAP_DIO3_LORA_CRC ));
-	
-	// Set the mask for interrupts (we do not want to listen to) except for
-	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) ~(
-		IRQ_LORA_CDDONE_MASK | 
-		IRQ_LORA_CDDETD_MASK | 
-		IRQ_LORA_CRCERR_MASK | 
-		IRQ_LORA_HEADER_MASK));
-	
-	// Set the opMode to CAD
-	opmode(OPMODE_CAD);
-
-	// Clear all relevant interrupts
-	//writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );						// May work better, clear ALL interrupts
-	
-	// If we are here. we either might have set the SF or we have a timeout in which
-	// case the receive is started just as normal.
-	return;
-	
-}// cadScanner
-
-
-// ----------------------------------------------------------------------------
-// First time initialisation of the LoRa modem
-// Subsequent changes to the modem state etc. done by txLoraModem or rxLoraModem
-// After initialisation the modem is put in rx mode (listen)
-// ----------------------------------------------------------------------------
-void initLoraModem(
-				)
-{
-	_state = S_INIT;
-#if ESP32_ARCH==1
-	digitalWrite(pins.rst, LOW);
-	delayMicroseconds(10000);
-    digitalWrite(pins.rst, HIGH);
-	delayMicroseconds(10000);
-	digitalWrite(pins.ss, HIGH);
-#if DUSB>=1
-
-#endif
-
-#else
-	// Reset the transceiver chip with a pulse of 10 mSec
-	digitalWrite(pins.rst, HIGH);
-	delayMicroseconds(10000);
-    digitalWrite(pins.rst, LOW);
-	delayMicroseconds(10000);
-#endif
-	// 2. Set radio to sleep
-	opmode(OPMODE_SLEEP);										// set register 0x01 to 0x00
-
-	// 1 Set LoRa Mode
-	opmode(OPMODE_LORA);										// set register 0x01 to 0x80
-	
-	// 3. Set frequency based on value in freq
-	setFreq(freqs[ifreq].upFreq);												// set to 868.1MHz or the last saved frequency
-	
-	// 4. Set spreading Factor
-    setRate(sf, 0x04);
-	
-	// Low Noise Amplifier used in receiver
-    writeRegister(REG_LNA, (uint8_t) LNA_MAX_GAIN);  			// 0x0C, 0x23
-#if _PIN_OUT==4
-	delay(1);
-#endif
-    uint8_t version = readRegister(REG_VERSION);				// Read the LoRa chip version id
-    if (version == 0x22) {
-        // sx1272
-#if DUSB>=2
-        Serial.println(F("WARNING:: SX1272 detected"));
-#endif
-        sx1272 = true;
-    } 
-	
-	else if (version == 0x12) {
-        // sx1276?
-#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
-		// Maybe this issue can be resolved of we try one of the other defined 
-		// boards. (Comresult or Hallard or ...)
-#if DUSB>=1
-		Serial.print(F("Unknown transceiver="));
-		Serial.print(version,HEX);
-		Serial.print(F(", pins.rst =")); Serial.print(pins.rst);
-		Serial.print(F(", pins.ss  =")); Serial.print(pins.ss);
-		Serial.print(F(", pins.dio0 =")); Serial.print(pins.dio0);
-		Serial.print(F(", pins.dio1 =")); Serial.print(pins.dio1);
-		Serial.print(F(", pins.dio2 =")); Serial.print(pins.dio2);
-		Serial.println();
-		Serial.flush();
-#endif
-		die("");												// Maybe first try another kind of receiver
-    }
-	// If we are here, the chip is recognized successfully
-	
-	// 7. set sync word
-	writeRegister(REG_SYNC_WORD, (uint8_t) 0x34);				// set 0x39 to 0x34 LORA_MAC_PREAMBLE
-	
-	// prevent node to node communication
-	writeRegister(REG_INVERTIQ,0x27);							// 0x33, 0x27; to reset from TX
-	
-	// Max Payload length is dependent on 256 byte buffer. At startup TX starts at
-	// 0x80 and RX at 0x00. RX therefore maximized at 128 Bytes
-	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_HOP_PERIOD,0x00);							// reg 0x24, set to 0x00
-
-	// 5. Config PA Ramp up time								// set reg 0x0A  
-	writeRegister(REG_PARAMP, (readRegister(REG_PARAMP) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
-	
-	// Set 0x4D PADAC for SX1276 ; XXX register is 0x5a for sx1272
-	writeRegister(REG_PADAC_SX1276,  0x84); 					// set 0x4D (PADAC) to 0x84
-	//writeRegister(REG_PADAC, readRegister(REG_PADAC) | 0x4);
-	
-	// Reset interrupt Mask, enable all interrupts
-	writeRegister(REG_IRQ_FLAGS_MASK, 0x00);
-	
-	// 9. clear all radio IRQ flags
-    writeRegister(REG_IRQ_FLAGS, 0xFF);
-}// initLoraModem
-
-
-// ----------------------------------------------------------------------------
-// Void function startReceiver.
-// This function starts the receiver loop of the LoRa service.
-// It starts the LoRa modem with initLoraModem(), and then starts
-// the receiver either in single message (CAD) of in continuous
-// reception (STD).
-// ----------------------------------------------------------------------------
-void startReceiver() {
-	initLoraModem();								// XXX 180326, after adapting this function 
-	if (_cad) {
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_SCAN )) {
-			Serial.println(F("S PULL:: _state set to S_SCAN"));
-			if (debug>=2) Serial.flush();
-		}
-#endif
-		_state = S_SCAN;
-		sf = SF7;
-		cadScanner();
-	}
-	else {
-		_state = S_RX;
-		rxLoraModem();
-	}
-	writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
-	writeRegister(REG_IRQ_FLAGS, 0xFF);				// Reset all interrupt flags
-}
-
-
-// ----------------------------------------------------------------------------
-// Interrupt_0 Handler.
-// Both interrupts DIO0 and DIO1 are mapped on GPIO15. Se we have to look at 
-// the interrupt flags to see which interrupt(s) are called.
-//
-// NOTE:: This method may work not as good as just using more GPIO pins on 
-//  the ESP8266 mcu. But in practice it works good enough
-// ----------------------------------------------------------------------------
-void ICACHE_RAM_ATTR Interrupt_0()
-{
-	_event=1;
-}
-
-
-// ----------------------------------------------------------------------------
-// Interrupt handler for DIO1 having High Value
-// As DIO0 and DIO1 may be multiplexed on one GPIO interrupt handler
-// (as we do) we have to be careful only to call the right Interrupt_x
-// handler and clear the corresponding interrupts for that dio.
-// NOTE: Make sure all Serial communication is only for debug level 3 and up.
-// Handler for:
-//		- CDDETD
-//		- RXTIMEOUT
-//		- (RXDONE error only)
-// ----------------------------------------------------------------------------
-void ICACHE_RAM_ATTR Interrupt_1()
-{
-	_event=1;
-}
-
-// ----------------------------------------------------------------------------
-// Frequency Hopping Channel (FHSS) dio2
-// ----------------------------------------------------------------------------
-void ICACHE_RAM_ATTR Interrupt_2() 
-{
-	_event=1;
-}
-
-

+ 0 - 100
ESP-sc-gway/_oLED.ino

@@ -1,100 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the state machine code enabling to receive
-// and transmit packages/messages.
-// ========================================================================================
-//
-
-#if OLED>=1
-
-
-// --------------------------------------------------------------------	
-// Initilize the OLED functions.
-// This function will init the OLED screenb. Depending on the 
-// availability of the reset button it will reset the display first.
-// --------------------------------------------------------------------
-void init_oLED() 
-{
-#if defined OLED_RST
-	pinMode(OLED_RST,OUTPUT);
-	digitalWrite(OLED_RST, LOW); 	// low to reset OLED
-	delay(100); 
-	digitalWrite(OLED_RST, HIGH); 	// must be high to turn on OLED
-	delay(50);
-#else
-#endif
-	// Initialising the UI will init the display too.
-	display.init();
-	delay(100);
-	//display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR, FALSE)
-	display.flipScreenVertically();
-	display.setFont(ArialMT_Plain_24);
-	display.setTextAlignment(TEXT_ALIGN_LEFT);
-	display.drawString(0, 24, "STARTING");
-	display.display();
-}
-
-// --------------------------------------------------------------------
-// Activate the OLED
-//
-// --------------------------------------------------------------------
-void acti_oLED() 
-{
-	// Initialising the UI will init the display too.
-	display.clear();
-	
-#if OLED==1
-	display.setFont(ArialMT_Plain_16);
-	display.drawString(0, 16, "READY,  SSID=");
-	display.drawString(0, 32, WiFi.SSID());
-#elif OLED==2
-	display.setFont(ArialMT_Plain_16);
-	display.drawString(0, 16, "READY,  SSID=");
-	display.drawString(0, 32, WiFi.SSID());
-#endif
-
-	display.display();
-}
-
-// --------------------------------------------------------------------
-// Print a message on the OLED.
-// Note: The whole message must fit in the buffer
-//
-// --------------------------------------------------------------------
-void msg_oLED(String tim, String sf) {
-    display.clear();
-    display.setFont(ArialMT_Plain_16);
-    display.setTextAlignment(TEXT_ALIGN_LEFT);
-	
-	display.drawString(0, 48, "LEN: " );
-//    display.drawString(40, 48, String((int)messageLength) );
-    display.display();
-	yield();
-}
-
-// --------------------------------------------------------------------
-// Print the OLED address in use
-//
-// --------------------------------------------------------------------
-void addr_oLED() 
-{
-	Serial.print(F("OLED_ADDR=0x"));
-	Serial.println(OLED_ADDR, HEX);
-}
-
-#endif

+ 0 - 121
ESP-sc-gway/_otaServer.ino

@@ -1,121 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the ota code for the ESP Single Channel Gateway.
-
-// Provide OTA server funcionality so the 1ch gateway can be updated 
-// over the air.
-// This code uses the ESPhttpServer functions to update the gateway.
-
-#if A_OTA==1
-
-//extern ArduinoOTAClass ArduinoOTA;
-
-// Make sure that webserver is running before continuing
-
-// ----------------------------------------------------------------------------
-// setupOta
-// Function to run in the setup() function to initialise the update function
-// ----------------------------------------------------------------------------
-void setupOta(char *hostname) {
-
-	ArduinoOTA.begin();
-#if DUSB>=1
-	Serial.println(F("setupOta:: Started"));
-#endif	
-	// Hostname defaults to esp8266-[ChipID]
-	ArduinoOTA.setHostname(hostname);
-	
-	ArduinoOTA.onStart([]() {
-		String type;
-		// XXX version mismatch of platform.io and ArduinoOtaa
-		// see https://github.com/esp8266/Arduino/issues/3020
-		//if (ArduinoOTA.getCommand() == U_FLASH)
-			type = "sketch";
-		//else // U_SPIFFS
-		//	type = "filesystem";
-
-		// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
-		Serial.println("Start updating " + type);
-	});
-	
-	ArduinoOTA.onEnd([]() {
-		Serial.println("\nEnd");
-	});
-	
-	ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
-		Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
-	});
-	
-	ArduinoOTA.onError([](ota_error_t error) {
-		Serial.printf("Error[%u]: ", error);
-		if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
-		else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
-		else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
-		else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
-		else if (error == OTA_END_ERROR) Serial.println("End Failed");
-	});
-	
-#if DUSB>=1
-	Serial.println("Ready");
-	Serial.print("IP address: ");
-	Serial.println(WiFi.localIP());
-#endif
-	
-	// Only if the Webserver is active also
-#if A_SERVER==2										// Displayed for the moment
-	ESPhttpUpdate.rebootOnUpdate(false);
-   
-	server.on("/esp", HTTP_POST, [&](){
-   
-      HTTPUpdateResult ret = ESPhttpUpdate.update(server.arg("firmware"), "1.0.0");
-	  
-      switch(ret) {
-        case HTTP_UPDATE_FAILED:
-            //PREi::sendJSON(500, "Update failed.");
-			Serial.println(F("Update failed"));
-            break;
-        case HTTP_UPDATE_NO_UPDATES:
-            //PREi::sendJSON(304, "Update not necessary.");
-			Serial.println(F("Update not necessary"));
-            break;
-        case HTTP_UPDATE_OK:
-            //PREi::sendJSON(200, "Update started.");
-			Serial.println(F("Update started"));
-            ESP.restart();
-            break;
-		default:
-			Serial.println(F("setupOta:: Unknown ret="));
-      }
-	});
-#endif
-}
-
-
-// ----------------------------------------------------------------------------
-// updateOtaa()
-//
-// ----------------------------------------------------------------------------
-void updateOtaa() {
-
-	String response="";
-	printIP((IPAddress)WiFi.localIP(),'.',response);
-	
-	ESPhttpUpdate.update(response, 80, "/arduino.bin");
-
-}
-
-
-#endif

+ 0 - 47
ESP-sc-gway/_repeater.ino

@@ -1,47 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg
-// Verison 6.1.0
-// Date: 2019-10-20
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains code for using the single channel gateway also as a repeater node. 
-// Please note that for node to node communication your should change the polarity
-// of messages.
-//
-// ============================================================================
-		
-#if _REPEATER==1
-
-// Define input channel and output channel
-#define _ICHAN 0
-#define _OCHAN 1
-
-#ifdef _TTNSERVER
-#error "Please undefined _THINGSERVER, for REPEATER shutdown WiFi"
-#endif
-
-// Send a LoRa message out from the gateway transmitter
-// XXX Maybe we should block the received ontul the message is transmitter
-
-int sendLora(char *msg, int len) {
-	// Check when len is not exceeding maximum length
-	Serial.print("sendLora:: ");
-	
-	for (int i=0; i< len; i++) {
-		Serial.print(msg[1],HEX);
-		Serial.print('.');
-	}
-	
-	if (debug>=2) Serial.flush();
-	return(1);
-}
-
-#endif //_REPEATER==1

+ 0 - 676
ESP-sc-gway/_sensor.ino

@@ -1,676 +0,0 @@
-// sensor.ino; 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg
-// Verison 6.1.0
-// Date: 2019-10-20
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains code for using the single channel gateway also as a sensor node. 
-// Please specify the DevAddr and the AppSKey below (and on your LoRa backend).
-// Also you will have to choose what sensors to forward to your application.
-//
-// Note: disable sensors not used in ESP-sc-gway.h
-//	- The GPS is included on TTGO T-Beam ESP32 boards by default.
-//	- The battery sensor works by connecting the VCC pin to A0 analog port
-// ============================================================================
-	
-#if GATEWAYNODE==1
-
-#include "LoRaCode.h"
-
-unsigned char DevAddr[4]  = _DEVADDR ;				// see ESP-sc-gway.h
-
-
-// Only used by GPS sensor code
-#if _GPS==1
-// ----------------------------------------------------------------------------
-// Smartdelay is a function to delay processing but in the loop get info 
-// from the GPS device
-// ----------------------------------------------------------------------------
-static void smartDelay(unsigned long ms)                
-{
-  unsigned long start = millis();
-  do
-  {
-    while (Serial1.available())
-      gps.encode(Serial1.read());
-  } while (millis() - start < ms);
-}
-#endif //_GPS
-
-
-
-
-
-// ----------------------------------------------------------------------------
-// LoRaSensors() is a function that puts sensor values in the MACPayload and 
-// sends these values up to the server. For the server it is impossible to know 
-// whther or not the message comes from a LoRa node or from the gateway.
-//
-// The example code below adds a battery value in lCode (encoding protocol) but
-// of-course you can add any byte string you wish
-//
-// Parameters: 
-//	- buf: contains the buffer to put the sensor values in (max==xx);
-// Returns:
-//	- The amount of sensor characters put in the buffer
-//
-// NOTE: The code in LoRaSensors() is provided as an example only.
-//	The amount of sensor values as well as their message layout may differ
-//	for each implementation.
-//	Also, the message format used by this gateway is LoraCode, a message format
-//	developed by me for sensor values. Each value is uniquely coded with an
-//	id and a value, and the total message contains its length (less than 64 bytes)
-//	and a parity value in byte[0] bit 7.
-// ----------------------------------------------------------------------------
-static int LoRaSensors(uint8_t *buf) {
-	
-	uint8_t tchars = 1;
-	buf[0] = 0x86;									// 134; User code <lCode + len==3 + Parity
-
-#if DUSB>=1
-	if (debug>=0)
-		Serial.print(F("LoRaSensors:: "));
-#endif
-
-#if _BATTERY==1
-#if DUSB>=1
-	if (debug>=0)
-		Serial.print(F("Battery "));
-#endif
-#if defined(ARDUINO_ARCH_ESP8266) || defined(ESP32)
-	// For ESP there is no standard battery library
-	// What we do is to measure GPIO35 pin which has a 100K voltage divider
-	pinMode(35, INPUT);
-#if defined(ESP32)
-	int devider=4095;
-#else
-	int devider=1023;
-#endif //ESP32
-	float volts=3.3 * analogRead(35) / 4095 * 2;	// T_Beam connects to GPIO35
-#else
-	// For ESP8266 no sensor defined
-	float volts=0;
-#endif
-	tchars += lcode.eBattery(volts, buf + tchars);
-#endif
-
-#if _GPS==1
-#if DUSB>=1
-	if (debug>=0)
-		Serial.print(F("M GPS "));
-
-	if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-		Serial.print("\tLatitude  : ");
-		Serial.println(gps.location.lat(), 5);
-		Serial.print("\tLongitude : ");
-		Serial.println(gps.location.lng(), 4);
-		Serial.print("\tSatellites: ");
-		Serial.println(gps.satellites.value());
-		Serial.print("\tAltitude  : ");
-		Serial.print(gps.altitude.feet() / 3.2808);
-		Serial.println("M");
-		Serial.print("\tTime      : ");
-		Serial.print(gps.time.hour());
-		Serial.print(":");
-		Serial.print(gps.time.minute());
-		Serial.print(":");
-		Serial.println(gps.time.second());
-	}
-#endif
-
-	smartDelay(1000);
-	
-	if (millis() > 5000 && gps.charsProcessed() < 10) {
-#if DUSB>=1
-		Serial.println(F("No GPS data received: check wiring"));
-#endif
-		return(0);
-	}
-	
-	// Assuming we have a value, put it in the buf
-	// The layout of this message is specific to the user,
-	// so adapt as needed.
-	tchars += lcode.eGpsL(gps.location.lat(), gps.location.lng(), gps.altitude.value(),
-                       gps.satellites.value(), buf + tchars);
-
-#endif
-
-#if DUSB>=1
-	if (debug>=0)
-		Serial.println();
-#endif
-
-	// If all sensor data is encoded, we encode the buffer	
-	lcode.eMsg(buf, tchars);								// Fill byte 0 with bytecount and Parity
-	
-	return(tchars);	// return the number of bytes added to payload
-}
-
-
-// ----------------------------------------------------------------------------
-// XOR()
-// perform x-or function for buffer and key
-// Since we do this ONLY for keys and X, Y we know that we need to XOR 16 bytes.
-//
-// ----------------------------------------------------------------------------
-static void mXor(uint8_t *buf, uint8_t *key) {
-	for (uint8_t i = 0; i < 16; ++i) buf[i] ^= key[i];
-}
-
-
-// ----------------------------------------------------------------------------
-// SHIFT-LEFT
-// Shift the buffer buf left one bit
-// Parameters:
-//	- buf: An array of uint8_t bytes
-//	- len: Length of the array in bytes
-// ----------------------------------------------------------------------------
-static void shift_left(uint8_t * buf, uint8_t len) {
-    while (len--) {
-        uint8_t next = len ? buf[1] : 0;			// len 0 to 15
-
-        uint8_t val = (*buf << 1);
-        if (next & 0x80) val |= 0x01;
-        *buf++ = val;
-    }
-}
-
-
-// ----------------------------------------------------------------------------
-// generate_subkey
-// RFC 4493, para 2.3
-// ----------------------------------------------------------------------------
-static void generate_subkey(uint8_t *key, uint8_t *k1, uint8_t *k2) {
-
-	memset(k1, 0, 16);								// Fill subkey1 with 0x00
-	
-	// Step 1: Assume k1 is an all zero block
-	AES_Encrypt(k1,key);
-	
-	// Step 2: Analyse outcome of Encrypt operation (in k1), generate k1
-	if (k1[0] & 0x80) {
-		shift_left(k1,16);
-		k1[15] ^= 0x87;
-	}
-	else {
-		shift_left(k1,16);
-	}
-	
-	// Step 3: Generate k2
-	for (uint8_t i=0; i<16; i++) k2[i]=k1[i];
-	if (k1[0] & 0x80) {								// use k1(==k2) according rfc 
-		shift_left(k2,16);
-		k2[15] ^= 0x87;
-	}
-	else {
-		shift_left(k2,16);
-	}
-	
-	// step 4: Done, return k1 and k2
-	return;
-}
-
-
-// ----------------------------------------------------------------------------
-// MICPACKET()
-// Provide a valid MIC 4-byte code (par 2.4 of spec, RFC4493)
-// 		see also https://tools.ietf.org/html/rfc4493
-//
-// Although our own handler may choose not to interpret the last 4 (MIC) bytes
-// of a PHYSPAYLOAD physical payload message of in internal sensor,
-// The official TTN (and other) backends will intrpret the complete message and
-// conclude that the generated message is bogus.
-// So we sill really simulate internal messages coming from the -1ch gateway
-// to come from a real sensor and append 4 MIC bytes to every message that are 
-// perfectly legimate
-// Parameters:
-//	- data:			uint8_t array of bytes = ( MHDR | FHDR | FPort | FRMPayload )
-//	- len:			8=bit length of data, normally less than 64 bytes
-//	- FrameCount:	16-bit framecounter
-//	- dir:			0=up, 1=down
-//
-// B0 = ( 0x49 | 4 x 0x00 | Dir | 4 x DevAddr | 4 x FCnt |  0x00 | len )
-// MIC is cmac [0:3] of ( aes128_cmac(NwkSKey, B0 | Data )
-//
-// ----------------------------------------------------------------------------
-uint8_t micPacket(uint8_t *data, uint8_t len, uint16_t FrameCount, uint8_t * NwkSKey, uint8_t dir) {
-
-
-	//uint8_t NwkSKey[16] = _NWKSKEY;
-	uint8_t Block_B[16];
-	uint8_t X[16];
-	uint8_t Y[16];
-	
-	// ------------------------------------
-	// build the B block used by the MIC process
-	Block_B[0]= 0x49;						// 1 byte MIC code
-			
-	Block_B[1]= 0x00;						// 4 byte 0x00
-	Block_B[2]= 0x00;
-	Block_B[3]= 0x00;
-	Block_B[4]= 0x00;
-	
-	Block_B[5]= dir;						// 1 byte Direction
-	
-	Block_B[6]= DevAddr[3];					// 4 byte DevAddr
-	Block_B[7]= DevAddr[2];
-	Block_B[8]= DevAddr[1];
-	Block_B[9]= DevAddr[0];
-	
-	Block_B[10]= (FrameCount & 0x00FF);		// 4 byte FCNT
-	Block_B[11]= ((FrameCount >> 8) & 0x00FF);
-	Block_B[12]= 0x00; 						// Frame counter upper Bytes
-	Block_B[13]= 0x00;						// These are not used so are 0
-	
-	Block_B[14]= 0x00;						// 1 byte 0x00
-	
-	Block_B[15]= len;						// 1 byte len
-	
-	// ------------------------------------
-	// Step 1: Generate the subkeys
-	//
-	uint8_t k1[16];
-	uint8_t k2[16];
-	generate_subkey(NwkSKey, k1, k2);
-	
-	// ------------------------------------
-	// Copy the data to a new buffer which is prepended with Block B0
-	//
-	uint8_t micBuf[len+16];					// B0 | data
-	for (uint8_t i=0; i<16; i++) micBuf[i]=Block_B[i];
-	for (uint8_t i=0; i<len; i++) micBuf[i+16]=data[i];
-	
-	// ------------------------------------
-	// Step 2: Calculate the number of blocks for CMAC
-	//
-	uint8_t numBlocks = len/16 + 1;			// Compensate for B0 block
-	if ((len % 16)!=0) numBlocks++;			// If we have only a part block, take it all
-	
-	// ------------------------------------
-	// Step 3: Calculate padding is necessary
-	//
-	uint8_t restBits = len%16;				// if numBlocks is not a multiple of 16 bytes
-	
-	
-	// ------------------------------------
-	// Step 5: Make a buffer of zeros
-	//
-	memset(X, 0, 16);
-	
-	// ------------------------------------
-	// Step 6: Do the actual encoding according to RFC
-	//
-	for(uint8_t i= 0x0; i < (numBlocks - 1); i++) {
-		for (uint8_t j=0; j<16; j++) Y[j] = micBuf[(i*16)+j];
-		mXor(Y, X);
-		AES_Encrypt(Y, NwkSKey);
-		for (uint8_t j=0; j<16; j++) X[j] = Y[j];
-	}
-	
-
-	// ------------------------------------
-	// Step 4: If there is a rest Block, padd it
-	// Last block. We move step 4 to the end as we need Y
-	// to compute the last block
-	// 
-	if (restBits) {
-		for (uint8_t i=0; i<16; i++) {
-			if (i< restBits) Y[i] = micBuf[((numBlocks-1)*16)+i];
-			if (i==restBits) Y[i] = 0x80;
-			if (i> restBits) Y[i] = 0x00;
-		}
-		mXor(Y, k2);
-	}
-	else {
-		for (uint8_t i=0; i<16; i++) {
-			Y[i] = micBuf[((numBlocks-1)*16)+i];
-		}
-		mXor(Y, k1);
-	}
-	mXor(Y, X);
-	AES_Encrypt(Y,NwkSKey);
-	
-	// ------------------------------------
-	// Step 7: done, return the MIC size. 
-	// Only 4 bytes are returned (32 bits), which is less than the RFC recommends.
-	// We return by appending 4 bytes to data, so there must be space in data array.
-	//
-	data[len+0]=Y[0];
-	data[len+1]=Y[1];
-	data[len+2]=Y[2];
-	data[len+3]=Y[3];
-	return 4;
-}
-
-
-#if _CHECK_MIC==1
-// ----------------------------------------------------------------------------
-// CHECKMIC
-// Function to check the MIC computed for existing messages and for new messages
-// Parameters:
-//	- buf: LoRa buffer to check in bytes, last 4 bytes contain the MIC
-//	- len: Length of buffer in bytes
-//	- key: Key to use for MIC. Normally this is the NwkSKey
-//
-// ----------------------------------------------------------------------------
-static void checkMic(uint8_t *buf, uint8_t len, uint8_t *key) {
-	uint8_t cBuf[len+1];
-	uint8_t NwkSKey[16] = _NWKSKEY;
-	
-	if (debug>=2) {
-		Serial.print(F("old="));
-		for (uint8_t i=0; i<len; i++) { 
-			printHexDigit(buf[i]); 
-			Serial.print(' '); 
-		}
-		Serial.println();
-	}	
-	for (uint8_t i=0; i<len-4; i++) cBuf[i] = buf[i];
-	len -=4;
-	
-	uint16_t FrameCount = ( cBuf[7] * 256 ) + cBuf[6];
-	len += micPacket(cBuf, len, FrameCount, NwkSKey, 0);
-	
-	if (debug>=2) {
-		Serial.print(F("new="));
-		for (uint8_t i=0; i<len; i++) { 
-			printHexDigit(cBuf[i]); 
-			Serial.print(' '); 
-		}
-		Serial.println();
-	}
-	// Mic is only checked, but len is not corrected
-}
-#endif //_CHECK_MIC
-
-// ----------------------------------------------------------------------------
-// SENSORPACKET
-// The gateway may also have local sensors that need reporting.
-// We will generate a message in gateway-UDP format for upStream messaging
-// so that for the backend server it seems like a LoRa node has reported a
-// sensor value.
-//
-// NOTE: We do not need ANY LoRa functions here since we are on the gateway.
-// We only need to send a gateway message upstream that looks like a node message.
-//
-// NOTE:: This function does encrypt the sensorpayload, and the backend
-//		picks it up fine as decoder thinks it is a MAC message.
-//
-// Par 4.0 LoraWan spec:
-//	PHYPayload =	( MHDR | MACPAYLOAD | MIC ) 
-// which is equal to
-//					( MHDR | ( FHDR | FPORT | FRMPAYLOAD ) | MIC )
-//
-//	This function makes the totalpackage and calculates MIC
-// The maximum size of the message is: 12 + ( 9 + 2 + 64 ) + 4	
-// So message size should be lass than 128 bytes if Payload is limited to 64 bytes.
-//
-// return value:
-//	- On success returns the number of bytes to send
-//	- On error returns -1
-// ----------------------------------------------------------------------------
-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;
-	uint32_t tmst = micros();
-	struct LoraUp LUP;
-	uint8_t NwkSKey[16] = _NWKSKEY;
-	uint8_t AppSKey[16] = _APPSKEY;
-	uint8_t DevAddr[4]  = _DEVADDR;
-	
-	// Init the other LoraUp fields
-	LUP.sf = 8;											// Send with SF8
-	LUP.prssi = -50;
-	LUP.rssicorr = 139;
-	LUP.snr = 0;
-	
-	// In the next few bytes the fake LoRa message must be put
-	// PHYPayload = MHDR | MACPAYLOAD | MIC
-	// MHDR, 1 byte
-	// MIC, 4 bytes
-	
-	// ------------------------------
-	// MHDR (Para 4.2), bit 5-7 MType, bit 2-4 RFU, bit 0-1 Major
-	LUP.payLoad[0] = 0x40;								// MHDR 0x40 == unconfirmed up message,
-														// FRU and major are 0
-	
-	// -------------------------------
-	// FHDR consists of 4 bytes addr, 1 byte Fctrl, 2 byte FCnt, 0-15 byte FOpts
-	// We support ABP addresses only for Gateways
-	LUP.payLoad[1] = DevAddr[3];						// Last byte[3] of address
-	LUP.payLoad[2] = DevAddr[2];
-	LUP.payLoad[3] = DevAddr[1];
-	LUP.payLoad[4] = DevAddr[0];						// First byte[0] of Dev_Addr
-	
-	LUP.payLoad[5] = 0x00;								// FCtrl is normally 0
-	LUP.payLoad[6] = frameCount % 0x100;				// LSB
-	LUP.payLoad[7] = frameCount / 0x100;				// MSB
-
-	// -------------------------------
-	// FPort, either 0 or 1 bytes. Must be != 0 for non MAC messages such as user payload
-	//
-	LUP.payLoad[8] = 0x01;								// FPort must not be 0
-	LUP.payLength  = 9;
-	
-	// FRMPayload; Payload will be AES128 encoded using AppSKey
-	// See LoRa spec para 4.3.2
-	// You can add any byte string below based on you personal choice of sensors etc.
-	//
-	
-	// Payload bytes in this example are encoded in the LoRaCode(c) format
-	uint8_t PayLength = LoRaSensors((uint8_t *)(LUP.payLoad + LUP.payLength));
-
-#if DUSB>=1
-	if ((debug>=2) && (pdebug & P_RADIO )) {
-		Serial.print(F("old: "));
-		for (int i=0; i<PayLength; i++) {
-			Serial.print(LUP.payLoad[i],HEX);
-			Serial.print(' ');
-		}
-		Serial.println();
-	}
-#endif	
-	
-	// 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.payLength), PayLength, (uint16_t)frameCount, DevAddr, AppSKey, 0);
-
-#if DUSB>=1
-	if ((debug>=2) && (pdebug & P_RADIO )) {
-		Serial.print(F("new: "));
-		for (int i=0; i<CodeLength; i++) {
-			Serial.print(LUP.payLoad[i],HEX);
-			Serial.print(' ');
-		}
-		Serial.println();
-	}
-#endif
-
-	LUP.payLength += CodeLength;								// length inclusive sensor data
-	
-	// MIC, Message Integrity Code
-	// As MIC is used by TTN (and others) we have to make sure that
-	// framecount is valid and the message is correctly encrypted.
-	// Note: Until MIC is done correctly, TTN does not receive these messages
-	//		 The last 4 bytes are MIC bytes.
-	//
-	LUP.payLength += micPacket((uint8_t *)(LUP.payLoad), LUP.payLength, (uint16_t)frameCount, NwkSKey, 0);
-
-#if DUSB>=1
-	if ((debug>=2) && (pdebug & P_RADIO )) {
-		Serial.print(F("mic: "));
-		for (int i=0; i<LUP.payLength; i++) {
-			Serial.print(LUP.payLoad[i],HEX);
-			Serial.print(' ');
-		}
-		Serial.println();
-	}
-#endif
-
-	// So now our package is ready, and we can send it up through the gateway interface
-	// Note Be aware that the sensor message (which is bytes) in message will be
-	// be expanded if the server expects JSON messages.
-	//
-	int buff_index = buildPacket(tmst, buff_up, LUP, true);
-	
-	frameCount++;
-    statc.msg_ttl++;				// XXX Should we count sensor messages as well?
-	switch(ifreq) {
-		case 0: statc.msg_ttl_0++; break;
-		case 1: statc.msg_ttl_1++; break;
-		case 2: statc.msg_ttl_2++; break;
-	}
-	
-	// In order to save the memory, we only write the framecounter
-	// to EEPROM every 10 values. It also means that we will invalidate
-	// 10 value when restarting the gateway.
-	//
-	if (( frameCount % 10)==0) writeGwayCfg(CONFIGFILE);
-	
-	if (buff_index > 512) {
-		if (debug>0) Serial.println(F("sensorPacket:: ERROR buffer size too large"));
-		return(-1);
-	}
-
-#ifdef _TTNSERVER	
-	if (!sendUdp(ttnServer, _TTNPORT, buff_up, buff_index)) {
-		return(-1);
-	}
-#endif
-#ifdef _THINGSERVER
-	if (!sendUdp(thingServer, _THINGPORT, buff_up, buff_index)) {
-		return(-1);
-	}
-#endif
-
-#if DUSB>=1
-	// If all is right, we should after decoding (which is the same as encoding) get
-	// the original message back again.
-	if ((debug>=2) && (pdebug & P_RADIO )) {
-		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);
-			Serial.print(' ');
-		}
-		Serial.print(F(", addr="));
-		for (int i=0; i<4; i++) {
-			Serial.print(DevAddr[i],HEX);
-			Serial.print(' ');
-		}
-		Serial.println();
-	}
-#endif
-
-	if (_cad) {
-		// Set the state to CAD scanning after sending a packet
-		_state = S_SCAN;						// Inititialise scanner
-		sf = SF7;
-		cadScanner();
-	}
-	else {
-		// Reset all RX lora stuff
-		_state = S_RX;
-		rxLoraModem();	
-	}
-		
-	return(buff_index);
-}
-
-#endif //GATEWAYNODE==1
-
-#if (GATEWAYNODE==1) || (_LOCALSERVER==1)
-// ----------------------------------------------------------------------------
-// ENCODEPACKET
-// In Sensor mode, we have to encode the user payload before sending.
-// The same applies to decoding packages in the payload for _LOCALSERVER.
-// The library files for AES are added to the library directory in AES.
-// For the moment we use the AES library made by ideetron as this library
-// is also used in the LMIC stack and is small in size.
-//
-// The function below follows the LoRa spec exactly.
-//
-// The resulting mumber of Bytes is returned by the functions. This means
-// 16 bytes per block, and as we add to the last block we also return 16
-// bytes for the last block.
-//
-// The LMIC code does not do this, so maybe we shorten the last block to only
-// the meaningful bytes in the last block. This means that encoded buffer
-// is exactly as big as the original message.
-//
-// NOTE:: Be aware that the LICENSE of the used AES library files 
-//	that we call with AES_Encrypt() is GPL3. It is used as-is,
-//  but not part of this code.
-//
-// cmac = aes128_encrypt(K, Block_A[i])
-// ----------------------------------------------------------------------------
-uint8_t encodePacket(uint8_t *Data, uint8_t DataLength, uint16_t FrameCount, uint8_t *DevAddr, uint8_t *AppSKey, uint8_t Direction) {
-
-#if DUSB>=1
-	if (( debug>=2 ) && ( pdebug & P_GUI )) {
-		Serial.print(F("G encodePacket:: DevAddr="));
-		for (int i=0; i<4; i++ ) { Serial.print(DevAddr[i],HEX); Serial.print(' '); }
-		Serial.print(F("G encodePacket:: AppSKey="));
-		for (int i=0; i<16; i++ ) { Serial.print(AppSKey[i],HEX); Serial.print(' '); }
-		Serial.println();
-	}
-#endif
-
-	//unsigned char AppSKey[16] = _APPSKEY ;	// see ESP-sc-gway.h
-	uint8_t i, j;
-	uint8_t Block_A[16];
-	uint8_t bLen=16;						// Block length is 16 except for last block in message
-		
-	uint8_t restLength = DataLength % 16;	// We work in blocks of 16 bytes, this is the rest
-	uint8_t numBlocks  = DataLength / 16;	// Number of whole blocks to encrypt
-	if (restLength>0) numBlocks++;			// And add block for the rest if any
-
-	for(i = 1; i <= numBlocks; i++) {
-		Block_A[0] = 0x01;
-		
-		Block_A[1] = 0x00; 
-		Block_A[2] = 0x00; 
-		Block_A[3] = 0x00; 
-		Block_A[4] = 0x00;
-
-		Block_A[5] = Direction;				// 0 is uplink
-
-		Block_A[6] = DevAddr[3];			// Only works for and with ABP
-		Block_A[7] = DevAddr[2];
-		Block_A[8] = DevAddr[1];
-		Block_A[9] = DevAddr[0];
-
-		Block_A[10] = (FrameCount & 0x00FF);
-		Block_A[11] = ((FrameCount >> 8) & 0x00FF);
-		Block_A[12] = 0x00; 				// Frame counter upper Bytes
-		Block_A[13] = 0x00;					// These are not used so are 0
-
-		Block_A[14] = 0x00;
-
-		Block_A[15] = i;
-
-		// Encrypt and calculate the S
-		AES_Encrypt(Block_A, AppSKey);
-		
-		// Last block? set bLen to rest
-		if ((i == numBlocks) && (restLength>0)) bLen = restLength;
-		
-		for(j = 0; j < bLen; j++) {
-			*Data = *Data ^ Block_A[j];
-			Data++;
-		}
-	}
-	//return(numBlocks*16);			// Do we really want to return all 16 bytes in lastblock
-	return(DataLength);				// or only 16*(numBlocks-1)+bLen;
-}
-
-#endif

+ 0 - 950
ESP-sc-gway/_stateMachine.ino

@@ -1,950 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the state machine code enabling to receive
-// and transmit packages/messages.
-// ============================================================================================
-//
-
-
-// --------------------------------------------------------------------------------------------
-// stateMachine handler of the state machine.
-// We use ONE state machine for all kind of interrupts. This assures that we take
-// the correct action upon receiving an interrupt.
-//
-// _event is the software interrupt: If set this function is executed from loop(),
-// the function should itself take care of setting or resetting the variable.
-//
-// STATE MACHINE
-// The program uses the following state machine (in _state), all states
-// are done in interrupt routine, only the follow-up of S-RXDONE is done
-// in the main loop() program. This is because otherwise the interrupt processing
-// would take too long to finish
-//
-// So _state has one of the following state values:
-//
-// S-INIT=0, 	The commands in this state are executed only once
-//	- Goto S_SCAN
-//
-// S-SCAN, 		CadScanner() part
-//	- Upon CDDECT (int1) goto S_RX, 
-//	- upon CDDONE (int0) goto S_CAD, walk through all SF until CDDETD
-//	- Else stay in SCAN state
-//
-// S-CAD, 		
-//	- Upon CDDECT (int1) goto S_RX, 
-//	- Upon CDDONE (int0) goto S_SCAN, start with SF7 recognition again
-//
-// S-RX, 		Received CDDECT so message detected, RX cycle started. 
-//	- Upon RXDONE (int0) package read. If read ok continue to read message
-//	- upon RXTOUT (int1) error, goto S_SCAN
-//
-// S-TX			Transmitting a message
-//	- Upon TXDONE goto S_SCAN
-//
-// S-TXDONE		Transmission complete by loop() now again in interrupt
-//	- Set the Mask
-//	- reset the Flags
-//	- Goto either SCAN or RX
-//
-// This interrupt routine has been kept as simple and short as possible.
-// If we receive an interrupt that does not belong to a _state then print error.
-// _event is a special variable which indicate that an interrupt event has happened
-// and we need to take action OR that we generate a soft interrupt for state machine.
-// 
-// NOTE: We may clear the interrupt but leave the flag for the moment. 
-//	The eventHandler should take care of repairing flags between interrupts.
-// --------------------------------------------------------------------------------------------
-
-void stateMachine()
-{
-	// Determine what interrupt flags are set
-	//
-	uint8_t flags = readRegister(REG_IRQ_FLAGS);
-	uint8_t mask  = readRegister(REG_IRQ_FLAGS_MASK);
-	uint8_t intr  = flags & ( ~ mask );							// Only react on non masked interrupts
-	uint8_t rssi;
-	_event=0;													// Reset the interrupt detector	
-	
-#if DUSB>=1
-	if (intr != flags) {
-		Serial.print(F("FLAG  ::"));
-		SerialStat(intr);
-	}
-#endif
-
-	// If Hopping is selected AND if there is NO event interrupt detected 
-	// and the state machine is called anyway
-	// then we know its a soft interrupt and we do nothing and return to main loop.
-	//
-	if ((_hop) && (intr == 0x00) )
-	{
-		// eventWait is the time since we have had a CDDETD event (preamble detected)
-		// If we are not in scanning state, and there will be an interrupt coming,
-		// In state S_RX it could be RXDONE in which case allow kernel time
-		//
-		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;
-				default:
-					eventWait=0;
-#if DUSB>=1
-					Serial.print(F("DEFAULT :: "));
-					SerialStat(intr);
-#endif
-			}
-			
-			// 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
-			// Assume symbols in SF8 take twice the time of SF7
-			//
-			uint32_t doneWait = DONE_WAIT;						// Initial value
-			switch (sf) {
-				case SF7: 	break;
-				case SF8: 	doneWait *= 2;	break;
-				case SF9: 	doneWait *= 4;	break;
-				case SF10:	doneWait *= 8;	break;
-				case SF11:	doneWait *= 16;	break;
-				case SF12:	doneWait *= 32;	break;
-				default:
-					doneWait *= 1;
-#if DUSB>=1
-					if (( debug>=0 ) && ( pdebug & P_PRE )) {
-						Serial.print(F("PRE:: DEF set"));
-						Serial.println();
-					}
-#endif
-					break;
-			}
-
-			// If micros is starting over again after 51 minutes 
-			// it's value is smaller than an earlier value of eventTime/doneTime
-			//
-			if (eventTime > micros())	eventTime=micros();
-			if (doneTime > micros())	doneTime=micros();
-
-			if (((micros() - doneTime) > doneWait ) &&
-				(( _state == S_SCAN ) || ( _state == S_CAD )))
-			{
-				_state = S_SCAN;
-				hop();											// increment ifreq = (ifreq + 1) % NUM_HOPS ;
-				cadScanner();									// Reset to initial SF, leave frequency "freqs[ifreq]"
-#if DUSB>=1
-				if (( debug >= 1 ) && ( pdebug & P_PRE )) {
-					Serial.print(F("DONE  :: "));
-					SerialStat(intr);
-				}
-#endif
-				eventTime=micros();								// reset the timer on timeout
-				doneTime=micros();								// reset the timer on timeout
-				return;
-			}
-			// If timeout occurs and still no _event, then hop
-			// and start scanning again
-			//
-			if ((micros() - eventTime) > eventWait ) 
-			{
-				_state = S_SCAN;
-				hop();											// increment ifreq = (ifreq + 1) % NUM_HOPS ;
-				cadScanner();									// Reset to initial SF, leave frequency "freqs[ifreq]"
-#if DUSB>=1
-				if (( debug >= 2 ) && ( pdebug & P_PRE )) {
-					Serial.print(F("HOP ::  "));
-					SerialStat(intr);
-				}
-#endif
-				eventTime=micros();								// reset the timer on timeout
-				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
-#if DUSB>=1
-			if (( debug>=3 ) && ( pdebug & P_PRE )) {
-				Serial.print(F("PRE:: eventTime="));
-				Serial.print(eventTime);
-				Serial.print(F(", micros="));
-				Serial.print(micros());
-				Serial.print(F(": "));
-				SerialStat(intr);
-			}
-#endif
-		} // if SCAN or CAD
-		
-		// else, S_RX of S_TX for example
-		else {
-			//yield();												// May take too much time for RX
-		} // else S_RX or S_TX, TXDONE
-		
-		yield();
-		
-	}// intr==0 && _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
-	// simulate and generate events ourselves.
-	//
-	switch (_state) 
-	{
-	  // ----------------------------------------------------------------------------------------
-	  // If the state is init, we are starting up.
-	  // The initLoraModem() function is already called in setup();
-	  //
-	  case S_INIT:
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_PRE )) { 
-			Serial.println(F("S_INIT")); 
-		}
-#endif
-		// 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
-		_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.
-	  // If so find the right SF with CDDETD. 
-	  //
-	  case S_SCAN:
-	    //
-		// Intr==IRQ_LORA_CDDETD_MASK
-		// We detected a message on this frequency and SF when scanning
-		// We clear both CDDETD and swich to reading state to read the message
-		//
-		if (intr & IRQ_LORA_CDDETD_MASK) {
-
-			_state = S_RX;											// Set state to receiving
-
-			// Set RXDONE interrupt to dio0, RXTOUT to dio1
-			writeRegister(REG_DIO_MAPPING_1, (
-				MAP_DIO0_LORA_RXDONE | 
-				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) ~(
-				IRQ_LORA_RXDONE_MASK | 
-				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 (_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 DUSB>=1
-			if (( debug>=1 ) && ( pdebug & P_SCAN )) {
-				Serial.print(F("SCAN:: "));
-				SerialStat(intr);
-			}
-#endif
-			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF );			// reset all interrupt flags
-			opmode(OPMODE_RX_SINGLE);								// set reg 0x01 to 0x06 for receiving
-			
-		}//if
-
-		// CDDONE
-		// We received a CDDONE int telling us that we received a message on this
-		// frequency and possibly on one of its SF. Only when the incoming message
-		// matches the SF then also CDDETD is raised.
-		// If so, we switch to CAD state where we will wait for CDDETD event.
-		//
-		else if (intr & IRQ_LORA_CDDONE_MASK) {
-
-			opmode(OPMODE_CAD);
-			rssi = readRegister(REG_RSSI);							// Read the RSSI
-
-#if DUSB>=1
-			if (( debug>=2 ) && ( pdebug & P_SCAN )) {
-				Serial.print(F("SCAN:: CDDONE: "));
-				SerialStat(intr);
-			}
-#endif
-			// We choose the generic RSSI as a sorting mechanism for packages/messages
-			// The pRSSI (package RSSI) is calculated upon successful reception of message
-			// So we expect that this value makes little sense for the moment with CDDONE.
-			// Set the rssi as low as the noise floor. Lower values are not recognized then.
-			// Every cycle starts with ifreq==0 and sf=SF7 (or the set init SF)
-			//
-			//if ( rssi > RSSI_LIMIT )								// Is set to 35
-			if ( rssi > (RSSI_LIMIT - (_hop * 7)))					// Is set to 35, or 29 for HOP
-			{
-#if DUSB>=1
-				if (( debug>=2 ) && ( pdebug & P_SCAN )) {
-					Serial.print(F("SCAN:: -> CAD: "));
-					SerialStat(intr);
-				}
-#endif
-				_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 {
-#if DUSB>=1
-				if (( debug>=2 ) && ( pdebug & P_SCAN )) {
-					Serial.print("SCAN:: rssi=");
-					Serial.print(rssi);
-					Serial.print(F(": "));
-					SerialStat(intr);
-				}
-#endif
-				_state = S_SCAN;
-				//_event=1;											// loop() scan until CDDONE
-			}
-
-			// Clear the CADDONE flag
-			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
-			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
-			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 _hop we change the frequency and restart the
-		// interrupt in order to check for CDONE on other frequencies
-		// if _hop we start at the next frequency, hop () sets the sf to SF7.
-		// If we are at the end of all frequencies, reset frequencies and sf
-		// and go to S_SCAN state.
-		//
-		// Note:: We should make sure that all frequencies are scanned in a row
-		// and when we switch to ifreq==0 we should stop for a while
-		// to allow system processing.
-		// We should make sure that we enable webserver etc every once in a while.
-		// We do this by changing _event to 1 in loop() only for _hop and
-		// use _event=0 for non hop.
-		//
-		else if (intr == 0x00) 
-		{
-			_event=0;												// XXX 26/12/2017 !!! NEED
-		}
-		
-		// Unkown Interrupt, so we have an error
-		//
-		else {
-#if DUSB>=1
-			if (( debug>=0 ) && ( pdebug & P_SCAN )) {
-				Serial.print(F("SCAN unknown:: "));
-				SerialStat(intr);
-			}
-#endif
-			_state=S_SCAN;
-			//_event=1;												// XXX 06/03 loop until interrupt
-			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
-	  // on the frequency but may be on another SF.
-	  //
-	  // If message is of the right frequency and SF, IRQ_LORA_CDDETD_MSAK interrupt
-	  // is raised, indicating that we can start beging reading the message from SPI.
-	  //
-	  // DIO0 interrupt IRQ_LORA_CDDONE_MASK in state S_CAD==2 means that we might have
-	  // a lock on the Freq but not the right SF. So we increase the SF
-	  //
-	  case S_CAD:
-
-		// Intr=IRQ_LORA_CDDETD_MASK
-		// We have to set the sf based on a strong RSSI for this channel
-		// Also we set the state to S_RX and start receiving the message
-		//
-		if (intr & IRQ_LORA_CDDETD_MASK) {
-
-			// Set RXDONE interrupt to dio0, RXTOUT to dio1
-			writeRegister(REG_DIO_MAPPING_1, (
-				MAP_DIO0_LORA_RXDONE | 
-				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
-			_rssi = rssi;											// Read the RSSI in the state variable
-
-			detTime = micros();
-#if DUSB>=1
-			if (( debug>=1 ) && ( pdebug & P_CAD )) {
-				Serial.print(F("CAD:: "));
-				SerialStat(intr);
-			}
-#endif
-			_state = S_RX;											// Set state to start receiving
-			
-		}// CDDETD
-		
-		// Intr == CADDONE
-		// So we scan this SF and if not high enough ... next
-		//
-		else if (intr & IRQ_LORA_CDDONE_MASK) {
-			// If this is not the max SF, increment the SF and try again
-			// Depending on the frequency scheme this is for example SF8, SF10 or SF12
-			// We expect on other SF get CDDETD
-			//
-			if (((uint8_t)sf) < freqs[ifreq].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
-
-#if DUSB>=1
-				if (( debug>=2 ) && ( pdebug & P_CAD )) {
-					Serial.print(F("S_CAD:: CDONE, SF="));
-					Serial.println(sf);
-				}
-#endif
-			}
-
-			// If we reach the highest SF for the frequency plan,
-			// we should go back to SCAN state
-			//
-			else {
-
-				// Reset Interrupts
-				_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[ifreq].upLo;
-				cadScanner();										// Which will reset SF to lowest SF
-
-#if DUSB>=1		
-				if (( debug>=2 ) && ( pdebug & P_CAD )) {
-					Serial.print(F("CAD->SCAN:: "));
-					SerialStat(intr);
-				}
-#endif
-			}
-			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
-		// This means _event was set but there was no real interrupt (yet).
-		// So we clear _event and wait for next (soft) interrupt.
-		// We stay in the CAD state because CDDONE means something is 
-		// coming on this frequency so we wait on CDECT.
-		//
-		else if (intr == 0x00) {
-#if DUSB>=0
-			if (( debug>=3 ) && ( pdebug & P_CAD )) {
-				Serial.println("Err CAD:: intr is 0x00");
-			}
-#endif
-			_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 even start at ifreq==1
-		//
-		else {
-#if DUSB>=1
-			if (( debug>=0) && ( pdebug & P_CAD )) { 
-				Serial.print(F("Err CAD: Unknown::")); 
-				SerialStat(intr);
-			}
-#endif
-			_state = S_SCAN;
-				sf = SF7;
-				cadScanner();										// Scan and set SF7
-			
-			// Reset Interrupts
-			_event=1;												// If unknown interrupt, restarts
-			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);		// Reset the interrupt mask
-			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// Reset all interrupts
-
-		}
-	  break; //S_CAD
-	  
-	  // ----------------------------------------------------------------------------------------
-	  // If we receive an RXDONE interrupt on dio0 with state==S_RX
-	  // 	So we should handle the received message
-	  // Else if it is RXTOUT interrupt
-	  //	So we handle this, and get modem out of standby
-	  // Else
-	  //	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.
-			// Could be CRC error or message too large.
-			// CRC error checking requires DIO3
-			//
-			if (intr & IRQ_LORA_CRCERR_MASK) {
-#if DUSB>=1
-				if (( debug>=0 ) && ( pdebug & P_RX )) {
-					Serial.print(F("Rx CRC err: "));
-					SerialStat(intr);
-				}
-#endif
-				if (_cad) {
-					sf = SF7;
-					_state = S_SCAN;
-					cadScanner();
-				}
-				else {
-					_state = S_RX;
-					rxLoraModem();
-				}
-
-				// Reset interrupts
-				_event=0;												// CRC error
-				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);		// Reset the interrupt mask
-				writeRegister(REG_IRQ_FLAGS, (uint8_t)(
-					IRQ_LORA_RXDONE_MASK | 
-					IRQ_LORA_RXTOUT_MASK | 
-					IRQ_LORA_HEADER_MASK | 
-					IRQ_LORA_CRCERR_MASK ));
-
-				break;
-			}// RX-CRC
-#endif // CRCCHECK
-			
-			// If we are here, no CRC error occurred, start timer
-#if DUSB>=1
-			unsigned long ffTime = micros();	
-#endif			
-			// There should not be an error in the message
-			LoraUp.payLoad[0]= 0x00;									// Empty the message
-
-			// If receive S_RX error, 
-			// - print Error message
-			// - Set _state to SCAN
-			// - Set _event=1 so that we loop until we have an interrupt
-			// - Reset the interrupts
-			// - break
-			if((LoraUp.payLength = receivePkt(LoraUp.payLoad)) <= 0) {
-#if DUSB>=1
-				if (( debug>=1 ) && ( pdebug & P_RX )) {
-					Serial.print(F("sMachine:: Error S-RX: "));
-					Serial.print(F("payLength="));
-					Serial.print(LoraUp.payLength);
-					Serial.println();
-				}
-#endif
-				_event=1;
-				writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);	// Reset the interrupt mask
-				//writeRegister(REG_IRQ_FLAGS, (uint8_t)(
-				//	IRQ_LORA_RXDONE_MASK | 
-				//	IRQ_LORA_RXTOUT_MASK | 
-				//	IRQ_LORA_HEADER_MASK | 
-				//	IRQ_LORA_CRCERR_MASK ));
-				writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);
-				
-				_state = S_SCAN;
-				break;
-			}
-#if DUSB>=1
-			if (( debug>=1 ) && ( pdebug & P_RX )) {
-				Serial.print(F("R RXDONE in dT="));
-				Serial.print(ffTime - detTime);
-				Serial.print(F(": "));
-				SerialStat(intr);
-			}
-#endif
-				
-			// 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
-				
-				value = ( ( ~value + 1 ) & 0xFF ) >> 2;				// Invert and divide by 4
-				LoraUp.snr = -value;
-			}
-			else {
-				// Divide by 4
-				LoraUp.snr = ( value & 0xFF ) >> 2;
-			}
-
-			// 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
-			//
-			if (receivePacket() <= 0) {								// read is not successful
-#if DUSB>=1
-				if (( debug>=0 ) && ( pdebug & P_RX )) {
-					Serial.println(F("sMach:: Error receivePacket"));
-				}
-#endif
-			}
-			
-			// Set the modem to receiving BEFORE going back to user space.
-			// 
-			if ((_cad) || (_hop)) {
-				_state = S_SCAN;
-				sf = SF7;
-				cadScanner();
-			}
-			else {
-				_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
-		// that receiving has started too late in the middle of a message
-		// (according to the documentation). So is there a way to start receiving
-		// 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
-			//
-			if ((_cad) || (_hop)) {
-				// Set the state to CAD scanning
-#if DUSB>=1
-				if (( debug>=2 ) && ( pdebug & P_RX )) {
-					Serial.print(F("RXTOUT:: "));
-					SerialStat(intr);
-				}
-#endif
-				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
-			//writeRegister(REG_IRQ_FLAGS, IRQ_LORA_HEADER_MASK);
-#if DUSB>=1
-			if (( debug>=3 ) && ( pdebug & P_RX )) {
-				Serial.print(F("RX HEADER:: "));
-				SerialStat(intr);
-			}
-#endif
-			//_event=1;
-		}
-
-		// If we did not receive a hard interrupt
-		// Then probably do not do anything, because in the S_RX
-		// state there always comes a RXTOUT or RXDONE interrupt
-		//
-		else if (intr == 0x00) {
-#if DUSB>=1
-			if (( debug>=3) && ( pdebug & P_RX )) {
-				Serial.print(F("S_RX no INTR:: "));
-				SerialStat(intr);
-			}
-#endif
-		}
-		
-		// The interrupt received is not RXDONE, RXTOUT or HEADER
-		// therefore we wait. Make sure to clear the interrupt
-		// as HEADER interrupt comes just before RXDONE
-		else {							
-#if DUSB>=1
-			if (( debug>=0 ) && ( pdebug & P_RX )) {
-				Serial.print(F("R S_RX:: no RXDONE, RXTOUT, HEADER:: "));
-				SerialStat(intr);
-			}
-#endif
-			//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
-	  // This is not an interrupt state, we use this state to start transmission
-	  // the interrupt TX-DONE tells us that the transmission was successful.
-	  // It therefore is no use to set _event==1 as transmission might
-	  // not be finished in the next loop iteration
-	  //
-	  case S_TX:
-	  
-		// We need a timeout for this case. In case there does not come an interrupt,
-		// then there will nog be a TXDONE but probably another CDDONE/CDDETD before
-		// we have a timeout in the main program (Keep Alive)
-		if (intr == 0x00) {
-#if DUSB>=1
-			if (( debug>=2 ) && ( pdebug & P_TX )) {
-				Serial.println(F("TX:: 0x00"));
-			}
-#endif
-			_event=1;
-			_state=S_TXDONE;
-		}
-
-		// Set state to transmit
-		_state = S_TXDONE;
-		
-		// 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 Interrupt space)
-		// We react on ALL interrupts if we are in TX state.
-		txLoraModem(
-			LoraDown.payLoad,
-			LoraDown.payLength,
-			LoraDown.tmst,
-			LoraDown.sfTx,
-			LoraDown.powe,
-			LoraDown.fff,
-			LoraDown.crc,
-			LoraDown.iiq
-		);
-		// After filling the buffer we only react on TXDONE interrupt
-		
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_TX )) { 
-			Serial.print(F("T TX done:: ")); 
-			SerialStat(intr);
-		}
-#endif
-		// More or less start at the "case TXDONE:" below 
-		_state=S_TXDONE;
-		_event=1;													// Or remove the break below
-		
-	  break; // S_TX
-
-	  
-	  // ----------------------------------------------------------------------------------------
-	  // After the transmission is completed by the hardware, 
-	  // the interrupt TXDONE is raised telling us that the tranmission
-	  // was successful.
-	  // If we receive an interrupt on dio0 _state==S_TX it is a TxDone interrupt
-	  // Do nothing with the interrupt, it is just an indication.
-	  // send Packet switch back to scanner mode after transmission finished OK
-	  //
-	  case S_TXDONE:
-		if (intr & IRQ_LORA_TXDONE_MASK) {
-
-#if DUSB>=1
-			if (( debug>=0 ) && ( pdebug & P_TX )) {
-				Serial.print(F("T TXDONE:: rcvd="));
-				Serial.print(micros());
-				Serial.print(F(", diff="));
-				Serial.println(micros()-LoraDown.tmst);
-				if (debug>=2) Serial.flush();
-			}
-#endif
-			// After transmission reset to receiver
-			if ((_cad) || (_hop)) {									// XXX 26/02
-				// Set the state to CAD scanning
-				_state = S_SCAN;
-				sf = SF7;
-				cadScanner();										// Start the scanner after TX cycle
-			}
-			else {
-				_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 DUSB>=1
-			if (( debug>=1 ) && ( pdebug & P_TX )) {
-				Serial.println(F("T TXDONE:: done OK"));
-			}
-#endif
-		}
-		
-		// If a soft _event==0 interrupt and no transmission finished:
-		else if ( intr != 0 ) {
-#if DUSB>=1
-			if (( debug>=0 ) && ( pdebug & P_TX )) {
-				Serial.print(F("T TXDONE:: unknown int:"));
-				SerialStat(intr);
-			}
-#endif
-			writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
-			writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);			// reset interrupt flags
-			_event=0;
-			_state=S_SCAN;
-		}
-		
-		// intr == 0
-		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 )) {
-#if DUSB>=1
-				if (( debug>=1 ) && ( pdebug & P_TX )) {
-					Serial.println(F("T TXDONE:: reset TX"));
-					Serial.flush();
-				}
-#endif
-				startReceiver();
-			}
-#if DUSB>=1
-			if (( debug>=3 ) && ( pdebug & P_TX )) {
-				Serial.println(F("T TXDONE:: No Interrupt"));
-			}
-#endif
-		}
-	
-
-	  break; // S_TXDONE	  
-
-	  
-	  // ----------------------------------------------------------------------------------------
-	  // If _STATE is in an undefined state
-	  // If such a thing happens, we should re-init the interface and 
-	  // make sure that we pick up next interrupt
-	  default:
-#if DUSB>=1
-		if (( debug>=0) && ( pdebug & P_PRE )) { 
-			Serial.print("ERR state="); 
-			Serial.println(_state);	
-		}
-#endif
-		if ((_cad) || (_hop)) {
-#if DUSB>=1
-			if (debug>=0) {
-				Serial.println(F("default:: Unknown _state "));
-				SerialStat(intr);
-			}
-#endif
-			_state = S_SCAN;
-			sf = SF7;
-			cadScanner();											// Restart the state machine
-			_event=0;									
-		}
-		else														// Single channel AND single SF
-		{
-			_state = S_RX;
-			rxLoraModem();
-			_event=0;
-		}
-		writeRegister(REG_IRQ_FLAGS_MASK, (uint8_t) 0x00);
-		writeRegister(REG_IRQ_FLAGS, (uint8_t) 0xFF);				// Reset all interrupts
-		eventTime=micros();											// Reset event for unkonwn state
-		
-	  break;// default
-	}// switch(_state)
-	
-	return;
-}

+ 0 - 67
ESP-sc-gway/_tcpTTN.ino

@@ -1,67 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// Description:
-//	_tcpTTN.ino: 
-//
-// This file contains the tcp specific code enabling to receive
-// and transmit packages/messages to the TTN server using their new protocol.
-//
-// The TTN code has been developed as an alternative to the Semtech UDP code.
-// According to the TTN website the Semtech gateway interface code is less secure and 
-// works on UDP which is less reliable. The new protocol of TTN should solve these issues.
-//
-// Initial look at the code of TTN shows that it is overly complex and not written for C++
-// or other languages (except for Go). The old Semtech protocol may be too simple but
-// the new code is a brainiac.
-// As of half 2018 the code is on hold. Some does work, but acording to the documentation 
-// it should be simpler to use.
-//
-// ========================================================================================
-
-#if defined(_TTNROUTER)
-#if defined(_UDPROUTER)
-#error "Error: Please undefine _UDPROUTER if you like to use _TTNROUTER"
-#endif
-
-// The following functions ae defined in this modue:
-//
-// int readTtn(int Packetsize)
-// int sendTtn(IPAddress server, int port, uint8_t *msg, int length)
-// bool connectTtn()
-// void pullData()
-// void sendstat();
-
-// Add gateway code of functions here
-
-void connectTtn() {
-#error "Error: Please define and use _UDPROUTER instead of _TTNROUTER"
-}
-
-int readTtn(int Packetsize) {
-#error "Error: Please define and use _UDPROUTER instead of _TTNROUTER"
-}
-
-int sendTtn(IPAddress server, int port, uint8_t *msg, int length) {
-#error "Error: Please define and use _UDPROUTER instead of _TTNROUTER"
-}
-
-
-
-
-
-#endif// _TTNROUTER

+ 0 - 744
ESP-sc-gway/_txRx.ino

@@ -1,744 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the LoRa modem specific code enabling to receive
-// and transmit packages/messages.
-// ========================================================================================
-
-
-
-// ----------------------------------------------------------------------------
-// DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN 
-// Send DOWN a LoRa packet over the air to the node. This function does all the 
-// decoding of the server message and prepares a Payload buffer.
-// The payload is actually transmitted by the sendPkt() function.
-// This function is used for regular downstream messages and for JOIN_ACCEPT
-// messages.
-// NOTE: This is not an interrupt function, but is started by loop().
-// The _status is set an the end of the function to TX and in _stateMachine
-// function the actual transmission function is executed.
-// The LoraDown.tmst contains the timestamp that the tranmission should finish.
-// ----------------------------------------------------------------------------
-int sendPacket(uint8_t *buf, uint8_t length) 
-{
-	// Received package with Meta Data (for example):
-	// codr	: "4/5"
-	// data	: "Kuc5CSwJ7/a5JgPHrP29X9K6kf/Vs5kU6g=="	// for example
-	// freq	: 868.1 									// 868100000
-	// ipol	: true/false
-	// modu : "LORA"
-	// powe	: 14										// Set by default
-	// rfch : 0											// Set by default
-	// size	: 21
-	// tmst : 1800642 									// for example
-	// datr	: "SF7BW125"
-	
-	// 12-byte header;
-	//		HDR (1 byte)
-	//		
-	//
-	// Data Reply for JOIN_ACCEPT as sent by server:
-	//		AppNonce (3 byte)
-	//		NetID (3 byte)
-	//		DevAddr (4 byte) [ 31..25]:NwkID , [24..0]:NwkAddr
- 	//		DLSettings (1 byte)
-	//		RxDelay (1 byte)
-	//		CFList (fill to 16 bytes)
-			
-	int i=0;
-	StaticJsonDocument<312> jsonBuffer;							// Use of arduinoJson version 6!
-	char * bufPtr = (char *) (buf);
-	buf[length] = 0;
-	
-#if DUSB>=1
-	if (debug>=2) {
-		Serial.println((char *)buf);
-		Serial.print(F("<"));
-		Serial.flush();
-	}
-#endif
-	// Use JSON to decode the string after the first 4 bytes.
-	// The data for the node is in the "data" field. This function destroys original buffer
-	auto error = deserializeJson(jsonBuffer, bufPtr);
-		
-	if (error) {
-#if DUSB>=1
-		if (( debug>=1) && (pdebug & P_TX)) {
-			Serial.print (F("T sendPacket:: ERROR Json Decode"));
-			if (debug>=2) {
-				Serial.print(':');
-				Serial.println(bufPtr);
-			}
-			Serial.flush();
-		}
-#endif
-		return(-1);
-	}
-	yield();
-	
-	// Meta Data sent by server (example)
-	// {"txpk":{"codr":"4/5","data":"YCkEAgIABQABGmIwYX/kSn4Y","freq":868.1,"ipol":true,"modu":"LORA","powe":14,"rfch":0,"size":18,"tmst":1890991792,"datr":"SF7BW125"}}
-
-	// Used in the protocol of Gateway:
-	JsonObject root		= jsonBuffer.to<JsonObject>();
-	
-	const char * data	= root["txpk"]["data"];			// Downstream Payload
-	uint8_t psize		= root["txpk"]["size"];			// Payload size
-	bool ipol			= root["txpk"]["ipol"];
-	uint8_t powe		= root["txpk"]["powe"];			// power, e.g. 14 or 27
-	LoraDown.tmst		= (uint32_t) root["txpk"]["tmst"].as<unsigned long>();
-	const float ff		= root["txpk"]["freq"];			// eg 869.525
-	
-	// Not used in the protocol of Gateway TTN:
-	const char * datr	= root["txpk"]["datr"];			// eg "SF7BW125"
-	const char * modu	= root["txpk"]["modu"];			// =="LORA"
-	const char * codr	= root["txpk"]["codr"];			// e.g. "4/5"
-	//if (root["txpk"].containsKey("imme") ) {
-	//	const bool imme = root["txpk"]["imme"];			// Immediate Transmit (tmst don't care)
-	//}
-
-	if ( data != NULL ) {
-#if DUSB>=1
-		if (( debug>=2 ) && ( pdebug & P_TX )) { 
-			Serial.print(F("T data: ")); 
-			Serial.println((char *) data);
-			if (debug>=2) Serial.flush();
-		}
-#endif
-	}
-	else {												// There is data!
-#if DUSB>=1
-		if ((debug>0) && ( pdebug & P_TX )) {
-			Serial.println(F("T sendPacket:: ERROR: data is NULL"));
-			if (debug>=2) Serial.flush();
-		}
-#endif
-		return(-1);
-	}
-
-	LoraDown.sfTx = atoi(datr+2);						// Convert "SF9BW125" or what is received from gateway to number
-	LoraDown.iiq = (ipol? 0x40: 0x27);					// if ipol==true 0x40 else 0x27
-	LoraDown.crc = 0x00;								// switch CRC off for TX
-	LoraDown.payLength = base64_dec_len((char *) data, strlen(data));// Length of the Payload data	
-	base64_decode((char *) payLoad, (char *) data, strlen(data));	// Fill payload w decoded message
-
-	// Compute wait time in microseconds
-	uint32_t w = (uint32_t) (LoraDown.tmst - micros());	// Wait Time compute
-
-// _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.
-// This way, we can bettrer communicate as a single gateway machine
-//
-#if _STRICT_1CH == 1
-	// RX1 is requested frequency
-	// RX2 is SF12
-	// If possible use RX1 timeslot as this is our frequency.
-	// Do not use RX2 or JOIN2 as they contain other frequencies
-	
-	// Wait time RX1
-	if ((w>1000000) && (w<3000000)) { 
-		LoraDown.tmst-=1000000; 
-	}
-	// RX2. Is tmst correction necessary
-	else if ((w>6000000) && (w<7000000)) { 
-		LoraDown.tmst-=500000; 
-	}
-	LoraDown.powe = 14;										// On all freqs except 869.5MHz power is limited
-	LoraDown.sfTx = sfi;									// Take care, TX sf not to be mixed with SCAN
-	//LoraDown.fff = freqs[ifreq].dwnFreq;					// Use the corresponsing Down frequency
-	
-#else
-// If _STRICT_1CH == 0, we will receive messags from the TTN gateway presumably on SF9/869.5MHz
-// And since the Gateway is a single channel gateway, and its nodes are probably
-// single channel too. They will not listen to that frequency at all.
-// Pleae note that this parameter is more for nodes (that cannot change freqs)
- than for gateways.
-//
-	LoraDown.powe = powe;
-
-	// convert double frequency (MHz) into uint32_t frequency in Hz.
-	LoraDown.fff = (uint32_t) ((uint32_t)((ff+0.000035)*1000)) * 1000;
-#endif
-	
-	LoraDown.payLoad = payLoad;				
-
-#if DUSB>=1
-	if (( debug>=1 ) && ( pdebug & P_TX)) {
-	
-		Serial.print(F("T LoraDown tmst="));
-		Serial.print(LoraDown.tmst);
-		//Serial.print(F(", w="));
-		//Serial.print(w);
-		
-		if ( debug>=2 ) {
-			Serial.print(F(" Request:: "));
-			Serial.print(F(" tmst="));		Serial.print(LoraDown.tmst); Serial.print(F(" wait=")); Serial.println(w);
-		
-			Serial.print(F(" strict="));	Serial.print(_STRICT_1CH);
-			Serial.print(F(" datr="));		Serial.println(datr);
-			Serial.print(F(" Rfreq=")); 	Serial.print(freqs[ifreq].dwnFreq); 
-			Serial.print(F(", Request=")); 	Serial.print(freqs[ifreq].dwnFreq); 
-			Serial.print(F(" ->")); 		Serial.println(LoraDown.fff);
-			Serial.print(F(" sf  =")); 		Serial.print(atoi(datr+2)); Serial.print(F(" ->")); Serial.println(LoraDown.sfTx);
-		
-			Serial.print(F(" modu="));		Serial.println(modu);
-			Serial.print(F(" powe="));		Serial.println(powe);
-			Serial.print(F(" codr="));		Serial.println(codr);
-
-			Serial.print(F(" ipol="));		Serial.println(ipol);
-		}
-		Serial.println();
-	}
-#endif
-
-	if (LoraDown.payLength != psize) {
-#if DUSB>=1
-		Serial.print(F("sendPacket:: WARNING payLength: "));
-		Serial.print(LoraDown.payLength);
-		Serial.print(F(", psize="));
-		Serial.println(psize);
-		if (debug>=2) Serial.flush();
-#endif
-	}
-#if DUSB>=1
-	else if (( debug >= 2 ) && ( pdebug & P_TX )) {
-		Serial.print(F("T Payload="));
-		for (i=0; i<LoraDown.payLength; i++) {
-			Serial.print(payLoad[i],HEX); 
-			Serial.print(':'); 
-		}
-		Serial.println();
-	}
-#endif
-
-	// Update downstream statistics
-	statc.msg_down++;
-	switch(statr[0].ch) {
-		case 0: statc.msg_down_0++; break;
-		case 1: statc.msg_down_1++; break;
-		case 2: statc.msg_down_2++; break;
-	}
-
-#if DUSB>=1
-	if (( debug>=2 ) && ( pdebug & P_TX )) {
-		Serial.println(F("T sendPacket:: fini OK"));
-		Serial.flush();
-	}
-#endif // DUSB
-
-	// All data is in Payload and parameters and need to be transmitted.
-	// The function is called in user-space
-	_state = S_TX;										// _state set to transmit
-	
-	return 1;
-}//sendPacket
-
-
-
-
-// ----------------------------------------------------------------------------
-// UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP
-// Based on the information read from the LoRa transceiver (or fake message)
-// build a gateway message to send upstream (to the user somewhere on the web).
-//
-// parameters:
-// 	tmst: Timestamp to include in the upstream message
-// 	buff_up: The buffer that is generated for upstream
-// 	message: The payload message to include in the the buff_up
-//	messageLength: The number of bytes received by the LoRa transceiver
-// 	internal: Boolean value to indicate whether the local sensor is processed
-//
-// returns:
-//	buff_index
-// ----------------------------------------------------------------------------
-int buildPacket(uint32_t tmst, uint8_t *buff_up, struct LoraUp LoraUp, bool internal) 
-{
-	long SNR;
-    int rssicorr;
-	int prssi;											// packet rssi
-	
-	char cfreq[12] = {0};								// Character array to hold freq in MHz
-	//lastTmst = tmst;									// Following/according to spec
-	int buff_index=0;
-	char b64[256];
-	
-	uint8_t *message = LoraUp.payLoad;
-	char messageLength = LoraUp.payLength;
-		
-#if _CHECK_MIC==1
-	unsigned char NwkSKey[16] = _NWKSKEY;
-	checkMic(message, messageLength, NwkSKey);
-#endif // _CHECK_MIC
-
-	// Read SNR and RSSI from the register. Note: Not for internal sensors!
-	// For internal sensor we fake these values as we cannot read a register
-	if (internal) {
-		SNR = 12;
-		prssi = 50;
-		rssicorr = 157;
-	}
-	else {
-		SNR = LoraUp.snr;
-		prssi = LoraUp.prssi;								// read register 0x1A, packet rssi
-		rssicorr = LoraUp.rssicorr;
-	}
-
-#if STATISTICS >= 1
-	// 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=( MAX_STAT -1); m>0; m--) statr[m]=statr[m-1];
-	
-	// From now on we can fill start[0] with sensor data
-#if _LOCALSERVER==1
-	statr[0].datal=0;
-	int index;
-	if ((index = inDecodes((char *)(LoraUp.payLoad+1))) >=0 ) {
-
-		uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
-		
-		for (int k=0; (k<LoraUp.payLength) && (k<23); k++) {
-			statr[0].data[k] = LoraUp.payLoad[k+9];
-		};
-		
-		// XXX Check that k<23 when leaving the for loop
-		// XXX or we can not display in statr
-		
-		uint8_t DevAddr[4]; 
-		DevAddr[0]= LoraUp.payLoad[4];
-		DevAddr[1]= LoraUp.payLoad[3];
-		DevAddr[2]= LoraUp.payLoad[2];
-		DevAddr[3]= LoraUp.payLoad[1];
-
-		statr[0].datal = encodePacket((uint8_t *)(statr[0].data), 
-								LoraUp.payLength-9-4, 
-								(uint16_t)frameCount, 
-								DevAddr, 
-								decodes[index].appKey, 
-								0);
-	}
-#endif //_LOCALSERVER
-	statr[0].tmst = now();
-	statr[0].ch= ifreq;
-	statr[0].prssi = prssi - rssicorr;
-#if RSSI==1
-	statr[0].rssi = _rssi - rssicorr;
-#endif // RSII
-	statr[0].sf = LoraUp.sf;
-#if DUSB>=2
-	if (debug>=0) {
-		if ((message[4] != 0x26) || (message[1]==0x99)) {
-			Serial.print(F("addr="));
-			for (int i=messageLength; i>0; i--) {
-				if (message[i]<0x10) Serial.print('0');
-				Serial.print(message[i],HEX);
-				Serial.print(' ');
-			}
-			Serial.println();
-		}
-	}
-#endif //DUSB
-	statr[0].node = ( message[1]<<24 | message[2]<<16 | message[3]<<8 | message[4] );
-
-#if STATISTICS >= 2
-	// Fill in the statistics that we will also need for the GUI.
-	// So 
-	switch (statr[0].sf) {
-		case SF7:  statc.sf7++;  break;
-		case SF8:  statc.sf8++;  break;
-		case SF9:  statc.sf9++;  break;
-		case SF10: statc.sf10++; break;
-		case SF11: statc.sf11++; break;
-		case SF12: statc.sf12++; break;
-	}
-#endif //STATISTICS >= 2
-
-#if STATISTICS >= 3
-	if (statr[0].ch == 0) {
-		statc.msg_ttl_0++;
-		switch (statr[0].sf) {
-			case SF7:  statc.sf7_0++;  break;
-			case SF8:  statc.sf8_0++;  break;
-			case SF9:  statc.sf9_0++;  break;
-			case SF10: statc.sf10_0++; break;
-			case SF11: statc.sf11_0++; break;
-			case SF12: statc.sf12_0++; break;
-		}
-	}
-	else 
-	if (statr[0].ch == 1) {
-		statc.msg_ttl_1++;
-		switch (statr[0].sf) {
-			case SF7:  statc.sf7_1++;  break;
-			case SF8:  statc.sf8_1++;  break;
-			case SF9:  statc.sf9_1++;  break;
-			case SF10: statc.sf10_1++; break;
-			case SF11: statc.sf11_1++; break;
-			case SF12: statc.sf12_1++; break;
-		}
-	}
-	else 
-	if (statr[0].ch == 2) {
-		statc.msg_ttl_2++;
-		switch (statr[0].sf) {
-			case SF7:  statc.sf7_2++;  break;
-			case SF8:  statc.sf8_2++;  break;
-			case SF9:  statc.sf9_2++;  break;
-			case SF10: statc.sf10_2++; break;
-			case SF11: statc.sf11_2++; break;
-			case SF12: statc.sf12_2++; break;
-		}
-	}
-#endif //STATISTICS >= 3
-
-#endif //STATISTICS >= 2
-
-#if DUSB>=1	
-	if (( debug>=2 ) && ( pdebug & P_RADIO )){
-		Serial.print(F("R buildPacket:: pRSSI="));
-		Serial.print(prssi-rssicorr);
-		Serial.print(F(" RSSI: "));
-		Serial.print(_rssi - rssicorr);
-		Serial.print(F(" SNR: "));
-		Serial.print(SNR);
-		Serial.print(F(" Length: "));
-		Serial.print((int)messageLength);
-		Serial.print(F(" -> "));
-		int i;
-		for (i=0; i< messageLength; i++) {
-					Serial.print(message[i],HEX);
-					Serial.print(' ');
-		}
-		Serial.println();
-		yield();
-	}
-#endif // DUSB
-
-// Show received message status on OLED display
-#if OLED>=1
-    char timBuff[20];
-    sprintf(timBuff, "%02i:%02i:%02i", hour(), minute(), second());
-	
-    display.clear();
-    display.setFont(ArialMT_Plain_16);
-    display.setTextAlignment(TEXT_ALIGN_LEFT);
-
-//	msg_oLED(timBuff, prssi-rssicorr, SNR, message)
-	
-    display.drawString(0, 0, "Time: " );
-    display.drawString(40, 0, timBuff);
-	
-    display.drawString(0, 16, "RSSI: " );
-    display.drawString(40, 16, String(prssi-rssicorr));
-	
-    display.drawString(70, 16, ",SNR: " );
-    display.drawString(110, 16, String(SNR) );
-	  
-	display.drawString(0, 32, "Addr: " );
-	  
-    if (message[4] < 0x10) display.drawString( 40, 32, "0"+String(message[4], HEX)); else display.drawString( 40, 32, String(message[4], HEX));
-	if (message[3] < 0x10) display.drawString( 61, 32, "0"+String(message[3], HEX)); else display.drawString( 61, 32, String(message[3], HEX));
-	if (message[2] < 0x10) display.drawString( 82, 32, "0"+String(message[2], HEX)); else display.drawString( 82, 32, String(message[2], HEX));
-	if (message[1] < 0x10) display.drawString(103, 32, "0"+String(message[1], HEX)); else display.drawString(103, 32, String(message[1], HEX));
-	  
-    display.drawString(0, 48, "LEN: " );
-    display.drawString(40, 48, String((int)messageLength) );
-    display.display();
-	//yield();
-
-#endif //OLED>=1
-			
-	int j;
-	
-	// XXX Base64 library is nopad. So we may have to add padding characters until
-	// 	message Length is multiple of 4!
-	// Encode message with messageLength into b64
-	int encodedLen = base64_enc_len(messageLength);		// max 341
-#if DUSB>=1
-	if ((debug>=1) && (encodedLen>255) && ( pdebug & P_RADIO )) {
-		Serial.print(F("R buildPacket:: b64 err, len="));
-		Serial.println(encodedLen);
-		if (debug>=2) Serial.flush();
-		return(-1);
-	}
-#endif // DUSB
-	base64_encode(b64, (char *) message, messageLength);// max 341
-	// start composing datagram with the header 
-	uint8_t token_h = (uint8_t)rand(); 					// random token
-	uint8_t token_l = (uint8_t)rand(); 					// random token
-	
-	// pre-fill the data buffer with fixed fields
-	buff_up[0] = PROTOCOL_VERSION;						// 0x01 still
-
-
-	buff_up[1] = token_h;
-	buff_up[2] = token_l;
-	
-	buff_up[3] = PKT_PUSH_DATA;							// 0x00
-	
-	// READ MAC ADDRESS OF ESP8266, and insert 0xFF 0xFF in the middle
-	buff_up[4]  = MAC_array[0];
-	buff_up[5]  = MAC_array[1];
-	buff_up[6]  = MAC_array[2];
-	buff_up[7]  = 0xFF;
-	buff_up[8]  = 0xFF;
-	buff_up[9]  = MAC_array[3];
-	buff_up[10] = MAC_array[4];
-	buff_up[11] = MAC_array[5];
-
-
-	buff_index = 12; 									// 12-byte binary (!) header
-
-	// start of JSON structure that will make payload
-	memcpy((void *)(buff_up + buff_index), (void *)"{\"rxpk\":[", 9);
-	buff_index += 9;
-	buff_up[buff_index] = '{';
-	++buff_index;
-	j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "\"tmst\":%u", tmst);
-#if DUSB>=1
-	if ((j<0) && ( debug>=1 ) && ( pdebug & P_RADIO )) {
-		Serial.println(F("buildPacket:: Error "));
-	}
-#endif
-	buff_index += j;
-	ftoa((double)freqs[ifreq].upFreq / 1000000, cfreq, 6);					// XXX This can be done better
-	
-	j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"chan\":%1u,\"rfch\":%1u,\"freq\":%s", 0, 0, cfreq);
-	buff_index += j;
-	memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":1", 9);
-	buff_index += 9;
-	memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"LORA\"", 14);
-	buff_index += 14;
-	
-	/* Lora datarate & bandwidth, 16-19 useful chars */
-	switch (LoraUp.sf) {
-		case SF6:
-			memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF6", 12);
-			buff_index += 12;
-			break;
-		case SF7:
-			memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF7", 12);
-			buff_index += 12;
-			break;
-		case SF8:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF8", 12);
-            buff_index += 12;
-            break;
-		case SF9:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF9", 12);
-            buff_index += 12;
-            break;
-		case SF10:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF10", 13);
-            buff_index += 13;
-            break;
-		case SF11:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF11", 13);
-            buff_index += 13;
-            break;
-		case SF12:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF12", 13);
-            buff_index += 13;
-            break;
-		default:
-            memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF?", 12);
-            buff_index += 12;
-	}
-	memcpy((void *)(buff_up + buff_index), (void *)"BW125\"", 6);
-	buff_index += 6;
-	memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/5\"", 13);
-	buff_index += 13;
-	j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"lsnr\":%li", SNR);
-	buff_index += j;
-	j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"rssi\":%d,\"size\":%u", prssi-rssicorr, messageLength);
-	buff_index += j;
-	memcpy((void *)(buff_up + buff_index), (void *)",\"data\":\"", 9);
-	buff_index += 9;
-
-	// Use gBase64 library to fill in the data string
-	encodedLen = base64_enc_len(messageLength);			// max 341
-	j = base64_encode((char *)(buff_up + buff_index), (char *) message, messageLength);
-
-	buff_index += j;
-	buff_up[buff_index] = '"';
-	++buff_index;
-
-	// End of packet serialization
-	buff_up[buff_index] = '}';
-	++buff_index;
-	buff_up[buff_index] = ']';
-	++buff_index;
-	
-	// end of JSON datagram payload */
-	buff_up[buff_index] = '}';
-	++buff_index;
-	buff_up[buff_index] = 0; 							// add string terminator, for safety
-
-#if STAT_LOG == 1	
-	// Do statistics logging. In first version we might only
-	// write part of the record to files, later more
-
-	addLog( (unsigned char *)(buff_up), buff_index );
-#endif	
-	
-#if DUSB>=1
-	if (( debug>=2 ) && ( pdebug & P_RX )) {
-		Serial.print(F("R RXPK:: "));
-		Serial.println((char *)(buff_up + 12));			// debug: display JSON payload
-		Serial.print(F("R RXPK:: package length="));
-		Serial.println(buff_index);
-	}
-#endif
-	return(buff_index);
-}// buildPacket
-
-
-
-
-
-// ----------------------------------------------------------------------------
-// UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP UP 
-// Receive a LoRa package over the air, LoRa and deliver to server(s)
-//
-// Receive a LoRa message and fill the buff_up char buffer.
-// returns values:
-// - returns the length of string returned in buff_up
-// - returns -1 or -2 when no message arrived, depending connection.
-//
-// This is the "highlevel" function called by loop()
-// ----------------------------------------------------------------------------
-int receivePacket()
-{
-	uint8_t buff_up[TX_BUFF_SIZE]; 						// buffer to compose the upstream packet to backend server
-	long SNR;
-	uint8_t message[128] = { 0x00 };					// MSG size is 128 bytes for rx
-	uint8_t messageLength = 0;
-	
-	// Regular message received, see SX1276 spec table 18
-	// Next statement could also be a "while" to combine several messages received
-	// in one UDP message as the Semtech Gateway spec does allow this.
-	// XXX Not yet supported
-
-		// Take the timestamp as soon as possible, to have accurate reception timestamp
-		// TODO: tmst can jump if micros() overflow.
-		uint32_t tmst = (uint32_t) micros();			// Only microseconds, rollover in 5X minutes
-		//lastTmst = tmst;								// Following/according to spec
-		
-		// Handle the physical data read from LoraUp
-		if (LoraUp.payLength > 0) {
-
-			// externally received packet, so last parameter is false (==LoRa external)
-            int build_index = buildPacket(tmst, buff_up, LoraUp, false);
-
-			// REPEATER is a special function where we retransmit received 
-			// message on _ICHANN to _OCHANN.
-			// Note:: For the moment _OCHANN is not allowed to be same as _ICHANN
-#if _REPEATER==1
-			if (!sendLora(LoraUp.payLoad, LoraUp.payLength)) {
-				return(-3);
-			}
-#endif
-			
-			// This is one of the potential problem areas.
-			// If possible, USB traffic should be left out of interrupt routines
-			// rxpk PUSH_DATA received from node is rxpk (*2, par. 3.2)
-#ifdef _TTNSERVER
-			if (!sendUdp(ttnServer, _TTNPORT, buff_up, build_index)) {
-				return(-1); 							// received a message
-			}
-			yield();
-#endif
-			// Use our own defined server or a second well kon server
-#ifdef _THINGSERVER
-			if (!sendUdp(thingServer, _THINGPORT, buff_up, build_index)) {
-				return(-2); 							// received a message
-			}
-#endif
-
-#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
-
-			//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
-
-			int index=0;
-			if ((index = inDecodes((char *)(LoraUp.payLoad+1))) >=0 ) {
-
-				uint8_t DevAddr[4]; 
-				DevAddr[0]= LoraUp.payLoad[4];
-				DevAddr[1]= LoraUp.payLoad[3];
-				DevAddr[2]= LoraUp.payLoad[2];
-				DevAddr[3]= LoraUp.payLoad[1];
-				uint16_t frameCount=LoraUp.payLoad[7]*256 + LoraUp.payLoad[6];
-
-#if DUSB>=1
-				if (( debug>=1 ) && ( pdebug & P_RX )) {
-					Serial.print(F("R receivePacket:: Ind="));
-					Serial.print(index);
-					Serial.print(F(", Len="));
-					Serial.print(LoraUp.payLength);
-					Serial.print(F(", A="));
-					for (int i=0; i<4; i++) {
-						if (DevAddr[i]<0x0F) Serial.print('0');
-						Serial.print(DevAddr[i],HEX);
-						//Serial.print(' ');
-					}
-				
-					Serial.print(F(", Msg="));
-					for (int i=0; (i<statr[0].datal) && (i<23); i++) {
-						if (statr[0].data[i]<0x0F) Serial.print('0');
-						Serial.print(statr[0].data[i],HEX);
-						Serial.print(' ');
-					}
-					Serial.println();
-				}
-			}
-			else if (( debug>=2 ) && ( pdebug & P_RX )) {
-					Serial.println(F("receivePacket:: No Index"));
-			}
-#endif //DUSB
-#endif // _LOCALSERVER
-
-			// Reset the message area
-			LoraUp.payLength = 0;
-			LoraUp.payLoad[0] = 0x00;
-			return(build_index);
-        }
-		
-	return(0);											// failure no message read
-	
-}//receivePacket
-

+ 0 - 571
ESP-sc-gway/_udpSemtech.ino

@@ -1,571 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// _udpSemtech.ino: This file contains the UDP specific code enabling to receive
-// and transmit packages/messages to the server usig Semtech protocol.
-// ========================================================================================
-
-// Also referred to as Semtech code
-
-#if defined(_UDPROUTER)
-
-//	If _UDPROUTER is defined, _TTNROUTER should NOT be defined. So...
-#if defined(_TTNROUTER)
-#error "Please make sure that either _UDPROUTER or _TTNROUTER are defined but not both"
-#endif
-
-// The following functions ae defined in this modue:
-// int readUdp(int Packetsize)
-// int sendUdp(IPAddress server, int port, uint8_t *msg, int length)
-// bool connectUdp()
-// void pullData()
-// void sendstat();
-
-// ----------------------------------------------------------------------------
-// connectUdp()
-//	connect to UDP (which is a local thing, after all UDP 
-// connections do not exist.
-// Parameters:
-//	<None>
-// Returns
-//	Boollean indicating success or not
-// ----------------------------------------------------------------------------
-bool connectUdp() {
-
-	bool ret = false;
-	unsigned int localPort = _LOCUDPPORT;			// To listen to return messages from WiFi
-#if DUSB>=1
-	if (debug>=1) {
-		Serial.print(F("Local UDP port="));
-		Serial.println(localPort);
-	}
-#endif	
-	if (Udp.begin(localPort) == 1) {
-#if DUSB>=1
-		if (debug>=1) Serial.println(F("Connection successful"));
-#endif
-		ret = true;
-	}
-	else{
-#if DUSB>=1
-		if (debug>=1) Serial.println("Connection failed");
-#endif
-	}
-	return(ret);
-}// connectUdp
-
-// ----------------------------------------------------------------------------
-// readUdp()
-// Read DOWN a package from UDP socket, can come from any server
-// Messages are received when server responds to gateway requests from LoRa nodes 
-// (e.g. JOIN requests etc.) or when server has downstream data.
-// We respond only to the server that sent us a message!
-//
-// Note: So normally we can forget here about codes that do upstream
-//
-// Parameters:
-//	Packetsize: size of the buffer to read, as read by loop() calling function
-//
-// Returns:
-//	-1 or false if not read
-//	Or number of characters read is success
-//
-// ----------------------------------------------------------------------------
-int readUdp(int packetSize)
-{
-	uint8_t protocol;
-	uint16_t token;
-	uint8_t ident; 
-	uint8_t buff[32]; 						// General buffer to use for UDP, set to 64
-	uint8_t buff_down[RX_BUFF_SIZE];		// Buffer for downstream
-
-//	if ((WiFi.status() != WL_CONNECTED) &&& (WlanConnect(10) < 0)) {
-	if (WlanConnect(10) < 0) {
-#if DUSB>=1
-			Serial.print(F("readUdp: ERROR connecting to WLAN"));
-			if (debug>=2) Serial.flush();
-#endif
-			Udp.flush();
-			yield();
-			return(-1);
-	}
-
-	yield();
-	
-	if (packetSize > RX_BUFF_SIZE) {
-#if DUSB>=1
-		Serial.print(F("readUdp:: ERROR package of size: "));
-		Serial.println(packetSize);
-#endif
-		Udp.flush();
-		return(-1);
-	}
-  
-	// We assume here that we know the originator of the message
-	// In practice however this can be any sender!
-	if (Udp.read(buff_down, packetSize) < packetSize) {
-#if DUSB>=1
-		Serial.println(F("A readUdp:: Reading less chars"));
-		return(-1);
-#endif
-	}
-
-	// Remote Address should be known
-	IPAddress remoteIpNo = Udp.remoteIP();
-
-	// Remote port is either of the remote TTN server or from NTP server (=123)
-	unsigned int remotePortNo = Udp.remotePort();
-
-	if (remotePortNo == 123) {
-		// This is an NTP message arriving
-#if DUSB>=1
-		if ( debug>=0 ) {
-			Serial.println(F("A readUdp:: NTP msg rcvd"));
-		}
-#endif
-		gwayConfig.ntpErr++;
-		gwayConfig.ntpErrTime = now();
-		return(0);
-	}
-	
-	// If it is not NTP it must be a LoRa message for gateway or node
-	else {
-		uint8_t *data = (uint8_t *) ((uint8_t *)buff_down + 4);
-		protocol = buff_down[0];
-		token = buff_down[2]*256 + buff_down[1];
-		ident = buff_down[3];
-
-#if DUSB>=1
-	if ((debug>1) && (pdebug & P_MAIN)) {
-		Serial.print(F("M readUdp:: message waiting="));
-		Serial.print(ident);
-		Serial.println();
-	}
-#endif
-		// now parse the message type from the server (if any)
-		switch (ident) {
-
-		// This message is used by the gateway to send sensor data to the
-		// server. As this function is used for downstream only, this option
-		// will never be selected but is included as a reference only
-		case PKT_PUSH_DATA: // 0x00 UP
-#if DUSB>=1
-			if (debug >=1) {
-				Serial.print(F("PKT_PUSH_DATA:: size ")); Serial.print(packetSize);
-				Serial.print(F(" From ")); Serial.print(remoteIpNo);
-				Serial.print(F(", port ")); Serial.print(remotePortNo);
-				Serial.print(F(", data: "));
-				for (int i=0; i<packetSize; i++) {
-					Serial.print(buff_down[i],HEX);
-					Serial.print(':');
-				}
-				Serial.println();
-				if (debug>=2) Serial.flush();
-			}
-#endif
-		break;
-	
-		// This message is sent by the server to acknowledge receipt of a
-		// (sensor) message sent with the code above.
-		case PKT_PUSH_ACK:	// 0x01 DOWN
-#if DUSB>=1
-			if (( debug>=2) && (pdebug & P_MAIN )) {
-				Serial.print(F("M PKT_PUSH_ACK:: size ")); 
-				Serial.print(packetSize);
-				Serial.print(F(" From ")); 
-				Serial.print(remoteIpNo);
-				Serial.print(F(", port ")); 
-				Serial.print(remotePortNo);
-				Serial.print(F(", token: "));
-				Serial.println(token, HEX);
-				Serial.println();
-			}
-#endif
-		break;
-	
-		case PKT_PULL_DATA:	// 0x02 UP
-#if DUSB>=1
-			Serial.print(F(" Pull Data"));
-			Serial.println();
-#endif
-		break;
-	
-		// This message type is used to confirm OTAA message to the node
-		// XXX This message format may also be used for other downstream communication
-		case PKT_PULL_RESP:	// 0x03 DOWN
-#if DUSB>=1
-			if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-				Serial.println(F("M readUdp:: PKT_PULL_RESP received"));
-			}
-#endif
-//			lastTmst = micros();					// Store the tmst this package was received
-			
-			// Send to the LoRa Node first (timing) and then do reporting to Serial
-			_state=S_TX;
-			sendTime = micros();					// record when we started sending the message
-			
-			if (sendPacket(data, packetSize-4) < 0) {
-#if DUSB>=1
-				if ( debug>=0 ) {
-					Serial.println(F("A readUdp:: Error: PKT_PULL_RESP sendPacket failed"));
-				}
-#endif
-				return(-1);
-			}
-
-			// Now respond with an PKT_TX_ACK; 0x04 UP
-			buff[0]=buff_down[0];
-			buff[1]=buff_down[1];
-			buff[2]=buff_down[2];
-			//buff[3]=PKT_PULL_ACK;					// Pull request/Change of Mogyi
-			buff[3]=PKT_TX_ACK;
-			buff[4]=MAC_array[0];
-			buff[5]=MAC_array[1];
-			buff[6]=MAC_array[2];
-			buff[7]=0xFF;
-			buff[8]=0xFF;
-			buff[9]=MAC_array[3];
-			buff[10]=MAC_array[4];
-			buff[11]=MAC_array[5];
-			buff[12]=0;
-#if DUSB>=1
-			if (( debug >= 2 ) && ( pdebug & P_MAIN )) {
-				Serial.println(F("M readUdp:: TX buff filled"));
-			}
-#endif
-			// Only send the PKT_PULL_ACK to the UDP socket that just sent the data!!!
-			Udp.beginPacket(remoteIpNo, remotePortNo);
-			if (Udp.write((unsigned char *)buff, 12) != 12) {
-#if DUSB>=1
-				if (debug>=0)
-					Serial.println("A readUdp:: Error: PKT_PULL_ACK UDP write");
-#endif
-			}
-			else {
-#if DUSB>=1
-				if (( debug>=0 ) && ( pdebug & P_TX )) {
-					Serial.print(F("M PKT_TX_ACK:: micros="));
-					Serial.println(micros());
-				}
-#endif
-			}
-
-			if (!Udp.endPacket()) {
-#if DUSB>=1
-				if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-					Serial.println(F("M PKT_PULL_DATALL Error Udp.endpaket"));
-				}
-#endif
-			}
-			
-			yield();
-#if DUSB>=1
-			if (( debug >=1 ) && (pdebug & P_MAIN )) {
-				Serial.print(F("M PKT_PULL_RESP:: size ")); 
-				Serial.print(packetSize);
-				Serial.print(F(" From ")); 
-				Serial.print(remoteIpNo);
-				Serial.print(F(", port ")); 
-				Serial.print(remotePortNo);	
-				Serial.print(F(", data: "));
-				data = buff_down + 4;
-				data[packetSize] = 0;
-				Serial.print((char *)data);
-				Serial.println(F("..."));
-			}
-#endif		
-		break;
-	
-		case PKT_PULL_ACK:	// 0x04 DOWN; the server sends a PULL_ACK to confirm PULL_DATA receipt
-#if DUSB>=1
-			if (( debug >= 2 ) && (pdebug & P_MAIN )) {
-				Serial.print(F("M PKT_PULL_ACK:: size ")); Serial.print(packetSize);
-				Serial.print(F(" From ")); Serial.print(remoteIpNo);
-				Serial.print(F(", port ")); Serial.print(remotePortNo);	
-				Serial.print(F(", data: "));
-				for (int i=0; i<packetSize; i++) {
-					Serial.print(buff_down[i],HEX);
-					Serial.print(':');
-				}
-				Serial.println();
-			}
-#endif
-		break;
-	
-		default:
-#if GATEWAYMGT==1
-			// For simplicity, we send the first 4 bytes too
-			gateway_mgt(packetSize, buff_down);
-#else
-
-#endif
-#if DUSB>=1
-			Serial.print(F(", ERROR ident not recognized="));
-			Serial.println(ident);
-#endif
-		break;
-		}
-#if DUSB>=2
-		if (debug>=1) {
-			Serial.print(F("readUdp:: returning=")); 
-			Serial.println(packetSize);
-		}
-#endif
-		// For downstream messages
-		return packetSize;
-	}
-}//readUdp
-
-
-// ----------------------------------------------------------------------------
-// sendUdp()
-// Send UP an UDP/DGRAM message to the MQTT server
-// If we send to more than one host (not sure why) then we need to set sockaddr 
-// before sending.
-// Parameters:
-//	IPAddress
-//	port
-//	msg *
-//	length (of msg)
-// return values:
-//	0: Error
-//	1: Success
-// ----------------------------------------------------------------------------
-int sendUdp(IPAddress server, int port, uint8_t *msg, int length) {
-
-	// Check whether we are conected to Wifi and the internet
-	if (WlanConnect(3) < 0) {
-#if DUSB>=1
-		if (( debug>=0 ) && ( pdebug & P_MAIN )) {
-			Serial.print(F("M sendUdp: ERROR connecting to WiFi"));
-			Serial.flush();
-		}
-#endif
-		Udp.flush();
-		yield();
-		return(0);
-	}
-
-	yield();
-
-	//send the update
-#if DUSB>=1
-	if (( debug>=3 ) && ( pdebug & P_MAIN )) {
-		Serial.println(F("M WiFi connected"));
-	}
-#endif	
-	if (!Udp.beginPacket(server, (int) port)) {
-#if DUSB>=1
-		if (( debug>=1 ) && ( pdebug & P_MAIN )) {
-			Serial.println(F("M sendUdp:: Error Udp.beginPacket"));
-		}
-#endif
-		return(0);
-	}
-	
-	yield();
-	
-
-	if (Udp.write((unsigned char *)msg, length) != length) {
-#if DUSB>=1
-		if (( debug<=1 ) && ( pdebug & P_MAIN )) {
-			Serial.println(F("M sendUdp:: Error write"));
-		}
-#endif
-		Udp.endPacket();						// Close UDP
-		return(0);								// Return error
-	}
-	
-	yield();
-	
-	if (!Udp.endPacket()) {
-#if DUSB>=1
-		if (debug>=1) {
-			Serial.println(F("sendUdp:: Error Udp.endPacket"));
-			Serial.flush();
-		}
-#endif
-		return(0);
-	}
-	return(1);
-}//sendUDP
-
-
-
-
-// ----------------------------------------------------------------------------
-// pullData()
-// Send UDP periodic Pull_DATA message to server to keepalive the connection
-// and to invite the server to send downstream messages when these are available
-// *2, par. 5.2
-//	- Protocol Version (1 byte)
-//	- Random Token (2 bytes)
-//	- PULL_DATA identifier (1 byte) = 0x02
-//	- Gateway unique identifier (8 bytes) = MAC address
-// ----------------------------------------------------------------------------
-void pullData() {
-
-    uint8_t pullDataReq[12]; 								// status report as a JSON object
-    int pullIndex=0;
-	int i;
-	
-	uint8_t token_h = (uint8_t)rand(); 						// random token
-    uint8_t token_l = (uint8_t)rand();						// random token
-	
-    // pre-fill the data buffer with fixed fields
-    pullDataReq[0]  = PROTOCOL_VERSION;						// 0x01
-    pullDataReq[1]  = token_h;
-    pullDataReq[2]  = token_l;
-    pullDataReq[3]  = PKT_PULL_DATA;						// 0x02
-	// READ MAC ADDRESS OF ESP8266, and return unique Gateway ID consisting of MAC address and 2bytes 0xFF
-    pullDataReq[4]  = MAC_array[0];
-    pullDataReq[5]  = MAC_array[1];
-    pullDataReq[6]  = MAC_array[2];
-    pullDataReq[7]  = 0xFF;
-    pullDataReq[8]  = 0xFF;
-    pullDataReq[9]  = MAC_array[3];
-    pullDataReq[10] = MAC_array[4];
-    pullDataReq[11] = MAC_array[5];
-    //pullDataReq[12] = 0/00; 								// add string terminator, for safety
-	
-    pullIndex = 12;											// 12-byte header
-	
-    //send the update
-	
-	uint8_t *pullPtr;
-	pullPtr = pullDataReq,
-#ifdef _TTNSERVER
-    sendUdp(ttnServer, _TTNPORT, pullDataReq, pullIndex);
-	yield();
-#endif
-
-#if DUSB>=1
-	if (pullPtr != pullDataReq) {
-		Serial.println(F("pullPtr != pullDatReq"));
-		Serial.flush();
-	}
-
-#endif
-#ifdef _THINGSERVER
-	sendUdp(thingServer, _THINGPORT, pullDataReq, pullIndex);
-#endif
-
-#if DUSB>=1
-    if (( debug>=2 ) && ( pdebug & P_MAIN )) {
-		yield();
-		Serial.print(F("M PKT_PULL_DATA request, len=<"));
-		Serial.print(pullIndex);
-		Serial.print(F("> "));
-		for (i=0; i<pullIndex; i++) {
-			Serial.print(pullDataReq[i],HEX);				// debug: display JSON stat
-			Serial.print(':');
-		}
-		Serial.println();
-		if (debug>=2) Serial.flush();
-	}
-#endif
-	return;
-}//pullData
-
-
-// ----------------------------------------------------------------------------
-// sendstat()
-// Send UP periodic status message to server even when we do not receive any
-// data. 
-// Parameters:
-//	- <none>
-// ----------------------------------------------------------------------------
-void sendstat() {
-
-    uint8_t status_report[STATUS_SIZE]; 					// status report as a JSON object
-    char stat_timestamp[32];								// XXX was 24
-    time_t t;
-	char clat[10]={0};
-	char clon[10]={0};
-
-    int stat_index=0;
-	uint8_t token_h   = (uint8_t)rand(); 					// random token
-    uint8_t token_l   = (uint8_t)rand();					// random token
-	
-    // pre-fill the data buffer with fixed fields
-    status_report[0]  = PROTOCOL_VERSION;					// 0x01
-	status_report[1]  = token_h;
-    status_report[2]  = token_l;
-    status_report[3]  = PKT_PUSH_DATA;						// 0x00
-	
-	// READ MAC ADDRESS OF ESP8266, and return unique Gateway ID consisting of MAC address and 2bytes 0xFF
-    status_report[4]  = MAC_array[0];
-    status_report[5]  = MAC_array[1];
-    status_report[6]  = MAC_array[2];
-    status_report[7]  = 0xFF;
-    status_report[8]  = 0xFF;
-    status_report[9]  = MAC_array[3];
-    status_report[10] = MAC_array[4];
-    status_report[11] = MAC_array[5];
-
-    stat_index = 12;										// 12-byte header
-	
-    t = now();												// get timestamp for statistics
-	
-	// XXX Using CET as the current timezone. Change to your timezone	
-	sprintf(stat_timestamp, "%04d-%02d-%02d %02d:%02d:%02d CET", year(),month(),day(),hour(),minute(),second());
-	yield();
-	
-	ftoa(lat,clat,5);										// Convert lat to char array with 5 decimals
-	ftoa(lon,clon,5);										// As IDE CANNOT prints floats
-	
-	// Build the Status message in JSON format, XXX Split this one up...
-	delay(1);
-	
-    int j = snprintf((char *)(status_report + stat_index), STATUS_SIZE-stat_index, 
-		"{\"stat\":{\"time\":\"%s\",\"lati\":%s,\"long\":%s,\"alti\":%i,\"rxnb\":%u,\"rxok\":%u,\"rxfw\":%u,\"ackr\":%u.0,\"dwnb\":%u,\"txnb\":%u,\"pfrm\":\"%s\",\"mail\":\"%s\",\"desc\":\"%s\"}}", 
-		stat_timestamp, clat, clon, (int)alt, statc.msg_ttl, statc.msg_ok, statc.msg_down, 0, 0, 0, platform, email, description);
-		
-	yield();												// Give way to the internal housekeeping of the ESP8266
-
-    stat_index += j;
-    status_report[stat_index] = 0; 							// add string terminator, for safety
-
-#if DUSB>=1
-    if (( debug>=2 ) && ( pdebug & P_MAIN )) {
-		Serial.print(F("M stat update: <"));
-		Serial.print(stat_index);
-		Serial.print(F("> "));
-		Serial.println((char *)(status_report+12));			// DEBUG: display JSON stat
-	}
-#endif	
-	if (stat_index > STATUS_SIZE) {
-#if DUSB>=1
-		Serial.println(F("A sendstat:: ERROR buffer too big"));
-#endif
-		return;
-	}
-	
-    //send the update
-#ifdef _TTNSERVER
-    sendUdp(ttnServer, _TTNPORT, status_report, stat_index);
-	yield();
-#endif
-
-#ifdef _THINGSERVER
-	sendUdp(thingServer, _THINGPORT, status_report, stat_index);
-#endif
-	return;
-}//sendstat
-
-
-#endif //_UDPROUTER

+ 0 - 272
ESP-sc-gway/_utils.ino

@@ -1,272 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the utilities for time and other functions
-// ========================================================================================
-
-
-// ==================== STRING STRING STRING ==================================
-
-// ----------------------------------------------------------------------------
-// Fill a HEXadecimal String  from a 4-byte char array
-//
-// ----------------------------------------------------------------------------
-static void printHEX(char * hexa, const char sep, String& response) 
-{
-	char m;
-	m = hexa[0]; if (m<016) response+='0'; response += String(m, HEX);  response+=sep;
-	m = hexa[1]; if (m<016) response+='0'; response += String(m, HEX);  response+=sep;
-	m = hexa[2]; if (m<016) response+='0'; response += String(m, HEX);  response+=sep;
-	m = hexa[3]; if (m<016) response+='0'; response += String(m, HEX);  response+=sep;
-}
-
-
-
-// ----------------------------------------------------------------------------
-// stringTime
-// Print the time t into the String reponse. t is of type time_t in seconds.
-// Only when RTC is present we print real time values
-// t contains number of seconds since system started that the event happened.
-// So a value of 100 would mean that the event took place 1 minute and 40 seconds ago
-// ----------------------------------------------------------------------------
-static void stringTime(time_t t, String& response) {
-
-	if (t==0) { response += "--"; return; }
-	
-	// now() gives seconds since 1970
-	// as millis() does rotate every 50 days
-	// So we need another timing parameter
-	time_t eTime = t;
-	
-	// Rest is standard
-	byte _hour   = hour(eTime);
-	byte _minute = minute(eTime);
-	byte _second = second(eTime);
-	
-	switch(weekday(eTime)) {
-		case 1: response += "Sunday "; break;
-		case 2: response += "Monday "; break;
-		case 3: response += "Tuesday "; break;
-		case 4: response += "Wednesday "; break;
-		case 5: response += "Thursday "; break;
-		case 6: response += "Friday "; break;
-		case 7: response += "Saturday "; break;
-	}
-	response += String() + day(eTime) + "-";
-	response += String() + month(eTime) + "-";
-	response += String() + year(eTime) + " ";
-	
-	if (_hour < 10) response += "0";
-	response += String() + _hour + ":";
-	if (_minute < 10) response += "0";
-	response += String() + _minute + ":";
-	if (_second < 10) response += "0";
-	response += String() + _second;
-}
-
-// ============== SERIAL SERIAL SERIAL ========================================
-
-// ----------------------------------------------------------------------------
-// Print utin8_t values in HEX with leading 0 when necessary
-// ----------------------------------------------------------------------------
-void printHexDigit(uint8_t digit)
-{
-    // utility function for printing Hex Values with leading 0
-    if(digit < 0x10)
-        Serial.print('0');
-    Serial.print(digit,HEX);
-}
-
-// ----------------------------------------------------------------------------
-// Print leading '0' digits for hours(0) and second(0) when
-// printing values less than 10
-// ----------------------------------------------------------------------------
-void printDigits(unsigned long digits)
-{
-    // utility function for digital clock display: prints leading 0
-    if(digits < 10)
-        Serial.print(F("0"));
-    Serial.print(digits);
-}
-
-
-// ----------------------------------------------------------------------------
-// Print the current time
-// ----------------------------------------------------------------------------
-static void printTime() {
-	switch (weekday())
-	{
-		case 1: Serial.print(F("Sunday")); break;
-		case 2: Serial.print(F("Monday")); break;
-		case 3: Serial.print(F("Tuesday")); break;
-		case 4: Serial.print(F("Wednesday")); break;
-		case 5: Serial.print(F("Thursday")); break;
-		case 6: Serial.print(F("Friday")); break;
-		case 7: Serial.print(F("Saturday")); break;
-		default: Serial.print(F("ERROR")); break;
-	}
-	Serial.print(F(" "));
-	printDigits(hour());
-	Serial.print(F(":"));
-	printDigits(minute());
-	Serial.print(F(":"));
-	printDigits(second());
-	return;
-}
-
-
-// ----------------------------------------------------------------------------
-// SerialTime
-// Print the current time on the Serial (USB), with leading 0.
-// ----------------------------------------------------------------------------
-void SerialTime() 
-{
-
-	uint32_t thrs = hour();
-	uint32_t tmin = minute();
-	uint32_t tsec = second();
-			
-	if (thrs<10) Serial.print('0'); Serial.print(thrs);
-	Serial.print(':');
-	if (tmin<10) Serial.print('0'); Serial.print(tmin);
-	Serial.print(':');
-	if (tsec<10) Serial.print('0'); Serial.print(tsec);
-			
-	if (debug>=2) Serial.flush();
-		
-	return;
-}
-
-// ----------------------------------------------------------------------------
-// SerialStat
-// Print the statistics on Serial (USB) port
-// ----------------------------------------------------------------------------
-
-void SerialStat(uint8_t intr) 
-{
-#if DUSB>=1
-	if (debug>=0) {
-		Serial.print(F("I="));
-
-		if (intr & IRQ_LORA_RXTOUT_MASK) Serial.print(F("RXTOUT "));		// 0x80
-		if (intr & IRQ_LORA_RXDONE_MASK) Serial.print(F("RXDONE "));		// 0x40
-		if (intr & IRQ_LORA_CRCERR_MASK) Serial.print(F("CRCERR "));		// 0x20
-		if (intr & IRQ_LORA_HEADER_MASK) Serial.print(F("HEADER "));		// 0x10
-		if (intr & IRQ_LORA_TXDONE_MASK) Serial.print(F("TXDONE "));		// 0x08
-		if (intr & IRQ_LORA_CDDONE_MASK) Serial.print(F("CDDONE "));		// 0x04
-		if (intr & IRQ_LORA_FHSSCH_MASK) Serial.print(F("FHSSCH "));		// 0x02
-		if (intr & IRQ_LORA_CDDETD_MASK) Serial.print(F("CDDETD "));		// 0x01
-
-		if (intr == 0x00) Serial.print(F("  --  "));
-			
-		Serial.print(F(", F="));
-		Serial.print(ifreq);
-		Serial.print(F(", SF="));
-		Serial.print(sf);
-		Serial.print(F(", E="));
-		Serial.print(_event);
-			
-		Serial.print(F(", S="));
-		//Serial.print(_state);
-		switch (_state) {
-			case S_INIT:
-				Serial.print(F("INIT "));
-			break;
-			case S_SCAN:
-				Serial.print(F("SCAN "));
-			break;
-			case S_CAD:
-				Serial.print(F("CAD  "));
-			break;
-			case S_RX:
-				Serial.print(F("RX   "));
-			break;
-			case S_TX:
-				Serial.print(F("TX   "));
-			break;
-			case S_TXDONE:
-				Serial.print(F("TXDONE"));
-			break;
-			default:
-				Serial.print(F(" -- "));
-		}
-		Serial.print(F(", eT="));
-		Serial.print( micros() - eventTime );
-		Serial.print(F(", dT="));
-		Serial.print( micros() - doneTime );
-		Serial.println();
-	}
-#endif
-}
-
-
-	
-// ----------------------------------------------------------------------------
-// SerialName(id, response)
-// Check whether for address a (4 bytes in Unsigned Long) there is a name
-// This function only works if _TRUSTED_NODES is set
-// ----------------------------------------------------------------------------
-
-int SerialName(char * a, String& response)
-{
-#if _TRUSTED_NODES>=1
-	uint32_t id = ((a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3]);
-
-	int i;
-	for ( i=0; i< (sizeof(nodes)/sizeof(nodex)); i++) {
-
-		if (id == nodes[i].id) {
-#if DUSB >=1
-			if (( debug>=3 ) && ( pdebug & P_GUI )) {
-				Serial.print(F("G Name="));
-				Serial.print(nodes[i].nm);
-				Serial.print(F(" for node=0x"));
-				Serial.print(nodes[i].id,HEX);
-				Serial.println();
-			}
-#endif
-			response += nodes[i].nm;
-			return(i);
-		}
-	}
-
-#endif
-	return(-1);									// If no success OR is TRUSTED NODES not defined
-}
-
-#if _LOCALSERVER==1
-// ----------------------------------------------------------------------------
-// inDecodes(id)
-// Find the id in Decodes array, and return the index of the item
-// Parameters:
-//		id: The first field in the array (normally DevAddr id). Must be char[4]
-// Returns:
-//		The index of the ID in the Array. Returns -1 if not found
-// ----------------------------------------------------------------------------
-int inDecodes(char * id) {
-
-	uint32_t ident = ((id[3]<<24) | (id[2]<<16) | (id[1]<<8) | id[0]);
-
-	int i;
-	for ( i=0; i< (sizeof(decodes)/sizeof(codex)); i++) {
-		if (ident == decodes[i].id) {
-			return(i);
-		}
-	}
-	return(-1);
-}
-#endif

+ 0 - 1452
ESP-sc-gway/_wwwServer.ino

@@ -1,1452 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by many people and making use of several libraries.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains the webserver code for the ESP Single Channel Gateway.
-
-// Note:
-// The ESP Webserver works with Strings to display HTML content. 
-// Care must be taken that not all data is output to the webserver in one string
-// as this will use a LOT of memory and possibly kill the heap (cause system
-// crash or other unreliable behaviour.
-// Instead, output of the various tables on the webpage should be displayed in
-// chunks so that strings are limited in size.
-// Be aware that using no strings but only sendContent() calls has its own
-// disadvantage that these calls take a lot of time and cause the page to be
-// displayed like an old typewriter.
-// So, the trick is to make chucks that are sent to the website by using
-// a response String but not make those Strings too big.
-//
-// Also, selecting too many options for Statistics, display, Hopping channels
-// etc makes the gateway more sluggish and may impact the available memory and 
-// thus its performance and reliability. It's up to the user to select wisely!
-//
-
-
-// --------------------------------------------------------------------------------
-// PRINT IP
-// Output the 4-byte IP address for easy printing.
-// As this function is also used by _otaServer.ino do not put in #define
-// --------------------------------------------------------------------------------
-static void printIP(IPAddress ipa, const char sep, String& response)
-{
-	response+=(IPAddress)ipa[0]; response+=sep;
-	response+=(IPAddress)ipa[1]; response+=sep;
-	response+=(IPAddress)ipa[2]; response+=sep;
-	response+=(IPAddress)ipa[3];
-}
-
-//
-// The remainder of the file ONLY works is A_SERVER=1 is set.
-//
-#if A_SERVER==1
-
-// ================================================================================
-// WEBSERVER DECLARATIONS 
-// ================================================================================
-
-// None at the moment
-
-
-// ================================================================================
-// WEBSERVER FUNCTIONS 
-// ================================================================================
-
-
-// --------------------------------------------------------------------------------
-// Used by all functions requiring user confirmation
-// Displays a menu by user and two buttons "OK" and "CANCEL"
-// The function returns true for OK and false for CANCEL
-// Usage: Call this function ONCE during startup to declare and init
-// the ynDialog JavaScript function, and call the function
-// from the program when needed.
-// Paramters of the JavaScript function:
-//	s: Th strig contining the question to be answered
-//	o: The OK tab for the webpage where to go to
-//	c: The Cancel string (optional)
-// --------------------------------------------------------------------------------
-boolean YesNo()
-{
-	boolean ret = false;
-	String response = "";
-	response += "<script>";
-	
-	response += "var ch = \"\"; ";								// Init choice
-	response += "function ynDialog(s,y) {";
-	response += "  try { adddlert(s); }";
-	response += "  catch(err) {";
-	response += "    ch  = \" \" + s + \".\\n\\n\"; ";
-	response += "    ch += \"Click OK to continue,\\n\"; ";
-	response += "    ch += \"or Cancel\\n\\n\"; ";
-	response += "    if(!confirm(ch)) { ";
-	response += "      javascript:window.location.reload(true);";
-	response += "    } ";
-	response += "    else { ";
-	response += "      document.location.href = '/'+y; ";
-	response += "    } ";
-	response += "  }";
-	response += "}";
-	response += "</script>";
-	server.sendContent(response);
-	
-// Put something like this in the ESP program
-//	response += "<input type=\"button\" value=\"YesNo\" onclick=\"ynDialog()\" />";
-	
-	return(ret);
-}
-
-
-// --------------------------------------------------------------------------------
-// WWWFILE
-// This function will open a pop-up in the browser and then 
-//	display the contents of a file in that window
-// Output is sent to server.sendContent()
-// Parameters:
-//		fn; String with filename
-// Returns:
-//		<none>
-// --------------------------------------------------------------------------------
-void wwwFile(String fn) {
-
-	if (!SPIFFS.exists(fn)) {
-#if DUSB>=1
-		Serial.print(F("wwwFile:: ERROR: file not found="));
-		Serial.println(fn);
-#endif
-		return;
-	}
-#if DUSB>=2
-	else {
-		Serial.print(F("wwwFile:: File existist= "));
-		Serial.println(fn);
-	}
-#endif
-
-#if DUSB>=1
-		File f = SPIFFS.open(fn, "r");					// Open the file for reading
-		
-		int j;
-		for (j=0; j<LOGFILEREC; j++) {
-			
-			String s=f.readStringUntil('\n');
-			if (s.length() == 0) {
-				Serial.print(F("wwwFile:: String length 0"));
-				break;
-			}
-			server.sendContent(s.substring(12));		// Skip the first 12 Gateway specific binary characters
-			server.sendContent("\n");
-			yield();
-		}
-#endif
-	
-}
-
-// --------------------------------------------------------------------------------
-// Button function Docu, display the documentation pages.
-// This is a button on the top of the GUI screen.
-// --------------------------------------------------------------------------------
-void buttonDocu()
-{
-
-	String response = "";
-	response += "<script>";
-	
-	response += "var txt = \"\";";
-	response += "function showDocu() {";
-	response += "  try { adddlert(\"Welcome,\"); }";
-	response += "  catch(err) {";
-	response += "    txt  = \"Do you want the documentation page.\\n\\n\"; ";
-	response += "    txt += \"Click OK to continue viewing documentation,\\n\"; ";
-	response += "    txt += \"or Cancel to return to the home page.\\n\\n\"; ";
-	response += "    if(confirm(txt)) { ";
-	response += "      document.location.href = \"https://things4u.github.io/UserGuide/One%20Channel%20Gateway/Introduction%205.html\"; ";
-	response += "    }";
-	response += "  }";
-	response += "}";
-	
-	response += "</script>";
-	server.sendContent(response);
-}
-
-
-
-
-// --------------------------------------------------------------------------------
-// Button function Log displays  logfiles.
-// This is a button on the top of the GUI screen
-// --------------------------------------------------------------------------------
-void buttonLog() 
-{
-	
-	String response = "";
-	String fn = "";
-	int i = 0;
-	
-	while (i< LOGFILEMAX ) {
-		fn = "/log-" + String(gwayConfig.logFileNo - i);
-		wwwFile(fn);									// Display the file contents in the browser
-		i++;
-	}
-	
-	server.sendContent(response);
-}
-
-// --------------------------------------------------------------------------------
-// Navigate webpage by buttons. This method has some advantages:
-// - Less time/cpu usage
-// - Less memory usage		<a href=\"SPEED=160\">
-// --------------------------------------------------------------------------------
-static void wwwButtons()
-{
-	String response = "";
-	String mode = (gwayConfig.expert ? "Basic Mode" : "Expert Mode");
-
-	YesNo();												// Init the Yes/No function
-	buttonDocu();
-
-	response += "<input type=\"button\" value=\"Documentation\" onclick=\"showDocu()\" >";
-	
-	response += "<a href=\"EXPERT\" download><button type=\"button\">" + mode + "</button></a>";
-	response += "<a href=\"LOG\" download><button type=\"button\">Log Files</button></a>";
-
-	server.sendContent(response);							// Send to the screen
-}
-
-
-// --------------------------------------------------------------------------------
-// SET ESP8266 WEB SERVER VARIABLES
-//
-// This funtion implements the WiFi Webserver (very simple one). The purpose
-// of this server is to receive simple admin commands, and execute these
-// results which are sent back to the web client.
-// Commands: DEBUG, ADDRESS, IP, CONFIG, GETTIME, SETTIME
-// The webpage is completely built response and then printed on screen.
-//
-// Parameters:
-//		cmd: Contains a character array with the command to execute
-//		arg: Contains the parameter value of that command
-// Returns:
-//		<none>
-// --------------------------------------------------------------------------------
-static void setVariables(const char *cmd, const char *arg) {
-
-	// DEBUG settings; These can be used as a single argument
-	if (strcmp(cmd, "DEBUG")==0) {									// Set debug level 0-2
-		if (atoi(arg) == 1) {
-			debug = (debug+1)%4;
-		}	
-		else if (atoi(arg) == -1) {
-			debug = (debug+3)%4;
-		}
-		writeGwayCfg(CONFIGFILE);									// Save configuration to file
-	}
-	
-	if (strcmp(cmd, "CAD")==0) {									// Set -cad on=1 or off=0
-		_cad=(bool)atoi(arg);
-		writeGwayCfg(CONFIGFILE);									// Save configuration to file
-	}
-	
-	if (strcmp(cmd, "HOP")==0) {									// Set -hop on=1 or off=0
-		_hop=(bool)atoi(arg);
-		if (! _hop) { 
-			ifreq=0; 
-			setFreq(freqs[ifreq].upFreq);			
-			rxLoraModem();
-			sf = SF7;
-			cadScanner();
-		}
-		writeGwayCfg(CONFIGFILE);									// Save configuration to file
-	}
-	
-	if (strcmp(cmd, "DELAY")==0) {									// Set delay usecs
-		txDelay+=atoi(arg)*1000;
-	}
-	
-	// SF; Handle Spreading Factor Settings
-	if (strcmp(cmd, "SF")==0) {
-		uint8_t sfi = sf;
-		if (atoi(arg) == 1) {
-			if (sf>=SF12) sf=SF7; else sf= (sf_t)((int)sf+1);
-		}	
-		else if (atoi(arg) == -1) {
-			if (sf<=SF7) sf=SF12; else sf= (sf_t)((int)sf-1);
-		}
-		rxLoraModem();												// Reset the radio with the new spreading factor
-		writeGwayCfg(CONFIGFILE);									// Save configuration to file
-	}
-	
-	// FREQ; Handle Frequency  Settings
-	if (strcmp(cmd, "FREQ")==0) {
-		uint8_t nf = sizeof(freqs)/ sizeof(freqs[0]);				// Number of frequency elements in array
-		
-		// Compute frequency index
-		if (atoi(arg) == 1) {
-			if (ifreq==(nf-1)) ifreq=0; else ifreq++;
-		}
-		else if (atoi(arg) == -1) {
-			Serial.println("down");
-			if (ifreq==0) ifreq=(nf-1); else ifreq--;
-		}
-		setFreq(freqs[ifreq].upFreq);
-		rxLoraModem();												// Reset the radio with the new frequency
-		writeGwayCfg(CONFIGFILE);									// Save configuration to file
-	}
-
-	//if (strcmp(cmd, "GETTIME")==0) { Serial.println(F("gettime tbd")); }	// Get the local time
-	
-	//if (strcmp(cmd, "SETTIME")==0) { Serial.println(F("settime tbd")); }	// Set the local time
-	
-	if (strcmp(cmd, "HELP")==0)    { Serial.println(F("Display Help Topics")); }
-	
-#if GATEWAYNODE==1
-	if (strcmp(cmd, "NODE")==0) {									// Set node on=1 or off=0
-		gwayConfig.isNode =(bool)atoi(arg);
-		writeGwayCfg(CONFIGFILE);									// Save configuration to file
-	}
-	
-	if (strcmp(cmd, "FCNT")==0)   { 
-		frameCount=0; 
-		rxLoraModem();												// Reset the radio with the new frequency
-		writeGwayCfg(CONFIGFILE);
-	}
-#endif
-	
-#if WIFIMANAGER==1
-	if (strcmp(cmd, "NEWSSID")==0) { 
-		WiFiManager wifiManager;
-		strcpy(wpa[0].login,""); 
-		strcpy(wpa[0].passw,"");
-		WiFi.disconnect();
-		wifiManager.autoConnect(AP_NAME, AP_PASSWD );
-	}
-#endif
-
-#if A_OTA==1
-	if (strcmp(cmd, "UPDATE")==0) {
-		if (atoi(arg) == 1) {
-			updateOtaa();
-		}
-	}
-#endif
-
-#if A_REFRESH==1
-	if (strcmp(cmd, "REFR")==0) {									// Set refresh on=1 or off=0
-		gwayConfig.refresh =(bool)atoi(arg);
-		writeGwayCfg(CONFIGFILE);									// Save configuration to file
-	}
-#endif
-
-}
-
-
-// --------------------------------------------------------------------------------
-// OPEN WEB PAGE
-//	This is the init function for opening the webpage
-//
-// --------------------------------------------------------------------------------
-static void openWebPage()
-{
-	++gwayConfig.views;									// increment number of views
-#if A_REFRESH==1
-	//server.client().stop();							// Experimental, stop webserver in case something is still running!
-#endif
-	String response="";	
-
-	server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
-	server.sendHeader("Pragma", "no-cache");
-	server.sendHeader("Expires", "-1");
-	
-	// init webserver, fill the webpage
-	// NOTE: The page is renewed every _WWW_INTERVAL seconds, please adjust in ESP-sc-gway.h
-	//
-	server.setContentLength(CONTENT_LENGTH_UNKNOWN);
-	server.send(200, "text/html", "");
-#if A_REFRESH==1
-	if (gwayConfig.refresh) {
-		response += String() + "<!DOCTYPE HTML><HTML><HEAD><meta http-equiv='refresh' content='"+_WWW_INTERVAL+";http://";
-		printIP((IPAddress)WiFi.localIP(),'.',response);
-		response += "'><TITLE>ESP8266 1ch Gateway</TITLE>";
-	}
-	else {
-		response += String() + "<!DOCTYPE HTML><HTML><HEAD><TITLE>ESP8266 1ch Gateway</TITLE>";
-	}
-#else
-	response += String() + "<!DOCTYPE HTML><HTML><HEAD><TITLE>ESP8266 1ch Gateway</TITLE>";
-#endif
-	response += "<META HTTP-EQUIV='CONTENT-TYPE' CONTENT='text/html; charset=UTF-8'>";
-	response += "<META NAME='AUTHOR' CONTENT='M. Westenberg (mw1554@hotmail.com)'>";
-
-	response += "<style>.thead {background-color:green; color:white;} ";
-	response += ".cell {border: 1px solid black;}";
-	response += ".config_table {max_width:100%; min-width:400px; width:98%; border:1px solid black; border-collapse:collapse;}";
-	response += "</style></HEAD><BODY>";
-	
-	response +="<h1>ESP Gateway Config</h1>";
-
-	response +="<p style='font-size:10px;'>";
-	response +="Version: "; response+=VERSION;
-	response +="<br>ESP alive since "; 					// STARTED ON
-	stringTime(startTime, response);
-
-	response +=", Uptime: ";							// UPTIME
-	uint32_t secs = millis()/1000;
-	uint16_t days = secs / 86400;						// Determine number of days
-	uint8_t _hour   = hour(secs);
-	uint8_t _minute = minute(secs);
-	uint8_t _second = second(secs);
-	response += String() + days + "-";
-	if (_hour < 10) response += "0";
-	response += String() + _hour + ":";
-	if (_minute < 10) response += "0";
-	response += String() + _minute + ":";
-	if (_second < 10) response += "0";
-	response += String() + _second;
-	
-	response +="<br>Current time    "; 					// CURRENT TIME
-	stringTime(now(), response);
-	response +="<br>";
-	response +="</p>";
-	
-	server.sendContent(response);
-}
-
-
-// --------------------------------------------------------------------------------
-// H2 Gateway Settings
-//
-// Display the configuration and settings data. This is an interactive setting
-// allowing the user to set CAD, HOP, Debug and several other operating parameters
-//
-// --------------------------------------------------------------------------------
-static void gatewaySettings() 
-{
-	String response="";
-	String bg="";
-	
-	response +="<h2>Gateway Settings</h2>";
-	
-	response +="<table class=\"config_table\">";
-	response +="<tr>";
-	response +="<th class=\"thead\">Setting</th>";
-	response +="<th colspan=\"2\" style=\"background-color: green; color: white; width:120px;\">Value</th>";
-	response +="<th colspan=\"4\" style=\"background-color: green; color: white; width:100px;\">Set</th>";
-	response +="</tr>";
-	
-	bg = " background-color: ";
-	bg += ( _cad ? "LightGreen" : "orange" );
-	response +="<tr><td class=\"cell\">CAD</td>";
-	response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
-	response += ( _cad ? "ON" : "OFF" );
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=1\"><button>ON</button></a></td>";
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=0\"><button>OFF</button></a></td>";
-	response +="</tr>";
-	
-	bg = " background-color: ";
-	bg += ( _hop ? "LightGreen" : "orange" );
-	response +="<tr><td class=\"cell\">HOP</td>";
-	response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
-	response += ( _hop ? "ON" : "OFF" );
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=1\"><button>ON</button></a></td>";
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=0\"><button>OFF</button></a></td>";
-	response +="</tr>";
-	
-	response +="<tr><td class=\"cell\">SF Setting</td><td class=\"cell\" colspan=\"2\">";
-	if (_cad) {
-		response += "AUTO</td>";
-	}
-	else {
-		response += sf;
-		response +="<td class=\"cell\"><a href=\"SF=-1\"><button>-</button></a></td>";
-		response +="<td class=\"cell\"><a href=\"SF=1\"><button>+</button></a></td>";
-	}
-	response +="</tr>";
-	
-	// Channel
-	response +="<tr><td class=\"cell\">Channel</td>";
-	response +="<td class=\"cell\" colspan=\"2\">"; 
-	if (_hop) {
-		response += "AUTO</td>";
-	}
-	else {
-		response += String() + ifreq; 
-		response +="</td>";
-		response +="<td class=\"cell\"><a href=\"FREQ=-1\"><button>-</button></a></td>";
-		response +="<td class=\"cell\"><a href=\"FREQ=1\"><button>+</button></a></td>";
-	}
-	response +="</tr>";
-
-	// Debugging options, only when DUSB is set, otherwise no
-	// serial activity
-#if DUSB>=1	
-	response +="<tr><td class=\"cell\">Debug level</td><td class=\"cell\" colspan=\"2\">"; 
-	response +=debug; 
-	response +="</td>";
-	response +="<td class=\"cell\"><a href=\"DEBUG=-1\"><button>-</button></a></td>";
-	response +="<td class=\"cell\"><a href=\"DEBUG=1\"><button>+</button></a></td>";
-	response +="</tr>";
-	
-	response +="<tr><td class=\"cell\">Debug pattern</td>"; 
-	
-	bg = ( (pdebug & P_SCAN) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=SCAN\">";
-	response +="<button>SCN</button></a></td>";
-	
-	bg = ( (pdebug & P_CAD) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=CAD\">";
-	response +="<button>CAD</button></a></td>";
-
-	bg = ( (pdebug & P_RX) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=RX\">";
-	response +="<button>RX</button></a></td>";
-
-	bg = ( (pdebug & P_TX) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=TX\">";
-	response +="<button>TX</button></a></td>";
-	response += "</tr>";
-	
-	// Use a second Line
-	response +="<tr><td class=\"cell\"></td>";
-	bg = ( (pdebug & P_PRE) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=PRE\">";
-	response +="<button>PRE</button></a></td>";
-
-	bg = ( (pdebug & P_MAIN) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=MAIN\">";
-	response +="<button>MAI</button></a></td>";
-	
-	bg = ( (pdebug & P_GUI) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=GUI\">";
-	response +="<button>GUI</button></a></td>";
-
-	bg = ( (pdebug & P_RADIO) ? "LightGreen" : "orange" ); 
-	response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
-	response += bg;	response += "\">";
-	response +="<a href=\"PDEBUG=RADIO\">";
-	response +="<button>RDIO</button></a></td>";
-	response +="</tr>";
-#endif
-	// Serial Debugging
-	response +="<tr><td class=\"cell\">Usb Debug</td><td class=\"cell\" colspan=\"2\">"; 
-	response +=DUSB; 
-	response +="</td>";
-	//response +="<td class=\"cell\"> </td>";
-	//response +="<td class=\"cell\"> </td>";
-	response +="</tr>";
-	
-#if GATEWAYNODE==1
-	response +="<tr><td class=\"cell\">Framecounter Internal Sensor</td>";
-	response +="<td class=\"cell\" colspan=\"2\">";
-	response +=frameCount;
-	response +="</td><td colspan=\"2\" style=\"border: 1px solid black;\">";
-	response +="<button><a href=\"/FCNT\">RESET</a></button></td>";
-	response +="</tr>";
-	
-	bg = " background-color: ";
-	bg += ( (gwayConfig.isNode == 1) ? "LightGreen" : "orange" );
-	response +="<tr><td class=\"cell\">Gateway Node</td>";
-	response +="<td class=\"cell\" style=\"border: 1px solid black;" + bg + "\">";
-	response += ( (gwayConfig.isNode == true) ? "ON" : "OFF" );
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"NODE=1\"><button>ON</button></a></td>";
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"NODE=0\"><button>OFF</button></a></td>";
-	response +="</tr>";
-#endif
-
-#if A_REFRESH==1
-	bg = " background-color: ";
-	bg += ( (gwayConfig.refresh == 1) ? "LightGreen" : "orange" );
-	response +="<tr><td class=\"cell\">WWW Refresh</td>";
-	response +="<td class=\"cell\" colspan=\"2\" style=\"border: 1px solid black; " + bg + "\">";
-	response += ( (gwayConfig.refresh == 1) ? "ON" : "OFF" );
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=1\"><button>ON</button></a></td>";
-	response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=0\"><button>OFF</button></a></td>";
-	response +="</tr>";
-#endif
-
-	// Reset Accesspoint
-#if WIFIMANAGER==1
-	response +="<tr><td><tr><td>";
-	response +="Click <a href=\"/NEWSSID\">here</a> to reset accesspoint<br>";
-	response +="</td><td></td></tr>";
-#endif
-
-	// Update Firmware all statistics
-	response +="<tr><td class=\"cell\">Update Firmware</td><td colspan=\"2\"></td>";
-	response +="<td class=\"cell\" colspan=\"2\" class=\"cell\"><a href=\"/UPDATE=1\"><button>UPDATE</button></a></td></tr>";
-
-	// Format the Filesystem
-	response +="<tr><td class=\"cell\">Format SPIFFS</td>";
-	response +=String() + "<td class=\"cell\" colspan=\"2\" >"+""+"</td>";
-	response +="<td colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"FORMAT\" onclick=\"ynDialog(\'Do you really want to format?\',\'FORMAT\')\" /></td></tr>";
-
-	// Reset all statistics
-#if STATISTICS >= 1
-	response +="<tr><td class=\"cell\">Statistics</td>";
-	response +=String() + "<td class=\"cell\" colspan=\"2\" >"+statc.resets+"</td>";
-	response +="<td colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"RESET\" onclick=\"ynDialog(\'Do you really want to reset statistics?\',\'RESET\')\" /></td></tr>";
-
-	// Reset
-	response +="<tr><td class=\"cell\">Boots and Resets</td>";
-	response +=String() + "<td class=\"cell\" colspan=\"2\" >"+gwayConfig.boots+"</td>";
-	response +="<td colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"RESET\" onclick=\"ynDialog(\'Do you want to reset boots?\',\'BOOT\')\" /></td></tr>";
-#endif
-	
-	response +="</table>";
-	
-	server.sendContent(response);
-}
-
-
-// --------------------------------------------------------------------------------
-// H2 Package Statistics
-//
-// This section display a matrix on the screen where everay channel and spreading
-// factor is displayed.
-// --------------------------------------------------------------------------------
-static void statisticsData()
-{
-	String response="";
-
-	// Header
-	response +="<h2>Package Statistics</h2>";
-	response +="<table class=\"config_table\">";
-	response +="<tr><th class=\"thead\">Counter</th>";
-#if STATISTICS == 3
-	response +="<th class=\"thead\">C 0</th>";
-	response +="<th class=\"thead\">C 1</th>";
-	response +="<th class=\"thead\">C 2</th>";
-#endif
-	response +="<th class=\"thead\">Pkgs</th>";
-	response +="<th class=\"thead\">Pkgs/hr</th>";
-	response +="</tr>";
-
-	//
-	// Table rows
-	//
-	response +="<tr><td class=\"cell\">Packages Downlink</td>";
-#if STATISTICS == 3
-		response +="<td class=\"cell\">" + String(statc.msg_down_0) + "</td>";
-		response +="<td class=\"cell\">" + String(statc.msg_down_1) + "</td>";
-		response +="<td class=\"cell\">" + String(statc.msg_down_2) + "</td>"; 
-#endif
-	response += "<td class=\"cell\">" + String(statc.msg_down) + "</td>";
-	response +="<td class=\"cell\"></td></tr>";
-		
-	response +="<tr><td class=\"cell\">Packages Uplink Total</td>";
-#if STATISTICS == 3
-		response +="<td class=\"cell\">" + String(statc.msg_ttl_0) + "</td>";
-		response +="<td class=\"cell\">" + String(statc.msg_ttl_1) + "</td>";
-		response +="<td class=\"cell\">" + String(statc.msg_ttl_2) + "</td>";
-#endif
-		response +="<td class=\"cell\">" + String(statc.msg_ttl) + "</td>";
-		response +="<td class=\"cell\">" + String((statc.msg_ttl*3600)/(now() - startTime)) + "</td></tr>";
-		
-	response +="<tr><td class=\"cell\">Packages Uplink OK </td>";
-#if STATISTICS == 3
-		response +="<td class=\"cell\">" + String(statc.msg_ok_0) + "</td>";
-		response +="<td class=\"cell\">" + String(statc.msg_ok_1) + "</td>";
-		response +="<td class=\"cell\">" + String(statc.msg_ok_2) + "</td>";
-#endif
-	response +="<td class=\"cell\">" + String(statc.msg_ok) + "</td>";
-	response +="<td class=\"cell\"></td></tr>";
-		
-
-	// Provide a table with all the SF data including percentage of messsages
-#if STATISTICS == 2
-	response +="<tr><td class=\"cell\">SF7 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf7; 
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf7/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-	response +="<tr><td class=\"cell\">SF8 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf8;
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf8/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-	response +="<tr><td class=\"cell\">SF9 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf9;
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf9/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-	response +="<tr><td class=\"cell\">SF10 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf10; 
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf10/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-	response +="<tr><td class=\"cell\">SF11 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf11; 
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf11/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-	response +="<tr><td class=\"cell\">SF12 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf12; 
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf12/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-#endif
-#if STATISTICS == 3
-	response +="<tr><td class=\"cell\">SF7 rcvd</td>";
-		response +="<td class=\"cell\">"; response +=statc.sf7_0; 
-		response +="<td class=\"cell\">"; response +=statc.sf7_1; 
-		response +="<td class=\"cell\">"; response +=statc.sf7_2; 
-		response +="<td class=\"cell\">"; response +=statc.sf7; 
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf7/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-		
-	response +="<tr><td class=\"cell\">SF8 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf8_0;
-		response +="<td class=\"cell\">"; response +=statc.sf8_1;
-		response +="<td class=\"cell\">"; response +=statc.sf8_2;
-		response +="<td class=\"cell\">"; response +=statc.sf8;
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf8/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-		
-	response +="<tr><td class=\"cell\">SF9 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf9_0;
-		response +="<td class=\"cell\">"; response +=statc.sf9_1;
-		response +="<td class=\"cell\">"; response +=statc.sf9_2;
-		response +="<td class=\"cell\">"; response +=statc.sf9;
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf9/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-		
-	response +="<tr><td class=\"cell\">SF10 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf10_0; 
-		response +="<td class=\"cell\">"; response +=statc.sf10_1; 
-		response +="<td class=\"cell\">"; response +=statc.sf10_2; 
-		response +="<td class=\"cell\">"; response +=statc.sf10; 
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf10/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-		
-	response +="<tr><td class=\"cell\">SF11 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf11_0;
-		response +="<td class=\"cell\">"; response +=statc.sf11_1; 
-		response +="<td class=\"cell\">"; response +=statc.sf11_2; 
-		response +="<td class=\"cell\">"; response +=statc.sf11; 
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf11/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-		
-	response +="<tr><td class=\"cell\">SF12 rcvd</td>"; 
-		response +="<td class=\"cell\">"; response +=statc.sf12_0;
-		response +="<td class=\"cell\">"; response +=statc.sf12_1;
-		response +="<td class=\"cell\">"; response +=statc.sf12_1;
-		response +="<td class=\"cell\">"; response +=statc.sf12;		
-		response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf12/statc.msg_ttl : 0)+" %"; 
-		response +="</td></tr>";
-#endif
-
-	response +="</table>";
-	server.sendContent(response);
-}
-
-
-
-
-// --------------------------------------------------------------------------------
-// Message History
-// If enabled, display the sensor messageHistory on the current webserver Page.
-// In this GUI section a number of statr[x] records are displayed such as:
-//
-// Time, The time the sensor message was received
-// Node, the DevAddr or even Node name for Trusted nodes,
-// Data (Localserver), when _LOCALSERVER is enabled contains decoded data
-// C, Channel frequency on which the sensor was received
-// Freq, The frequency of the channel
-// SF, Spreading Factor
-// pRSSI, Packet RSSI
-//
-// Parameters:
-//	- <none>
-// Returns:
-//	- <none>
-// --------------------------------------------------------------------------------
-static void messageHistory() 
-{
-#if STATISTICS >= 1
-	String response="";
-	
-	response += "<h2>Message History</h2>";
-	response += "<table class=\"config_table\">";
-	response += "<tr>";
-	response += "<th class=\"thead\">Time</th>";
-	response += "<th class=\"thead\">Node</th>";
-#if _LOCALSERVER==1
-	response += "<th class=\"thead\">Data</th>";
-#endif
-	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) {
-		response += "<th class=\"thead\" style=\"width: 50px;\">RSSI</th>";
-	}
-#endif
-	response += "</tr>";
-	server.sendContent(response);
-
-	for (int i=0; i<MAX_STAT; i++) {
-		if (statr[i].sf == 0) break;
-		
-		response = "";
-		
-		response += String() + "<tr><td class=\"cell\">";					// Tmst
-		stringTime((statr[i].tmst), response);			// XXX Change tmst not to be millis() dependent
-		response += "</td>";
-		
-		response += String() + "<td class=\"cell\">"; 						// Node
-		if (SerialName((char *)(& (statr[i].node)), response) < 0) {		// works with TRUSTED_NODES >= 1
-			printHEX((char *)(& (statr[i].node)),' ',response);				// else
-		}
-		response += "</td>";
-		
-#if _LOCALSERVER==1
-		response += String() + "<td class=\"cell\">";						// Data
-		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
-
-
-		response += String() + "<td class=\"cell\">" + statr[i].ch + "</td>";
-		response += String() + "<td class=\"cell\">" + freqs[statr[i].ch].upFreq + "</td>";
-		response += String() + "<td class=\"cell\">" + statr[i].sf + "</td>";
-
-		response += String() + "<td class=\"cell\">" + statr[i].prssi + "</td>";
-#if RSSI==1
-		if (debug >= 2) {
-			response += String() + "<td class=\"cell\">" + statr[i].rssi + "</td>";
-		}
-#endif
-		response += "</tr>";
-		server.sendContent(response);
-	}
-	
-	server.sendContent("</table>");
-	
-#endif
-}
-
-
-// --------------------------------------------------------------------------------
-// SEND WEB PAGE() 
-// Call the webserver and send the standard content and the content that is 
-// passed by the parameter. Each time a variable is changed, this function is 
-// called to display the webpage again/
-//
-// NOTE: This is the only place where yield() or delay() calls are used.
-//
-// --------------------------------------------------------------------------------
-void sendWebPage(const char *cmd, const char *arg)
-{
-	openWebPage(); yield();						// Do the initial website setup
-	
-	wwwButtons();								// Display buttons such as Documentation, Mode, Logfiles
-	
-	setVariables(cmd,arg); yield();				// Read Webserver commands from line
-
-	statisticsData(); yield();		 			// Node statistics
-	messageHistory(); yield();					// Display the sensor history, message statistics
-
-	gatewaySettings(); yield();					// Display web configuration
-	wifiConfig(); yield();						// WiFi specific parameters
-	
-	systemStatus(); yield();					// System statistics such as heap etc.
-	interruptData(); yield();					// Display interrupts only when debug >= 2
-	
-	websiteFooter(); yield();
-	
-
-	
-	server.client().stop();
-}
-
-
-// --------------------------------------------------------------------------------
-// setupWWW is the main function for webserver functions/
-// SetupWWW function called by main setup() program to setup webserver
-// It does actually not much more than installing all the callback handlers
-// for messages sent to the webserver
-//
-// Implemented is an interface like:
-// http://<server>/<Variable>=<value>
-//
-// --------------------------------------------------------------------------------
-void setupWWW() 
-{
-	server.begin();									// Start the webserver
-	
-	// -----------------
-	// BUTTONS, define what should happen with the buttons we press on the homepage
-	
-	server.on("/", []() {
-		sendWebPage("","");							// Send the webPage string
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	
-	server.on("/HELP", []() {
-		sendWebPage("HELP","");					// Send the webPage string
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// Format the filesystem
-	server.on("/FORMAT", []() {
-		Serial.print(F("FORMAT ..."));
-		
-		SPIFFS.format();								// Normally disabled. Enable only when SPIFFS corrupt
-		initConfig(&gwayConfig);
-		writeConfig( CONFIGFILE, &gwayConfig);
-#if DUSB>=1
-		Serial.println(F("DONE"));
-#endif
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	
-	
-	// Reset the statistics
-	server.on("/RESET", []() {
-		Serial.println(F("RESET"));
-		startTime= now() - 1;					// Reset all timers too	
-		
-		statc.msg_ttl = 0;						// Reset package statistics
-		statc.msg_ok = 0;
-		statc.msg_down = 0;
-		
-#if STATISTICS >= 3
-		statc.msg_ttl_0 = 0;
-		statc.msg_ttl_1 = 0;
-		statc.msg_ttl_2 = 0;
-		statc.msg_ok_0 = 0;
-		statc.msg_ok_1 = 0;
-		statc.msg_ok_2 = 0;
-		statc.msg_down_0 = 0;
-		statc.msg_down_1 = 0;
-		statc.msg_down_2 = 0;	
-#endif
-
-#if STATISTICS >= 1
-		for (int i=0; i<MAX_STAT; i++) { statr[i].sf = 0; }
-#if STATISTICS >= 2
-		statc.sf7 = 0;
-		statc.sf8 = 0;
-		statc.sf9 = 0;
-		statc.sf10= 0;
-		statc.sf11= 0;
-		statc.sf12= 0;
-		
-		statc.resets= 0;
-		writeGwayCfg(CONFIGFILE);
-#if STATISTICS >= 3
-		statc.sf7_0 = 0; statc.sf7_1 = 0; statc.sf7_2 = 0;
-		statc.sf8_0 = 0; statc.sf8_1 = 0; statc.sf8_2 = 0;
-		statc.sf9_0 = 0; statc.sf9_1 = 0; statc.sf9_2 = 0;
-		statc.sf10_0= 0; statc.sf10_1= 0; statc.sf10_2= 0;
-		statc.sf11_0= 0; statc.sf11_1= 0; statc.sf11_2= 0;
-		statc.sf12_0= 0; statc.sf12_1= 0; statc.sf12_2= 0;
-#endif
-#endif
-#endif
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// Reset the boot counter
-	server.on("/BOOT", []() {
-		Serial.println(F("BOOT"));
-#if STATISTICS >= 2
-		gwayConfig.boots = 0;
-		gwayConfig.wifis = 0;
-		gwayConfig.views = 0;
-		gwayConfig.ntpErr = 0;					// NTP errors
-		gwayConfig.ntpErrTime = 0;				// NTP last error time
-		gwayConfig.ntps = 0;					// Number of NTP calls
-#endif
-		gwayConfig.reents = 0;					// Re-entrance
-
-		writeGwayCfg(CONFIGFILE);
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	server.on("/NEWSSID", []() {
-		sendWebPage("NEWSSID","");				// Send the webPage string
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// Set debug parameter
-	server.on("/DEBUG=-1", []() {				// Set debug level 0-2						
-		debug = (debug+3)%4;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/DEBUG=1", []() {
-		debug = (debug+1)%4;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// Set PDEBUG parameter
-	//
-		server.on("/PDEBUG=SCAN", []() {		// Set debug level 0-2						
-		pdebug ^= P_SCAN;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/PDEBUG=CAD", []() {				// Set debug level 0-2						
-		pdebug ^= P_CAD;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/PDEBUG=RX", []() {				// Set debug level 0-2						
-		pdebug ^= P_RX;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/PDEBUG=TX", []() {				// Set debug level 0-2						
-		pdebug ^= P_TX;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/PDEBUG=PRE", []() {				// Set debug level 0-2						
-		pdebug ^= P_PRE;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/PDEBUG=MAIN", []() {				// Set debug level 0-2						
-		pdebug ^= P_MAIN;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/PDEBUG=GUI", []() {				// Set debug level 0-2						
-		pdebug ^= P_GUI;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/PDEBUG=RADIO", []() {				// Set debug level 0-2						
-		pdebug ^= P_RADIO;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	
-	// Set delay in microseconds
-	server.on("/DELAY=1", []() {
-		txDelay+=5000;
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/DELAY=-1", []() {
-		txDelay-=5000;
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-
-	// Spreading Factor setting
-	server.on("/SF=1", []() {
-		if (sf>=SF12) sf=SF7; else sf= (sf_t)((int)sf+1);
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/SF=-1", []() {
-		if (sf<=SF7) sf=SF12; else sf= (sf_t)((int)sf-1);
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// Set Frequency of the GateWay node
-	server.on("/FREQ=1", []() {
-		uint8_t nf = sizeof(freqs)/sizeof(freqs[0]);	// Number of elements in array
-#if DUSB==2
-		Serial.print("FREQ==1:: For freq[0] sizeof vector=");
-		Serial.print(sizeof(freqs[0]));
-		Serial.println();
-#endif
-		if (ifreq==(nf-1)) ifreq=0; else ifreq++;
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/FREQ=-1", []() {
-		uint8_t nf = sizeof(freqs)/sizeof(freqs[0]);	// Number of elements in array
-		if (ifreq==0) ifreq=(nf-1); else ifreq--;
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// Set CAD function off/on
-	server.on("/CAD=1", []() {
-		_cad=(bool)1;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/CAD=0", []() {
-		_cad=(bool)0;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// GatewayNode
-	server.on("/NODE=1", []() {
-#if GATEWAYNODE==1
-		gwayConfig.isNode =(bool)1;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#endif
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/NODE=0", []() {
-#if GATEWAYNODE==1
-		gwayConfig.isNode =(bool)0;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#endif
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-#if GATEWAYNODE==1	
-	// Framecounter of the Gateway node
-	server.on("/FCNT", []() {
-
-		frameCount=0; 
-		rxLoraModem();							// Reset the radio with the new frequency
-		writeGwayCfg(CONFIGFILE);
-
-		//sendWebPage("","");						// Send the webPage string
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-#endif
-	// WWW Page refresh function
-	server.on("/REFR=1", []() {					// WWW page auto refresh ON
-#if A_REFRESH==1
-		gwayConfig.refresh =1;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#endif		
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/REFR=0", []() {					// WWW page auto refresh OFF
-#if A_REFRESH==1
-		gwayConfig.refresh =0;
-		writeGwayCfg(CONFIGFILE);				// Save configuration to file
-#endif
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	
-	// Switch off/on the HOP functions
-	server.on("/HOP=1", []() {
-		_hop=true;
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/HOP=0", []() {
-		_hop=false;
-		ifreq=0; 
-		setFreq(freqs[ifreq].upFreq);
-		rxLoraModem();
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-#if !defined ESP32_ARCH
-	// Change speed to 160 MHz
-	server.on("/SPEED=80", []() {
-		system_update_cpu_freq(80);
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-	server.on("/SPEED=160", []() {
-		system_update_cpu_freq(160);
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-#endif
-	// Display Documentation pages
-	server.on("/DOCU", []() {
-
-		server.sendHeader("Location", String("/"), true);
-		buttonDocu();
-		server.send ( 302, "text/plain", "");
-	});
-	
-	server.on("/LOG", []() {
-		server.sendHeader("Location", String("/"), true);
-#if DUSB>=1
-		Serial.println(F("LOG button"));
-#endif
-		buttonLog();
-		server.send ( 302, "text/plain", "");
-	});
-	
-	// Display Expert mode or Simple mode
-	server.on("/EXPERT", []() {
-		server.sendHeader("Location", String("/"), true);
-		gwayConfig.expert = bool(1 - (int) gwayConfig.expert) ;
-		server.send ( 302, "text/plain", "");
-	});
-
-	
-	// Update the sketch. Not yet implemented
-	server.on("/UPDATE=1", []() {
-#if A_OTA==1
-		updateOtaa();
-#endif
-		server.sendHeader("Location", String("/"), true);
-		server.send ( 302, "text/plain", "");
-	});
-
-	// -----------
-	// This section from version 4.0.7 defines what PART of the
-	// webpage is shown based on the buttons pressed by the user
-	// Maybe not all information should be put on the screen since it
-	// may take too much time to serve all information before a next
-	// package interrupt arrives at the gateway
-	
-	Serial.print(F("WWW Server started on port "));
-	Serial.println(A_SERVERPORT);
-	return;
-} // setupWWW
-
-
-
-// --------------------------------------------------------------------------------
-// WIFI CONFIG
-// wifiConfig() displays the most important Wifi parameters gathered
-//
-// --------------------------------------------------------------------------------
-static void wifiConfig()
-{
-	if (gwayConfig.expert) {
-	String response="";
-	response +="<h2>WiFi Config</h2>";
-
-	response +="<table class=\"config_table\">";
-
-	response +="<tr><th class=\"thead\">Parameter</th><th class=\"thead\">Value</th></tr>";
-	
-	response +="<tr><td class=\"cell\">WiFi host</td><td class=\"cell\">"; 
-#if ESP32_ARCH==1
-	response +=WiFi.getHostname(); response+="</tr>";
-#else
-	response +=wifi_station_get_hostname(); response+="</tr>";
-#endif
-
-	response +="<tr><td class=\"cell\">WiFi SSID</td><td class=\"cell\">"; 
-	response +=WiFi.SSID(); response+="</tr>";
-	
-	response +="<tr><td class=\"cell\">IP Address</td><td class=\"cell\">"; 
-	printIP((IPAddress)WiFi.localIP(),'.',response); 
-	response +="</tr>";
-	response +="<tr><td class=\"cell\">IP Gateway</td><td class=\"cell\">"; 
-	printIP((IPAddress)WiFi.gatewayIP(),'.',response); 
-	response +="</tr>";
-	response +="<tr><td class=\"cell\">NTP Server</td><td class=\"cell\">"; response+=NTP_TIMESERVER; response+="</tr>";
-	response +="<tr><td class=\"cell\">LoRa Router</td><td class=\"cell\">"; response+=_TTNSERVER; response+="</tr>";
-	response +="<tr><td class=\"cell\">LoRa Router IP</td><td class=\"cell\">"; 
-	printIP((IPAddress)ttnServer,'.',response); 
-	response +="</tr>";
-#ifdef _THINGSERVER
-	response +="<tr><td class=\"cell\">LoRa Router 2</td><td class=\"cell\">"; response+=_THINGSERVER; 
-	response += String() + ":" + _THINGPORT + "</tr>";
-	response +="<tr><td class=\"cell\">LoRa Router 2 IP</td><td class=\"cell\">"; 
-	printIP((IPAddress)thingServer,'.',response);
-	response +="</tr>";
-#endif
-	response +="</table>";
-
-	server.sendContent(response);
-	} // gwayConfig.expert
-} // wifiConfig
-
-
-// --------------------------------------------------------------------------------
-// H2 systemStatus
-// systemStatus is additional and only available in the expert mode.
-// It provides a number of system specific data such as heap size etc.
-// --------------------------------------------------------------------------------
-static void systemStatus()
-{
-	if (gwayConfig.expert) {
-		String response="";
-		response +="<h2>System Status</h2>";
-	
-		response +="<table class=\"config_table\">";
-		response +="<tr>";
-		response +="<th class=\"thead\">Parameter</th>";
-		response +="<th class=\"thead\">Value</th>";
-		response +="<th colspan=\"2\" class=\"thead\">Set</th>";
-		response +="</tr>";
-	
-		response +="<tr><td style=\"border: 1px solid black; width:120px;\">Gateway ID</td>";
-		response +="<td class=\"cell\">";	
-		if (MAC_array[0]< 0x10) response +='0'; response +=String(MAC_array[0],HEX);	// The MAC array is always returned in lowercase
-		if (MAC_array[1]< 0x10) response +='0'; response +=String(MAC_array[1],HEX);
-		if (MAC_array[2]< 0x10) response +='0'; response +=String(MAC_array[2],HEX);
-		response +="FFFF"; 
-		if (MAC_array[3]< 0x10) response +='0'; response +=String(MAC_array[3],HEX);
-		if (MAC_array[4]< 0x10) response +='0'; response +=String(MAC_array[4],HEX);
-		if (MAC_array[5]< 0x10) response +='0'; response +=String(MAC_array[5],HEX);
-		response+="</tr>";
-	
-
-		response +="<tr><td class=\"cell\">Free heap</td><td class=\"cell\">"; response+=ESP.getFreeHeap(); response+="</tr>";
-// XXX We Shoudl find an ESP32 alternative
-#if !defined ESP32_ARCH
-		response +="<tr><td class=\"cell\">ESP speed</td><td class=\"cell\">"; response+=ESP.getCpuFreqMHz(); 
-		response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=80\"><button>80</button></a></td>";
-		response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=160\"><button>160</button></a></td>";
-		response+="</tr>";
-		response +="<tr><td class=\"cell\">ESP Chip ID</td><td class=\"cell\">"; response+=ESP.getChipId(); response+="</tr>";
-#endif
-		response +="<tr><td class=\"cell\">OLED</td><td class=\"cell\">"; response+=OLED; response+="</tr>";
-		
-#if STATISTICS>=1
-		response +="<tr><td class=\"cell\">WiFi Setups</td><td class=\"cell\">"; response+=gwayConfig.wifis; response+="</tr>";
-		response +="<tr><td class=\"cell\">WWW Views</td><td class=\"cell\">"; response+=gwayConfig.views; response+="</tr>";
-#endif
-
-		response +="</table>";
-		server.sendContent(response);
-	} // gwayConfig.expert
-} // systemStatus
-
-
-// --------------------------------------------------------------------------------
-// H2 System State and Interrupt
-// Display interrupt data, but only for debug >= 2
-//
-// --------------------------------------------------------------------------------
-static void interruptData()
-{
-	if (gwayConfig.expert) {
-		uint8_t flags = readRegister(REG_IRQ_FLAGS);
-		uint8_t mask = readRegister(REG_IRQ_FLAGS_MASK);
-		String response="";
-		
-		response +="<h2>System State and Interrupt</h2>";
-		
-		response +="<table class=\"config_table\">";
-		response +="<tr>";
-		response +="<th class=\"thead\">Parameter</th>";
-		response +="<th class=\"thead\">Value</th>";
-		response +="<th colspan=\"2\"  class=\"thead\">Set</th>";
-		response +="</tr>";
-		
-		response +="<tr><td class=\"cell\">_state</td>";
-		response +="<td class=\"cell\">";
-		switch (_state) {							// See loraModem.h
-			case S_INIT: response +="INIT"; break;
-			case S_SCAN: response +="SCAN"; break;
-			case S_CAD: response +="CAD"; break;
-			case S_RX: response +="RX"; break;
-			case S_TX: response +="TX"; break;
-			default: response +="unknown"; break;
-		}
-		response +="</td></tr>";
-		
-		response +="<tr><td class=\"cell\">_STRICT_1CH</td>";
-		response +="<td class=\"cell\">" ;
-		response += String() + _STRICT_1CH;
-		response +="</td></tr>";		
-
-		response +="<tr><td class=\"cell\">flags (8 bits)</td>";
-		response +="<td class=\"cell\">0x";
-		if (flags <16) response += "0";
-		response +=String(flags,HEX); response+="</td></tr>";
-
-		
-		response +="<tr><td class=\"cell\">mask (8 bits)</td>";
-		response +="<td class=\"cell\">0x"; 
-		if (mask <16) response += "0";
-		response +=String(mask,HEX); response+="</td></tr>";
-		
-		response +="<tr><td class=\"cell\">Re-entrant cntr</td>";
-		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.reents;
-		response +="</td></tr>";
-
-		response +="<tr><td class=\"cell\">ntp call cntr</td>";
-		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.ntps;
-		response+="</td></tr>";
-		
-		response +="<tr><td class=\"cell\">ntpErr cntr</td>";
-		response +="<td class=\"cell\">"; 
-		response += String() + gwayConfig.ntpErr;
-		response +="</td>";
-		response +="<td colspan=\"2\" style=\"border: 1px solid black;\">";
-		stringTime(gwayConfig.ntpErrTime, response);
-		response +="</td>";
-		response +="</tr>";
-		
-		response +="<tr><td class=\"cell\">Time Correction (uSec)</td><td class=\"cell\">"; 
-		response += txDelay; 
-		response +="</td>";
-		response +="<td class=\"cell\"><a href=\"DELAY=-1\"><button>-</button></a></td>";
-		response +="<td class=\"cell\"><a href=\"DELAY=1\"><button>+</button></a></td>";
-		response +="</tr>";
-		
-		response +="</table>";
-		
-		server.sendContent(response);
-	}// if gwayConfig.expert
-} // interruptData
-
-
-// --------------------------------------------------------------------------------
-// websiteFooter
-// 
-// Thi function displays the last messages without header on the webpage and then
-// closes the webpage.
-// --------------------------------------------------------------------------------
-static void websiteFooter()
-{
-	// Close the client connection to server
-	server.sendContent(String() + "<br><br /><p style='font-size:10px'>Click <a href=\"/HELP\">here</a> to explain Help and REST options</p><br>");
-	server.sendContent(String() + "</BODY></HTML>");
-	
-	server.sendContent(""); yield();
-}
-
-
-#endif // A_SERVER==1
-

+ 0 - 92
ESP-sc-gway/loraFiles.h

@@ -1,92 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains a number of compile-time settings that can be set on (=1) or off (=0)
-// The disadvantage of compile time is minor compared to the memory gain of not having
-// too much code compiled and loaded on your ESP8266.
-//
-// ----------------------------------------------------------------------------------------
-
-// At this moment there is only one record written to the ESP8266
-// filesystem. We can add more info, which makes the gateway even more usable,
-// however for large data we should only append to the existing file used.
-// This also means we'll have to check for available space so we won't run out of 
-// storage space to quickly.
-// One way would be to use let's say 10 files of each 10000 lines and when full
-// delete the first file and start writing on a new one (for example)
-
-
-
-//
-// Define Pattern debug settings, this allows debugging per
-// module rather than per level. See also pdebug.
-//
-#define P_SCAN		0x01
-#define P_CAD		0x02
-#define P_RX		0x04
-#define P_TX		0x08
-#define P_PRE		0x10
-#define P_MAIN		0x20
-#define P_GUI		0x40
-#define P_RADIO		0x80
-
-// Definition of the configuration record that is read at startup and written
-// when settings are changed.
-
-struct espGwayConfig {
-	uint16_t fcnt;				// =0 as init value	XXX Could be 32 bit in size
-	uint16_t boots;				// Number of restarts made by the gateway after reset
-	uint16_t resets;			// Number of statistics resets
-	uint16_t views;				// Number of sendWebPage() calls
-	uint16_t wifis;				// Number of WiFi Setups
-	uint16_t reents;			// Number of re-entrant interrupt handler calls
-	uint16_t ntpErr;			// Number of UTP requests that failed
-	uint16_t ntps;
-
-	uint32_t ntpErrTime;		// Record the time of the last NTP error
-	uint8_t ch;					// index to freqs array, freqs[ifreq]=868100000 default
-	uint8_t sf;					// range from SF7 to SF12
-	uint8_t debug;				// range 0 to 4
-	uint8_t pdebug;				// pattern debug, 
-
-	uint16_t logFileRec;		// Logging File Record number
-	uint16_t logFileNo;			// Logging File Number
-	uint16_t logFileNum;		// Number of log files
-	
-	bool cad;					// is CAD enabled?
-	bool hop;					// Is HOP enabled (Note: default be disabled)
-	bool isNode;				// Is gateway node enabled
-	bool refresh;				// Is WWW browser refresh enabled
-	bool expert;
-	
-	String ssid;				// SSID of the last connected WiFi Network
-	String pass;				// Password of WiFi network
-} gwayConfig;
-
-// Define a log record to be written to the log file
-// Keep logfiles SHORT in name! to save memory
-#if STAT_LOG == 1
-
-// We do keep admin of logfiles by number
-// 
-//uint32_t logFileNo = 1;		// Included in struct espGwayConfig LogFile number
-//uint32_t logFileRec = 0;		// Number of records in a single logfile
-//uint32_t logFileNum = 1;		// Number of log files
-#define LOGFILEMAX 10
-#define LOGFILEREC 100
-
-#endif

+ 0 - 564
ESP-sc-gway/loraModem.h

@@ -1,564 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many other contributors.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains a number of compile-time settings and declarations that are
-// specific to the LoRa rfm95, sx1276, sx1272 radio of the gateway.
-//
-//
-// ------------------------------------------------------------------------------------
-
-
-// ----------------------------------------
-// Used by REG_PAYLOAD_LENGTH to set receive payload length
-#define PAYLOAD_LENGTH              0x40		// 64 bytes
-#define MAX_PAYLOAD_LENGTH          0x80		// 128 bytes
-
-// In order to make the CAD behaviour dynamic we set a variable
-// when the CAD functions are defined. Value of 3 is minimum frequencies a
-// gateway should support to be fully LoRa compliant.
-// For performance reasons, 3 is the maximum as well!
-//
-#define NUM_HOPS 3
-
-// Do not change these setting for RSSI detection. They are used for CAD
-// Given the correction factor of 157, we can get to -122dB with this rating
-// 
-#define RSSI_LIMIT	35							// 
-
-// How long to wait in LoRa mode before using the RSSI value.
-// This period should be as short as possible, yet sufficient
-// 
-#define RSSI_WAIT	6							// was 25
-
-// How long will it take when hopping before a CDONE or CDETD value
-// is present and can be measured.
-//
-#define EVENT_WAIT 15000						// XXX 180520 was 25 milliseconds before CDDETD timeout
-#define DONE_WAIT 1950							// 2000 microseconds (1/500) sec between CDDONE events
-
-
-// Our code should correct the server Tramission delay settings
-long txDelay= 0x00;								// tx delay time on top of server TMST
-
-// SPI setting. 8MHz seems to be the max
-#define SPISPEED 8000000						// Set to 8 * 10E6
-
-// Frequencies
-// Set center frequency. If in doubt, choose the first one, comment all others
-// Each "real" gateway should support the first 3 frequencies according to LoRa spec.
-// NOTE: This means you have to specify at least 3 frequencies here for the single
-//	channel gateway to work. 
-struct vector {
-	// Upstream messages
-	uint32_t upFreq;							// 4 bytes
-	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
-	uint16_t dwnBW;								// 2 bytes BW Specification
-	uint8_t  dwnLo;								// 1 bytes Spreading Factor
-	uint8_t  dwnHi;								// 1 bytes
-};
-
-
-#ifdef EU863_870
-// This the the EU863_870 format as used in most of Europe
-// It is also the default for most of the single channel gateway work.
-// For each frequency SF7-SF12 are used.
-vector freqs [] = 
-{
-	{ 868100000, 125, 7, 12, 868100000, 125, 7, 12},			// Channel 0, 868.1 MHz/125 primary
-	{ 868300000, 125, 7, 12, 868300000, 125, 7, 12},			// Channel 1, 868.3 MHz/125 mandatory and (SF7BW250)
-	{ 868500000, 125, 7, 12, 868500000, 125, 7, 12},			// Channel 2, 868.5 MHz/125 mandatory
-	{ 867100000, 125, 7, 12, 867100000, 125, 7, 12},			// Channel 3, 867.1 MHz/125 Optional
-	{ 867300000, 125, 7, 12, 867300000, 125, 7, 12},			// Channel 4, 867.3 MHz/125 Optional
-	{ 867500000, 125, 7, 12, 867500000, 125, 7, 12}, 			// Channel 5, 867.5 MHz/125 Optional
-	{ 867700000, 125, 7, 12, 867700000, 125, 7, 12},			// Channel 6, 867.7 MHz/125 Optional 
-	{ 867900000, 125, 7, 12, 867900000, 125, 7, 12},			// Channel 7, 867.9 MHz/125 Optional 
-	{ 868800000, 125, 7, 12, 868800000, 125, 7, 12},			// Channel 8, 868.9 MHz/125 FSK Only										
-	{ 0,         0  , 0,  0, 869525000, 125, 9, 9}				// Channel 9, 869.5 MHz/125 for RX2 responses SF9(10%)
-	// TTN defines an additional channel at 869.525 MHz using SF9 for class B. Not used
-};
-
-#elif defined(EU433)
-// The following 3 frequencies should be defined/used in an EU433 
-// environment. The plan is not defined for TTN yet so we use this one.
-vector freqs [] = {
-	{ 433175000, 125, 7, 12, 433175000, 125, 7, 12},			// Channel 0, 433.175 MHz/125 primary
-	{ 433375000, 125, 7, 12, 433375000, 125, 7, 12},			// Channel 1, 433.375 MHz primary
-	{ 433575000, 125, 7, 12, 433575000, 125, 7, 12},			// Channel 2, 433.575 MHz primary
-	{ 433775000, 125, 7, 12, 433775000, 125, 7, 12},			// Channel 3, 433.775 MHz primary
-	{ 433975000, 125, 7, 12, 433975000, 125, 7, 12},			// Channel 4, 433.975 MHz primary
-	{ 434175000, 125, 7, 12, 434175000, 125, 7, 12},			// Channel 5, 434.175 MHz primary
-	{ 434375000, 125, 7, 12, 434375000, 125, 7, 12},			// Channel 6, 434.375 MHz primary
-	{ 434575000, 125, 7, 12, 434575000, 125, 7, 12},			// Channel 7, 434.575 MHz primary
-	{ 434775000, 125, 7, 12, 434775000, 125, 7, 12}				// Channel 8, 434.775 MHz primary
-};
-
-#elif defined(US902_928)
-// The frequency plan for USA is a difficult one. As yout can see, the uplink protocol uses
-// SF7-SF10 and BW125 whereas the downlink protocol uses SF7-SF12 and BW500.
-// Also the number of chanels is not equal.
-vector freqs [] = {
-	// Uplink
-	{ 903900000, 125, 7, 10, 923300000, 500, 7, 12},			// Up Ch 0, SF7BW125 to SF10BW125 primary
-	{ 904100000, 125, 7, 10, 923900000, 500, 7, 12},			// Up Ch 1, SF7BW125 to SF10BW125
-	{ 904300000, 125, 7, 10, 924500000, 500, 7, 12},			// Up Ch 2, SF7BW125 to SF10BW125, Dwn SF7-SF12 924,5 BW500
-	{ 904500000, 125, 7, 10, 925100000, 500, 7, 12},			// Up Ch 3, SF7BW125 to SF10BW125, Dwn SF7-SF12 925,1 BW500
-	{ 904700000, 125, 7, 10, 925700000, 500, 7, 12},			// Up Ch 3, SF7BW125 to SF10BW125, Dwn SF7-SF12 925,1
-	{ 904900000, 125, 7, 10, 926300000, 500, 7, 12},			// Up Ch 4, SF7BW125 to SF10BW125, Dwn SF7-SF12 
-	{ 905100000, 125, 7, 10, 926900000, 500, 7, 12},			// Up Ch 5, SF7BW125 to SF10BW125, Dwn SF7-SF12 
-	{ 905300000, 125, 7, 10, 927500000, 500, 7, 12},			// Up Ch 6, SF7BW125 to SF10BW125, Dwn SF7-SF12 
-	{ 904600000, 500, 8,  8, 0        , 0,   0, 00},			// Up Ch 7, SF8BW5000, no Dwn 0 																						// SFxxxBW500
-};
-
-#elif defined(AU925_928)
-// Australian plan or TTN/Lora frequencies
-vector freqs [] = { 
-	{ 916800000, 125, 7, 10, 916800000, 125, 7, 12},			// Channel 0, 916.8 MHz primary
-	{ 917000000, 125, 7, 10, 917000000, 125, 7, 12},			// Channel 1, 917.0 MHz mandatory
-	{ 917200000, 125, 7, 10, 917200000, 125, 7, 12},			// Channel 2, 917.2 MHz mandatory
-	{ 917400000, 125, 7, 10, 917400000, 125, 7, 12},			// Channel 3, 917.4 MHz Optional
-	{ 917600000, 125, 7, 10, 917600000, 125, 7, 12},			// Channel 4, 917.6 MHz Optional
-	{ 917800000, 125, 7, 10, 917800000, 125, 7, 12},			// Channel 5, 917.8 MHz Optional
-	{ 918000000, 125, 7, 10, 918000000, 125, 7, 12}, 			// Channel 6, 918.0 MHz Optional 
-	{ 918200000, 125, 7, 10, 918200000, 125, 7, 12}	,  			// Channel 7, 918.2 MHz Optional
-	{ 917500000, 500, 8,  8,         0,   0, 0,  0}	  			// Channel 8, 917.5 SF8BW500 MHz Optional Uplink
-};
-
-#elif defined(CN470_510)
-// China plan for TTN frequencies
-vector freqs [] = { 
-	{ 486300000, 125, 7, 12, 486300000, 125, 7, 12},			// 486.3 - SF7BW125 to SF12BW125
-	{ 486500000, 125, 7, 12, 486500000, 125, 7, 12},			// 486.5 - SF7BW125 to SF12BW125
-	{ 486700000, 125, 7, 12, 486700000, 125, 7, 12},			// 486.7 - SF7BW125 to SF12BW125
-	{ 486900000, 125, 7, 12, 486900000, 125, 7, 12},			// 486.9 - SF7BW125 to SF12BW125
-	{ 487100000, 125, 7, 12, 487100000, 125, 7, 12},			// 487.1 - SF7BW125 to SF12BW125
-	{ 487300000, 125, 7, 12, 487300000, 125, 7, 12},			// 487.3 - SF7BW125 to SF12BW125
-	{ 487500000, 125, 7, 12, 487500000, 125, 7, 12},			// 487.5 - SF7BW125 to SF12BW125
-	{ 487700000, 125, 7, 12, 487700000, 125, 7, 12}				// 487.7 - SF7BW125 to SF12BW125
-};
-
-#else
-int freqs [] = {
-	// Print an Error, Not supported
-#error "Sorry, but your frequency plan is not supported"
-};
-#endif
-
-
-
-// Set the structure for spreading factor
-enum sf_t { SF6=6, SF7, SF8, SF9, SF10, SF11, SF12 };
-
-// The state of the receiver. See Semtech Datasheet (rev 4, March 2015) page 43
-// The _state is of the enum type (and should be cast when used as a number)
-enum state_t { S_INIT=0, S_SCAN, S_CAD, S_RX, S_TX, S_TXDONE};
-
-volatile state_t _state=S_INIT;
-volatile uint8_t _event=0;
-
-// rssi is measured at specific moments and reported on others
-// so we need to store the current value we like to work with
-uint8_t _rssi;	
-
-bool _cad= (bool) _CAD;	// Set to true for Channel Activity Detection, only when dio 1 connected
-bool _hop= (bool) false;// experimental; frequency hopping. Only use when dio2 connected
-
-unsigned long nowTime=0;
-unsigned long msgTime=0;
-unsigned long hopTime=0;
-unsigned long detTime=0;
-
-#if _PIN_OUT==1
-// ----------------------------------------------------------------------------
-// Definition of the GPIO pins used by the Gateway for Hallard type boards
-//
-struct pins {
-	uint8_t dio0=15;	// GPIO15 / D8. For the Hallard board shared between DIO0/DIO1/DIO2
-	uint8_t dio1=15;	// GPIO15 / D8. Used for CAD, may or not be shared with DIO0
-	uint8_t dio2=15;	// GPIO15 / D8. Used for frequency hopping, don't care
-	uint8_t ss=16;		// GPIO16 / D0. Select pin connected to GPIO16 / D0
-	uint8_t rst=0;		// GPIO 0 / D3. Reset pin not used	
-	// MISO 12 / D6
-	// MOSI 13 / D7
-	// CLK  14 / D5
-} pins;
-
-#elif _PIN_OUT==2
-// ----------------------------------------------------------------------------
-// For ComResult gateway PCB use the following settings
-struct pins {
-	uint8_t dio0=5;		// GPIO5 / D1. Dio0 used for one frequency and one SF
-	uint8_t dio1=4;		// GPIO4 / D2. Used for CAD, may or not be shared with DIO0
-	uint8_t dio2=0;		// GPIO0 / D3. Used for frequency hopping, don't care
-	uint8_t ss=15;		// GPIO15 / D8. Select pin connected to GPIO15
-	uint8_t rst=0;		// GPIO0  / D3. Reset pin not used	
-} pins;
-
-
-#elif _PIN_OUT==3
-// ----------------------------------------------------------------------------
-// For ESP32/Wemos based board
-// SCK  == GPIO5/ PIN5
-// SS   == GPIO18/PIN18
-// MISO == GPIO19/ PIN19
-// MOSI == GPIO27/ PIN27
-// RST  == GPIO14/ PIN14
-struct pins {
-	uint8_t dio0=26;		// GPIO26 / Dio0 used for one frequency and one SF
-	uint8_t dio1=26;		// GPIO26 / Used for CAD, may or not be shared with DIO0
-	uint8_t dio2=26;		// GPI2O6 / Used for frequency hopping, don't care
-	uint8_t ss=18;			// GPIO18 / Dx. Select pin connected to GPIO18
-	uint8_t rst=14;			// GPIO0  / D3. Reset pin not used	
-} pins;
-
-
-#elif _PIN_OUT==4
-// ----------------------------------------------------------------------------
-// For ESP32/TTGO based board.
-// SCK  == GPIO5/ PIN5
-// SS   == GPIO18/PIN18 CS
-// MISO == GPIO19/ PIN19
-// MOSI == GPIO27/ PIN27
-// RST  == GPIO14/ PIN14
-struct pins {
-	uint8_t dio0=26;		// GPIO26 / Dio0 used for one frequency and one SF
-	uint8_t dio1=33;		// GPIO26 / Used for CAD, may or not be shared with DIO0
-	uint8_t dio2=32;		// GPIO26 / Used for frequency hopping, don't care
-	uint8_t ss=18;			// GPIO18 / Dx. Select pin connected to GPIO18
-	uint8_t rst=14;			// GPIO0  / D3. Reset pin not used	
-} pins;
-#define SCK 5
-#define MISO 19
-#define MOSI 27
-#define RST 14
-#define SS 18
-#define GPS_RX 15
-#define GPS_TX 12
-
-#elif _PIN_OUT==5
-// ----------------------------------------------------------------------------
-// For ESP32/TTGO based board for EU32 with 0.9" OLED
-// NOTE: This board shoudl be same as general type TTGO (nr 4)
-// but for the moment we include this as a separate item
-//
-// SCK  == GPIO5/ PIN5
-// SS   == GPIO18/PIN18 CS
-// MISO == GPIO19/ PIN19
-// MOSI == GPIO27/ PIN27
-// RST  == GPIO14/ PIN14
-struct pins {
-	uint8_t dio0=26;		// GPIO26 / Dio0 used for one frequency and one SF
-	uint8_t dio1=33;		// GPIO26 / Used for CAD, may or not be shared with DIO0
-	uint8_t dio2=32;		// GPIO26 / Used for frequency hopping, don't care
-	uint8_t ss=18;			// GPIO18 / Dx. Select pin connected to GPIO18
-	uint8_t rst=14;			// GPIO0 / D3. Reset pin not used	
-} pins;
-#define SCK 5				// Check
-#define MISO 19				// Check
-#define MOSI 27				// Check
-#define RST 14				// Check
-#define SS 18
-
-#else
-// ----------------------------------------------------------------------------
-// Use your own pin definitions, and comment #error line below
-// MISO 12 / D6
-// MOSI 13 / D7
-// CLK  14 / D5
-// SS   16 / D0
-#error "Pin Definitions _PIN_OUT must be 1(HALLARD) or 2 (COMRESULT)"
-#endif
-
-// stat_t contains the statistics that are kept by message. 
-// Each time a message is received or sent the statistics are updated.
-// In case STATISTICS==1 we define the last MAX_STAT messages as statistics
-struct stat_t {
-	unsigned long tmst;						// Time since 1970 in seconds		
-	unsigned long node;						// 4-byte DEVaddr (the only one known to gateway)
-	uint8_t ch;								// Channel index to freqs array
-	uint8_t sf;
-#if RSSI==1
-	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
-	uint8_t datal;							// Length of decoded message 1 char
-#endif
-} stat_t;
-
-
-#if STATISTICS >= 1
-// statc_c contains the statistic that are gateway related and not per
-// message. Example: Number of messages received on SF7 or number of (re) boots
-// So where statr contains the statistics gathered per packet the statc_c
-// contains general statistics of the node
-
-struct stat_c {
-
-	unsigned long msg_ok;
-	unsigned long msg_ttl;
-	unsigned long msg_down;
-
-#if STATISTICS >= 2							// Only if we explicitly set it higher	
-	unsigned long sf7;						// Spreading factor 7 statistics/Count
-	unsigned long sf8;						// Spreading factor 8
-	unsigned long sf9;						// Spreading factor 9
-	unsigned long sf10;						// Spreading factor 10
-	unsigned long sf11;						// Spreading factor 11
-	unsigned long sf12;						// Spreading factor 12
-	
-	// If STATISTICS is 3, we add statistics about the channel 
-	// When only one channel is used, we normally know the spread of
-	// statistics, but when HOP mode is selected we migth want to add this info
-#if STATISTICS >=3
-	unsigned long msg_ok_0, msg_ok_1, msg_ok_2;
-	unsigned long msg_ttl_0, msg_ttl_1, msg_ttl_2;
-	unsigned long msg_down_0, msg_down_1, msg_down_2;
-
-	unsigned long sf7_0, sf7_1, sf7_2;
-	unsigned long sf8_0, sf8_1, sf8_2;
-	unsigned long sf9_0, sf9_1, sf9_2;
-	unsigned long sf10_0, sf10_1, sf10_2;
-	unsigned long sf11_0, sf11_1, sf11_2;
-	unsigned long sf12_0, sf12_1, sf12_2;
-#endif //3
-	
-	uint16_t boots;							// Number of boots
-	uint16_t resets;
-#endif // 2
-
-} stat_c;
-struct stat_c statc;
-
-
-
-// History of received uplink messages from nodes
-struct stat_t statr[MAX_STAT];
-
-
-
-
-#else // STATISTICS==0
-struct stat_t	statr[1];					// Always have at least one element to store in
-#endif
-
-// Define the payload structure used to separate interrupt ans SPI
-// processing from the loop() part
-uint8_t payLoad[128];						// Payload i
-struct LoraBuffer {
-	uint8_t	* 	payLoad;
-	uint8_t		payLength;
-	uint32_t	tmst;						// in millis()
-	uint8_t		sfTx;
-	uint8_t		powe;
-	uint32_t	fff;
-	uint8_t		crc;
-	uint8_t		iiq;
-} LoraDown;
-
-// Up buffer (from Lora sensor to UDP)
-//
-
-struct LoraUp {
-	uint8_t		payLoad[128];
-	uint8_t		payLength;
-	int			prssi; 
-	long		snr;
-	int			rssicorr;
-	uint8_t		sf;
-} LoraUp;
-
-
-
-
-// ============================================================================
-// Set all definitions for Gateway
-// ============================================================================	
-// Register definitions. These are the addresses of the RFM95, SX1276 that we 
-// need to set in the program.
-
-#define REG_FIFO                    0x00		// rw FIFO address
-#define REG_OPMODE                  0x01
-// 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_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_PKT_SNR_VALUE			0x19
-#define REG_PKT_RSSI				0x1A		// latest package
-#define REG_RSSI					0x1B		// Current RSSI, section 6.4, or  5.5.5
-#define REG_HOP_CHANNEL				0x1C
-#define REG_MODEM_CONFIG1           0x1D
-#define REG_MODEM_CONFIG2           0x1E
-#define REG_SYMB_TIMEOUT_LSB  		0x1F
-
-#define REG_PAYLOAD_LENGTH          0x22
-#define REG_MAX_PAYLOAD_LENGTH 		0x23
-#define REG_HOP_PERIOD              0x24
-#define REG_MODEM_CONFIG3           0x26
-#define REG_RSSI_WIDEBAND			0x2C
-
-#define REG_INVERTIQ				0x33
-#define REG_DET_TRESH				0x37		// SF6
-#define REG_SYNC_WORD				0x39
-#define REG_TEMP					0x3C
-
-#define REG_DIO_MAPPING_1           0x40
-#define REG_DIO_MAPPING_2           0x41
-#define REG_VERSION	  				0x42
-
-#define REG_PADAC					0x5A
-#define REG_PADAC_SX1272			0x5A
-#define REG_PADAC_SX1276			0x4D
-
-
-// ----------------------------------------
-// opModes
-#define SX72_MODE_SLEEP             0x80
-#define SX72_MODE_STANDBY           0x81
-#define SX72_MODE_FSTX              0x82
-#define SX72_MODE_TX                0x83		// 0x80 | 0x03
-#define SX72_MODE_RX_CONTINUOS      0x85
-
-// ----------------------------------------
-// LMIC Constants for radio registers
-#define OPMODE_LORA      			0x80
-#define OPMODE_MASK      			0x07
-#define OPMODE_SLEEP     			0x00
-#define OPMODE_STANDBY   			0x01
-#define OPMODE_FSTX      			0x02
-#define OPMODE_TX        			0x03
-#define OPMODE_FSRX      			0x04
-#define OPMODE_RX        			0x05
-#define OPMODE_RX_SINGLE 			0x06
-#define OPMODE_CAD       			0x07
-
-
-
-// ----------------------------------------
-// LOW NOISE AMPLIFIER
-
-#define LNA_MAX_GAIN                0x23		// Max gain 0x20 | Boost 0x03
-#define LNA_OFF_GAIN                0x00
-#define LNA_LOW_GAIN		    	0x20
-
-// CONF REG
-#define REG1                        0x0A
-#define REG2                        0x84
-
-// ----------------------------------------
-// MC1 sx1276 RegModemConfig1
-#define SX1276_MC1_BW_125           0x70
-#define SX1276_MC1_BW_250           0x80
-#define SX1276_MC1_BW_500           0x90
-#define SX1276_MC1_CR_4_5           0x02			// sx1276
-#define SX1276_MC1_CR_4_6           0x04
-#define SX1276_MC1_CR_4_7           0x06
-#define SX1276_MC1_CR_4_8           0x08
-#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON  0x01
-
-#define SX72_MC1_LOW_DATA_RATE_OPTIMIZE     0x01 	// mandated for SF11 and SF12
-
-// ----------------------------------------
-// MC2 definitions
-#define SX72_MC2_FSK                0x00
-#define SX72_MC2_SF7                0x70		// SF7 == 0x07, so (SF7<<4) == SX7_MC2_SF7
-#define SX72_MC2_SF8                0x80
-#define SX72_MC2_SF9                0x90
-#define SX72_MC2_SF10               0xA0
-#define SX72_MC2_SF11               0xB0
-#define SX72_MC2_SF12               0xC0
-
-// ----------------------------------------
-// MC3
-#define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE  0x08
-#define SX1276_MC3_AGCAUTO                 0x04
-
-// ----------------------------------------
-// FRF
-#define FRF_MSB						0xD9		// 868.1 MHz
-#define FRF_MID						0x06
-#define FRF_LSB						0x66
-
-// ----------------------------------------
-// DIO function mappings           		     D0D1D2D3
-#define MAP_DIO0_LORA_RXDONE   		0x00  // 00------ bit 7 and 6
-#define MAP_DIO0_LORA_TXDONE   		0x40  // 01------
-#define MAP_DIO0_LORA_CADDONE  		0x80  // 10------
-#define MAP_DIO0_LORA_NOP   		0xC0  // 11------
-
-#define MAP_DIO1_LORA_RXTOUT   		0x00  // --00---- bit 5 and 4
-#define MAP_DIO1_LORA_FCC			0x10  // --01----
-#define MAP_DIO1_LORA_CADDETECT		0x20  // --10----
-#define MAP_DIO1_LORA_NOP      		0x30  // --11----
-
-#define MAP_DIO2_LORA_FCC0      	0x00  // ----00-- bit 3 and 2
-#define MAP_DIO2_LORA_FCC1      	0x04  // ----01-- bit 3 and 2
-#define MAP_DIO2_LORA_FCC2      	0x08  // ----10-- bit 3 and 2
-#define MAP_DIO2_LORA_NOP      		0x0C  // ----11-- bit 3 and 2
-
-#define MAP_DIO3_LORA_CADDONE  		0x00  // ------00 bit 1 and 0
-#define MAP_DIO3_LORA_HEADER		0x01  // ------01
-#define MAP_DIO3_LORA_CRC			0x02  // ------10
-#define MAP_DIO3_LORA_NOP      		0x03  // ------11
-
-// FSK specific
-#define MAP_DIO0_FSK_READY     		0x00  // 00------ (packet sent / payload ready)
-#define MAP_DIO1_FSK_NOP       		0x30  // --11----
-#define MAP_DIO2_FSK_TXNOP     		0x04  // ----01--
-#define MAP_DIO2_FSK_TIMEOUT   		0x08  // ----10--
-
-// ----------------------------------------
-// Bits masking the corresponding IRQs from the radio
-#define IRQ_LORA_RXTOUT_MASK 		0x80	// RXTOUT
-#define IRQ_LORA_RXDONE_MASK 		0x40	// RXDONE after receiving the header and CRC, we receive payload part
-#define IRQ_LORA_CRCERR_MASK 		0x20	// CRC error detected. Note that RXDONE will also be set
-#define IRQ_LORA_HEADER_MASK 		0x10	// valid HEADER mask. This interrupt is first when receiving a message
-#define IRQ_LORA_TXDONE_MASK 		0x08	// End of TRansmission
-#define IRQ_LORA_CDDONE_MASK 		0x04	// CDDONE
-#define IRQ_LORA_FHSSCH_MASK 		0x02
-#define IRQ_LORA_CDDETD_MASK 		0x01	// Detect preamble channel
-
-
-// ----------------------------------------
-// Definitions for UDP message arriving from server
-#define PROTOCOL_VERSION			0x01
-#define PKT_PUSH_DATA				0x00
-#define PKT_PUSH_ACK				0x01
-#define PKT_PULL_DATA				0x02
-#define PKT_PULL_RESP				0x03
-#define PKT_PULL_ACK				0x04
-#define PKT_TX_ACK                  0x05
-
-#define MGT_RESET					0x15		// Not a LoRa Gateway Spec message
-#define MGT_SET_SF					0x16
-#define MGT_SET_FREQ				0x17
-

+ 0 - 69
ESP-sc-gway/oLED.h

@@ -1,69 +0,0 @@
-// 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-// and many others.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains a number of compile-time settings and definitions for OLED support.
-//
-// ----------------------------------------------------------------------------------------
-
-// OLEDs supported by this program must be I2C.
-// This is because we do not want any disturbance in the SPI area
-// which is also interfacing the LORA tranceiver.
-//
-// The following OLEDs are supported:
-// 0. No OLED connected
-// 1. 0.9" OLED (cheap)
-// 2. 1.3" OLED with much better and larger display
-// 4. TTGO board
-
-#if OLED>=1										// If OLED is used
-
-// --------------------------------------------------------	
-// Define the different PIN's used for SCL/SDA for each arch.
-//
-#if _PIN_OUT==1									// HALLARD
-#define OLED_SCL 5								// GPIO5 / D1
-#define OLED_SDA 4								// GPIO4 / D2
-
-#elif _PIN_OUT==2								// COMRESULT				
-#define OLED_SCL 0								// GPIO0 / D3
-#define OLED_SDA 2								// GPIO2 / D4
-
-#elif _PIN_OUT==4								// TTGO (onboard version used, also for DIY)
-#define OLED_SCL 15								// GPIO15 / 
-#define OLED_SDA 4								// GPIO4 / 
-#define OLED_RST 16								// Reset pin (Some OLED displays do not have it)
-
-#endif
-
-
-// --------------------------------------------------------	
-// Define the different OLED versions
-//
-#if OLED==1
-#include "SSD1306.h"
-#define OLED_ADDR 0x3C							// Default 0x3C for 0.9", for 1.3" it is 0x78
-SSD1306  display(OLED_ADDR, OLED_SDA, OLED_SCL);// i2c ADDR & SDA, SCL on wemos
-#endif
-
-// This is an 1.3" OLED display which is running on I2C
-#if OLED==2
-#include "SH1106.h"
-#define OLED_ADDR 0x3C							// Default 0x3C for 1.3" SH1106
-SH1106  display(OLED_ADDR, OLED_SDA, OLED_SCL);	// i2c ADDR & SDA, SCL on wemos
-#endif
-
-#endif//OLED>=1

+ 0 - 68
ESP-sc-gway/sensor.h

@@ -1,68 +0,0 @@
-// sensor.h; 1-channel LoRa Gateway for ESP8266
-// Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
-// Version 6.1.0
-// Date: 2019-10-20
-//
-// 	based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
-//	and many other contributors.
-//
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the MIT License
-// which accompanies this distribution, and is available at
-// https://opensource.org/licenses/mit-license.php
-//
-// NO WARRANTY OF ANY KIND IS PROVIDED
-//
-// Author: Maarten Westenberg (mw12554@hotmail.com)
-//
-// This file contains a number of compile-time settings and declarations that are
-// specific to the LoRa rfm95, sx1276, sx1272 radio of the gateway.
-//
-//
-// ------------------------------------------------------------------------------------
-
-#if _TRUSTED_NODES >= 1
-struct nodex {
-	uint32_t id;				// This is the LoRa ID (coded in 4 bytes uint32_t
-	char nm[32];				// Name of the node
-};
-
-// Add all your named and trusted nodes to this list
-nodex nodes[] = {
-	{ 0x2601148C , "lora-36 test node"  },						// F=0
-	{ 0x00000000 , "lora-00 well known sensor" }				// F=0
-};
-#endif //_TRUSTED_NODES
-
-
-// In some cases we like to decode the lora message at the single channel gateway.
-// In thisase, we need the NkwSKey and the AppsSKey of the node so that we can decode
-// its messages.
-// Although this is probably overkill in normal gateway situations, it greatly helps
-// in debugging the node messages before they reach the TTN severs.
-//
-#if _LOCALSERVER==1
-struct codex  {
-	uint32_t id;				// This is the device ID (coded in 4 bytes uint32_t
-	char nm[32];				// A name string which is free to choose
-	uint8_t nwkKey[16];			// The Network Session Key of 16 bytes
-	uint8_t appKey[16];			// The Application Session Key of 16 bytes
-};
-
-// Sometimes we want to decode the sensor completely as we do in the TTN server
-// This means that for all nodes we want to view the data of, we need to provide
-// the AppsSKey and the NwkSKey
-
-// Definition of all nodes that we want to decode locally on the gateway.
-//
-codex decodes[] = {
-	{ 0x2601148C , "lora-36", 	// F=0
-		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
-		{ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } 
-	},
-	{ 0x00000000 , "lora-00",	// F=0
-		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
-		{ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } 
-	}					
-};
-#endif //_LOCALSERVER

+ 0 - 21
LICENSE

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2017, 2018, 2019 things4u
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 0 - 407
README.md

@@ -1,407 +0,0 @@
-# Single Channel LoRaWAN Gateway
-
-Version 6.0.1, October 20, 2019  
-Author: M. Westenberg (mw12554@hotmail.com)  
-Copyright: M. Westenberg (mw12554@hotmail.com)  
-
-All rights reserved. This program and the accompanying materials are made available under the terms 
-of the MIT License which accompanies this distribution, and is available at
-https://opensource.org/licenses/mit-license.php  
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-Maintained by Maarten Westenberg (mw12554@hotmail.com)
-
-
-# Description
-
-First of all: PLEASE READ THIS FILE AND HTTP://THINGS4U.GITHUB.IO it should contain most of the 
-information you need to get going.
-Unfortunately I do not have the time to follow up on all emails, and as most information including pin-outs 
-etc etc are contained on these pages I hope you have the time to read them before posting any questions.
-
-I do have more than 10 Wemos D1 mini boards running, some I built myself, 
-some 10+ on Hallard, 3 on ComResult and 4 ESP32 boards. They ALL work without problems
-on this code.
-I did find however that good soldering joints and wiring makes all the difference,
-so if you get resets you cannot explain, please have a second look at your wiring.
-
-This repository contains a proof-of-concept implementation of a single channel LoRaWAN gateway for the ESP8266. 
-Starting version 5.2 also the ESP32 of TTGO (and others) is supported.
-The software implements a standard LoRa gateway with the following exceptions and changes:
-
--  This LoRa gateway is not a full gateway but it implements just a one-channel/one frequency gateway. 
-The minimum amount of frequencies supported by a full gateway is 3, most support 9 or more frequencies.
-This software started as a proof-of-concept to prove that a single low-cost RRFM95 chip which was present 
-in almost every LoRa node in Europe could be used as a cheap alternative to the far more expensive full 
-gateways that were making use of the SX1301 chip.
-
-- As the software of this gateway will often be used during the development phase of a project or in 
-demo situations, the software is flexible and can be easily configured according to environment or 
-customer requirements. There are two ways of interacting with the software: 
-1. Modifying the ESP-sc-gway.h file at compile time allows the administrator to set almost all parameters. 
-2. Using the webinterface (http://<gateway_IP>) will allow administrators to set and reset several of the 
-parameters at runtime.
-
-Full documentation of the Single Channel Gateway is found at things4u.github.io, please look at the Hardware Guide 
-under the Gateway chapter.
-
-
-## testing
-
-The single channel gateway has been tested on a gateway with the Wemos D1 Mini, using a HopeRF RFM95W transceiver.  
-The LoRa nodes tested againts this gateway are:
-
-- TeensyLC with HopeRF RFM95 radio
-- Arduino Pro-Mini (default Armega328 model, 8MHz 3.3V and 16MHz 3.3V)
-- ESP8266 based nodes with RFM95 transceivers.
-
-The code has been tested on at least 8 separate gateway boards both based on the Hallard and the Comresult boards. 
-I'm still working on the ESP32 pin-out and functions (expected soon).
-
-# Getting Started
-
-It is recommended to compile and start the single channel gateway with as little modificatons as possible. 
-This means that you should use the default settings in the configuration files as much as possible and 
-only change the SSID/Password for your WiFi setup and the pins of your ESP8266 that you use in loraModem.h.
-This section describes the minimum of configuration necessary to get a working gateway which than can be 
-configured further using the webpage.
-
-1. Unpack the source code including the libraries in a separate folder.
-2. Connect the gateway to a serial port of your computer, and configure that port in the IDE. 
-Switch on the Serial Monitor for the gateway. As the Wemos chip does not contain any code, you will probably 
-see nothing on the Serial Monitor.
-3. Modify the _loraModem.h file and change the "struct pins" area and configure either for a traditional
-(=Comresult) PCB or configure for a Hallard PCB where the dio0, dio1 and dio2 pins are shared. You HAVE to check 
-this section.
-4. Edit the ESP-sc-gway.h file and adapt the "wpas" structure. `Make sure that the first line of this structure 
-remains empty and put the SSID and Password of your router on the second line of the array.
-5. In the preferences part of the IDE, set the location of your sketch to the place where you put the 
-sketch on your computer. This will make sure that for example the required libraries that are shipped 
-with this sketch in the libraries folder can be found by the compiler
-6. If not yet done: Load the support for ESP8266 in your IDE. <Tools><Board><Board Manager...>
-7. Load the other necessary libraries that are not shipped with this sketch in your IDE. 
-Goto <Sketch><Include Library><Manage Libraries...> in the IDE to do so. 
-- ArduinoJson (version 5.13.1)
-- WifiManager (Version 0.12.0 by Tzapu)
-8. Compile the code and download the executable over USB to the gateway. If all is right, you should
-see the gateway starting up on the Serial Monitor.
-9. Note the IP address that the device receives from your router. Use that IP address in a browser on 
-your computer to connect to the gateway with the browser.
-
-Now your gateway should be running. Use the webpage to set "debug" to 1 and you should be able to see packages
-coming in on the Serial monitor.
-
-
-# Configuration
-
-There are two ways of changing the configuration of the single channel gateway:
-
-1. Changing the ESP-sc-gway.h file at compile-time
-2. Run the http://<gateway-IP> web interface to change settings at run time.
-
-
-## Editing the ESP-sc-gway.h file
-
-The ESP-sc-gway.h file contains all the user configurable settings. All have their definitions set through #define statements. 
-In general, setting a #define to 1 will enable the function and setting it to 0 will disable it. 
-
-Also, some settings cn be initialised by setting their value with a #define but can be changed at runtime in the web interface.
-For some settings, disabling the function with a #define will remove the function from the webserver as well.
-
-NOTE regarding memory usage: The ESP8266 has an enormous amount of memory available for program space and SPIFFS filesystem. 
-However the memory available for heap and variables is limited to about 80K bytes (For the ESP-32 this is higher). 
-The user is advised to turn off functions not used in order to save on memory usage. 
-If the heap drops below 18 KBytes some functions may not behave as expected (in extreme case the program may crash).
-
-
-### Setting USB
-
-The user can determine whether or not the USB console is used for output messages.
-When setting DUSB to 0 all output by Serial is disabled 
-(actually the Serial statements are not included in the code).
-
- \#define DUSB 1
-
-
-### Debug
-
-The user can set the initial value of the DEBUG parameter. 
-Setting this parameter will also detemine some settings of the webserver.
-
- \#define DEBUG 1
-
- 
-### Selecting you standard pin-out
-
-We support two pin-out configurations out-of-the-box: HALLARD and COMPRESULT.
-If you use one of these two, just set the parameter to the right value.
-If your pin definitions are different, update the loraModem.h file to reflect these settings.
-	1: HALLARD
-	2: COMRESULT pin out
-	3: ESP32 pin out
-	4: Other, define your own in loraModem.h
-
- \#define _PIN_OUT 1
-
-
-### Forcing a SPIFF format at startup
-
-The following parameter shoudl be set to 0 under normal circumstances.
-It does allow the system to foce formatting of the SPIFFS filesystem.
-
- \#define SPIFF_FORMAT 0  
- 
-### Setting Spreading Factor
-
-Set the _SPREADING factor to the desired SF7, SF8 - SF12 value. 
-Please note that this value is closely related to the value used for _CAD. 
-If _CAD is enabled, the value of _SPREADING is not used by the gateway as it has all sreading factors enabled.
-
- \#define _SPREADING SF9
- 
-Please note that the default frequency used is 868.1 MHz which can be changed in the loraModem.h file. 
-The user is advised NOT to change this etting and only use the default 868.1 MHz frequency.
-
-
-### Channel Activity Detection
-
-Channel Activity Detection (CAD) is a function of the LoRa RFM95 chip to detect incoming messages (activity). 
-These incoming messages might arrive on any of the well know spreading factors SF7-SF12. 
-By enabling CAD, the gateway can receive messages of any of the spreading factors.
-
-Actually it is used in normal operation to tell the receiver that another signal is using the 
-channel already.
-
-The CAD functionality comes at a (little) price: The chip will not be able to receive very weak signals as 
-the CAD function will use the RSSI register setting of the chip to determine whether or not it received a 
-signal (or just noise). As a result, very weak signals are not received which means that the range of the 
-gateway will be reduced in CAD mode.
-
- \#define _CAD 1
-
- 
-### Over the Air Updates (OTA)
-
-As from version 4.0.6 the gateway allows over the air updating if the setting A_OTA is on. 
-The over the air software requires once setting of the 4.0.6 version over USB to the gateway,
-after which the software is (default) enabled for use.
-
-The first release only supports OTA function using the IDE which in practice means the IDE has to 
-be on the same network segment as the gateway.
-
-Note: You have to use Bonjour software (Apple) on your network somewhere. A version is available
-for most platforms (shipped with iTunes for windows for example). The Bonjour software enables the
-gateway to use mDNS to resolve the gateway ID set by OTA after which download ports show up in the IDE.
-
-Todo: The OTA software has not (yet) been tested in conjuction with the WiFiManager software.
-
- \#define A_OTA 1  
-
-
-
-### Enable Webserver
-
-This setting enables the webserver. Although the webserver itself takes a lot of memory, it greatly helps 
-to configure the gatewayat run-time and inspects its behaviour. It also provides statistics of last messages received.
-The A_REFRESH parameter defines whether the webserver should renew every X seconds.
-
- \#define A_SERVER 1				// Define local WebServer only if this define is set  
- \#define A_REFRESH 0				// Will the webserver refresh or not?  
- \#define A_SERVERPORT 80			// local webserver port  
- \#define A_MAXBUFSIZE 192			// Must be larger than 128, but small enough to work  
-
- The A_REFRESH parameter determines the refresh frequency of the webserver.  
- 
-### Strict LoRa behaviour
-
-In order to have the gateway send downlink messages on the pre-set spreading factor and 
-on the default frequency, you have to set the _STRICT_1CH parameter to 1. Note that when 
-it is not set to 1, the gateway will respond to downlink requests with the frequency 
-and spreading factor set by the backend server. And at the moment TTN responds to downlink 
-messages for SF9-SF12 in the RX2 timeslot and with frequency 869.525MHz and on SF12 
-(according to the LoRa standard when sending in the RX2 timeslot). 
-
- \#define _STRICT_1CH 0
-
-You are advised not to change the default setting of this parameter.
-
-### Enable OLED panel
-
-By setting the OLED you configure the system to work with OLED panels over I2C.
-Some panels work by both SPI and I2C where I2c is solwer. However, since SPI is use for RFM95 transceiver 
-communication you are stronly discouvared using one of these as they will not work with this software.
-Instead choose a OLED solution that works over I2C.
-
- \#define OLED 1
-
-The following values are defined for OLED:
-1. 0.9 inch OLED screen for I2C bus
-2. 1.1 inch OLED screen for I2C bus
-
-### Define to gather statistics
-
-When this is defined (==1) we will gather the statistics of every message and output
-it to the SPIFFS filesystem. We make sure that we use a number of files with each a fixed number of records
-for statistics. The REC number tells us how many records are allowed in each statistics file.
-As soon as the REC number is higher than the number of records allowed, we open a new file.
-Once the number of files exceeds the NUM amount of statistics files, we delete the oldeest file and 
-open a new file.
-When selecting the "log" button on top of the GUI screen, all rthe log files are ouptu to the USB
-Serial device. This way, we can examine far more records than fitting the GUI screen or the Serial
-output.
- 
- \#define STAT_LOG 1
- 
-
- 
-Setting the I2C SDA/SCL pins is done in the ESP-sc-gway.h file right after the #define of OLED.
-Standard the ESP8266 uses pins D1 and D2 for the I2C bus SCL and SDA lines but these can be changed by the user.
-Normally thsi is not necessary. 
-The OLED functions are found in the _loraModem.ino file, and can be adapted to show other fields. 
-The functions are called when a message is received(!) and therefore potentionally this will add to the
-instability of the ESP as these functions may require more time than expected.
-If so, swithc off the OLED function or build in a function in the main loop() that displays in user time 
-(not interrupt).
-
-### Setting TTN server
-
-The gateway allows to connect to 2 servers at the same time (as most LoRa gateways do BTW). 
-You have to connect to at least one standard LoRa router, in case you use The Things Network (TTN) 
-than make sure that you set:
-
- \#define _TTNSERVER "router.eu.thethings.network"  
- \#define _TTNPORT 1700  
-  
-In case you setup your own server, you can specify as follows using your own router URL and your own port:
-
- \#define _THINGSERVER "your_server.com"			// Server URL of the LoRa udp.js server program  
- \#define _THINGPORT 1701							// Your UDP server should listen to this port  
-
- 
-### Gateway Identity
-Set the identity parameters for your gateway:   
-
-\#define _DESCRIPTION "ESP-Gateway"  
-\#define _EMAIL "your.email@provider.com"  
-\#define _PLATFORM "ESP8266"  
-\#define _LAT 52.00  
-\#define _LON 5.00  
-\#define _ALT 0  
-
-
-### Using the gateway as a sensor node
-
-It is possible to use the gateway as a node. This way, local/internal sensor values are reported.
-This is a cpu and memory intensive function as making a sensor message involves EAS and CMAC functions.
-
- \#define GATEWAYNODE 0  
-
-Further below in the configuration file, it is possible to set the address and other  LoRa information of the gateway node.
-
- \#if GATEWAYNODE==1  
- \#define _DEVADDR { 0x26, 0x01, 0x15, 0x3D }  
- \#define _APPSKEY { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }  
- \#define _NWKSKEY { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }  
- \#define _SENSOR_INTERVAL 300  
- \#endif  
-
-
-### Connect to WiFi with WiFiManager
-
-The easiest way to configure the Gateway on WiFi is by using the WiFimanager function. This function works out of the box. 
-WiFiManager will put the gateway in accesspoint mode so that you can connect to it as a WiFi accesspoint. 
-
- \#define WIFIMANAGER 0  
-
-If Wifi Manager is enabled, make sure to define the name of the accesspoint if the gateway is in accesspoint 
-mode and the password.
-
- \#define AP_NAME "ESP8266-Gway-Things4U"  
- \#define AP_PASSWD "ttnAutoPw"  
-
-The standard access point name used by the gateway is "ESP8266 Gway" and its password is "ttnAutoPw". 
-After binding to the access point with your mobile phone or computer, go to htp://192.168.4.1 in a browser and tell the gateway to which WiFi network you want it to connect, and specify the password.
-
-The gateway will then reset and bind to the given network. If all goes well you are now set and the ESP8266 will remember the network that it must connect to. NOTE: As long as the accesspoint that the gateway is bound to is present, the gateway will not any longer work with the wpa list of known access points.
-If necessary, you can delete the current access point in the webserver and power cycle the gateway to force it to read the wpa array again.
-
-## Specify a name for known nodes
-- It is possible to substitue the address for known nodes with a chosen name. This will greatly enhance the readibility of the statistics overview 
-especially for your own nodes, Now you will find names for your own nodes in the webserver.
-- set the TRUSTED_NODES to either 0 (no names), 1 (specify names for known nodes) and 2 (Do not show or transfer to TTN other than known nodes)
-- Although this will work with OTAA nodes as well, please remind that OTAA nodes will change
-their LORA id with every reboot. So for these nodes this function does not add much value.
-
-### Other Settings
-
-- static char *wpa[WPASIZE][2] contains the array of known WiFi access points the Gateway will connect to.
-Make sure that the dimensions of the array are correctly defined in the WPASIZE settings. 
-Note: When the WiFiManager software is enabled (it is by default) there must at least be one entry in the wpa file, wpa[0] is used for storing WiFiManager information.
-- Only the sx1276 (and HopeRF 95) radio modules are supported at this time. The sx1272 code should be 
-working without much work, but as I do not have one of these modules available I cannot test this.
-
-
-## Webserver
-
-The built-in webserver can be used to display status and debugging information. 
-Also the webserver allows the user to change certain settings at run-time such as the debug level or switch on 
-and off the CAD function.
-It can be accessed with the following URL: http://<YourGatewayIP>:80 where <YourGatewayIP> is the IP given by 
-the router to the ESP8266 at startup. It is probably something like 192.168.1.XX
-The webserver shows various configuration settings as well as providing functions to set parameters.
-
-The following parameters can be set using the webServer. 
-- Debug Level (0-4)
-- CAD mode on or off (STD mode)
-- Switch frequency hopping on and off (Set to OFF)
-- When frequency Hopping is off: Select the frequency the gateway will work with. 
-NOTE: Frequency hopping is experimental and does not work correctly.
-- When CAD mode is off: Select the Spreading Factor (SF) the gateway will work with
-
-
-# Dependencies
-
-The software is dependent on several pieces of software, the Arduino IDE for ESP8266 
-being the most important. Several other libraries are also used by this program, 
-make sure you install those libraries with the IDE:
-
-- gBase64 library, The gBase library is actually a base64 library made 
-	by Adam Rudd (url=https://github.com/adamvr/arduino-base64). I changed the name because I had
-	another base64 library installed on my system and they did not coexist well.
-- Time library (http://playground.arduino.cc/code/time)
-- Arduino JSON; Needed to decode downstream messages
-- SimpleTimer; ot yet used, but reserved for interrupt and timing
-- WiFiManager
-- ESP8266 Web Server
-- Streaming library, used in the wwwServer part
-- AES library (taken from ideetron.nl) for downstream messages
-- Time
-
-For convenience, the libraries are also found in this github repository in the libraries directory. 
-Please note that they are NOT part of the ESP 1channel gateway and may have their own licensing.
-However, these libraries are not part of the single-channel Gateway software.
-
-
-# Pin Connections
-
-See http://things4u.github.io in the hardware section for building and connection instructions.
-
-
-# To-DO
-
-The following things are still on my wish list to make to the single channel gateway:  
-
-- Receive downstream message with commands from the server. These can be used to configure
-  the gateway through downlink messages (such as setting the SF)
-- Support for ESP32 and RFM95 on 433 MHz
-- Use the SPIFFS for storing .css files
-- Look at CLass B and C support
-
-
-
-# License
-
-The source files of the gateway sketch in this repository is made available under the MIT
-license. The libraries included in this repository are included for convenience only and all have their own license, 
-and are not part of the ESP 1ch gateway code.