Major changes. Hard work on this new releae.

Improvements
- Even more intelligent behavior in "Allow failback Mode AP"
- Webserver: Current GPS location can be stored as current lat/lon;
             And fixed a not-so-nice down-rounding from i.e.
             53.2100N to 53.2099N
- Webserver: better input handling for ap password, remoteAP ssid and
  password, syslog and ntp server
- Webserver: fixed typos in tooltip texts, and improved documentation,
  especially for the new features
- Position ambiguity and higher precision
  You can choose now between
    - compressed position (also when fixed position).
    - uncompressed aprs position
    - uncompressed aprs position with higher precision (DAO W and w)
  Improvement for unknown position: encode it according to aprs spec
- OLED: more variants to display lat/lon positions.
  Displayed lat/lon resolution depends on setting and if you move,
  and current gps hdop.
  You can also configure if maidenhead grid locator is shown (always,
  never, in intervals). Locator could be shown as RR99XX, RR99XX99
  or RR99XX99xx - you can choose which variant you like.
- Oled Lines: one-liners now cut at end of display-length;
  except for line2 (if line3-5 are empty).
  Oled display.display() is called only if display is on.
  Improvement for fillDisplayLines3to5 (may be forced)
- Serial output on boot: Warn for unser preference variables only once,
  and set them accordingly
- Digipeating / Gate handling. Don't send 3rd-party packets
  back to aprsis. Digipeat telemetry only do secondary qrg.
- aprs-is:
    - 3rd-party traffic: it's not seldom that igates use
  lowercase calls. Don't tread this as (minor) error anymore.
    - aprs-is: improved filters according to aprsis spec
- digipeating:
  - if we are a WIDE1 (= fill-in) digi and if a packet is in
  lora_TXBUF_for_digipeating and we hear a repeated one with same
  source-address and content, we clear it from queue.
  Improved viscous-delay.

For development (compile time): different debug-verbose levels

Fixes
- aprsLatPreset (etc..) variables are now changed from their temporary
  variable names at once. Reading from preferences, a separate
  variable is filled. This mitigates a smp problem between webserver
  and main threads
- aprsis login messages missed word "vers " placed before the version string
- Small fix for aprsis 3rd party traffic encoding according to the spec.
- Some numbers with decimals are now shown complete (instead of cut'ed
  to two decimals (default of String(floatVariable)).
- fixes for some buffer dimensions; detected two buffer overflow conditions
- Telemetry: assurance that values > 255 are ceiled and not start from 0 again
   (An analoge value must not exceet 255)

This dedicated to the three-country-edge SysOp meeting
in Engen 2023-02-11 ;)
LoRa was one topic..

Signed-off-by: DL3EL <dl3el@darc.de>
Signed-off-by: Thomas Osterried <dl9sau@darc.de>
pull/8/head
Thomas Osterried 2023-02-19 20:36:05 +01:00
rodzic 7600d5bc6e
commit 38387dc189
5 zmienionych plików z 1321 dodań i 389 usunięć

Wyświetl plik

@ -82,14 +82,24 @@
</div>
<div>
<label for="syslog_server">Syslog Server</label>
<input type="text" name="syslog_server" id="syslog_server" placeholder="" title="Syslog Server name or IP Address. Leave empty to switch off. Syslog needs do be compiled in (it's by default now)">
<input type="text" name="syslog_server" id="syslog_server" placeholder="" title="Syslog Server name or IP Address. Leave empty to switch off. If unsure, you may use the broadcast address 255.255.255.255. Syslog needs do be compiled in (it's by default now)">
</div>
</div>
</div>
<div class="grid-container quarters">
<div>
<label for="wifi_failAP">Allow failback to Mode AP</label>
<input name="wifi_failAP" id="wifi_failAP" type="checkbox" value="1" title="Allow failback to mode AP after once connected successfully connected (after boot) to configured remote AP. Disable for igates, where you don't need your tracker to be a hotspot. You like to enable, if you use your tracker portable and it should automatically be wifi client to your home network, and be AP if you are outside.">
<input name="wifi_failAP" id="wifi_failAP" type="checkbox" value="1" title="
If a remoteAP is configured or uptime <3min (grace time for him to be able to reach Webinterface for change config):
If wifi-client is connected:
If wifi_do_fallback_mode is enabled, we'll keep his connection alive.
else: we'll disconnect the wifi-client and search for a remoteAP
else: search for a remoteAP
else:
selfAP will stay on and connections are not interrupted.
Disable this for igates, where you don't need your tracker to be a hotspot; or if your phone (which knows your tracker's AP SSID) should not mis-interprete the tracker as Wifi-Hotspot with Internet-Access.
You like to enable, if you use your tracker portable and it should automatically be wifi client to your home network, and be AP if you are outside, and should not search for a remoteAP.">
</div>
<div>
<label for="tncsrvr_en">Enable TNC-Server</label>
@ -207,11 +217,11 @@
</div>
<div>
<label for="aprs_alt_r">Altitude ratio [%]</label>
<input name="aprs_alt_r" id="aprs_alt_r" type="number" min="0" max="100" title="Altitude ratio every n'th packet.. Use 100 for every packet, 0 for no altitude, or any number in between. Recommended: 10 (altitude every tenth's frame). If you use compression ('Send Course/Speed along with Altitude switched off') for reducing airtime (-> then n% altitude-encoding packets are sent, and 100-n% course/speed-encoded packets), you may choose 50 for ballons, where speed/dir and altitude are of equal interrest; if you choose 10, then 90 % of your transmissions encode speed/direction. Cave: if you set it to 100 and switch next option 'Send Course/Speed along with Altitude' to off, then only altitude packets are sent. If you configure 0, altitude is never sent (-> only compressed speed). If ratio is < 100 and gps altitude is not refreshed, only encoded speed is sent." placeholder="10">
<input name="aprs_alt_r" id="aprs_alt_r" type="number" min="0" max="100" title="Altitude ratio every n'th packet.. Use 100 for every packet, 0 for no altitude, or any number in between. Recommended: 10 (altitude every tenth's frame). If you use compression ('Send Course/Speed along with Altitude switched off') for reducing airtime (-> then n% altitude-encoding packets are sent, and 100-n% course/speed-encoded packets), you may choose 50 for ballons, where speed/dir and altitude are of equal interrest; if you choose 10, then 90 % of your transmissions encode speed/direction. Cave: if you set it to 100 and switch next option 'Always send CSE/SPD and ALT' to off, then only altitude packets are sen; if you switch the next option on, then altitude is always sent and this configured Altitude ratio is ignored. If you configure 0, altitude is never sent (-> only compressed speed). If ratio is < 100 and gps altitude is not refreshed, only encoded speed is sent." placeholder="10">
</div>
<div>
<label for="aprs_CSandA">Send Course/Speed along with Altitude</label>
<input name="aprs_CSandA" id="aprs_CSandA" type="checkbox" value="1" title="If set to on, course/speed and altitude are always sent both in one (larger) packet. If gps signal for course/speed is valid, cse/spd will be encoded in the compressed part and altitude is added as /A=...... in the message-part. If set off, either compressed cse/spd OR compressed altitude packets are sent, according to the 'Altitude ratio' setting.">
<label for="aprs_CSandA">Always send CSE/SPD and ALT</label>
<input name="aprs_CSandA" id="aprs_CSandA" type="checkbox" value="1" title="If set to on, course/speed and altitude are always sent both in one (larger) packet. If gps signal for course/speed is valid, cse/spd will be encoded in the compressed part and altitude is added as /A=...... in the message-part (this actually overwrites altitude ratio = 100 setting in most cases). If set off, either compressed cse/spd OR compressed altitude packets are sent, according to the 'Altitude ratio' setting.">
</div>
<div>
<label for="show_cmt">Show Comment</label>
@ -256,7 +266,7 @@
</div>
<div>
<label for="tnc_tel_mic">Self Telemetry Sequence</label>
<select id="tnc_tel_mic" name="tnc_tel_mic" title="self telemetry sequence type (only 'numeric' sequences and 'time based numeric sequences' are supported by aprs.fi and aprsdirect.de). Sequence overflow: Type 'time based, alphanumeric' uses digits and letters 0-9,A-Z,a-z and has a resolution of 23s in two months; 'numeric timebased' has only digits and has resolotuin of 10min in one week. Type 'Numeric' (except for numeric time based): Caution: sequence number is stored to flash; flash has a limited number of writes before it becomes defect.">
<select id="tnc_tel_mic" name="tnc_tel_mic" title="self telemetry sequence type (only 'numeric' sequences and 'time based numeric sequences' are supported by aprs.fi and aprsdirect.de). Time based secuence needs a proper system time (GPS or NTP); else it fails back to 'MIC'. Sequence overflow: Type 'time based, alphanumeric' uses digits and letters 0-9,A-Z,a-z and has a resolution of 23s in two months; 'numeric timebased' has only digits and has resolotuin of 10min in one week. Type 'Numeric' (except for numeric time based): Caution: sequence number is stored to flash; flash has a limited number of writes before it becomes defect.">
<option value="-2">Time based, numeric encoding</option>
<option value="-1">Time based, alphanumeric encoding</option>
<option value="0">Numeric</option>
@ -265,7 +275,7 @@
</div>
<div>
<label for="tnc_tel_path">Self Telemetry Relay Path</label>
<input class="u-full-width" type="text" minlength="0" name="tnc_tel_path" id="tnc_tel_path" title="APRS path for self telemetry, use the shortest as possible (émpty path is recommended; for aprs-is connection, no path is necessary). Or use WIDE2-1.">
<input class="u-full-width" type="text" minlength="0" name="tnc_tel_path" id="tnc_tel_path" title="APRS path for self telemetry, use the shortest as possible (empty path is recommended; for aprs-is connection, no path is necessary). Or use WIDE2-1. Path is not honored on RF transmission.">
</div>
</div>
<div class="grid-container full">
@ -282,11 +292,43 @@
</div>
<div>
<label for="aprs_lat_p">Latitude</label>
<input class="u-full-width" type="text" minlength="0" name="aprs_lat_p" id="aprs_lat_p" title="latitude for fixed beacon, APRS format for example: 5215.00N. 'dd.nnnnS', '-dd.nnnn', 'dd mm[.nnn]' and 'dd mm ss' and 'dd mm' ss&quot;' and 'dd-mm[.nn]N' are also supported. If position is south, you can prefix '-' instead of writing 'S' behind the coordinate. '-nnS' does not make sense. If you like to add a locator, add it here and leave longitude field blank. If GPS is enabled and a valid position has been received, that one will be used instead of the configured one, until the next system reboot">
<input class="u-full-width" type="text" minlength="0" name="aprs_lat_p" id="aprs_lat_p" title="latitude for fixed beacon, APRS format for example: 5215.00N (this is ddmm.mmN). 'dd.nnnnN', '-dd.nnnn', 'dd mm[.nnn]' and 'dd mm ss' and 'dd mm' ss&quot;' and 'dd-mm[.nn]N' are also supported. If position is south, you can prefix '-' instead of writing 'S' behind the coordinate. '-nnS' does not make sense. If you like to add a locator, add it here and leave longitude field blank. If GPS is enabled and a valid position has been received, that one will be used instead of the configured one, until the next system reboot">
</div>
<div>
<label for="aprs_lon_p">Longitude</label>
<input class="u-full-width" type="text" minlength="0" name="aprs_lon_p" id="aprs_lon_p" title="longtitude for fixed beacon, APRS format for example 02050.59E. 'ddd.nnnnS', '-ddd.nnnn', 'ddd mm[.nnn]' and 'ddd mm ss' and 'ddd mm' ss&quot;' and 'ddd-mm[.nn]E' are also supported. If position is west, you can prefix '-' instead of writing 'W' behind the coordinate. '-nnW' does not make sense.. If you like to add a locator, add it to the latitude field and leave this field blank.">
<input class="u-full-width" type="text" minlength="0" name="aprs_lon_p" id="aprs_lon_p" title="longtitude for fixed beacon, APRS format for example 02050.59Ei (this is ddd.mmE). 'ddd.nnnnE', '-ddd.nnnn', 'ddd mm[.nnn]' and 'ddd mm ss' and 'ddd mm' ss&quot;' and 'ddd-mm[.nn]E' are also supported. If position is west, you can prefix '-' instead of writing 'W' behind the coordinate. '-nnW' does not make sense.. If you like to add a locator, add it to the latitude field and leave this field blank.">
</div>
</div>
<div class="grid-container quarters">
<div>
<label for="aprs_llfgps">Use lat/lon of current GPS position</label>
<input name="aprs_llfgps" id="aprs_llfgps" type="checkbox" value="1" title="Use lat/lon of current GPS position. Overwrites Latitude / Longitude settings above. Requires valid GPS position.">
</div>
</div>
<div class="grid-container full">
<h5 class="u-full-width">Position format and precision / ambiguity</h5>
</div>
<div class="grid-container quarters">
<div>
<label for="pos_amb">Position precision *</label>
<select id="pos_amb" name="pos_amb" title="Position precision / Ambiguity
I. High precision: default is compressed (sends cse/speed or altitude without overhead; position is more acurate than uncompressed position, and needs only 8 bytes for lat/lon (but the price is, that the position is not human readable) and it's resolution is 29.17cm for latitude distances, and up to 58.34cm for longitude. Be aware that course has a resolution of only 4 degrees, and height resolution is non-linear (1.002^cs), and could not be negative.
Uncompressed (APRS default notation) is not very precise: >18.52m (APRS Notation 1234.56N/01234.56E == 12-34.56N 012-34.56E).
Uncompressed can be enhanced with the DAO extension in Text message part: !W..!: 1.852m or !w..!: 20.35cm to 22.39cm. DAO W is better human readable; DAO w is base91-encoded (-> precision loss for the decimals 3+4 by factor 1.10); good for manually positioning your digipeager antenna or fox hunting equipment on the map - but keep in mind that your GPS does not have this great precision anyway.
Uncompressed (with / without DAO): If GPS signal is lost and you was not moving and last coordinates have not changed, DAO variant will still be used if configured.
II: Ambiguiti 1/10' -> >185.2m), 1' -> > 1.852km, 10' -> >18.12km, 1 deg == 60'-> >111.12km. Works for both modes, compressed and uncompressed.
III: Values above are referring to latitude; distance between two latitudes is always equal; distance between two longitudes becomes smaller towards the north / south poles of the earth (at 0 deg, even high values align to 0.0m). At aequator, lat/lon relation is 1:1. At 60 deg N or S it's about factor 2).
Keep in mind: While this is is good for high precision, it's worse for ambiguity.
Compressed positions have a 2 times lesser precision on the longitude, which leads to factor 1:2 at aequator, and an 1:1 ratio at abt. 60 deg N or S); this is comparable how maidenhead grid locators are defined.">
<option value="0">Compressed (default) == >25.17cm</option>
<option value="-1">Uncompressed == >18.52m.</option>
<option value="-2">Uncompressed, with DAO W == >1.852m</option>
<option value="-3">Uncompressed, with DAO w == >20.35cm</option>
<option value="1">Ambiguity 1/10' == 185.2m</option>
<option value="2">Ambiguity 1' == >1.852km</option>
<option value="3">Ambiguity 10' == >18.12km</option>
<option value="4">Ambiguity 1 deg == 60' == >111.12km</option>
</select>
</div>
</div>
<div class="grid-container full">
@ -429,7 +471,7 @@
<div class="grid-container halves">
<div>
<label for="aprsis_en">Enable APRS-IS connection</label>
<input name="aprsis_en" id="aprsis_en" type="checkbox" value="1" title="If we are configured as WIFI client, connet to the APRS-IS net">
<input name="aprsis_en" id="aprsis_en" type="checkbox" value="1" title="If we are configured as WIFI client, connect to the APRS-IS net">
</div>
<div>
<label for="aprsis_srv_h">Server Name</label>
@ -555,12 +597,78 @@
<option value="72">kn, m (nautic)</option>
</select>
</div>
</div>
<div class="grid-container quarters">
<div>
<label for="oledl3l4fmt">OLED Line3 and Line4 Format</label>
<select id="oledl3l4fmt" name="oledl3l4fmt" title="A: (default): Original format, L3: Lat/Lon; L4: speed, course, altitude. Lat/Lon in APRS format. Good for learning how aprs works.
Bx: Left side: L3: course, altitude. L4: speed. Right side: see below:
B1: Lat/Lon in classic format, good for non-technicals. Lat/Lon on right side.
B2: Lat/Lon in nautical notation. Lat/Lon Lat/Lon on right side.
Cx: Right side: L3: speed. L4: course, altitude. Left side: see below:
C1: Lat/Lon in classic format, good for non-technicals. Lat/Lon on left side.
C2: Lat/Lon in nautical notation. Lat/Lon on left side.
About Lat/Lon notations: Acuracy depends on speed, gps signal quality and choosen format; B2 and C2 has room for precision up to 0.1'.
APRS-style is 1234.56N 01234.56E.
Beginners style is 012°34.56'.
Nautical style is 12-34,567N 012-34.567E.
See also the option beneath about showing maidenhead grid locator.">
<option value="0">A: Lat/Lon in APRS-notation</option>
<option value="1">B1: Lat/Lon in classic notation</option>
<option value="2">B2: Lat/Lon in nautical notation</option>
<option value="3">C1: Lat/Lon in classic notation, left side</option>
<option value="4">C1: Lat/Lon in nautical notation, left side</option>
</select>
</div>
<div>
<label for="oledlocator">Maidenhead Locator</label>
<select id="oledlocator" name="oledlocator" title="Show Maidenhead grid locator: always (instead of Lat/Lon), never, alternating. Alternating:
0: Never
1: Always
2: Maidenhead 10s, Lat/Lon 50s
3: Maidenhead 20s, Lat/Lon 100s
4: Maidenhead 20s, Lat/Lon 20s
While showing maidenhead grid locator, free space is left at one side of line3 or line4 (depending on your 'Oled Line3 and Line4 Format' settings), so other values like measurement of temp/humidity/pressure or statistics, etc. may be displayed.">
<option value="0">Off (only Lat/Lon)</option>
<option value="1">On (never Lat/Lon)</option>
<option value="2">Loc 10s, Lat/Lon 50s</option>
<option value="3">Loc 20s, Lat/Lon 100s</option>
<option value="4">Loc 20s, Lat/Lon 20s</option>
</select>
</div>
<div>
<label for="oled_loc_amb">Locator precision</label>
<select id="oled_loc_amb" name="oled_loc_amb" title="Maidenhead grid locator resolution on your display.
The longer the string is, the harder it's to read. That's why we toggle between the length of 10 and the length of 8,
depending on your speed and your configured position precision.
If you prefer the max. displayed length of 6, choose the first entry.
RR99XX (default)
RR99XX99
RR99XX99xx
For RR99XX99xx99, we do not have enough space on the display.
Length of 6 has a precision (for lattitude) with 2.5nm; longitude: 5nm on aequator (and abt 2nm at 60deg N or S).
Background:
RR99 has a range of 18*10 degrees in latitude and 18*10*2 degress in longitude and has a resolution of 1 deg (60min == 60nm == 111.12km ) in lat and 2 deg (120min in lon).
Length of 4 (RR99) would have a resolution 25nm in lat (46.3km). It does not make sense to have this ambiguity being displayed.
RR99XX is 180deg / 24 = 2.5min = 2.5nm (= 4.63km) in lat (and 5min = 5nm (= 9.26km in lon at 0 deg north).
RR99XX99 divides the values above by 10, as you might have expected: 463m in lat, 926m in lon. Good to read, good resolution if you are moving.
RR99XX99xx has a resolution of 0.010416 nm (== 19.3m) in latitude; standard aprs resolution is 0.01nm (18.52m) -> Matches quite good - for latitude.
In longgitude, maidenhead's resolution is 0.02083 nm (385.83m at aequator).
Hard readable lengths / too long for our display:
RR99XX99xx99 has half the resolution than the one above. -> 1.93m in lat. It matches quite good to the Position precision 'uncompressed with DAO (!W..!)' extension (which has a resolutuion of 1.852m in lat and lon).
RR99XX99xx99xx is unreadable and would give us a resolution of 0.000434' (8.043cm) in lat. So precise is no GPS, and your antenna is probably longer than that locator.">
<option value="0">RR99XX (default)</option>
<option value="-1">RR99XX99</option>
<option value="-2">RR99XX99xx</option>
</select>
</div>
</div>
<div class="grid-container halves">
<div>
<label for="UptimeMinutes">Uptime of Device [min]</label>
<input type="text" name="UptimeMinutes" id="UptimeMinutes" readonly title="uptime device in minutes">
</div>
</div>
<div class="grid-container halves">
<div>
<label for="curPos">Current Position</label>
<input type="text" name="curPos" id="curPos" readonly title="Current Position of device [P if fixed mode; p, if gps is invalid and used as temporary preset]">

Wyświetl plik

@ -79,11 +79,13 @@ static const char *const PREF_APRS_ALTITUDE_RATIO_INIT = "aprs_alt_r_i";
static const char *const PREF_APRS_ALWAYS_SEND_CSE_SPEED_AND_ALTITUDE = "aprs_CSandA";
static const char *const PREF_APRS_ALWAYS_SEND_CSE_SPEED_AND_ALTITUDE_INIT = "aprs_CSandA_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";
static const char *const PREF_APRS_LATITUDE_PRESET_INIT = "aprs_lat_p_init";
static const char *const PREF_APRS_LATLON_FROM_GPS = "aprs_llfgps"; // no _INIT needed. Checkbox is evaluated on "save" in the Web interface
static const char *const PREF_APRS_POSITION_AMBIGUITY = "pos_amb";
static const char *const PREF_APRS_POSITION_AMBIGUITY_INIT = "pos_amb_init";
static const char *const PREF_APRS_LONGITUDE_PRESET = "aprs_lon_p";
static const char *const PREF_APRS_LONGITUDE_PRESET_INIT = "aprs_lon_p_init";
static const char *const PREF_APRS_SENDER_BLACKLIST = "aprs_blist";
@ -152,6 +154,12 @@ static const char *const PREF_DEV_CPU_FREQ = "cpufreq";
static const char *const PREF_DEV_CPU_FREQ_INIT = "cpufreq_i";
static const char *const PREF_DEV_UNITS = "units";
static const char *const PREF_DEV_UNITS_INIT = "units_i";
static const char *const PREF_DEV_OLED_L3_L4_FORMAT = "oledl3l4fmt";
static const char *const PREF_DEV_OLED_L3_L4_FORMAT_INIT = "oledl3l4fmt_i";
static const char *const PREF_DEV_OLED_LOCATOR = "oledlocator";
static const char *const PREF_DEV_OLED_LOCATOR_INIT = "locator_i";
static const char *const PREF_DEV_OLED_LOCATOR_AMBIGUITY = "oled_loc_amb";
static const char *const PREF_DEV_OLED_LOCATOR_AMBIGUITY_INIT = "oled_loc_amb_i";
// APRSIS settings

Wyświetl plik

@ -39,7 +39,7 @@ build_flags =
; -D 'FIXED_BEACON_EN' ; can be set from www interface
-D 'SB_ALGO_KENWOOD' ; Kenwood skales better on lower speed.
-D 'LATITUDE_PRESET="0000.00N"' ; can be set from www interface
-D 'LONGITUDE_PRESET="00000.00E"' ; can be set from www interface
-D 'LONGITUDE_PRESET="00000.00W"' ; can be set from www interface
-D 'APRS_SYMBOL_TABLE="/"' ; can be set from www interface. Hint: if you need Symbol "&", you need to escape: "\&"
-D 'APRS_SYMBOL="["' ; can be set from www interface. Hint: if you need Symbol "&", you need to escape: "\&"
-D 'MY_COMMENT="Lora Tracker/iGate"' ; can be set from www interface

Wyświetl plik

@ -6,9 +6,12 @@
#include <time.h>
#include <ArduinoJson.h>
#include <esp_task_wdt.h>
#include "taskGPS.h"
#ifdef ENABLE_WIFI
extern int debug_verbose;
/**
* @see board_build.embed_txtfiles in platformio.ini
*/
@ -52,6 +55,7 @@ String dnsHostname;
extern bool tncServer_enabled;
extern bool gpsServer_enabled;
extern bool gps_state;
extern boolean wifi_do_fallback_to_mode_AP;
@ -76,7 +80,10 @@ extern boolean lora_tx_enabled;
extern String aprsLatPreset;
extern String aprsLonPreset;
extern String aprsLatPresetNiceNotation;
extern String aprsLonPresetNiceNotation;
extern String aprsPresetShown;
extern int oled_line3and4_format;
// last line of display, Sat & Batt Info
extern String OledLine1;
extern String OledLine2;
@ -244,6 +251,7 @@ void handle_ScanWifi() {
}
void handle_SaveWifiCfg() {
String s = "";
#if defined(ENABLE_SYSLOG)
syslog_log(LOG_INFO, String("WebServer: handle_SaveWifiCfg()"));
#endif
@ -258,14 +266,20 @@ void handle_SaveWifiCfg() {
preferences.putString(PREF_WIFI_SSID, server.arg(PREF_WIFI_SSID));
do_serial_println("WiFi: Updated remote SSID: " + server.arg(PREF_WIFI_SSID));
if (server.arg(PREF_WIFI_PASSWORD) != "" && server.arg(PREF_AP_PASSWORD) != "*") {
if (server.arg(PREF_WIFI_PASSWORD).length() < 8 || server.arg(PREF_AP_PASSWORD).length() > 63){
server.send(403, "text/plain", "WiFi Password must be minimum 8 characters, anx max 63.");
s = server.arg(PREF_WIFI_PASSWORD);
if (s.length() == 0 && server.arg(PREF_WIFI_SSID) == "") {
// user has deleted both, WIFI_SSID and WIFI_PASS
preferences.putString(PREF_WIFI_PASSWORD, "");
do_serial_println("WiFi: Deconfigured your remote AP (SSID and password cleared)");
} else if (s != "*") {
if (s.length() < 8 || s.length() > 63) {
preferences.putString(PREF_WIFI_SSID, server.arg(PREF_WIFI_SSID));
server.send(403, "text/plain", "WiFi Password must be minimum 8 characters, and max 63.");
return;
} else {
// Update WiFi password
preferences.putString(PREF_WIFI_PASSWORD, server.arg(PREF_WIFI_PASSWORD));
do_serial_println("WiFi: Updated remote PASS: " + server.arg(PREF_WIFI_PASSWORD));
preferences.putString(PREF_WIFI_PASSWORD, s);
do_serial_println("WiFi: Updated remote PASS: " + s);
}
}
if (server.hasArg(PREF_WIFI_TXPWR_MODE_STA)) {
@ -278,14 +292,21 @@ void handle_SaveWifiCfg() {
}
// Mode AP:
if (server.arg(PREF_AP_PASSWORD) != "" && server.arg(PREF_AP_PASSWORD) != "*") {
if (server.arg(PREF_AP_PASSWORD).length() < 8 || server.arg(PREF_AP_PASSWORD).length() > 63) {
s = server.arg(PREF_AP_PASSWORD);
if (s.length() == 0) {
// user has deleted both, WIFI_SSID and WIFI_PASS. Show ownly once
if (preferences.getString(PREF_AP_PASSWORD) != "") {
preferences.putString(PREF_AP_PASSWORD, "");
do_serial_println("WiFi: your AP password is now factory default: " + wifi_ModeAP_PASS_default);
}
} else if (s != "*") {
if (s.length() < 8 || s.length() > 63) {
server.send(403, "text/plain", "AP Password must be minimum 8 characters, and max 63.");
return;
} else {
// Update AP password
preferences.putString(PREF_AP_PASSWORD, server.arg(PREF_AP_PASSWORD));
do_serial_println("WiFi: Updated local AP PASS: " + server.arg(PREF_AP_PASSWORD));
preferences.putString(PREF_AP_PASSWORD, s);
do_serial_println("WiFi: Updated local AP PASS: " + s);
}
}
preferences.putBool(PREF_WIFI_STA_ALLOW_FAILBACK_TO_MODE_AP_AFTER_ONCE_CONNECTED, server.hasArg(PREF_WIFI_STA_ALLOW_FAILBACK_TO_MODE_AP_AFTER_ONCE_CONNECTED));
@ -303,13 +324,13 @@ void handle_SaveWifiCfg() {
preferences.putBool(PREF_TNCSERVER_ENABLE, server.hasArg(PREF_TNCSERVER_ENABLE));
preferences.putBool(PREF_GPSSERVER_ENABLE, server.hasArg(PREF_GPSSERVER_ENABLE));
String s = "";
if (server.hasArg(PREF_NTP_SERVER) && server.arg(PREF_NTP_SERVER).length()) {
s = "";
if (server.hasArg(PREF_NTP_SERVER)) {
s = server.arg(PREF_NTP_SERVER);
s.trim();
preferences.putString(PREF_NTP_SERVER, s);
}
if (server.hasArg(PREF_SYSLOG_SERVER) && server.arg(PREF_SYSLOG_SERVER).length()) {
if (server.hasArg(PREF_SYSLOG_SERVER)) {
s = server.arg(PREF_SYSLOG_SERVER);
s.trim();
preferences.putString(PREF_SYSLOG_SERVER, s);
@ -417,6 +438,7 @@ void refill_preferences_as_jsonData()
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_COMMENT);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_LATITUDE_PRESET);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_LONGITUDE_PRESET);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_APRS_POSITION_AMBIGUITY);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_SENDER_BLACKLIST);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_APRS_SB_MIN_INTERVAL_PRESET);
@ -451,6 +473,9 @@ void refill_preferences_as_jsonData()
s = s + "\n " + jsonLineFromPreferenceInt(PREF_DEV_SHOW_OLED_TIME);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_DEV_CPU_FREQ);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_DEV_UNITS);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_DEV_OLED_L3_L4_FORMAT);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_DEV_OLED_LOCATOR);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_DEV_OLED_LOCATOR_AMBIGUITY);
s = s + "\n " + jsonLineFromPreferenceBool(PREF_APRSIS_EN);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRSIS_SERVER_NAME);
s = s + "\n " + jsonLineFromPreferenceInt(PREF_APRSIS_SERVER_PORT);
@ -465,12 +490,17 @@ void refill_preferences_as_jsonData()
s = s + "\n " + jsonLineFromInt("FreeSketchSpace", ESP.getFreeSketchSpace());
s = s + "\n " + jsonLineFromInt("PSRAMSize", ESP.getPsramSize());
s = s + "\n " + jsonLineFromInt("PSRAMFree", ESP.getFreePsram());
s_tmp = aprsLatPreset + " " + aprsLonPreset + " [" + (aprsPresetShown == "" ? "GPS" : aprsPresetShown) + "]";
if (oled_line3and4_format == 0) {
s_tmp = aprsLatPreset + " " + aprsLonPreset + " [" + (aprsPresetShown == "" ? "GPS" : aprsPresetShown) + "]";
} else {
s_tmp = aprsLatPresetNiceNotation + " " + aprsLonPresetNiceNotation + " [" + (aprsPresetShown == "" ? "GPS" : aprsPresetShown) + "]";
}
s = s + jsonLineFromString("curPos", s_tmp.c_str());
s = s + "\n " + jsonLineFromInt("UptimeMinutes", millis()/1000/60);
s = s + "\n " + jsonLineFromString("OledLine1", OledLine1.c_str());
s = s + "\n " + jsonLineFromString("OledLine2", OledLine2.c_str());
s = s + "\n " + jsonLineFromString("OledLine3", OledLine3.c_str());
s_tmp = String(OledLine3); s_tmp.replace("\xF7", "°");
s = s + "\n " + jsonLineFromString("OledLine3", s_tmp.c_str());
s_tmp = String(OledLine4); s_tmp.replace("\xF7", "°");
s = s + "\n " + jsonLineFromString("OledLine4", s_tmp.c_str());
s = s + "\n " + jsonLineFromString("OledLine5", OledLine5.c_str(), true);
@ -622,7 +652,8 @@ void store_lat_long(float f_lat, float f_long) {
sprintf(buf, "%3.3d-%07.4f%c", i_deg, f_min, f_long < 0 ? 'W' : 'E');
preferences.putString(PREF_APRS_LONGITUDE_PRESET, String(buf));
#if defined(ENABLE_SYSLOG)
syslog_log(LOG_DEBUG, String("FlashWrite preferences: store_lat_long()"));
if (debug_verbose)
syslog_log(LOG_DEBUG, String("FlashWrite preferences: store_lat_long()"));
#endif
}
@ -722,7 +753,7 @@ void set_lat_long(String s_lat, String s_long) {
float f_lat = 0.0f;
float f_long = 0.0f;
int curr_long = 0;
int curr_deg = 0;
// If notation min ' sec "" is used, then sec has to follow min
if (s_lat.indexOf("\"") > -1 && (s_lat.indexOf("\"") == -1 || s_lat.indexOf("\"") < s_lat.indexOf("'"))) goto out;
@ -745,10 +776,10 @@ void set_lat_long(String s_lat, String s_long) {
}
char buf[64];
for (curr_long = 0; curr_long < 2; curr_long++) {
for (curr_deg = 0; curr_deg < 2; curr_deg++) {
float f_degree = 0.0f;
boolean is_negative = false;
strncpy(buf, (curr_long == 0) ? s_lat.c_str() : s_long.c_str(), sizeof(buf)-1);
strncpy(buf, (curr_deg == 0) ? s_lat.c_str() : s_long.c_str(), sizeof(buf)-1);
buf[sizeof(buf)-1] = 0;
char *p = buf;
char c = p[strlen(p)-1];
@ -760,7 +791,7 @@ void set_lat_long(String s_lat, String s_long) {
p = p+1;
while (*p && *p == ' ') p++;
}
} else if ((curr_long == 0 && (c == 'N' || c == 'S')) || (curr_long == 1 && (c == 'E' || c == 'W'))) {
} else if ((curr_deg == 0 && (c == 'N' || c == 'S')) || (curr_deg == 1 && (c == 'E' || c == 'W'))) {
if (c == 'S' || c == 'W')
is_negative = 1;
buf[strlen(buf)-1] = 0;
@ -807,10 +838,10 @@ void set_lat_long(String s_lat, String s_long) {
f_degree = f_minute / 60.0;
} else {
// dd.nnnn, or aprs notation ddmm.nn (latt) / dddmm.nn (long)
if (strlen(p) == (curr_long ? 8 : 7)) {
q = p + (curr_long ? 3 : 2);
if (strlen(p) == (curr_deg ? 8 : 7)) {
q = p + (curr_deg ? 3 : 2);
if (q[2] == '.') {
// atof of mm.nn. dd part comes later
// atof of mm.nn; dd part comes further down
f_degree = atof(q) / 60.0;
if (f_degree >= 1.0)
goto out;
@ -819,13 +850,18 @@ void set_lat_long(String s_lat, String s_long) {
}
}
}
f_degree = atof(p) + f_degree;
f_degree = atof(p) + f_degree + 0.0000001;
if (curr_deg == 0) {
if (f_degree > 89.99999) f_degree = 89.99999;
} else {
if (f_degree > 179.99999) f_degree = 179.99999;
}
if (f_degree < 0 || f_degree > (curr_long == 1 ? 180 : 90))
if (f_degree < 0 || f_degree > (curr_deg == 1 ? 180 : 90))
goto out;
if (is_negative) f_degree *= -1;
if (curr_long == 0)
if (curr_deg == 0)
f_lat = f_degree;
else
f_long = f_degree;
@ -943,7 +979,12 @@ void handle_SaveAPRSCfg() {
if (server.hasArg(PREF_APRS_COMMENT)){
preferences.putString(PREF_APRS_COMMENT, server.arg(PREF_APRS_COMMENT));
}
set_lat_long(server.hasArg(PREF_APRS_LATITUDE_PRESET) ? server.arg(PREF_APRS_LATITUDE_PRESET) : String(""), server.hasArg(PREF_APRS_LONGITUDE_PRESET) ? server.arg(PREF_APRS_LONGITUDE_PRESET) : String(""));
if (server.hasArg(PREF_APRS_LATLON_FROM_GPS) && gps_state && gps.location.isValid() && gps.location.age() < 10000) {
// String conversion precison: 6 decimals. 5 shoud be enough, the six's is for good rounding
set_lat_long(String(gps.location.lat(), 6), String(gps.location.lng(), 6));
} else {
set_lat_long(server.hasArg(PREF_APRS_LATITUDE_PRESET) ? server.arg(PREF_APRS_LATITUDE_PRESET) : String(""), server.hasArg(PREF_APRS_LONGITUDE_PRESET) ? server.arg(PREF_APRS_LONGITUDE_PRESET) : String(""));
}
//if (server.hasArg(PREF_APRS_LATITUDE_PRESET)){
////preferences.putString(PREF_APRS_LATITUDE_PRESET, server.arg(PREF_APRS_LATITUDE_PRESET));
//String s_lat = latORlon(server.arg(PREF_APRS_LATITUDE_PRESET), 0);
@ -956,6 +997,9 @@ void handle_SaveAPRSCfg() {
//if (s_lon.length() == 9)
//preferences.putString(PREF_APRS_LONGITUDE_PRESET, s_lon);
//}
if (server.hasArg(PREF_APRS_POSITION_AMBIGUITY)) {
preferences.putInt(PREF_APRS_POSITION_AMBIGUITY, server.arg(PREF_APRS_POSITION_AMBIGUITY).toInt());
}
if (server.hasArg(PREF_APRS_SENDER_BLACKLIST)){
String s = server.arg(PREF_APRS_SENDER_BLACKLIST);
s.toUpperCase(); s.trim(); s.replace(" ", ","); s.replace(",,", ",");
@ -1091,6 +1135,15 @@ void handle_saveDeviceCfg(){
if (server.hasArg(PREF_DEV_UNITS)){
preferences.putInt(PREF_DEV_UNITS, server.arg(PREF_DEV_UNITS).toInt());
}
if (server.hasArg(PREF_DEV_OLED_L3_L4_FORMAT)){
preferences.putInt(PREF_DEV_OLED_L3_L4_FORMAT, server.arg(PREF_DEV_OLED_L3_L4_FORMAT).toInt());
}
if (server.hasArg(PREF_DEV_OLED_LOCATOR)){
preferences.putInt(PREF_DEV_OLED_LOCATOR, server.arg(PREF_DEV_OLED_LOCATOR).toInt());
}
if (server.hasArg(PREF_DEV_OLED_LOCATOR_AMBIGUITY)){
preferences.putInt(PREF_DEV_OLED_LOCATOR_AMBIGUITY, server.arg(PREF_DEV_OLED_LOCATOR_AMBIGUITY).toInt());
}
// runtime reconfiguration with changed settings
load_preferences_from_flash();
@ -1125,15 +1178,15 @@ boolean restart_STA(String use_ssid, String use_password) {
while (WiFi.status() != WL_CONNECTED) {
esp_task_wdt_reset();
if (retryWifi > 30) {
do_serial_println(String("WiFi: Status " + String(int(WiFi.status())) + ". Try " + retryWifi + ". Giving up."));
do_serial_println(String("WiFi: Status " + String((int ) WiFi.status()) + ". Try " + retryWifi + ". Giving up."));
return false;
}
do_serial_println(String("WiFi: Status " + String(int(WiFi.status())) + ". Try " + retryWifi));
do_serial_println(String("WiFi: Status " + String((int ) WiFi.status()) + ". Try " + retryWifi));
retryWifi += 1;
vTaskDelay(500/portTICK_PERIOD_MS);
}
// WL_CONNECTED = Status 3
do_serial_println(String("WiFi: Status " + String(int(WiFi.status())) + ". Try " + retryWifi + ". Connected."));
do_serial_println(String("WiFi: Status " + String((int ) WiFi.status()) + ". Try " + retryWifi + ". Connected."));
esp_task_wdt_reset();
return true;;
}
@ -1160,24 +1213,29 @@ void restart_AP_or_STA(void) {
start_soft_ap = false;
for (pos = 0; pos < apcnt; pos++) {
do_serial_println("Wifi: Trying AP " + String(pos) + "/" + String(apcnt) + ": SSID " + APs[pos].ssid);
wifi_connection_status = WIFI_SEARCHING_FOR_AP;
successfully_associated = restart_STA(String(APs[pos].ssid), String(APs[pos].pw));
if (successfully_associated) {
used_wifi_ModeSTA_SSID = String(APs[pos].ssid);
used_wifi_ModeSTA_PASS = String(APs[pos].pw);
static uint32_t last_write = 0L;
boolean changed = false;
// store last successfull association into flash (preferences); ratelimit writing to flash
if (!last_write || millis() > last_write + 5*60*1000L) {
if (used_wifi_ModeSTA_PASS != preferences.getString(PREF_WIFI_PASSWORD, "")) {
preferences.putString(PREF_WIFI_PASSWORD, used_wifi_ModeSTA_PASS);
changed = true;
last_write = millis();
}
if (used_wifi_ModeSTA_SSID != preferences.getString(PREF_WIFI_SSID, "")) {
preferences.putString(PREF_WIFI_SSID, used_wifi_ModeSTA_SSID);
changed = true;
last_write = millis();
}
#if defined(ENABLE_SYSLOG)
syslog_log(LOG_DEBUG, String("FlashWrite preferences: restart_AP_or_STA()"));
if (changed && debug_verbose)
syslog_log(LOG_DEBUG, String("FlashWrite preferences: restart_AP_or_STA()"));
#endif
}
if (pos) {
@ -1191,16 +1249,23 @@ void restart_AP_or_STA(void) {
}
}
if (!successfully_associated && (!mode_sta_once_successfully_connected || wifi_do_fallback_to_mode_AP)) {
start_soft_ap = true;
if (!successfully_associated) {
if (wifi_do_fallback_to_mode_AP || (!mode_sta_once_successfully_connected && millis() < +3*60*1000L)) {
start_soft_ap = true;
} else {
// if not fallback to mode ap, we are finished here. wifi_connection_status is still WIFI_SEARCHING_FOR_AP
return;
}
}
} else {
// may start soft AP, if not already running as AP
if (WiFi.getMode() == WIFI_MODE_STA) {
start_soft_ap = true;
if (WiFi.getMode() == WIFI_MODE_AP) {
// nothing to do
return;
}
start_soft_ap = true;
}
@ -1257,7 +1322,7 @@ void restart_AP_or_STA(void) {
esp_wifi_set_max_tx_power(8);
}
} else {
log_msg="WiFi: Unexpected Mode: " + WiFi.getMode();
log_msg=String("WiFi: Unexpected Mode: ") + String(WiFi.getMode());
#ifdef ENABLE_SYSLOG
syslog_log(LOG_INFO, log_msg);
#endif
@ -1275,6 +1340,7 @@ void restart_AP_or_STA(void) {
ntp_server = "ntp.hc.r1.ampr.org";
else
ntp_server = "pool.ntp.org";
preferences.putString(PREF_NTP_SERVER, ntp_server);
}
configTime(0, 0, ntp_server.c_str());
#ifdef ENABLE_SYSLOG
@ -1372,7 +1438,7 @@ void do_send_status_message_about_connect_to_aprsis(void) {
else {
outString = outString + ", Booted[B" + buildnr;
if (millis() > 60*1000)
outString = outString + ",up:" + String(int(millis()/1000/60));
outString = outString + ",up:" + String((int ) (millis()/1000/60));
outString = outString + "]";
}
@ -1444,8 +1510,11 @@ int connect_to_aprsis(void) {
aprsis_status = "Login";
char buffer[1024];
sprintf(buffer, "user %s pass %s TTGO-T-Beam-LoRa-APRS 0.1%s%s\r\n", aprsis_callsign.c_str(), aprsis_password.c_str(), aprsis_filter.isEmpty() ? "" : " filter ", aprsis_filter.isEmpty() ? "" : aprsis_filter.c_str());
aprsis_client.print(String(buffer));
sprintf(buffer, "user %.9s pass %.5s vers TTGO-T-Beam-LoRa-APRS-MDD-SAU-EL 2023-02-19",
aprsis_callsign.c_str(), aprsis_password.c_str());
if (!aprsis_filter.isEmpty())
sprintf(buffer+strlen(buffer), " filter %.900s", aprsis_filter.c_str());
aprsis_client.print(String(buffer) + "\r\n");
t_start = millis();
while (!aprsis_client.available() && (millis()-t_start) < 25000L) { delay(100); esp_task_wdt_reset(); }
@ -1483,39 +1552,38 @@ String generate_third_party_packet(String callsign, String packet_in) {
char *p = strchr(s, '>');
char *q = strchr(s, ',');
char *r = strchr(s, ':');
char buf[20]; // room for max (due to spec) 'DL9SAU-15>APRSXX-NN' + \0
char buf[82]; // room for max (due to spec) 'DL9SAU-15>APRSXX-NN' + \0. No, we use buf also for digi path
// -> room for len("DL9SAU-12,") == 10, * up-to 8 digipeater, plus '*' plus \0. 10*8+1+1 = 82
if (p && q && r && p > s && p-s < 10 && p < q && q < r && (q-s) < sizeof(buf)) {
strncpy(buf, s, q-s);
buf[(q-s)] = 0;
packet_out = callsign + ">" + MY_APRS_DEST_IDENTIFYER + ":}" + buf + ",TCPIP,";
packet_out = callsign + ">" + MY_APRS_DEST_IDENTIFYER + ":}" + buf;
// ^ 3rd party traffic should be addressed directly (-> not to WIDE2-1 or so)
buf[0] = 0;
if ((q = strstr(q+1, ",q")) && q < r) {
if ((q = strchr(q+1, ',')) && q < r) {
q++;
// search for receiving igate: i.e. path...,qAR,DB0AAA:
// please note, that AE5PL>APRS,WIDE1*,qAI,AE5PL-10,AE5PL-JS:payload may also occur
char *t = strchr(q, ',');
if (!t || t > r)
t = r;
if (t-q < sizeof(buf)) {
strncpy(buf, q, t-q);
buf[t-q] = 0;
}
}
// Copy repeater ",DIGI1,DIGI2*,..". Buf size is 82 (incl. \0). Copy header (excl. ':'), without leading ''
// Skip leading ','
q++;
// snprintf len is incl. \0
snprintf(buf, r-q +1, "%.81s", q);
buf[81] = 0;
// strip q-construct
if (*(q = buf) == 'q' || (q = strstr(buf, ",q"))) {
*q = 0;
}
// no qAR,CALL found?
if (buf[0] == 0 && p-s < 10) {
// add his src callsign
strncpy(buf, s, p-s);
buf[p-s] = 0;
// Strip TCPIP if present. We'll add it. We like to avoid packets like TCPIP,TCPIP*
if ((q = strstr(buf, ",TCPIP")))
*q = 0;
// cut unused digipeaters. Remove '*' from the last-repeated one.
if ((q = strchr(buf, '*'))) {
*q = 0;
} else {
// no digipeater? -> Nothing to add as third-party header
*buf = 0;
}
// should never happen. A really bad packet
if (buf[0] == 0) {
packet_out = "";
return packet_out;
}
packet_out = packet_out + buf + "*" + r;
if (*buf)
packet_out = packet_out + "," + buf;
packet_out = packet_out + ",TCPIP," + callsign + "*" + r;
}
return packet_out;
}
@ -1638,7 +1706,10 @@ void read_from_aprsis(void) {
}
if (!err) {
for (q = s.c_str(); *q && *q != ':'; q++) {
if (! ( (*q >= '0' && *q <= '9') || (*q >= 'A' && *q <= 'Z') || *q == 'q' || *q == '>' || *q == '-' || *q == ',' || *q == '*' ) ) {
// q (for qAR) is also a valid character
//if (! ( (*q >= '0' && *q <= '9') || (*q >= 'A' && *q <= 'Z') || *q == 'q' || *q == '>' || *q == '-' || *q == ',' || *q == '*' ) ) {
//No, unfortunately some aprs-submitters have a lowercase call
if (! ( isalnum(*q) || *q == '>' || *q == '-' || *q == ',' || *q == '*' ) ) {
err = 1;
log_msg = "bad character in header";
break;
@ -1693,6 +1764,10 @@ void read_from_aprsis(void) {
}
}
// Don't gate, if packet has word TCPXX, NOGATE or RFONLY in header (TCPIP is allowed). See aprs-is iGateDetails spec
if ((q = strstr(s.c_str(), ",TCPIP")) || (q = strstr(s.c_str(), ",NOGATE")) || (q = strstr(s.c_str(), "RFONLY")))
return;
// generate third party packet. Use aprs_callsign (deriving from webServerCfg->callsign), because aprsis_callsign may have a non-aprs (but only aprsis-compatible) ssid like '-L4'
String third_party_packet = generate_third_party_packet(aprs_callsign, s);
if (!third_party_packet.isEmpty()) {
@ -1744,7 +1819,9 @@ void send_to_aprsis()
// Due to http://www.aprs-is.net/IGateDetails.aspx , never gate third-party traffic contining TCPIP or TCPXX
// IGATECALL>APRS,GATEPATH:}FROMCALL>TOCALL,TCPIP,IGATECALL*:original packet data
char *r; char *s;
if (!(q[1] == '}' && (r = strchr(q+2, '>')) && ((s = strstr(r+1, ",TCPIP,")) || (s = strstr(r+1, ",TCPXX,"))) && strstr(s+6, "*:"))) {
if (!(((s = strstr(p+1, ",TCPIP")) || (s = strstr(p+1, ",TCPXX")) || (s = strstr(p+1, ",NOGATE")) || (s = strstr(p+1, ",RFONLY"))) && s < q) &&
q[1] != '?' &&
!(q[1] == '}' && (r = strchr(q+2, '>')) && ((s = strstr(r+1, ",TCPIP,")) || (s = strstr(r+1, ",TCPXX,"))) && strstr(s+6, "*:")) ) {
char buf[256];
int len = (q-data.c_str());
if (len > 0 && len < sizeof(buf)) {
@ -1861,10 +1938,12 @@ void send_to_aprsis()
syslog_server=String(SYSLOG_IP);
#endif
// syslog server configured?
if (syslog_server.length())
if (syslog_server.length()) {
syslog.server(syslog_server.c_str(), 514);
else
} else {
syslog.server(NULL, 0);
preferences.putString(PREF_SYSLOG_SERVER, "");
}
syslog.deviceHostname(webServerCfg->callsign.c_str());
syslog.appName("TTGO");
//syslog.defaultPriority(LOG_KERN);
@ -1875,7 +1954,7 @@ void send_to_aprsis()
restart_AP_or_STA();
if (MDNS.begin(webServerCfg->callsign.c_str())) {
MDNS.setInstanceName(webServerCfg->callsign + " TTGO LoRa APRS TNC " + TXFREQ + "MHz");
MDNS.setInstanceName(webServerCfg->callsign + " TTGO LoRa APRS TNC " + String(TXFREQ, 4) + "MHz");
MDNS.addService("http", "tcp", 80);
#ifdef KISS_PROTOCOL
MDNS.addService("kiss-tnc", "tcp", NETWORK_TNC_PORT);
@ -1921,24 +2000,36 @@ void send_to_aprsis()
while (true) {
esp_task_wdt_reset();
// Mode STA and connection lost? -> reconnect. Or when dhcp renew failed?
if (WiFi.getMode() == WIFI_MODE_STA) {
if (WiFi.status() != WL_CONNECTED || WiFi.localIP() == IP_NULL || WiFi.subnetMask() == IP_SUBNET_NULL || WiFi.gatewayIP() == IP_GATEWAY_NULL) {
static uint32_t last_connection_attempt = millis();
if (aprsis_client.connected()) aprsis_client.stop();
if (millis() - last_connection_attempt > 20000L) {
esp_task_wdt_reset();
restart_AP_or_STA();
webserver_started = millis();
esp_task_wdt_reset();
last_connection_attempt = millis();
}
}
} else {
// If we are in self-AP-mode and remote APs are configured (but not had been reachable),
if (apcnt && millis() - webserver_started > 60*1000L &&
(millis() > 3*60*1000L && (!wifi_do_fallback_to_mode_AP || WiFi.getMode() != WIFI_MODE_AP || WiFi.softAPgetStationNum() < 1) ) ) {
// If a remote AP is configured and we are in self-AP-mode,
// try to give up self AP mode and try to reconnect an remote AP again. But only do this,
// if no user is currently associated with our self-AP.
if (apcnt && millis() - webserver_started > 60*1000L && WiFi.softAPgetStationNum() < 1) {
// uptime is >3min AND if wifi_do_fallback_to_mode_AP is not allowed AND
// we are either in WIFI_MODE_STA OR: in MODE_AP user is currently associated with our self-AP
// -> If a remoteAP is configured or uptime <3min (grace time for him to be able to reach Webinterface for change config):
// If wifi-client is connected:
// If wifi_do_fallback_mode is enabled, we'll keep his connection alive.
// else: we'll disconnect the wifi-client and search for a remoteAP
// else: search for a remoteAP
// else:
// selfAP will stay on and connections are not interrupted.
// wifi_do_fallback_to_mode_AP: false: Disable this for igates, where you don't need your tracker to be a hotspot; or if your phone (which knows your tracker's AP SSID) should not mis-interpre te the tracker as Wifi-Hotspot with Internet-Access.
// true: You like to enable, if you use your tracker portable and it should automatically be wifi client to your home network, and be AP if you are outside, and should not search for a remoteAP
// Mode STA and connection lost? -> reconnect. Or when dhcp renew failed?
if (WiFi.getMode() == WIFI_MODE_STA) {
if (WiFi.status() != WL_CONNECTED || WiFi.localIP() == IP_NULL || WiFi.subnetMask() == IP_SUBNET_NULL || WiFi.gatewayIP() == IP_GATEWAY_NULL) {
static uint32_t last_connection_attempt = millis();
if (aprsis_client.connected()) aprsis_client.stop();
if (millis() - last_connection_attempt > 20000L) {
esp_task_wdt_reset();
restart_AP_or_STA();
webserver_started = millis();
esp_task_wdt_reset();
last_connection_attempt = millis();
}
}
} else {
if (aprsis_client.connected()) aprsis_client.stop();
restart_AP_or_STA();
webserver_started = millis();
@ -1992,8 +2083,7 @@ void send_to_aprsis()
aprsis_client.stop();
// Known problems which usually resolve by reboot:
if (ret == -5 /* login denied, until reboot. Reason unknown */ ||
(ret == -1 /* sometimes after boot it can't connect. DNS- or IP-stack Problem? */ &&
(/* lora_rx_enabled || */ lora_digipeating_mode > 1) /* we are a digi */ )) {
(ret == -1 /* sometimes after boot it can't connect. DNS- or IP-stack Problem? */ && lora_digipeating_mode > 1) /* we are a digi */ ) {
// sometimes after boot, connection does not work:
// APRS-IS: connecting to 'aprs.hc.r1.ampr.org', tries 1
@ -2025,13 +2115,15 @@ void send_to_aprsis()
}
}
#if defined(ENABLE_SYSLOG)
syslog_log(LOG_INFO, log_msg);
#endif
do_serial_println(log_msg);
if (log_msg.length()) {
#if defined(ENABLE_SYSLOG)
syslog_log(LOG_INFO, log_msg);
#endif
do_serial_println(log_msg);
}
if (!aprsis_status.startsWith("Error: "))
aprsis_status = "Disconnected";
}
}
}
// session died during read / write?