diff --git a/include/main.h b/include/main.h index dab29fe..adaab48 100644 --- a/include/main.h +++ b/include/main.h @@ -2,21 +2,21 @@ Name: ESP32 APRS Internet Gateway Created: 1-Nov-2021 14:27:23 Author: HS5TQA/Atten - Support IS: host:aprs.dprns.com port:14580 - Support IS monitor: http://aprs.dprns.com:14501 + Support IS: host:aprs.dprns.com port:14580 or aprs.hs5tqa.ampr.org:14580 + Support IS monitor: http://aprs.dprns.com:14501 or http://aprs.hs5tqa.ampr.org:14501 Support in LINE Group APRS Only */ #ifndef MAIN_H #define MAIN_H -#define VERSION "0.6a" +#define VERSION "0.7" #define DEBUG //#define DEBUG_IS //#define SDCARD -//#define SA818 +#define SA818 //#define SR_FRS #ifdef SR_FRS @@ -98,10 +98,10 @@ typedef struct Config_Struct char aprs_filter[30]; char aprs_comment[50]; char aprs_path[72]; - char wifi_ssid[20]; - char wifi_pass[15]; - char wifi_ap_ssid[20]; - char wifi_ap_pass[15]; + char wifi_ssid[32]; + char wifi_pass[63]; + char wifi_ap_ssid[32]; + char wifi_ap_pass[63]; char tnc_path[50]; char tnc_btext[50]; char tnc_comment[50]; @@ -125,6 +125,17 @@ typedef struct Config_Struct bool rf_power; uint8_t volume; #endif + bool vpn; + bool modem; + uint16_t wg_port; + char wg_peer_address[16]; + char wg_local_address[16]; + char wg_netmask_address[16]; + char wg_gw_address[16]; + char wg_public_key[45]; + char wg_private_key[45]; + int8_t timeZone; + } Configuration; typedef struct igateTLM_struct @@ -182,7 +193,7 @@ typedef struct txQueue_struct char Info[300]; } txQueueType; -const char PARM[] = {"PARM.RF->INET,INET->RF,RxPkts,TxPkts,IGateDropRx"}; +const char PARM[] = {"PARM.RF->INET,INET->RF,TxPkts,RxPkts,IGateDropRx"}; const char UNIT[] = {"UNIT.Pkts,Pkts,Pkts,Pkts,Pkts"}; const char EQNS[] = {"EQNS.0,1,0,0,1,0,0,1,0,0,1,0,0,1,0"}; diff --git a/include/wireguard_vpn.h b/include/wireguard_vpn.h new file mode 100644 index 0000000..fd36672 --- /dev/null +++ b/include/wireguard_vpn.h @@ -0,0 +1,56 @@ + +//============================================================================== +// Wireguard VPN Client demo for LwIP/ESP32 +//============================================================================== +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +//============================================================================== +// Multi-include guard +//============================================================================== +#ifndef INC_WIREGUARD_VPN_H +#define INC_WIREGUARD_VPN_H + +//============================================================================== +// Includes +//============================================================================== + +//============================================================================== +// Defines +//============================================================================== + +#define WG_LOCAL_ADDRESS IPADDR4_INIT_BYTES(192, 168, 44, 202) +#define WG_LOCAL_NETMASK IPADDR4_INIT_BYTES(255, 255, 255, 255) +#define WG_GATEWAY_ADDRESS IPADDR4_INIT_BYTES(192, 168, 44, 195) +#define WG_CLIENT_PRIVATE_KEY "gH2YqDa+St6x5eFhomVQDwtV1F0YMQd3HtOElPkZgVY=" +//#define WG_CLIENT_PRIVATE_KEY "sHueMvT+zVP7Pm/zoRptYcDkCERaBoJc/oUi9n0bmGE=" +#define WG_CLIENT_PORT 51821 + +#define WG_PEER_PUBLIC_KEY "ZEFr+/B/T5+k0DhVG/GOTvAOjeOiuFKmwtu/cy23xVs=" +#define WG_PEER_PORT 51820 +#define WG_PEER_ADDRESS IPADDR4_INIT_BYTES(203, 150, 19, 23) + +//============================================================================== +// Exported types +//============================================================================== + +//============================================================================== +// Exported data +//============================================================================== + +//============================================================================== +// Exported functions +//============================================================================== +bool wireguard_active(); +void wireguard_remove(); +void wireguard_setup(); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // INC_WIREGUARD_VPN_H + + + diff --git a/lib/ESP32_PPPoS/LICENSE b/lib/ESP32_PPPoS/LICENSE new file mode 100644 index 0000000..d543487 --- /dev/null +++ b/lib/ESP32_PPPoS/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Volodymyr Shymanskyy + +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. diff --git a/lib/ESP32_PPPoS/README.md b/lib/ESP32_PPPoS/README.md new file mode 100644 index 0000000..a38859e --- /dev/null +++ b/lib/ESP32_PPPoS/README.md @@ -0,0 +1,2 @@ +# ESP32_PPPoS +PPP over Serial for ESP32 diff --git a/lib/ESP32_PPPoS/examples/PPPoS_Client/PPPoS_Client.ino b/lib/ESP32_PPPoS/examples/PPPoS_Client/PPPoS_Client.ino new file mode 100644 index 0000000..2ab25d8 --- /dev/null +++ b/lib/ESP32_PPPoS/examples/PPPoS_Client/PPPoS_Client.ino @@ -0,0 +1,78 @@ +#include +#include +#include + +#include "TTGO_TCall.h" + +#define PPP_APN "internet" +#define PPP_USER "" +#define PPP_PASS "" + +PPPoS ppp; + +void setup() +{ + Serial.begin(115200); + delay(100); + + setupModem(); + + Serial1.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX); + Serial1.setTimeout(10); + Serial1.setRxBufferSize(2048); + ppp.begin(&Serial1); + + Serial.print("Connecting PPPoS"); + ppp.connect(PPP_APN, PPP_USER, PPP_PASS); + while (!ppp.status()) { + delay(500); + Serial.print("."); + } + Serial.println("OK"); + + // Check plain TCP connection + requestJSON("http://httpbin.org/anything?client=ESP32_PPPoS"); + + // Check secure SSL/TLS connection + requestJSON("https://www.howsmyssl.com/a/check"); + + ppp.end(); +} + +void loop() { + /* do nothing */ + delay(1000); +} + +void requestJSON(String url) +{ + Serial.print("Requesting "); Serial.println(url); + HTTPClient http; + + if (!http.begin(url)) { + Serial.println("Cannot initiate request"); + return; + } + + int httpCode = http.GET(); + if (httpCode != HTTP_CODE_OK) { + Serial.print("Status code: "); + Serial.println(httpCode); + if (httpCode < 0) { + return; + } + } + + // Parse JSON + DynamicJsonDocument doc(1024*10); + DeserializationError error = deserializeJson(doc, http.getStream()); + if (error) { + Serial.print(F("deserializeJson() failed: ")); + Serial.print(error.f_str()); + } else { + serializeJsonPretty(doc, Serial); + } + + http.end(); + Serial.println(); +} diff --git a/lib/ESP32_PPPoS/examples/PPPoS_Client/TTGO_TCall.h b/lib/ESP32_PPPoS/examples/PPPoS_Client/TTGO_TCall.h new file mode 100644 index 0000000..f1bfd99 --- /dev/null +++ b/lib/ESP32_PPPoS/examples/PPPoS_Client/TTGO_TCall.h @@ -0,0 +1,63 @@ +#include + +#define MODEM_RST 5 +#define MODEM_PWRKEY 4 +#define MODEM_POWER_ON 23 +#define MODEM_TX 27 +#define MODEM_RX 26 + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define LED_GPIO 13 +#define LED_ON HIGH +#define LED_OFF LOW + +#define IP5306_ADDR 0x75 +#define IP5306_REG_SYS_CTL0 0x00 + +// setPowerBoostKeepOn +bool setupPMU() +{ + bool en = true; + Wire.begin(I2C_SDA, I2C_SCL); + Wire.beginTransmission(IP5306_ADDR); + Wire.write(IP5306_REG_SYS_CTL0); + if (en) { + Wire.write(0x37); // Set bit1: 1 enable 0 disable boost keep on + } else { + Wire.write(0x35); // 0x37 is default reg value + } + return Wire.endTransmission() == 0; +} + +void setupModem() +{ + + // Start power management + if (setupPMU() == false) { + Serial.println("Setting power error"); + } + +#ifdef MODEM_RST + // Keep reset high + pinMode(MODEM_RST, OUTPUT); + digitalWrite(MODEM_RST, HIGH); +#endif + + pinMode(MODEM_PWRKEY, OUTPUT); + pinMode(MODEM_POWER_ON, OUTPUT); + + // Turn on the Modem power first + digitalWrite(MODEM_POWER_ON, HIGH); + + // Pull down PWRKEY for more than 1 second according to manual requirements + digitalWrite(MODEM_PWRKEY, HIGH); + delay(100); + digitalWrite(MODEM_PWRKEY, LOW); + delay(1000); + digitalWrite(MODEM_PWRKEY, HIGH); + + // Initialize the indicator as an output + pinMode(LED_GPIO, OUTPUT); + digitalWrite(LED_GPIO, LED_OFF); +} diff --git a/lib/ESP32_PPPoS/keywords.txt b/lib/ESP32_PPPoS/keywords.txt new file mode 100644 index 0000000..75cf66d --- /dev/null +++ b/lib/ESP32_PPPoS/keywords.txt @@ -0,0 +1,16 @@ +####################################### +# Data types (KEYWORD1) +####################################### +PPPoS KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +connect KEYWORD2 +begin KEYWORD2 +status KEYWORD2 + +####################################### +# Literals (LITERAL1) +####################################### +PPP_CONNECTED LITERAL1 diff --git a/lib/ESP32_PPPoS/library.json b/lib/ESP32_PPPoS/library.json new file mode 100644 index 0000000..1f1fb28 --- /dev/null +++ b/lib/ESP32_PPPoS/library.json @@ -0,0 +1,21 @@ +{ + "name": "PPPoS", + "version": "0.1.0", + "description": "PPP over Serial for ESP32", + "keywords": "esp32, GSM, ppp, PPPoS", + "authors": [ + { + "name": "Volodymyr Shymanskyy", + "url": "https://github.com/vshymanskyy", + "maintainer": true + } + ], + "repository": + { + "type": "git", + "url": "https://github.com/vshymanskyy/ESP32_PPPoS.git" + }, + "homepage": "https://github.com/vshymanskyy/ESP32_PPPoS", + "frameworks": "*", + "platforms": "esp32" +} diff --git a/lib/ESP32_PPPoS/library.properties b/lib/ESP32_PPPoS/library.properties new file mode 100644 index 0000000..9af7ffa --- /dev/null +++ b/lib/ESP32_PPPoS/library.properties @@ -0,0 +1,12 @@ +name=PPPoS +version=0.1.0 +author=Volodymyr Shymanskyy +license=MIT +maintainer=Volodymyr Shymanskyy +sentence= +paragraph= +category=Connectivity +url=https://github.com/vshymanskyy/ESP32_PPPoS +repository=https://github.com/vshymanskyy/ESP32_PPPoS.git +architectures=esp32 +includes=gsm.h diff --git a/lib/ESP32_PPPoS/src/PPPoS.cpp b/lib/ESP32_PPPoS/src/PPPoS.cpp new file mode 100644 index 0000000..ccdf1b2 --- /dev/null +++ b/lib/ESP32_PPPoS/src/PPPoS.cpp @@ -0,0 +1,237 @@ + +#include "PPPoS.h" + +extern "C" { + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "driver/uart.h" +#include "driver/gpio.h" +#include "tcpip_adapter.h" +#include "netif/ppp/pppos.h" +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" +#include "netif/ppp/pppapi.h" + +} + +#define BUF_SIZE (1024) + + +/* The PPP control block */ +static ppp_pcb *ppp; + +/* The PPP IP interface */ +static struct netif ppp_netif; + +static const char *TAG = "pppos"; + +static void ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx) +{ + PPPoS* pppos = (PPPoS*)ctx; + + struct netif *pppif = ppp_netif(pcb); + + switch (err_code) { + case PPPERR_NONE: { + ESP_LOGE(TAG, "status_cb: Connected\n"); + #if PPP_IPV4_SUPPORT + ESP_LOGE(TAG, " our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr)); + ESP_LOGE(TAG, " his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw)); + ESP_LOGE(TAG, " netmask = %s\n", ipaddr_ntoa(&pppif->netmask)); + #endif /* PPP_IPV4_SUPPORT */ + #if PPP_IPV6_SUPPORT + ESP_LOGE(TAG, " our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); + #endif /* PPP_IPV6_SUPPORT */ + pppos->mConnected = true; + + break; + } + case PPPERR_PARAM: { + ESP_LOGE(TAG, "status_cb: Invalid parameter\n"); + break; + } + case PPPERR_OPEN: { + ESP_LOGE(TAG, "status_cb: Unable to open PPP session\n"); + break; + } + case PPPERR_DEVICE: { + ESP_LOGE(TAG, "status_cb: Invalid I/O device for PPP\n"); + break; + } + case PPPERR_ALLOC: { + ESP_LOGE(TAG, "status_cb: Unable to allocate resources\n"); + break; + } + case PPPERR_USER: { + ESP_LOGE(TAG, "status_cb: User interrupt\n"); + pppos->mStarted = false; + pppos->mConnected = false; + break; + } + case PPPERR_CONNECT: { + ESP_LOGE(TAG, "status_cb: Connection lost\n"); + pppos->mStarted = false; + pppos->mConnected = false; + break; + } + case PPPERR_AUTHFAIL: { + ESP_LOGE(TAG, "status_cb: Failed authentication challenge\n"); + break; + } + case PPPERR_PROTOCOL: { + ESP_LOGE(TAG, "status_cb: Failed to meet protocol\n"); + break; + } + case PPPERR_PEERDEAD: { + ESP_LOGE(TAG, "status_cb: Connection timeout\n"); + break; + } + case PPPERR_IDLETIMEOUT: { + ESP_LOGE(TAG, "status_cb: Idle Timeout\n"); + break; + } + case PPPERR_CONNECTTIME: { + ESP_LOGE(TAG, "status_cb: Max connect time reached\n"); + break; + } + case PPPERR_LOOPBACK: { + ESP_LOGE(TAG, "status_cb: Loopback detected\n"); + break; + } + default: { + ESP_LOGE(TAG, "status_cb: Unknown error code %d\n", err_code); + break; + } + } +} + +static u32_t ppp_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) +{ + PPPoS* pppos = (PPPoS*)ctx; + return pppos->mStream->write(data, len); +} + + +static void pppos_client_task(void *ctx) +{ + PPPoS* pppos = (PPPoS*)ctx; + + u8_t* data = (u8_t*)malloc(BUF_SIZE); + while (1) { + while (pppos->mStarted) { + //while (pppos->mStream->available()) { + int len = pppos->mStream->readBytes(data, BUF_SIZE); + if (len > 0) { + pppos_input_tcpip(ppp, data, len); + } + //} + vTaskDelay(10 / portTICK_PERIOD_MS); + } + vTaskDelay(100 / portTICK_PERIOD_MS); + } +} + +void PPPoS::begin(Stream* stream) +{ + mStream = stream; + + // This is needed, because WiFiClient and WiFiClientSecure are used to handle connections + WiFi.begin(); + + xTaskCreate(&pppos_client_task, "pppos_client_task", 10048, this, 5, NULL); +} + +bool PPPoS::waitResponse(String& data) +{ + unsigned timeout_ms = 500; + data.reserve(64); + uint8_t index = 0; + uint32_t startMillis = millis(); + do { + while (mStream->available() > 0) { + int8_t a = mStream->read(); + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); + if (data.endsWith("OK\r\n")) { + index = 1; + goto finish; + } else if (data.endsWith("ERROR\r\n")) { + index = 2; + goto finish; + } else if (data.endsWith("NO CARRIER\r\n")) { + index = 3; + goto finish; + } else if (data.endsWith("CONNECT\r\n")) { + index = 4; + goto finish; + } + } + } while (millis() - startMillis < timeout_ms); + finish: + if (!index) { + data = ""; + } + return index > 0; + } + +bool PPPoS::connect(const char* apn, const char* user, const char* pass) +{ + while (mStream->available()) { + mStream->read(); + } + while (1) { + mStream->print("AT+CGDCONT=1,\"IP\",\""); + mStream->print(apn); + mStream->print("\"\r\n"); + mStream->flush(); + String data; + waitResponse(data); + data.trim(); + if (data == "OK") break; + delay(1000); + } + while (1) { + mStream->print("ATD*99***1#\r\n"); + mStream->flush(); + String data; + waitResponse(data); + data.trim(); + if (data == "CONNECT") break; + delay(1000); + } + + if (!mFirstStart) { + ppp = pppapi_pppos_create(&ppp_netif, ppp_output_callback, ppp_status_cb, this); + + if (ppp == NULL) { + return false; + } + + pppapi_set_default(ppp); + pppapi_set_auth(ppp, PPPAUTHTYPE_PAP, user, pass); + ppp_set_usepeerdns(ppp, 1); + } + pppapi_connect(ppp, 0); + + mStarted = true; + mFirstStart = true; + + return true; +} + + +void PPPoS::end() { + pppapi_close(ppp, 0); +} diff --git a/lib/ESP32_PPPoS/src/PPPoS.h b/lib/ESP32_PPPoS/src/PPPoS.h new file mode 100644 index 0000000..4a19758 --- /dev/null +++ b/lib/ESP32_PPPoS/src/PPPoS.h @@ -0,0 +1,35 @@ +#ifndef _PPPOS_H_ +#define _PPPOS_H_ + +#ifndef ESP32 +#error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting. +#endif + +#include +#include + +class PPPoS { +public: + + void begin(Stream* stream); + + bool connect(const char* apn = "", const char* user = "", const char* pass = ""); + + bool status() { + return mConnected; + } + + void end(); + +private: + bool waitResponse(String& data); + +public: + Stream* mStream; + + bool mFirstStart = false; + bool mConnected = false; + bool mStarted = false; +}; + +#endif diff --git a/platformio.ini b/platformio.ini index 5c1eda6..8b2e486 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,4 +22,9 @@ board_build.partitions = min_spiffs.csv monitor_speed = 9600 upload_protocol = esptool monitor_filters = esp32_exception_decoder -lib_deps = densaugeo/base64@^1.2.1 +lib_deps = + densaugeo/base64@^1.2.1 +; ciniml/WireGuard-ESP32@^0.1.5 + zmeiresearch/Wireguard client for LwIP on ESP32@^1.0.1 +build_flags = + -L./lib diff --git a/src/main.cpp b/src/main.cpp index 5ede3cf..aaa6bc5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,11 +21,18 @@ #include "BluetoothSerial.h" #include "digirepeater.h" #include "igate.h" +#include "wireguardif.h" +#include "wireguard.h" + +#include "wireguard_vpn.h" +#include #include #include "AFSK.h" +#include + #define DEBUG_TNC #define EEPROM_SIZE 1024 @@ -49,6 +56,16 @@ HardwareSerial SerialRF(1); #endif +#define MODEM_PWRKEY 5 +#define MODEM_TX 17 +#define MODEM_RX 16 + +#define PPP_APN "internet" +#define PPP_USER "" +#define PPP_PASS "" + +PPPoS ppp; + time_t systemUptime = 0; time_t wifiUptime = 0; @@ -88,6 +105,8 @@ IPAddress local_IP(192, 168, 4, 1); IPAddress gateway(192, 168, 4, 254); IPAddress subnet(255, 255, 255, 0); +IPAddress vpn_IP(192, 168, 44, 195); + int pkgTNC_count = 0; String getValue(String data, char separator, int index) @@ -203,8 +222,18 @@ void defaultConfig() config.volume = 4; config.input_hpf = false; #endif - saveEEPROM(); input_HPF = config.input_hpf; + config.vpn = false; + config.modem = false; + config.wg_port = 51820; + sprintf(config.wg_peer_address, "203.150.19.23"); + sprintf(config.wg_local_address, "192.168.44.200"); + sprintf(config.wg_netmask_address, "255.255.255.255"); + sprintf(config.wg_gw_address, "192.168.44.254"); + sprintf(config.wg_public_key, ""); + sprintf(config.wg_private_key, ""); + config.timeZone = 7; + saveEEPROM(); } unsigned long NTP_Timeout; @@ -661,8 +690,8 @@ void setup() SA818_INIT(true); #endif - enableLoopWDT(); - enableCore0WDT(); + // enableLoopWDT(); + // enableCore0WDT(); enableCore1WDT(); // Task 1 @@ -673,17 +702,17 @@ void setup() NULL, /* Task input parameter */ 1, /* Priority of the task */ &taskAPRSHandle, /* Task handle. */ - 1); /* Core where the task should run */ + 0); /* Core where the task should run */ // Task 2 xTaskCreatePinnedToCore( taskNetwork, /* Function to implement the task */ "taskNetwork", /* Name of the task */ - 20000, /* Stack size in words */ + 32768, /* Stack size in words */ NULL, /* Task input parameter */ 1, /* Priority of the task */ &taskNetworkHandle, /* Task handle. */ - 0); /* Core where the task should run */ + 1); /* Core where the task should run */ } int pkgCount = 0; @@ -776,9 +805,17 @@ int packet2Raw(String &tnc2, AX25Msg &Packet) long sendTimer = 0; bool AFSKInitAct = false; int btn_count = 0; +long timeCheck = 0; void loop() { vTaskDelay(5 / portTICK_PERIOD_MS); + if (millis() > timeCheck) + { + timeCheck = millis() + 10000; + if (ESP.getFreeHeap() < 70000) + esp_restart(); + // Serial.println(String(ESP.getFreeHeap())); + } #ifdef SA818 // if (SerialRF.available()) // { @@ -817,7 +854,7 @@ void sendIsPkgMsg(char *raw) String tnc2Raw = String(str); if (aprsClient.connected()) aprsClient.println(tnc2Raw); // Send packet to Inet - if (config.tnc) + if (config.tnc && config.tnc_digi) pkgTxUpdate(str, 0); // APRS_sendTNC2Pkt(tnc2Raw); // Send packet to RF } @@ -964,7 +1001,7 @@ void taskAPRS(void *pvParameters) if (aprsClient.connected()) aprsClient.println(String(rawTlm)); // Send packet to Inet - if (config.tnc) + if (config.tnc && config.tnc_digi) pkgTxUpdate(rawTlm, 0); // APRS_sendTNC2Pkt(String(rawTlm)); // Send packet to RF igateTLM.Sequence++; @@ -1069,6 +1106,26 @@ void taskNetwork(void *pvParameters) { int c = 0; Serial.println("Task Network has been start"); + // pinMode(MODEM_PWRKEY, OUTPUT); + // // Pull down PWRKEY for more than 1 second according to manual requirements + // digitalWrite(MODEM_PWRKEY, HIGH); + // delay(100); + // digitalWrite(MODEM_PWRKEY, LOW); + // delay(1000); + // digitalWrite(MODEM_PWRKEY, HIGH); + + // Serial1.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX); + // Serial1.setTimeout(10); + // Serial1.setRxBufferSize(2048); + // ppp.begin(&Serial1); + + // Serial.print("Connecting PPPoS"); + // ppp.connect(PPP_APN, PPP_USER, PPP_PASS); + // while (!ppp.status()) { + // delay(500); + // Serial.print("."); + // } + // Serial.println("OK"); if (config.wifi_mode == WIFI_AP_STA_FIX || config.wifi_mode == WIFI_AP_FIX) { // AP=false @@ -1105,10 +1162,11 @@ void taskNetwork(void *pvParameters) } webService(); + pingTimeout = millis() + 10000; for (;;) { // wdtNetworkTimer = millis(); - vTaskDelay(10 / portTICK_PERIOD_MS); + vTaskDelay(5 / portTICK_PERIOD_MS); serviceHandle(); if (config.wifi_mode == WIFI_AP_STA_FIX || config.wifi_mode == WIFI_STA_FIX) @@ -1122,12 +1180,14 @@ void taskNetwork(void *pvParameters) AFSK_TimerEnable(false); #endif wifiTTL = tw + 60000; - Serial.print("WiFi connecting.."); + Serial.println("WiFi connecting.."); // udp.endPacket(); WiFi.disconnect(); WiFi.setTxPower((wifi_power_t)config.wifi_power); WiFi.setHostname("ESP32IGate"); WiFi.begin(config.wifi_ssid, config.wifi_pass); + if (config.vpn) + wireguard_remove(); // Wait up to 1 minute for connection... for (c = 0; (c < 30) && (WiFi.status() != WL_CONNECTED); c++) { @@ -1139,12 +1199,17 @@ void taskNetwork(void *pvParameters) { // If it didn't connect within 1 min Serial.println("Failed. Will retry..."); WiFi.disconnect(); + // WiFi.mode(WIFI_OFF); + delay(3000); + // WiFi.mode(WIFI_STA); + WiFi.reconnect(); continue; } Serial.println("WiFi connected"); - Serial.println("IP address: "); + Serial.print("IP address: "); Serial.println(WiFi.localIP()); + vTaskDelay(1000 / portTICK_PERIOD_MS); NTP_Timeout = millis() + 5000; // Serial.println("Contacting Time Server"); @@ -1157,13 +1222,14 @@ void taskNetwork(void *pvParameters) } else { + if (millis() > NTP_Timeout) { NTP_Timeout = millis() + 86400000; // Serial.println("Config NTP"); // setSyncProvider(getNtpTime); Serial.println("Contacting Time Server"); - configTime(3600 * timeZone, 0, "203.150.19.26", "110.170.126.101", "77.68.122.252"); + configTime(3600 * config.timeZone, 0, "203.150.19.26", "110.170.126.101", "77.68.122.252"); vTaskDelay(3000 / portTICK_PERIOD_MS); time_t systemTime; time(&systemTime); @@ -1172,6 +1238,15 @@ void taskNetwork(void *pvParameters) { systemUptime = now(); } + pingTimeout = millis() + 2000; + if (config.vpn) + { + if (!wireguard_active()) + { + Serial.println("Setup Wiregurad VPN!"); + wireguard_setup(); + } + } } if (config.aprs) @@ -1184,7 +1259,7 @@ void taskNetwork(void *pvParameters) { if (aprsClient.available()) { - pingTimeout = millis() + 300000; // Reset ping timout + // pingTimeout = millis() + 300000; // Reset ping timout String line = aprsClient.readStringUntil('\n'); //อ่านค่าที่ Server ตอบหลับมาทีละบรรทัด #ifdef DEBUG_IS printTime(); @@ -1245,20 +1320,51 @@ void taskNetwork(void *pvParameters) } } + // if (millis() > pingTimeout) + // { + // pingTimeout = millis() + 3000; + // Serial.print("Ping to " + vpn_IP.toString()); + // if (ping_start(vpn_IP, 3, 0, 0, 10) == true) + // { + // Serial.println("VPN Ping Success!!"); + // } + // else + // { + // Serial.println("VPN Ping Fail!"); + // } + // } + if (millis() > pingTimeout) { pingTimeout = millis() + 300000; - Serial.print("Ping to " + WiFi.gatewayIP().toString()); - if (ping_start(WiFi.gatewayIP(), 3, 0, 0, 10) == true) + Serial.println("Ping GW to " + WiFi.gatewayIP().toString()); + if (ping_start(WiFi.gatewayIP(), 3, 0, 0, 5) == true) { - Serial.println(" Success!!"); + Serial.println("GW Success!!"); } else { - Serial.println(" Fail!"); + Serial.println("GW Fail!"); WiFi.disconnect(); wifiTTL = 0; } + if (config.vpn) + { + IPAddress vpnIP; + vpnIP.fromString(String(config.wg_gw_address)); + Serial.println("Ping VPN to " + vpnIP.toString()); + if (ping_start(vpnIP, 2, 0, 0, 10) == true) + { + Serial.println("VPN Ping Success!!"); + } + else + { + Serial.println("VPN Ping Fail!"); + wireguard_remove(); + delay(3000); + wireguard_setup(); + } + } } } } diff --git a/src/webservice.cpp b/src/webservice.cpp index a83ef17..0507152 100644 --- a/src/webservice.cpp +++ b/src/webservice.cpp @@ -164,7 +164,7 @@ void setHTML(byte page) webString += "timeStamp=Number(json.timeStamp);\n"; webString += "});\n"; webString += "if(active==1){\nleft.update(dBV,false);\nchart.redraw();\n"; - webString += "var date=new Date(timeStamp * 1000).toLocaleString();\n"; + webString += "var date=new Date(timeStamp * 1000);\n"; webString += "var head=date+\"[\"+Vrms.toFixed(3)+\"Vrms,\"+dBV.toFixed(1)+\"dBV]\\n\";\n"; webString += "document.getElementById(\"raw_txt\").value+=head+atob(raw)+\"\\n\";\n"; webString += "}\n"; @@ -181,8 +181,11 @@ void setHTML(byte page) String strActiveP6 = ""; String strActiveP7 = ""; String strActiveP8 = ""; + String strActiveP9 = ""; - if (page == 7) + if (page == 8) + strActiveP9 = "class=active"; + else if (page == 7) strActiveP8 = "class=active"; else if (page == 6) strActiveP7 = "class=active"; @@ -199,7 +202,12 @@ void setHTML(byte page) else if (page == 0) strActiveP1 = "class=active"; webString += "\n"; - webString += "
ESP32 APRS Internet Gateway
\n"; + String myStation; + if (config.aprs_ssid == 0) + myStation = String(config.aprs_mycall); + else + myStation = String(config.aprs_mycall) + "-" + String(config.aprs_ssid); + webString += "
ESP32 APRS Internet Gateway by " + myStation + "
\n"; webString += "
\n"; webString += "
    \n"; webString += "
  • \nDash Board\n
  • \n"; @@ -210,6 +218,7 @@ void setHTML(byte page) #ifdef SA818 webString += "
  • \nRadio\n
  • \n"; #endif + webString += "
  • \nVPN\n
  • \n"; webString += "
  • \nService\n
  • \n"; webString += "
  • \nSystem\n
  • \n"; webString += "
  • \nTest\n
  • \n"; @@ -621,6 +630,8 @@ void handle_setting() webString += "\n"; server.send(200, "text/html", webString); // send to someones browser when asked + delay(100); + webString.clear(); } void handle_service() @@ -981,6 +992,8 @@ void handle_service() webString += "\n"; server.send(200, "text/html", webString); // send to someones browser when asked + delay(100); + webString.clear(); } #ifdef SA818 @@ -1117,7 +1130,11 @@ void handle_radio() webString += "
    \n"; webString += "
    \n"; +#ifdef SR_FRS + webString += "
    \n

    RF Module SR_FRS_1W

    \n"; +#else webString += "
    \n

    RF Module SA818/SA868

    \n"; +#endif webString += "
    \n"; webString += "\n"; webString += "
    \n"; @@ -1238,14 +1255,198 @@ void handle_radio() webString += "\n"; server.send(200, "text/html", webString); // send to someones browser when asked - - // delay(100); + delay(100); + webString.clear(); } #endif +void handle_vpn() +{ + // byte *ptr; + bool vpnEn = false; + // bool taretime = false; + // bool davisEn = false; + // bool moniEn = false; + + if (server.args() > 0) + { + // taretime = false; + for (uint8_t i = 0; i < server.args(); i++) + { + // Serial.print("SERVER ARGS "); + // Serial.print(server.argName(i)); + // Serial.print("="); + // Serial.println(server.arg(i)); + + if (server.argName(i) == "vpnEnable") + { + if (server.arg(i) != "") + { + // if (isValidNumber(server.arg(i))) + if (String(server.arg(i)) == "OK") + vpnEn = true; + } + } + + // if (server.argName(i) == "taretime") { + // if (server.arg(i) != "") + // { + // //if (isValidNumber(server.arg(i))) + // if (String(server.arg(i)) == "OK") + // taretime = true; + // } + // } + if (server.argName(i) == "wg_port") + { + if (server.arg(i) != "") + { + config.wg_port = server.arg(i).toInt(); + } + } + + if (server.argName(i) == "wg_public_key") + { + if (server.arg(i) != "") + { + strncpy(config.wg_public_key, server.arg(i).c_str(), 44); + config.wg_public_key[44] = 0; + } + } + + if (server.argName(i) == "wg_private_key") + { + if (server.arg(i) != "") + { + strncpy(config.wg_private_key, server.arg(i).c_str(), 44); + config.wg_private_key[44] = 0; + } + } + + if (server.argName(i) == "wg_peer_address") + { + if (server.arg(i) != "") + { + strcpy(config.wg_peer_address, server.arg(i).c_str()); + } + } + + if (server.argName(i) == "wg_local_address") + { + if (server.arg(i) != "") + { + strcpy(config.wg_local_address, server.arg(i).c_str()); + } + } + + if (server.argName(i) == "wg_netmask_address") + { + if (server.arg(i) != "") + { + strcpy(config.wg_netmask_address, server.arg(i).c_str()); + } + } + + if (server.argName(i) == "wg_gw_address") + { + if (server.arg(i) != "") + { + strcpy(config.wg_gw_address, server.arg(i).c_str()); + } + } + } + + config.vpn = vpnEn; + saveEEPROM(); + // topBar(WiFi.RSSI()); + } + + // getMoisture(); // read sensor + // webMessage = ""; + setHTML(8); + webString += "
    \n"; + webString += "\n"; + + webString += "
    \n

    Wireguard Configuration

    \n"; + + String syncFlage = ""; + if (config.vpn) + syncFlage = "checked"; + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; // div general + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + + webString += "
    \n"; + + webString += "\n"; + server.send(200, "text/html", webString); // send to someones browser when asked + delay(100); + webString.clear(); +} + void handle_system() { - if (server.hasArg("updateTimeNtp")) + if (server.hasArg("updateTimeZone")) + { + for (uint8_t i = 0; i < server.args(); i++) + { + if (server.argName(i) == "SetTimeZone") + { + if (server.arg(i) != "") + { + config.timeZone = server.arg(i).toInt(); + // Serial.println("WEB Config Time Zone); + configTime(3600 * config.timeZone, 0, "203.150.19.26"); + } + break; + } + } + saveEEPROM(); + } + else if (server.hasArg("updateTimeNtp")) { for (uint8_t i = 0; i < server.args(); i++) { @@ -1258,7 +1459,7 @@ void handle_system() if (server.arg(i) != "") { Serial.println("WEB Config NTP"); - configTime(3600 * timeZone, 0, server.arg(i).c_str()); + configTime(3600 * config.timeZone, 0, server.arg(i).c_str()); } break; } @@ -1299,9 +1500,9 @@ void handle_system() // tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec - time_t rtc = timeStamp - 25200; + time_t rtc = timeStamp - (config.timeZone * 3600); timeval tv = {rtc, 0}; - timezone tz = {TZ_SEC + DST_MN, 0}; + timezone tz = {(0) + DST_MN, 0}; settimeofday(&tv, &tz); // Serial.println("Update TIME " + server.arg(i)); @@ -1429,6 +1630,10 @@ void handle_system() } saveEEPROM(); } + else if (server.hasArg("REBOOT")) + { + esp_restart(); + } struct tm tmstruct; char strTime[20]; @@ -1466,7 +1671,22 @@ void handle_system() webString += "
    \n"; webString += "
    \n"; webString += "\n"; + webString += "
    \n\n\n"; + + webString += "
    \n"; + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + webString += "\n"; + webString += "
    \n
    \n\n"; + + webString += "
    \n"; + webString += "
    \n"; + webString += "\n"; + webString += "\n"; webString += "
    \n
    \n\n"; + ; webString += "

    \n"; @@ -1482,12 +1702,12 @@ void handle_system() webString += "
    \n"; webString += "\n"; - webString += "
    \n"; + webString += "
    \n"; webString += "
    \n"; webString += "
    \n"; webString += "\n"; - webString += "
    \n"; + webString += "
    \n"; webString += "

    \n"; webString += "
    \n"; @@ -1500,12 +1720,12 @@ void handle_system() webString += "
    \n"; webString += "\n"; - webString += "
    \n"; + webString += "
    \n"; webString += "
    \n"; webString += "
    \n"; webString += "\n"; - webString += "
    \n"; + webString += "
    \n"; webString += "
    \n"; webString += "
    \n"; @@ -1625,8 +1845,8 @@ void handle_system() "});\n\n"; webString += "\n"; server.send(200, "text/html", webString); // send to someones browser when asked - delay(100); + webString.clear(); } extern bool afskSync; @@ -1668,12 +1888,17 @@ void handle_realtime() } afskSync = false; server.send(200, "text/html", String(jsonMsg)); + delay(100); free(jsonMsg); } void handle_test() { + if (server.hasArg("REBOOT")) + { + esp_restart(); + } if (server.hasArg("sendBeacon")) { String tnc2Raw = send_fix_location(); @@ -1707,7 +1932,8 @@ void handle_test() webString += "
    \n"; webString += "

    \n"; webString += "
    TNC2 RAW: APE32I,WIDE1-1:>Test Status\"/>
    \n"; - webString += "
    \n"; + webString += "

    \n"; + webString += "

    \n"; webString += "
    \n"; webString += "
    \n"; webString += "
    \n"; @@ -1718,6 +1944,7 @@ void handle_test() server.send(200, "text/html", webString); // send to someones browser when asked delay(100); + webString.clear(); } void handle_firmware() @@ -1728,6 +1955,91 @@ void handle_firmware() // webMessage = ""; setHTML(5); + webString += "\n"; + webString += "Current Hardware Version: ESP32DR"; +#ifdef SA818 +#ifdef SR_FRS + webString += " (MODEL:SR_FRS_1W)"; +#else + webString += " (MODEL:SA818/SA868)"; +#endif +#else + webString += " (MODEL: Simple)"; +#endif + webString += "
    Current Firmware Version: V" + String(VERSION) + "\n
    "; + webString += "Develop by: HS5TQA\n
    "; + webString += "Chip ID: " + String(strCID) + "\n
    "; + webString += "
    \n

    Firmware Update

    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + // webString += "
    \n"; + // webString += "
    \n"; + webString += "
    \n"; + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += "\n"; + webString += "
    \n"; + webString += "
    \n"; + webString += "
    \n"; + + webString += "
    \n"; + webString += ""; + + webString += "\n"; + server.send(200, "text/html", webString); // send to someones browser when asked + + delay(100); + webString.clear(); +} + +void handle_upgrade() +{ + char strCID[50]; + uint64_t chipid = ESP.getEfuseMac(); + sprintf(strCID, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid); + webString = ""; + // setHTML(5); + webString += "\n"; webString += "Current Hardware Version: ESP32DR Simple\n
    "; webString += "Current Firmware Version: V" + String(VERSION) + "\n
    "; @@ -1793,6 +2105,7 @@ void handle_firmware() server.send(200, "text/html", webString); // send to someones browser when asked delay(100); + webString.clear(); } void handle_default() @@ -1970,12 +2283,14 @@ void webService() #ifdef SA818 server.on("/radio", handle_radio); #endif + server.on("/vpn", handle_vpn); server.on("/default", handle_default); server.on("/service", handle_service); server.on("/system", handle_system); server.on("/test", handle_test); server.on("/realtime", handle_realtime); server.on("/firmware", handle_firmware); + server.on("/upgrade", handle_upgrade); /*handling uploading firmware file */ server.on( "/update", HTTP_POST, []() @@ -2001,8 +2316,10 @@ void webService() disableCore0WDT(); disableCore1WDT(); disableLoopWDT(); +#ifdef I2S_INTERNAL i2s_adc_disable(I2S_NUM_0); dac_i2s_disable(); +#endif vTaskSuspend(taskAPRSHandle); // vTaskSuspend(taskNetworkHandle); config.aprs = false; diff --git a/src/wireguard_vpn.cpp b/src/wireguard_vpn.cpp new file mode 100644 index 0000000..e3faa92 --- /dev/null +++ b/src/wireguard_vpn.cpp @@ -0,0 +1,126 @@ +//============================================================================== +// Wireguard VPN Client demo for LwIP/ESP32 +//============================================================================== + +//============================================================================== +// Includes +//============================================================================== +#include +#include "main.h" + +//ใช้ตัวแปรโกลบอลในไฟล์ main.cpp +extern Configuration config; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include "wireguardif.h" +#include "wireguard.h" + +#include "wireguard_vpn.h" +//============================================================================== +// Defines +//============================================================================== +#define CMP_NAME "WG_VPN" + +#if !defined(WG_CLIENT_PRIVATE_KEY) || !defined(WG_PEER_PUBLIC_KEY) +#error "Please update configuratiuon with your VPN-specific keys!" +#endif + +//============================================================================== +// Local types +//============================================================================== + +//============================================================================== +// Local data +//============================================================================== +static struct netif wg_netif_struct = {0}; +static struct netif *wg_netif = NULL; +static uint8_t wireguard_peer_index_local = WIREGUARDIF_INVALID_INDEX; + +//============================================================================== +// Exported data +//============================================================================== + +//============================================================================== +// Local functions +//============================================================================== + +//============================================================================== +// Exported functions +//============================================================================== +bool wireguard_active() +{ + if(wg_netif!=NULL) return true; + return false; +} + +void wireguard_remove() +{ + + if(wg_netif!=NULL){ + wireguardif_disconnect(wg_netif, wireguard_peer_index_local); + wireguardif_remove_peer(wg_netif, wireguard_peer_index_local); + //netif_set_down(wg_netif); + //netif_remove(&wg_netif_struct); + } +} + +void wireguard_setup() +{ + struct wireguardif_init_data wg; + struct wireguardif_peer peer; + ip_addr_t ipaddr = WG_LOCAL_ADDRESS; + ip_addr_t netmask = WG_LOCAL_NETMASK; + ip_addr_t gateway = WG_GATEWAY_ADDRESS; + ip_addr_t peer_address = WG_PEER_ADDRESS; + + ipaddr_aton(config.wg_local_address,&ipaddr); + ipaddr_aton(config.wg_netmask_address,&netmask); + ipaddr_aton(config.wg_gw_address,&gateway); + ipaddr_aton(config.wg_peer_address,&peer_address); + + // Setup the WireGuard device structure + // wg.private_key = WG_CLIENT_PRIVATE_KEY; + // wg.listen_port = WG_CLIENT_PORT; + wg.private_key = config.wg_private_key; + wg.listen_port = config.wg_port+1; + wg.bind_netif = NULL; // NB! not working on ESP32 even if set! + + if(wg_netif==NULL){ + // Register the new WireGuard network interface with lwIP + wg_netif = netif_add(&wg_netif_struct, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gateway), &wg, &wireguardif_init, &ip_input); + + // Mark the interface as administratively up, link up flag is set automatically when peer connects + netif_set_up(wg_netif); + } + + // Initialise the first WireGuard peer structure + wireguardif_peer_init(&peer); + // peer.public_key = WG_PEER_PUBLIC_KEY; + peer.public_key = config.wg_public_key; + peer.preshared_key = NULL; + // Allow all IPs through tunnel + //peer.allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); + IP_ADDR4(&peer.allowed_ip, 0, 0, 0, 0); + IP_ADDR4(&peer.allowed_mask, 0, 0, 0, 0); + + // If we know the endpoint's address can add here + ip_addr_set(&peer.endpoint_ip, &peer_address); + //peer.endport_port = WG_PEER_PORT; + peer.endport_port = config.wg_port; + + // Register the new WireGuard peer with the netwok interface + wireguardif_add_peer(wg_netif, &peer, &wireguard_peer_index_local); + + if ((wireguard_peer_index_local != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) + { + // Start outbound connection to peer + wireguardif_connect(wg_netif, wireguard_peer_index_local); + } +} + +#ifdef __cplusplus +} +#endif // __cplusplus \ No newline at end of file