@@ -566,8 +624,10 @@
TTGO LoRa32 V2.1 (aka T3 V1.6.1)
Hardware limitation: if bluetooth is enabled and BT-client is connected, WIFI (-> Web-Server) does not work anymore.
+ You'll see the red LED while booting turned on for 60s as indicatior for waiting for BT-clients.
Hack: firmware compiled with -e ttgo-lora32-v2.1 and bluetooth configuration variable is set to enabled, now listens on boot up to one minute for your bluetooth device to connect.
- If a bluetooth device connects, it does not start the Web-Server. Else, it closes SerialBT port and starts the Web-Server.
+ If a bluetooth device connects, it does not start the Web-Server. Else, it closes SerialBT port and starts the Web-Server on LORA32_21 devices.
+ See also: new feature for switching WIFI off (i.e. if you use the device as portable tracker), if you don't need it: Webserver eats abt 80mA..
diff --git a/include/preference_storage.h b/include/preference_storage.h
index 8d91e19..8e55c5f 100644
--- a/include/preference_storage.h
+++ b/include/preference_storage.h
@@ -11,6 +11,17 @@ static const char *const PREF_WIFI_SSID = "wifi_ssid";
static const char *const PREF_WIFI_PASSWORD = "wifi_password";
static const char *const PREF_AP_PASSWORD = "ap_password";
static const char *const PREF_NTP_SERVER = "ntp_server";
+static const char *const PREF_WIFI_ENABLE_INIT = "wifi_en_i";
+static const char *const PREF_WIFI_ENABLE = "wifi_en";
+static const char *const PREF_WIFI_TXPWR_MODE_AP_INIT = "wifi_pwrAP_i";
+static const char *const PREF_WIFI_TXPWR_MODE_AP = "wifi_pwrAP";
+static const char *const PREF_WIFI_TXPWR_MODE_STA_INIT = "wifi_pwrSTA_i";
+static const char *const PREF_WIFI_TXPWR_MODE_STA = "wifi_pwrSTA";
+static const char *const PREF_TNCSERVER_ENABLE_INIT = "tncsrvr_en_i";
+static const char *const PREF_TNCSERVER_ENABLE = "tncsrvr_en";
+static const char *const PREF_GPSSERVER_ENABLE_INIT = "gpssrv_en_i";
+static const char *const PREF_GPSSERVER_ENABLE = "gpssrv_en";
+
// LoRa settings
static const char *const PREF_LORA_FREQ_PRESET_INIT = "lora_freq_i";
@@ -56,8 +67,13 @@ static const char *const PREF_APRS_COMMENT = "aprs_comment";
static const char *const PREF_APRS_COMMENT_INIT = "aprs_comm_init";
static const char *const PREF_APRS_COMMENT_RATELIMIT_PRESET = "aprs_comm_rt";
static const char *const PREF_APRS_COMMENT_RATELIMIT_PRESET_INIT = "aprs_comm_rt_i";
-static const char *const PREF_APRS_SHOW_ALTITUDE = "aprs_alt";
-static const char *const PREF_APRS_SHOW_ALTITUDE_INIT = "aprs_alt_init";
+static const char *const PREF_APRS_SHOW_ALTITUDE = "aprs_alt"; /* obsoleted. may be removed later. Use alt ratio 0 .. 100*/
+static const char *const PREF_APRS_SHOW_ALTITUDE_INIT = "aprs_alt_init"; /* obsoleted. may be removed later. Use alt ratio 0 .. 100*/
+static const char *const PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION = "aprs_ALTinC";
+static const char *const PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION_INIT = "aprs_ALTinC_i";
+static const char *const PREF_APRS_ALTITUDE_RATIO = "aprs_alt_r";
+static const char *const PREF_APRS_ALTITUDE_RATIO_INIT = "aprs_alt_r_i";
+
static const char *const PREF_APRS_SHOW_BATTERY = "aprs_batt";
static const char *const PREF_APRS_SHOW_BATTERY_INIT = "aprs_batt_init";
static const char *const PREF_APRS_LATITUDE_PRESET = "aprs_lat_p";
@@ -120,6 +136,9 @@ static const char *const PREF_DEV_REBOOT_INTERVAL = "reboot_intrvl";
static const char *const PREF_DEV_REBOOT_INTERVAL_INIT = "reboot_intrvl_i";
static const char *const PREF_DEV_SHOW_OLED_TIME = "sh_oledtime"; // set OLED timeout
static const char *const PREF_DEV_SHOW_OLED_TIME_INIT = "sh_oledtime_i";
+static const char *const PREF_DEV_CPU_FREQ = "cpufreq";
+static const char *const PREF_DEV_CPU_FREQ_INIT = "cpufreq_i";
+
// APRSIS settings
static const char *const PREF_APRSIS_EN_INIT = "aprsis_en_i";
diff --git a/lib/BG_RF95/BG_RF95.cpp b/lib/BG_RF95/BG_RF95.cpp
index 9a6ec9b..965832d 100644
--- a/lib/BG_RF95/BG_RF95.cpp
+++ b/lib/BG_RF95/BG_RF95.cpp
@@ -455,3 +455,8 @@ void BG_RF95::setPreambleLength(uint16_t bytes)
spiWrite(BG_RF95_REG_20_PREAMBLE_MSB, bytes >> 8);
spiWrite(BG_RF95_REG_21_PREAMBLE_LSB, bytes & 0xff);
}
+
+bool BG_RF95::SignalDetected(void)
+{
+ return ((spiRead(BG_RF95_REG_18_MODEM_STAT) & 0x01) == 0x01);
+}
diff --git a/lib/BG_RF95/BG_RF95.h b/lib/BG_RF95/BG_RF95.h
index 8534dc6..622bfc9 100644
--- a/lib/BG_RF95/BG_RF95.h
+++ b/lib/BG_RF95/BG_RF95.h
@@ -694,6 +694,8 @@ virtual uint8_t lastSNR();
/// \return true if sleep mode was successfully entered.
virtual bool sleep();
+ virtual bool SignalDetected();
+
protected:
/// This is a low level function to handle the interrupts for one instance of BG_RF95.
/// Called automatically by isr*()
diff --git a/src/TTGO_T-Beam_LoRa_APRS.ino b/src/TTGO_T-Beam_LoRa_APRS.ino
index 81e2f08..21c9289 100644
--- a/src/TTGO_T-Beam_LoRa_APRS.ino
+++ b/src/TTGO_T-Beam_LoRa_APRS.ino
@@ -150,10 +150,13 @@ int tel_sequence;
String tel_path;
#ifdef SHOW_ALT
- boolean showAltitude = true;
+ boolean showAltitude = true; /* obsolete. use altitude_ratio 0 .. 100 % */
+ uint8_t altitude_ratio = 100; // Recommended: 10%. May be 0 % speed (-> 100% altitude), 100 % speed (-> no altitude), or something in between
#else
- boolean showAltitude = false;
+ boolean showAltitude = false; /* obsolete. use altitude_ratio 0 .. 100 % */
+ uint8_t altitude_ratio = 0; // Recommended 10%. May be 0 % speed (-> 100% altitude), 100 % speed (-> no altitude), or something in between
#endif
+boolean showAltitudeInsideCompressedPosition = true;
#ifdef SHOW_BATT
boolean showBattery = true;
#else
@@ -180,6 +183,16 @@ String tel_path;
#else
boolean enable_bluetooth = false;
#endif
+#if defined(ENABLE_WIFI)
+ uint8_t enable_webserver = 2;
+ boolean webserverStarted = 0;
+ boolean tncServer_enabled = false;
+ boolean gpsServer_enabled = false;
+ // Mapping Table {Power, max_tx_power} = {{8, 2}, {20, 5}, {28, 7}, {34, 8}, {44, 11}, {52, 13}, {56, 14}, {60, 15}, {66, 16}, {72, 18}, {80,20}}.
+ // We'll use "min", "low", "mid", "high", "max" -> 2dBm (1.5mW) -> 8, 11dBm (12mW) -> 44, 15dBm (32mW) -> 60, 18dBm (63mW) ->72, 20dBm (100mW) ->80
+ int8_t wifi_txpwr_mode_AP = 8;
+ int8_t wifi_txpwr_mode_STA = 80;
+#endif
#ifdef ENABLE_OLED
boolean enabled_oled = true;
#else
@@ -325,6 +338,8 @@ uint32_t time_last_frame_via_kiss_received = 0L; // kiss client sends aprs-text-
boolean kiss_client_came_via_bluetooth = false;
#endif
+uint16_t adjust_cpuFreq_to = 80;
+
// do not configure
boolean dont_send_own_position_packets = false; // dynamicaly set if kiss device sends position. Maybe there are other usecases (-> kiss-independent)
boolean gps_state_before_autochange = false; // remember gps state before autochange
@@ -420,6 +435,9 @@ out_relay_path:
double Tspeed=0, Tcourse=0;
int i;
long Talt;
+ static uint8_t cnt = 0;
+ boolean time_to_add_alt = false;
+
Tlat=gps.location.lat();
Tlon=gps.location.lng();
Tcourse=gps.course.deg();
@@ -429,6 +447,16 @@ out_relay_path:
aprs_lon = 900000000 + Tlon * 10000000 / 2;
aprs_lon = aprs_lon / 26 - aprs_lon / 2710 + aprs_lon / 15384615;
+ // altitude_ratio: 0%, 10%, 25%, 50%, 75%, 90%, 100%
+ if (gps.altitude.isValid() && altitude_ratio > 0) {
+ if (altitude_ratio <= 50)
+ time_to_add_alt = (cnt % (100 / altitude_ratio) == 0);
+ else if (altitude_ratio < 100)
+ time_to_add_alt = (cnt % (100 / (100-altitude_ratio)) != 0);
+ else
+ time_to_add_alt = true;
+ }
+
outString += aprsSymbolTable;
ax25_base91enc(helper_base91, 4, aprs_lat);
for (i = 0; i < 4; i++) {
@@ -439,22 +467,39 @@ out_relay_path:
outString += helper_base91[i];
}
outString += aprsSymbol;
- ax25_base91enc(helper_base91, 1, (uint32_t) Tcourse / 4);
- outString += helper_base91[0];
- ax25_base91enc(helper_base91, 1, (uint32_t) (log1p(Tspeed) / 0.07696));
- outString += helper_base91[0];
- outString += "H";
- if (showAltitude){
+
+ if (showAltitudeInsideCompressedPosition && time_to_add_alt) {
Talt = gps.altitude.feet();
- char buf[7];
- outString += "/A=";
- if (Talt > 999999) Talt=999999;
- else if (Talt < -99999) Talt=-99999;
- sprintf(buf, "%06ld", Talt);
- outString += buf;
+ if (Talt < 0) Talt = 0;
+ else if (Talt > 15270967) Talt = 15270967; /* 1.002** (90*91+90-1) */
+ ax25_base91enc(helper_base91, 2, (uint32_t) (log1p(Talt) / 0.001998));
+ /* ^ math.log1p(1.002-1) */
+ outString += helper_base91[0];
+ outString += helper_base91[1];
+ outString += "X";
+ } else {
+ ax25_base91enc(helper_base91, 1, (uint32_t) Tcourse / 4);
+ outString += helper_base91[0];
+ if (Tspeed > 1018) Tspeed = 1018; /* 1.08**90 */
+ ax25_base91enc(helper_base91, 1, (uint32_t) (log1p(Tspeed) / 0.07696));
+ /* ^ math.log1p(1.08-1) */
+ outString += helper_base91[0];
+ outString += "H";
+
+ if (time_to_add_alt) {
+ Talt = gps.altitude.feet();
+ char buf[7];
+ outString += "/A=";
+ if (Talt > 999999) Talt=999999;
+ else if (Talt < -99999) Talt=-99999;
+ sprintf(buf, "%06ld", Talt);
+ outString += buf;
+ }
}
+ cnt++;
+
} else { //fixed position not compresed
outString += aprsLatPreset;
outString += aprsSymbolTable;
@@ -465,8 +510,19 @@ out_relay_path:
if(show_cmt){
static uint8_t comments_added = 0;
static uint32_t time_comment_added = 0L;
- if (!rate_limit_message_text || (time_comment_added + (gps_state ? sb_max_interval : fix_beacon_interval) < millis()))
+
+ if (!rate_limit_message_text) {
comments_added = 0;
+ } else {
+ uint32_t t_offset = (gps_state ? sb_max_interval : fix_beacon_interval);
+ // send comment text not under 10min, and at least every hour
+ if (t_offset < 600000)
+ t_offset = 600000;
+ else if (t_offset > 3600000)
+ t_offset = 3600000;
+ if ((time_comment_added + t_offset) < millis())
+ comments_added = 0;
+ }
if ((comments_added++ % 10) == 0) {
outString += aprsComment;
time_comment_added = millis();
@@ -563,26 +619,66 @@ void sendpacket(boolean force_fixed){
void loraSend(byte lora_LTXPower, float lora_FREQ, ulong lora_SPEED, const String &message) {
if (!lora_tx_enabled)
return;
- #ifdef ENABLE_LED_SIGNALING
- digitalWrite(TXLED, LOW);
- #endif
- lastTX = millis();
+#ifdef T_BEAM_V1_0
+ axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LoRa
+#endif
int messageSize = min(message.length(), sizeof(lora_TXBUFF) - 1);
message.toCharArray((char*)lora_TXBUFF, messageSize + 1, 0);
lora_set_speed(lora_SPEED);
rf95.setFrequency(lora_FREQ);
rf95.setTxPower(lora_LTXPower);
+
+ // kind of csma/cd. TODO: better approach: add to a tx-queue
+ // in SF12: preamble + lora header = 663.552 -> we wait 1300ms for check if lora-chip is in decoding
+ // See https://www.rfwireless-world.com/calculators/LoRaWAN-Airtime-calculator.html
+ // In detail: At our supported speed "names":
+ // SF7: 28.928ms
+ // SF8: 57.856ms
+ // SF9: 115.712ms 1200
+ // SF10: 231.424ms 610
+ // SF11: 331.776ms
+ // SF12: 663.552ms 300,240, 210, 180
+ uint32_t wait_for_signal = 700;
+ if (lora_speed == 610) wait_for_signal = 250;
+ else if (lora_speed == 1200) wait_for_signal = 125;
+
+ randomSeed(millis());
+ int n;
+ for (n = 0; n < 30; n++) {
+ delay(wait_for_signal);
+ if (rf95.SignalDetected()) {
+ continue;
+ }
+ delay(100);
+ if (!rf95.SignalDetected() && random(256) < 64) {
+ break;
+ }
+ }
+
+ #ifdef ENABLE_LED_SIGNALING
+ digitalWrite(TXLED, LOW);
+ #endif
+ lastTX = millis();
rf95.sendAPRS(lora_TXBUFF, messageSize);
rf95.waitPacketSent();
#ifdef ENABLE_LED_SIGNALING
digitalWrite(TXLED, HIGH);
#endif
// cross-digipeating may have altered our RX-frequency. Revert frequency change needed for this transmission.
- if (lora_FREQ != lora_freq_rx_curr)
+ if (lora_FREQ != lora_freq_rx_curr) {
rf95.setFrequency(lora_freq_rx_curr);
+ // flush cache. just to be sure, so that no cross-digi-qrg packet comes in the input-buffer of the main qrg.
+ // With no buffer / length called, recvAPRS directly calls clearRxBuf()
+ rf95.recvAPRS(0, 0);
+ }
if (lora_SPEED != lora_speed_rx_curr)
lora_set_speed(lora_speed_rx_curr);
+#ifdef T_BEAM_V1_0
+ // (if lora_digipeating_mode == 0 or not lora_rx_enabled) and no bt client is connected
+ if ((!lora_digipeating_mode || !lora_rx_enabled) && !SerialBT.hasClient())
+ axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LoRa
+#endif
}
void batt_read(){
@@ -839,6 +935,37 @@ void setup(){
}
preferences.begin("cfg", false);
+
+#ifdef ENABLE_WIFI
+ if (!preferences.getBool(PREF_WIFI_ENABLE_INIT)){
+ preferences.putBool(PREF_WIFI_ENABLE_INIT, true);
+ preferences.putInt(PREF_WIFI_ENABLE, enable_webserver);
+ }
+ enable_webserver = preferences.getInt(PREF_WIFI_ENABLE);
+ if (!preferences.getBool(PREF_TNCSERVER_ENABLE_INIT)){
+ preferences.putBool(PREF_TNCSERVER_ENABLE_INIT, true);
+ preferences.putBool(PREF_TNCSERVER_ENABLE, tncServer_enabled);
+ }
+ tncServer_enabled = preferences.getBool(PREF_TNCSERVER_ENABLE);
+
+ if (!preferences.getBool(PREF_GPSSERVER_ENABLE_INIT)){
+ preferences.putBool(PREF_GPSSERVER_ENABLE_INIT, true);
+ preferences.putBool(PREF_GPSSERVER_ENABLE, gpsServer_enabled);
+ }
+ gpsServer_enabled = preferences.getBool(PREF_GPSSERVER_ENABLE);
+
+ if (!preferences.getBool(PREF_WIFI_TXPWR_MODE_AP_INIT)){
+ preferences.putBool(PREF_WIFI_TXPWR_MODE_AP_INIT, true);
+ preferences.putInt(PREF_WIFI_TXPWR_MODE_AP, wifi_txpwr_mode_AP);
+ }
+ wifi_txpwr_mode_AP = preferences.getInt(PREF_WIFI_TXPWR_MODE_AP);
+
+ if (!preferences.getBool(PREF_WIFI_TXPWR_MODE_STA_INIT)){
+ preferences.putBool(PREF_WIFI_TXPWR_MODE_STA_INIT, true);
+ preferences.putInt(PREF_WIFI_TXPWR_MODE_STA, wifi_txpwr_mode_STA);
+ }
+ wifi_txpwr_mode_STA = preferences.getInt(PREF_WIFI_TXPWR_MODE_STA);
+#endif
// LoRa transmission settings
@@ -940,13 +1067,13 @@ void setup(){
// APRS station settings
- aprsSymbolTable = preferences.getString(PREF_APRS_SYMBOL_TABLE);
+ aprsSymbolTable = preferences.getString(PREF_APRS_SYMBOL_TABLE, "");
if (aprsSymbolTable.isEmpty()){
preferences.putString(PREF_APRS_SYMBOL_TABLE, APRS_SYMBOL_TABLE);
aprsSymbolTable = preferences.getString(PREF_APRS_SYMBOL_TABLE);
}
- aprsSymbol = preferences.getString(PREF_APRS_SYMBOL);
+ aprsSymbol = preferences.getString(PREF_APRS_SYMBOL, "");
if (aprsSymbol.isEmpty()){
preferences.putString(PREF_APRS_SYMBOL, APRS_SYMBOL);
aprsSymbol = preferences.getString(PREF_APRS_SYMBOL, APRS_SYMBOL);
@@ -956,19 +1083,31 @@ void setup(){
preferences.putBool(PREF_APRS_COMMENT_INIT, true);
preferences.putString(PREF_APRS_COMMENT, MY_COMMENT);
}
- aprsComment = preferences.getString(PREF_APRS_COMMENT);
+ aprsComment = preferences.getString(PREF_APRS_COMMENT, "");
if (!preferences.getBool(PREF_APRS_RELAY_PATH_INIT)){
preferences.putBool(PREF_APRS_RELAY_PATH_INIT, true);
preferences.putString(PREF_APRS_RELAY_PATH, DIGI_PATH);
}
- relay_path = preferences.getString(PREF_APRS_RELAY_PATH);
+ relay_path = preferences.getString(PREF_APRS_RELAY_PATH, "");
if (!preferences.getBool(PREF_APRS_SHOW_ALTITUDE_INIT)){
preferences.putBool(PREF_APRS_SHOW_ALTITUDE_INIT, true);
preferences.putBool(PREF_APRS_SHOW_ALTITUDE, showAltitude);
}
showAltitude = preferences.getBool(PREF_APRS_SHOW_ALTITUDE);
+ if (!preferences.getBool(PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION_INIT)){
+ preferences.putBool(PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION_INIT, true);
+ preferences.putBool(PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION, showAltitudeInsideCompressedPosition);
+ }
+ showAltitudeInsideCompressedPosition = preferences.getBool(PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION);
+ if (!preferences.getBool(PREF_APRS_ALTITUDE_RATIO_INIT)){
+ preferences.putBool(PREF_APRS_ALTITUDE_RATIO_INIT, true);
+ // preferences.putInt(PREF_APRS_ALTITUDE_RATIO, altitude_ratio); // until SHOW_ALTITUDE is obsolete, commented out
+ preferences.putInt(PREF_APRS_ALTITUDE_RATIO, showAltitude ? 100 : 0);
+ }
+ altitude_ratio = preferences.getInt(PREF_APRS_ALTITUDE_RATIO);
+
if (!preferences.getBool(PREF_APRS_GPS_EN_INIT)){
preferences.putBool(PREF_APRS_GPS_EN_INIT, true);
@@ -1023,27 +1162,27 @@ void setup(){
preferences.putBool(PREF_TNC_SELF_TELEMETRY_PATH_INIT, true);
preferences.putString(PREF_TNC_SELF_TELEMETRY_PATH, tel_path);
}
- tel_path = preferences.getString(PREF_TNC_SELF_TELEMETRY_PATH);
+ tel_path = preferences.getString(PREF_TNC_SELF_TELEMETRY_PATH, "");
if (!preferences.getBool(PREF_APRS_LATITUDE_PRESET_INIT)){
preferences.putBool(PREF_APRS_LATITUDE_PRESET_INIT, true);
preferences.putString(PREF_APRS_LATITUDE_PRESET, LATITUDE_PRESET);
}
- aprsLatPreset = preferences.getString(PREF_APRS_LATITUDE_PRESET);
+ aprsLatPreset = preferences.getString(PREF_APRS_LATITUDE_PRESET, "");
LatShownP = aprsLonPreset;
if (!preferences.getBool(PREF_APRS_LONGITUDE_PRESET_INIT)){
preferences.putBool(PREF_APRS_LONGITUDE_PRESET_INIT, true);
preferences.putString(PREF_APRS_LONGITUDE_PRESET, LONGITUDE_PRESET);
}
- aprsLonPreset = preferences.getString(PREF_APRS_LONGITUDE_PRESET);
+ aprsLonPreset = preferences.getString(PREF_APRS_LONGITUDE_PRESET, "");
LongShownP = aprsLonPreset;
if (!preferences.getBool(PREF_APRS_SENDER_BLACKLIST_INIT)){
preferences.putBool(PREF_APRS_SENDER_BLACKLIST_INIT, true);
preferences.putString(PREF_APRS_SENDER_BLACKLIST, "");
}
- { String s = preferences.getString(PREF_APRS_SENDER_BLACKLIST);
+ { String s = preferences.getString(PREF_APRS_SENDER_BLACKLIST, "");
s.toUpperCase(); s.trim(); s.replace(" ", ","); s.replace(",,", ",");
if (!s.isEmpty() && s != "," && s.length() < sizeof(blacklist_calls)-3) {
*blacklist_calls = ',';
@@ -1172,6 +1311,12 @@ void setup(){
}
enabled_oled = preferences.getBool(PREF_DEV_OL_EN);
+ if (!preferences.getBool(PREF_DEV_CPU_FREQ_INIT)){
+ preferences.putBool(PREF_DEV_CPU_FREQ_INIT, true);
+ preferences.putInt(PREF_DEV_CPU_FREQ, adjust_cpuFreq_to);
+ }
+ adjust_cpuFreq_to = preferences.getInt(PREF_DEV_CPU_FREQ);
+
// APRSIS settings
#ifdef ENABLE_WIFI
@@ -1185,7 +1330,7 @@ void setup(){
preferences.putBool(PREF_APRSIS_SERVER_NAME_INIT, true);
preferences.putString(PREF_APRSIS_SERVER_NAME, aprsis_host);
}
- aprsis_host = preferences.getString(PREF_APRSIS_SERVER_NAME);
+ aprsis_host = preferences.getString(PREF_APRSIS_SERVER_NAME, "");
if (!preferences.getBool(PREF_APRSIS_SERVER_PORT_INIT)){
preferences.putBool(PREF_APRSIS_SERVER_PORT_INIT, true);
@@ -1197,19 +1342,19 @@ void setup(){
preferences.putBool(PREF_APRSIS_FILTER_INIT, true);
preferences.putString(PREF_APRSIS_FILTER, aprsis_filter);
}
- aprsis_filter = preferences.getString(PREF_APRSIS_FILTER);
+ aprsis_filter = preferences.getString(PREF_APRSIS_FILTER, "");
if (!preferences.getBool(PREF_APRSIS_CALLSIGN_INIT)){
preferences.putBool(PREF_APRSIS_CALLSIGN_INIT, true);
preferences.putString(PREF_APRSIS_CALLSIGN, aprsis_callsign);
}
- aprsis_callsign = preferences.getString(PREF_APRSIS_CALLSIGN);
+ aprsis_callsign = preferences.getString(PREF_APRSIS_CALLSIGN, "");
if (!preferences.getBool(PREF_APRSIS_PASSWORD_INIT)){
preferences.putBool(PREF_APRSIS_PASSWORD_INIT, true);
preferences.putString(PREF_APRSIS_PASSWORD, aprsis_password);
}
- aprsis_password = preferences.getString(PREF_APRSIS_PASSWORD);
+ aprsis_password = preferences.getString(PREF_APRSIS_PASSWORD, "");
if (!preferences.getBool(PREF_APRSIS_ALLOW_INET_TO_RF_INIT)){
preferences.putBool(PREF_APRSIS_ALLOW_INET_TO_RF_INIT, true);
@@ -1276,14 +1421,18 @@ void setup(){
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
}
axp.setLowTemp(0xFF); //SP6VWX Set low charging temperature
- axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LoRa
+ if (lora_digipeating_mode > 0 || lora_rx_enabled || SerialBT.hasClient())
+ axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LoRa
+ else
+ axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LoRa
if (gps_state){
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // switch on GPS
} else {
axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // switch off GPS
}
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
- axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
+ axp.setPowerOutPut(AXP192_EXTEN, AXP202_OFF);
+ //axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON); // switch this on if you need it
axp.setDCDC1Voltage(3300);
// Enable ADC to measure battery current, USB voltage etc.
axp.adc1Enable(0xfe, true);
@@ -1291,6 +1440,9 @@ void setup(){
axp.setChgLEDMode(AXP20X_LED_OFF);
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // oled do not turn off
#endif
+ // can reduce cpu power consumtion up to 20 %
+ if (adjust_cpuFreq_to > 0)
+ setCpuFrequencyMhz(adjust_cpuFreq_to);
if(!display.begin(SSD1306_SWITCHCAPVCC, SSD1306_ADDRESS)) {
for(;;); // Don't proceed, loop forever
@@ -1319,7 +1471,7 @@ void setup(){
Tcall = prepareCallsign(String(CALLSIGN));
#ifdef ENABLE_PREFERENCES
- Tcall = preferences.getString(PREF_APRS_CALLSIGN);
+ Tcall = preferences.getString(PREF_APRS_CALLSIGN, "");
if (Tcall.isEmpty()){
preferences.putString(PREF_APRS_CALLSIGN, String(CALLSIGN));
Tcall = preferences.getString(PREF_APRS_CALLSIGN);
@@ -1367,14 +1519,33 @@ void setup(){
xTaskCreatePinnedToCore(taskTNC, "taskTNC", 10000, nullptr, 1, nullptr, xPortGetCoreID());
#endif
+
#if defined(KISS_PROTOCOL) && defined(ENABLE_BLUETOOTH)
- if (enable_bluetooth){
+ // LORA32_21: bug in hardware. cannot run bluetooth and wifi concurrently.
+ // We wait for a bt-client connecting, up to 60s. If none connected,
+ // we start the webserver.
+ // TTGO: webserver cunsumes abt 80mA. User may not start the webserver
+ // if bt-client is connected. We'll also wait herefor clients.
+ // If enable_webserver on LORA32_21 is set to 2, user
+ // likes the webserver always to be started -> do not start bluetooth.
+#if defined(ENABLE_WIFI)
+#if defined(LORA32_21)
+ if (enable_bluetooth && enable_webserver < 2) {
+#else
+ if (enable_bluetooth) {
+#endif /* LORA32_21 */
+#else
+ if (enable_bluetooth) {
+#endif /* ENABLE_WIFI */
+
#ifdef BLUETOOTH_PIN
- SerialBT.setPin(BLUETOOTH_PIN);
+ SerialBT.setPin(BLUETOOTH_PIN);
#endif
- SerialBT.begin(String("TTGO LORA APRS ") + Tcall);
- writedisplaytext("LoRa-APRS","","Init:","BT OK!","","");
-#if defined(ENABLE_WIFI) && defined(LORA32_21)
+ SerialBT.begin(String("TTGO LORA APRS ") + Tcall);
+ writedisplaytext("LoRa-APRS","","Init:","BT OK!","","");
+
+#if defined(ENABLE_WIFI)
+ if (enable_webserver == 1 && !aprsis_enabled) {
writedisplaytext("LoRa-APRS","","Init:","Waiting for BT-client","","");
// wait 60s until BT client connects
uint32_t t_end = millis() + 60000;
@@ -1384,30 +1555,41 @@ void setup(){
delay(100);
}
if (!SerialBT.hasClient()) {
+ #if defined(LORA32_21)
writedisplaytext("LoRa-APRS","","Init:","Waiting for BT-client","Disabling BT!","");
SerialBT.end();
+ #endif
} else {
writedisplaytext("LoRa-APRS","","Init:","Waiting for BT-clients","BT-client connected","Will NOT start WiFi!");
}
delay(1500);
-#endif /* ENABLE_WIFI && LORA32_21 */
}
+#endif /* ENABLE_WIFI */
+ }
#endif /* KISS_PROTOCOL && ENABLE_BLUETOOTH */
#ifdef ENABLE_WIFI
-#if defined(LORA32_21) && defined(ENABLE_BLUETOOTH)
- if (!SerialBT.hasClient()) {
-#endif
+ if (enable_webserver) {
+#if defined(KISS_PROTOCOL) && defined(ENABLE_BLUETOOTH)
+ // if enabble_webserver == 2 or (enable_webserver == 1 && (no serial-bt-client is connected OR aprs-is-connecion configuried)
+ if (enable_webserver > 1 || aprsis_enabled || !SerialBT.hasClient()) {
+#else
+ {
+#endif /* KISS_PROTOCOL && ENABLE_BLUETOOTH */
webServerCfg = {.callsign = Tcall};
xTaskCreate(taskWebServer, "taskWebServer", 12000, (void*)(&webServerCfg), 1, nullptr);
+ webserverStarted = true;
writedisplaytext("LoRa-APRS","","Init:","WiFi task started"," =:-) ","");
-#if defined(LORA32_21) && defined(ENABLE_BLUETOOTH)
+#if defined(KISS_PROTOCOL) && defined(ENABLE_BLUETOOTH)
} else {
writedisplaytext("LoRa-APRS","","Init:","WiFi NOT started!"," =:-S ","");
}
+#else
+ }
+#endif /* KISS_PROTOCOL && ENABLE_BLUETOOTH */
delay(1500);
-#endif
#endif /* ENABLE_WIFI */
+ }
writedisplaytext("LoRa-APRS","","Init:","FINISHED OK!"," =:-) ","");
writedisplaytext("","","","","","");
@@ -2094,7 +2276,7 @@ void loop() {
time_delay = millis() + 1500;
if(digitalRead(BUTTON)==HIGH){
if (!tempOled && enabled_oled) {
- enableOled(); // turn ON OLED temporary
+ enableOled(); // turn ON OLED temporary
} else {
if(gps_state == true && gps.location.isValid()){
writedisplaytext("((MAN TX))","","","","","");
@@ -2104,6 +2286,25 @@ void loop() {
sendpacket(1);
}
}
+ // hack: re-enable webserevr, if was set to off.
+#ifdef ENABLE_WIFI
+ if (!webserverStarted) {
+ enable_webserver = 1;
+#ifdef ENABLE_PREFERENCES
+ preferences.putInt("PREF_WIFI_ENABLED", enable_webserver);
+#endif
+#if defined(LORA32_21) && defined(ENABLE_BLUETOOTH)
+ // lora32_21 hardware bug: btt and wifi are mutual exclusive
+ SerialBT.end();
+ delay(100);
+#endif
+ webServerCfg = {.callsign = Tcall};
+ xTaskCreate(taskWebServer, "taskWebServer", 12000, (void*)(&webServerCfg), 1, nullptr);
+ webserverStarted = true;
+ writedisplaytext("LoRa-APRS","","Init:","WiFi task started"," =:-) ","");
+ delay(1500);
+#endif
+ }
key_up = true;
}
}
diff --git a/src/taskWebServer.cpp b/src/taskWebServer.cpp
index 6c5ca3b..cbcd651 100644
--- a/src/taskWebServer.cpp
+++ b/src/taskWebServer.cpp
@@ -27,6 +27,12 @@ extern String infoApName;
extern String infoApPass;
extern String infoApAddr;
+extern int8_t wifi_txpwr_mode_AP;
+extern int8_t wifi_txpwr_mode_STA;
+
+extern bool tncServer_enabled;
+extern bool gpsServer_enabled;
+
// For APRS-IS connection
extern String to_aprsis_data;
extern boolean aprsis_enabled;
@@ -66,7 +72,6 @@ extern ulong lora_speed_cross_digi;
extern double lora_freq_cross_digi;
extern void loraSend(byte, float, ulong, const String &);
-
WebServer server(80);
#ifdef KISS_PROTOCOL
WiFiServer tncServer(NETWORK_TNC_PORT);
@@ -101,7 +106,7 @@ String jsonEscape(String s){
}
String jsonLineFromPreferenceString(const char *preferenceName, bool last=false){
- return String("\"") + preferenceName + "\":\"" + jsonEscape(preferences.getString(preferenceName)) + (last ? + R"(")" : + R"(",)");
+ return String("\"") + preferenceName + "\":\"" + jsonEscape(preferences.getString(preferenceName, "")) + (last ? + R"(")" : + R"(",)");
}
String jsonLineFromPreferenceBool(const char *preferenceName, bool last=false){
return String("\"") + preferenceName + "\":" + (preferences.getBool(preferenceName) ? "true" : "false") + (last ? + R"()" : + R"(,)");
@@ -157,10 +162,12 @@ void handle_ScanWifi() {
}
void handle_SaveWifiCfg() {
+
if (!server.hasArg(PREF_WIFI_SSID) || !server.hasArg(PREF_WIFI_PASSWORD) || !server.hasArg(PREF_AP_PASSWORD)){
server.send(500, "text/plain", "Invalid request, make sure all fields are set");
}
+ // Mode STA:
if (!server.arg(PREF_WIFI_SSID).length()){
server.send(403, "text/plain", "Empty SSID");
} else {
@@ -178,7 +185,16 @@ void handle_SaveWifiCfg() {
Serial.println("Updated WiFi PASS: " + server.arg(PREF_WIFI_PASSWORD));
}
}
+ if (server.hasArg(PREF_WIFI_TXPWR_MODE_STA)) {
+ // Web chooser min, low, mid, high, max
+ // We'll use "min", "low", "mid", "high", "max" -> 2dBm (1.5mW) -> 8, 11dBm (12mW) -> 44, 15dBm (32mW) -> 60, 18dBm (63mW) ->72, 20dBm (100mW) ->80
+ int8_t choosed = server.arg(PREF_WIFI_TXPWR_MODE_STA).toInt();
+ if (choosed < 0) choosed = 8;
+ else if (choosed > 84) choosed = 84;
+ preferences.putInt(PREF_WIFI_TXPWR_MODE_STA, choosed);
+ }
+ // Mode AP:
if (server.arg(PREF_AP_PASSWORD)!="*" && server.arg(PREF_AP_PASSWORD).length()<8){
server.send(403, "text/plain", "AP Password must be minimum 8 character");
} else {
@@ -188,8 +204,22 @@ void handle_SaveWifiCfg() {
Serial.println("Updated AP PASS: " + server.arg(PREF_AP_PASSWORD));
}
}
+ if (server.hasArg(PREF_WIFI_TXPWR_MODE_AP)) {
+ // Web chooser min, low, mid, high, max
+ // We'll use "min", "low", "mid", "high", "max" -> 2dBm (1.5mW) -> 8, 11dBm (12mW) -> 44, 15dBm (32mW) -> 60, 18dBm (63mW) ->72, 20dBm (100mW) ->80
+ int8_t choosed = server.arg(PREF_WIFI_TXPWR_MODE_AP).toInt();
+ if (choosed < 0) choosed = 8;
+ else if (choosed > 84) choosed = 84;
+ preferences.putInt(PREF_WIFI_TXPWR_MODE_AP, choosed);
+ }
+
+ if (server.hasArg(PREF_WIFI_ENABLE))
+ preferences.putInt(PREF_WIFI_ENABLE, server.arg(PREF_WIFI_ENABLE).toInt());
+
+ preferences.putBool(PREF_TNCSERVER_ENABLE, server.hasArg(PREF_TNCSERVER_ENABLE));
+ preferences.putBool(PREF_GPSSERVER_ENABLE, server.hasArg(PREF_GPSSERVER_ENABLE));
String s = "";
- if (server.arg(PREF_NTP_SERVER).length()) {
+ if (server.hasArg(PREF_NTP_SERVER) && server.arg(PREF_NTP_SERVER).length()) {
s = server.arg(PREF_NTP_SERVER);
s.trim();
}
@@ -232,9 +262,14 @@ void handle_Restore() {
void handle_Cfg() {
String jsonData = "{";
- jsonData += String("\"") + PREF_WIFI_PASSWORD + "\": \"" + jsonEscape((preferences.getString(PREF_WIFI_PASSWORD).isEmpty() ? String("") : "*")) + R"(",)";
- jsonData += String("\"") + PREF_AP_PASSWORD + "\": \"" + jsonEscape((preferences.getString(PREF_AP_PASSWORD).isEmpty() ? String("") : "*")) + R"(",)";
+ jsonData += String("\"") + PREF_WIFI_PASSWORD + "\": \"" + jsonEscape((preferences.getString(PREF_WIFI_PASSWORD, "").isEmpty() ? String("") : "*")) + R"(",)";
+ jsonData += String("\"") + PREF_AP_PASSWORD + "\": \"" + jsonEscape((preferences.getString(PREF_AP_PASSWORD, "").isEmpty() ? String("") : "*")) + R"(",)";
+ jsonData += jsonLineFromPreferenceInt(PREF_WIFI_ENABLE);
jsonData += jsonLineFromPreferenceString(PREF_WIFI_SSID);
+ jsonData += jsonLineFromPreferenceInt(PREF_WIFI_TXPWR_MODE_AP);
+ jsonData += jsonLineFromPreferenceInt(PREF_WIFI_TXPWR_MODE_STA);
+ jsonData += jsonLineFromPreferenceBool(PREF_TNCSERVER_ENABLE);
+ jsonData += jsonLineFromPreferenceBool(PREF_GPSSERVER_ENABLE);
jsonData += jsonLineFromPreferenceString(PREF_NTP_SERVER);
jsonData += jsonLineFromPreferenceDouble(PREF_LORA_FREQ_PRESET);
jsonData += jsonLineFromPreferenceInt(PREF_LORA_SPEED_PRESET);
@@ -270,7 +305,9 @@ void handle_Cfg() {
jsonData += jsonLineFromPreferenceInt(PREF_APRS_SB_TURN_TIME_PRESET);
jsonData += jsonLineFromPreferenceBool(PREF_APRS_SHOW_BATTERY);
jsonData += jsonLineFromPreferenceBool(PREF_APRS_FIXED_BEACON_PRESET);
- jsonData += jsonLineFromPreferenceBool(PREF_APRS_SHOW_ALTITUDE);
+ //jsonData += jsonLineFromPreferenceBool(PREF_APRS_SHOW_ALTITUDE);
+ jsonData += jsonLineFromPreferenceBool(PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION);
+ jsonData += jsonLineFromPreferenceInt(PREF_APRS_ALTITUDE_RATIO);
jsonData += jsonLineFromPreferenceBool(PREF_APRS_GPS_EN);
jsonData += jsonLineFromPreferenceBool(PREF_ACCEPT_OWN_POSITION_REPORTS_VIA_KISS);
jsonData += jsonLineFromPreferenceBool(PREF_GPS_ALLOW_SLEEP_WHILE_KISS);
@@ -287,6 +324,7 @@ void handle_Cfg() {
jsonData += jsonLineFromPreferenceInt(PREF_DEV_AUTO_SHUT_PRESET);
jsonData += jsonLineFromPreferenceInt(PREF_DEV_REBOOT_INTERVAL);
jsonData += jsonLineFromPreferenceInt(PREF_DEV_SHOW_OLED_TIME);
+ jsonData += jsonLineFromPreferenceInt(PREF_DEV_CPU_FREQ);
jsonData += jsonLineFromPreferenceBool(PREF_APRSIS_EN);
jsonData += jsonLineFromPreferenceString(PREF_APRSIS_SERVER_NAME);
jsonData += jsonLineFromPreferenceInt(PREF_APRSIS_SERVER_PORT);
@@ -709,7 +747,11 @@ void handle_SaveAPRSCfg() {
preferences.putBool(PREF_APRS_SHOW_BATTERY, server.hasArg(PREF_APRS_SHOW_BATTERY));
preferences.putBool(PREF_ENABLE_TNC_SELF_TELEMETRY, server.hasArg(PREF_ENABLE_TNC_SELF_TELEMETRY));
- preferences.putBool(PREF_APRS_SHOW_ALTITUDE, server.hasArg(PREF_APRS_SHOW_ALTITUDE));
+ //preferences.putBool(PREF_APRS_SHOW_ALTITUDE, server.hasArg(PREF_APRS_SHOW_ALTITUDE));
+ preferences.putBool(PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION, server.hasArg(PREF_APRS_SHOW_ALTITUDE_INSIDE_COMPRESSED_POSITION));
+ if (server.hasArg(PREF_APRS_ALTITUDE_RATIO)){
+ preferences.putInt(PREF_APRS_ALTITUDE_RATIO, server.arg(PREF_APRS_ALTITUDE_RATIO).toInt());
+ }
preferences.putBool(PREF_APRS_FIXED_BEACON_PRESET, server.hasArg(PREF_APRS_FIXED_BEACON_PRESET));
preferences.putBool(PREF_APRS_GPS_EN, server.hasArg(PREF_APRS_GPS_EN));
preferences.putBool(PREF_ACCEPT_OWN_POSITION_REPORTS_VIA_KISS, server.hasArg(PREF_ACCEPT_OWN_POSITION_REPORTS_VIA_KISS));
@@ -739,6 +781,12 @@ void handle_saveDeviceCfg(){
if (server.hasArg(PREF_DEV_REBOOT_INTERVAL)){
preferences.putInt(PREF_DEV_REBOOT_INTERVAL, server.arg(PREF_DEV_REBOOT_INTERVAL).toInt());
}
+ if (server.hasArg(PREF_DEV_CPU_FREQ)){
+ uint8_t cpufreq = server.arg(PREF_DEV_CPU_FREQ).toInt();
+ if (cpufreq != 0 && cpufreq < 10)
+ cpufreq = 10;
+ preferences.putInt(PREF_DEV_CPU_FREQ, cpufreq);
+ }
server.sendHeader("Location", "/");
server.send(302,"text/html", "");
}
@@ -794,23 +842,25 @@ void handle_saveDeviceCfg(){
});
server.onNotFound(handle_NotFound);
- String wifi_password = preferences.getString(PREF_WIFI_PASSWORD);
- String wifi_ssid = preferences.getString(PREF_WIFI_SSID);
- if (preferences.getString(PREF_AP_PASSWORD).length() > 7) {
- // 8 characters is requirements for WPA2
- apPassword = preferences.getString(PREF_AP_PASSWORD);
- } else {
+ String wifi_password = preferences.getString(PREF_WIFI_PASSWORD, "");
+ String wifi_ssid = preferences.getString(PREF_WIFI_SSID, "");
+ apPassword = preferences.getString(PREF_AP_PASSWORD, "");
+ // 8 characters is requirements for WPA2
+ if (apPassword.length() < 8) {
apPassword = defApPassword;
}
if (!wifi_ssid.length()){
WiFi.softAP(apSSID.c_str(), apPassword.c_str());
+ esp_wifi_set_max_tx_power(wifi_txpwr_mode_AP);
} else {
int retryWifi = 0;
WiFi.begin(wifi_ssid.c_str(), wifi_password.length() ? wifi_password.c_str() : nullptr);
Serial.println("Connecting to " + wifi_ssid);
- // Set power to minimum (max 20)
+ // Set power: minimum 8 (2dBm) (max 80 (20dBm))
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html
- esp_wifi_set_max_tx_power(8);
+ // Mapping Table {Power, max_tx_power} = {{8, 2}, {20, 5}, {28, 7}, {34, 8}, {44, 11}, {52, 13}, {56, 14}, {60, 15}, {66, 16}, {72, 18}, {80, 20}}.
+ // We'll use "min", "low", "mid", "high", "max" -> 2dBm (1.5mW) -> 8, 11dBm (12mW) -> 44, 15dBm (32mW) -> 60, 18dBm (63mW) ->72, 20dBm (100mW) ->80
+ esp_wifi_set_max_tx_power(wifi_txpwr_mode_STA);
while (WiFi.status() != WL_CONNECTED) {
Serial.print("Not connected: ");
Serial.println((int)WiFi.status());
@@ -826,8 +876,7 @@ void handle_saveDeviceCfg(){
Serial.print(apSSID.c_str());
Serial.print(" Password: ");
Serial.println(apPassword.c_str());
- // Set power to minimum (max 20)
- esp_wifi_set_max_tx_power(8);
+ esp_wifi_set_max_tx_power(wifi_txpwr_mode_AP);
break;
}
}
@@ -860,7 +909,7 @@ void handle_saveDeviceCfg(){
syslog.defaultPriority(LOG_KERN);
syslog_log(LOG_INFO, "Connected. IP: " + WiFi.localIP().toString());
#endif
- String ntp_server = preferences.getString(PREF_NTP_SERVER);
+ String ntp_server = preferences.getString(PREF_NTP_SERVER, "");
if (ntp_server.isEmpty()) {
if (infoApAddr.startsWith("44."))
ntp_server = "ntp.hc.r1.ampr.org";
@@ -882,9 +931,11 @@ void handle_saveDeviceCfg(){
server.begin();
#ifdef KISS_PROTOCOL
- tncServer.begin();
+ if (tncServer_enabled)
+ tncServer.begin();
#endif
- gpsServer.begin();
+ if (gpsServer_enabled)
+ gpsServer.begin();
if (MDNS.begin(webServerCfg->callsign.c_str())) {
MDNS.setInstanceName(webServerCfg->callsign + " TTGO LoRa APRS TNC " + TXFREQ + "MHz");
MDNS.addService("http", "tcp", 80);
@@ -935,6 +986,23 @@ void handle_saveDeviceCfg(){
while (true){
esp_task_wdt_reset();
+ // Mode STA and connection lost? -> reconnect
+ if (WiFi.getMode() == 1 && WiFi.status() != WL_CONNECTED) {
+ static uint32_t last_connection_attempt = millis();
+ if (millis() - last_connection_attempt > 20000L) {
+ WiFi.disconnect();
+ esp_task_wdt_reset();
+ WiFi.reconnect();
+ esp_task_wdt_reset();
+ last_connection_attempt = millis();
+ }
+ if (WiFi.status() != WL_CONNECTED) {
+ // 500ms for reconnect should be enough, ant not too often (power consumption).. Or, if we did not try to reconnect, this value is also fine
+ delay(500);
+ continue;
+ }
+ }
+
server.handleClient();
if (xQueueReceive(webListReceivedQueue, &receivedPacketData, (1 / portTICK_PERIOD_MS)) == pdPASS) {
auto *receivedPacketToQueue = new tReceivedPacketData();