Fixes and improvements:

- platform.ini: changed env:xxx-1.0 to xxx-1_0, because latest
  platformio complains about the dot.

- Optional: send beacon as object
  This is recommended if you like an aps icon like L, while using
  your normal ssid like DL9SAU-12
  You can set it in the webinterface, of by compile time in platform.ini
- if you really insist in adding SSID -L4 to your callsign,
  your RF TX will be disabled. You can connect with that call to to aprs-is.

- renamed function name compute_locator() to locator_to_lat_lon(),
  because it's more clear

- GPS accuracy:
  GPS becomes inaccurate if you move very slow or halt.
  These jumps may have a distance of more than 100m.
  If we take hdop and visible satellites into acount, the situation
  improves significant.
  A measured height needs even more sats and better vdop.
  Beacons are also triggered by course change. Speed is not a good
  indicator, because speed is computed by location change. And if
  you jump 200m in between 5s, then you speed is interpreted as 144km/h.
  This leads to wrong assumptions about course change.
  As far as we know, our changes have no impact to the quality of the
  positions and the course change detection for smart-beaconing.
  hdop and sat values for exacter location, course, speed,
  and altitude have been testet by experiment. If you like, you
  may find better values.

After this commit, we'll test extensively. Then it will become
a release dedicated to HAMRADIO 2023 ;)

Signed-off-by: Thomas Osterried <dl9sau@darc.de>
pull/10/head
Thomas Osterried 2023-06-15 20:42:49 +02:00
rodzic a00555f9cc
commit d833835e16
5 zmienionych plików z 195 dodań i 78 usunięć

Wyświetl plik

@ -143,7 +143,7 @@ You like to enable, if you use your tracker portable and it should automatically
</div>
<div>
<label for="lora_tx_en">Enable LoRa transmitter</label>
<input name="lora_tx_en" id="lora_tx_en" type="checkbox" value="1" title="Allow TX on LoRa. Disable this if you like to prevent TX under all circumstances (i.e. if your tracker is behind an rx-amplifier)">
<input name="lora_tx_en" id="lora_tx_en" type="checkbox" value="1" title="Allow TX on LoRa. Disable this if you like to prevent TX under all circumstances (i.e. if your tracker is behind an rx-amplifier). If this checkbox keeps off after trying to enable, you might check if your configured CALLSIGN-SSID is correct (see explanation there).">
</div>
<div>
<label for="lora_rx_en">Enable LoRa receiver</label>
@ -201,7 +201,7 @@ You like to enable, if you use your tracker portable and it should automatically
<div class="grid-container quarters">
<div>
<label for="aprs_callsign">Callsign and SSID *</label>
<input class="u-full-width" type="text" minlength="3" maxlength="9" name="aprs_callsign" placeholder="NOCALL-1" id="aprs_callsign" title="your callsign with SSID">
<input class="u-full-width" type="text" minlength="3" maxlength="9" name="aprs_callsign" placeholder="NOCALL-1" id="aprs_callsign" title="your callsign with SSID. SSID is optional and should be in the range of -1 to -15". SSIDs like "-L4" are ok for aprs-is, but should not be sent on RF; thus LoRa TX will be disabled.">
</div>
<div>
<label for="aprs_relay_path">Relay Path</label>
@ -215,6 +215,10 @@ You like to enable, if you use your tracker portable and it should automatically
<label for="aprs_symbol">Symbol</label>
<input class="u-full-width" type="text" minlength="1" maxlength="1" name="aprs_symbol" id="aprs_symbol" title="select an icon, for example: [ - jogger, Y - jacht, > - car, b - bike">
</div>
<div>
<label for="aprs_objnam">ObjectName (optional)</label>
<input class="u-full-width" type="text" minlength="0" maxlength="9" name="aprs_objnam" id="aprs_objnam" title="This is optional; most users will leave this empty. If you set this to DL1AAA-L4 because like to see your gateway as DL1AAA-L4 on the map (and also like to send on RF), we'll send our position as type APRS Object (instead of a normal aprs position), with the configured Callsign you configured above.">
</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 '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">

Wyświetl plik

@ -68,6 +68,8 @@ static const char *const PREF_APRS_RELAY_PATH = "aprs_relay_path";
static const char *const PREF_APRS_RELAY_PATH_INIT = "aprs_relay_init";
static const char *const PREF_APRS_SYMBOL_TABLE = "aprs_s_table";
static const char *const PREF_APRS_SYMBOL = "aprs_symbol";
static const char *const PREF_APRS_OBJECT_NAME = "aprs_objnam";
static const char *const PREF_APRS_OBJECT_NAME_INIT = "aprs_objnam_i";
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";

Wyświetl plik

@ -42,6 +42,7 @@ build_flags =
-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 'APRS_OBJECT_NAME=""' ; can be set from www interface
-D 'MY_COMMENT="Lora Tracker/iGate"' ; can be set from www interface
-D 'SHOW_ALT' ; can be set from www interface
; -D 'SHOW_BATT' ; can be set from www interface
@ -62,7 +63,7 @@ build_flags =
-D 'TNC_SELF_TELEMETRY_INTERVAL=3600L' ; can be set from www interface (seconds)
-D 'SHOW_OLED_TIME=15000' ; can be set from www interface (OLED Timeout)
[env:ttgo-t-beam-v1.0]
[env:ttgo-t-beam-v1_0]
platform = espressif32 @ 3.5.0
board = ttgo-t-beam
build_flags =
@ -72,7 +73,7 @@ build_flags =
-D ENABLE_SYSLOG
-D ENABLE_BLUETOOTH
[env:ttgo-t-beam-v0.7]
[env:ttgo-t-beam-v0_7]
platform = espressif32 @ 3.5.0
board = ttgo-t-beam
build_flags =
@ -81,7 +82,7 @@ build_flags =
-D ENABLE_SYSLOG
-D T_BEAM_V0_7
[env:ttgo-lora32-v2.1]
[env:ttgo-lora32-v2_1]
platform = espressif32 @ 3.5.0
board = ttgo-lora32-v21
build_flags =
@ -127,7 +128,7 @@ build_flags =
-D ENABLE_SYSLOG
-D HELTEC_V2
[env:ttgo-t-beam-v1.0-development]
[env:ttgo-t-beam-v1_0-development]
platform = espressif32 @ 3.5.0
board = ttgo-t-beam
build_flags =

Wyświetl plik

@ -154,6 +154,11 @@ String Tcall; //your Call Sign for normal position reports
String aprsSymbolTable = APRS_SYMBOL_TABLE;
String aprsSymbol = APRS_SYMBOL;
String relay_path;
#ifdef APRS_OBJECT_NAME
String aprsObjectName = APRS_OBJECT_NAME;
#else
String aprsObjectName = "";
#endif
String aprsComment = MY_COMMENT;
String aprsLatPreset = LATITUDE_PRESET;
String aprsLonPreset = LONGITUDE_PRESET;
@ -166,6 +171,12 @@ String aprsLonPresetNiceNotation;
String aprsLatLonAsMaidenheadGridLocator;
String aprsLatLonDAO = "";
String aprsLatLonPresetCOMP = "";
RawDegrees bestRawLat;
RawDegrees bestRawLng;
double bestDoubleLat;
double bestDoubleLng;
double bestHdop = 99.9;
double debug_bestHdop = 99.9;
boolean no_gps_position_since_boot = true;
int position_ambiguity = 0; // 0: default, compressed. -1: uncompressed. -2: uncompressed, with DAO '!W..!'. -3: uncompressed, with DAO '!w..!'. 1: ambiguity 1/10'. 2: ambiguity 1'. 3: ambiguity 10'. 4: Ambuguity 1 deg (60').
@ -315,7 +326,9 @@ int sb_turn_slope = 26; // kenwood example: 26 in mph. Yaesu suggests 26 in hi
// TS 7 if <= 20km/h, TS 11 if <= 50km/h, TS 26 else.
int sb_turn_time = 30; // min. 30s between transmissions (kenwood example)
float average_speed[5] = {0,0,0,0,0}, average_speed_final=0;
float average_speed[5] = {0,0,0,0,0};
float average_speed_final = 0.0;
float average_speed_final_last = 0.0;
float old_course = 0, new_course = 0;
int point_avg_speed = 0, point_avg_course = 0;
@ -546,12 +559,15 @@ void store_compressed_position(double Tlat, double Tlon) {
void prepareAPRSFrame(uint8_t sp_flags) {
static uint8_t cnt = 0;
double curr_hdop = (gps.hdop.isValid() ? gps.hdop.hdop() : 99.9);
double curr_kmph = (gps.speed.isValid() ? gps.speed.kmph() : 0.0);
int curr_sats = gps.satellites.value();
boolean may_add_dao_extension = (position_ambiguity <= -2 && latlon_precision > 0 && aprsLatLonDAO != "");
boolean time_to_add_alt = false;
// altitude_ratio: 0%, 10%, 25%, 50%, 75%, 90%, 100%
// course change on turn has a heigher priority
boolean altitude_isValid = (gps_state && gps.altitude.isValid() && gps.altitude.age() < 10000);
boolean cseSpd_isValid = (gps_state && gps.speed.isValid() && gps.speed.age() < 10000 && gps.course.isValid() && gps.course.age() < 10000);
boolean altitude_isValid = (gps_state && gps.altitude.isValid() && gps.altitude.age() < 10000L && ((curr_hdop < 1.0 && curr_sats >= 5) || (curr_kmph > 16.0 && curr_sats >= 4)));
boolean cseSpd_isValid = (gps_state && gps.speed.isValid() && (sp_flags & SP_ENFORCE_COURSE || (gps.speed.age() < 10000L && gps.course.isValid() && gps.course.age() < 10000L && ((curr_hdop < 1.5 && curr_sats >= 5) || (curr_kmph > 16.0 && curr_sats >= 4)))));
int Tspeed = (cseSpd_isValid ? gps.speed.knots() : 0);
int Tcourse = (cseSpd_isValid ? gps.course.deg() : -1);
long Talt = (altitude_isValid ? gps.altitude.feet() : 0);
@ -612,16 +628,39 @@ void prepareAPRSFrame(uint8_t sp_flags) {
out_relay_path:
outString += ":";
if (
if (aprsObjectName.isEmpty()) {
if (
#if defined(ENABLE_BLUETOOTH) && defined(KISS_PROTOCOL)
(enable_bluetooth && SerialBT.hasClient()) ||
(enable_bluetooth && SerialBT.hasClient()) ||
#endif
(time_last_own_text_message_via_kiss_received &&
((time_last_own_text_message_via_kiss_received + 24*60*60*1000L) > millis()) )
)
outString += "=";
else
outString += "!";
(time_last_own_text_message_via_kiss_received &&
((time_last_own_text_message_via_kiss_received + 24*60*60*1000L) > millis()) )
)
outString += "=";
else
outString += "!";
} else {
// We can send our position as APRS objects. For those who love to see their tracker as "DL1AAA-L4"
// on the map (which whould not be a valid src-call on RF)
char buf[19]; // room for ";NameLen09*123456z" == 1 + 9 + 1 + 7 + \0 == 19
char buf_time[8]; //room for 123456z + \0 == 8
struct tm timeinfo;
char *p;
// Objects always have a length of 9 and a timestamp
if (getLocalTime(&timeinfo)) {
strftime(buf_time, sizeof(buf_time), "%H%M%Sz", &timeinfo);
} else {
strcpy(buf_time, "000000");
}
snprintf(buf, sizeof(buf), ";%-9.9s*%-7.7s", aprsObjectName.c_str(), buf_time);
buf[sizeof(buf)-1] = 0;
for (p = buf; *p; p++) {
if (!isprint(*p & 0xff))
*p = '_';
}
outString += String(buf);
}
// position_ambiguity is not defined for compressed positions.
// But we test it, in order to see what happens.
@ -2618,6 +2657,7 @@ void load_preferences_cfg_file()
aprsSymbolTable = jsonElementFromPreferenceCFGString(PREF_APRS_SYMBOL_TABLE,0);
aprsSymbol = jsonElementFromPreferenceCFGString(PREF_APRS_SYMBOL,0);
aprsObjectName = jsonElementFromPreferenceCFGString(PREF_APRS_OBJECT_NAME,0);
aprsComment = jsonElementFromPreferenceCFGString(PREF_APRS_COMMENT,PREF_APRS_COMMENT_INIT);
relay_path = jsonElementFromPreferenceCFGString(PREF_APRS_RELAY_PATH,PREF_APRS_RELAY_PATH_INIT);
showAltitude = jsonElementFromPreferenceCFGBool(PREF_APRS_SHOW_ALTITUDE,PREF_APRS_SHOW_ALTITUDE_INIT);
@ -2852,6 +2892,12 @@ void load_preferences_from_flash()
aprsSymbol = preferences.getString(PREF_APRS_SYMBOL, aprsSymbol.length() != 1 ? APRS_SYMBOL : aprsSymbol);
}
if (!preferences.getBool(PREF_APRS_OBJECT_NAME_INIT)){
preferences.putBool(PREF_APRS_OBJECT_NAME_INIT, true);
preferences.putString(PREF_APRS_OBJECT_NAME, aprsObjectName);
}
aprsObjectName = preferences.getString(PREF_APRS_OBJECT_NAME, "");
if (!preferences.getBool(PREF_APRS_COMMENT_INIT)){
preferences.putBool(PREF_APRS_COMMENT_INIT, true);
preferences.putString(PREF_APRS_COMMENT, aprsComment);
@ -4385,7 +4431,7 @@ void handle_usb_serial_input(void) {
Serial.print("cmd:");
inputBuf = "";
return;
}
}
// some commands need an non-binary agument
#ifdef ENABLE_PREFERENCES
if (cmd == "save_preferences_cfg") {
@ -4722,6 +4768,10 @@ void handle_usb_serial_input(void) {
// +---------------------------------------------------------------------+//
void loop()
{
double curr_knots = 0.0;
double curr_kmph = 0.0;
double curr_hdop = 99.9;
int curr_sats = 0;
esp_task_wdt_reset();
@ -4795,51 +4845,81 @@ void loop()
// aprsLatPreset = ggmm.dd[N|S]
boolean gps_isValid_oldState = gps_isValid;
gps_isValid = false;
if (gps_state && gps.hdop.hdop() < 8.0) {
if (gps.speed.isValid() && gps.speed.age() < 10000) {
// refresh speed and hdop
curr_kmph = (gps.speed.isValid() ? gps.speed.kmph() : 0.0);
curr_knots = (gps.speed.isValid() ? gps.speed.knots() : 0.0);
curr_hdop = (gps.hdop.isValid() ? gps.hdop.hdop() : 99.9);
curr_sats = gps.satellites.value();
//if (gps_state && curr_hdop < 8.0) {
if (gps_state && curr_hdop < (curr_kmph > 16.0 ? 8.0 : 4.0)) {
if (gps.speed.isValid() && gps.speed.age() < 10000L) {
if (gps.speed.isUpdated()) {
update_speed_from_gps();
}
} // else: assume we still move with last speed
}
if (gps_state && gps.location.isValid() && (gps.location.age() < 10000 || no_gps_position_since_boot)) {
gps_isValid = true;
if (gps_state && gps.location.isValid()) {
// store best hdop in a speed dependent time range
static uint32_t t_interval_start = millis();
int do_update = 0;
if (gps.location.isUpdated() || no_gps_position_since_boot) {
static uint32_t ratelimit_until = 0L;
// to smoothen the speed, the distance between pos is calculated on gps retrieval. (DL3EL)
//LatShownP = create_lat_aprs("-", gps.location.rawLat());
//LongShownP = create_long_aprs("-", gps.location.rawLng());
// save last valid position as new fixed location
// aprs resolution is 1sm/100 = 1852m/100 = 18.52m
// Updating this every 200ms is enough for getting this resolution at speed of 18.52*3.6*5 = 333.36km/h.
// aprsLatPreset and aprsLonPreset are used for displaying. The transmission uses the true value.
if (millis() > ratelimit_until || no_gps_position_since_boot) {
// always encode aprsLatPreset in notation ddmm.nn (N/S) and aprsLonPreset in notation dddmm.nn (E/W)
//aprsLatPreset = create_lat_aprs("", gps.location.rawLat(), 2);
//aprsLonPreset = create_long_aprs("", gps.location.rawLng(), 2);
if (latlon_precision > 0 && gps.hdop.hdop() < 1.0 && gps.speed.isValid() && gps.speed.age() < 2000 && gps.speed.knots() < 18) {
// DAO: heigher precision 1/1000 arc-minute, if not > 36 knots (valid gps measurered speed). Idea behind:
// 18.52 m/s are 36kn. We need abt 1s time for understanding the whole displayed line -> resolution of > 2 decimal points is not needed
// If we consider gps age of < 2s, we use 18kt as limit
storeLatLonPreset(create_lat_aprs("-", gps.location.rawLat(), (latlon_precision == 2 ? 4 : 3)),
create_long_aprs("-", gps.location.rawLng(), (latlon_precision == 2 ? 4 : 3)),
latlon_precision);
} else {
storeLatLonPreset(create_lat_aprs("-", gps.location.rawLat(), 2), create_long_aprs("-", gps.location.rawLng(), 2), 0);
}
// aprs compressed position has always a high precision (29.17 cm in latitude, 58.34 cm (or less) in longitude)
store_compressed_position(gps.location.lat(), gps.location.lng());
aprsPresetShown = "";
ratelimit_until = millis() + 200;
no_gps_position_since_boot = false;
}
if (gps.location.age() < 10000L) {
gps_isValid = true;
}
if (gps.location.isUpdated()) {
if (curr_hdop < bestHdop) {
// remember location with best hdop in this time range
bestRawLat = gps.location.rawLat();
bestRawLng = gps.location.rawLng();
bestDoubleLat = gps.location.lat();
bestDoubleLng = gps.location.lng();
bestHdop = curr_hdop;
debug_bestHdop = bestHdop;
}
uint32_t t_elapsed = millis() - t_interval_start;
if (curr_hdop < bestHdop && curr_sats >= 4) {
do_update = 1;
} else if (t_elapsed > 15000L && ((curr_hdop < 1.5 && curr_sats >= 5) || no_gps_position_since_boot)) {
// Approach to avoid gps inaccuracy (we observed bad gps positions in a range of 30m, or more):
// Resolution of GPS is +/- 3 to 5m. In 1s at 10m/s (= 36 km/h) we are in 'best' case still
// in behalf the resolution of GPS.
do_update = 1;
} else if (t_elapsed > 400L && gps.speed.isValid() && curr_knots > 20.0 && curr_sats >= 4) {
// aprs resolution is 1sm/100 = 1852m/100 = 18.52m
// Updating this every 200ms would be enough for getting this resolution at speed of 18.52*3.6*5 = 333.36km/h.
do_update = 1;
} else if (millis() >= next_fixed_beacon && curr_sats >= 5 &&
TinyGPSPlus::distanceBetween(bestDoubleLat, bestDoubleLng, gps.location.lat(), gps.location.lng()) > 185.2) {
// This hack tries to avoid position jumps due to inaccurate gps measurement, but it updates if we moved 185.2m in 10min
do_update = 1;
}
if (do_update) {
if (latlon_precision > 0 && bestHdop < 1.0 && gps.speed.age() < 2000 && curr_knots < 18.0) {
// DAO: heigher precision 1/1000 arc-minute, if not > 36 knots (valid gps measurered speed). Idea behind:
// 18.52 m/s are 36kn. We need abt 1s-2s time for understanding the whole displayed line -> resolution of > 2 decimal points is not needed
// If we consider gps age of < 2s, we use 18kt as limit
storeLatLonPreset(create_lat_aprs("-", bestRawLat, (latlon_precision == 2 ? 4 : 3)),
create_long_aprs("-", bestRawLng, (latlon_precision == 2 ? 4 : 3)),
latlon_precision);
} else {
storeLatLonPreset(create_lat_aprs("-", bestRawLat, 2), create_long_aprs("-", bestRawLng, 2), 0);
}
// aprs compressed position has always a high precision (29.17 cm in latitude, 58.34 cm (or less) in longitude)
store_compressed_position(bestDoubleLat, bestDoubleLng);
aprsPresetShown = "";
bestHdop = 99.9;
t_interval_start = millis();
no_gps_position_since_boot = false;
}
}
#ifdef notdef
static uint32_t lastTxdistance_millis = 0;
// code has no function, as currently gps_speed_kmph_oled is not used in getSpeedCourseAlti
@ -4867,13 +4947,19 @@ void loop()
if (!gps_isValid) {
// update to the old values
update_speed_from_gps();
if (gps_state && gps.speed.age() < 2000 && gps.speed.knots() > 4) {
if (gps_state && gps.speed.age() < 2000 && curr_knots > 4.0 && curr_hdop < 1.5) {
// if we stand still, we can keep high precision DAO. Only heigher precision's lat/lon values are comparable (due to rounding at next decimal)
// Background: if we look at the _minutes_, i.e. 42.237N, it's rounded for aprs position to 42.24N.
// DAO !W! or !w! needs the cut-off-string 42.23N for !W7x!.
if (aprsLatPresetDAO != create_lat_aprs("", gps.location.rawLat(), (latlon_precision == 2 ? 4 : 3)) || aprsLonPresetDAO != create_long_aprs("", gps.location.rawLng(), latlon_precision == 2 ? 4 : 3)) {
storeLatLonPreset(create_lat_aprs("-", gps.location.rawLat(), 2), create_long_aprs("-", gps.location.rawLng(), 2), 0);
store_compressed_position(gps.location.lat(), gps.location.lng());
// Do this only on good hdop; with bad hdop, the gps springs in a wide circle.
bestRawLat = gps.location.rawLat();
bestRawLng = gps.location.rawLng();
bestDoubleLat = gps.location.lat();
bestDoubleLng = gps.location.lng();
bestHdop = gps.hdop.hdop();
if (aprsLatPresetDAO != create_lat_aprs("", bestRawLat, (latlon_precision == 2 ? 4 : 3)) || aprsLonPresetDAO != create_long_aprs("", bestRawLng, latlon_precision == 2 ? 4 : 3)) {
storeLatLonPreset(create_lat_aprs("-", bestRawLat, 2), create_long_aprs("-", bestRawLng, 2), 0);
store_compressed_position(bestDoubleLat, bestDoubleLng);
}
}
aprsPresetShown = "p";
@ -5492,16 +5578,21 @@ invalid_packet:
if (!gps_state && (!dont_send_own_position_packets || !lora_tx_enabled))
goto behind_position_tx;
// refresh speed and hdop
curr_kmph = (gps.speed.isValid() ? gps.speed.kmph() : 0.0);
curr_hdop = (gps.hdop.isValid() ? gps.hdop.hdop() : 99.9);
curr_sats = gps.satellites.value();
average_speed[point_avg_speed] = gps.speed.kmph(); // calculate smart beaconing. Even a not-updated old speed is ok here.
average_speed[point_avg_speed] = (((curr_hdop < 1.5 && curr_sats >= 3 && curr_kmph <= 16.0) || (curr_hdop < 4.0 && curr_sats >= 3 && curr_kmph > 16.0)) ? curr_kmph : average_speed[(point_avg_speed-1) % 4]); // calculate smart beaconing. Even a not-updated old speed is ok here.
++point_avg_speed;
if (point_avg_speed>4) {
point_avg_speed=0;
if (point_avg_speed > 4) {
point_avg_speed = 0;
average_speed_final_last = average_speed_final;
}
average_speed_final = (average_speed[0]+average_speed[1]+average_speed[2]+average_speed[3]+average_speed[4])/5;
if (gps.course.isValid() && gps.course.age() < 10000) {
average_course[point_avg_course] = gps.course.deg(); // calculate smart beaconing course
if (gps.course.isValid() && gps.course.age() < 10000L) {
average_course[point_avg_course] = ((curr_kmph > 1.8 && ((curr_hdop < 1.5 && curr_sats >= 3 && curr_kmph <= 16.0) || (curr_hdop < 4.0 && curr_sats >= 3 && curr_kmph > 16.0))) ? gps.course.deg() : average_course[(point_avg_course-1) % ANGLE_AVGS]); // calculate smart beaconing course
++point_avg_course;
if (point_avg_course>(ANGLE_AVGS-1)) {
@ -5550,7 +5641,7 @@ invalid_packet:
}
// No course change (indicator nextTX==1)? Recompute nextTX
if (nextTX > 1 && millis()-lastTX >= sb_min_interval) {
if (nextTX > 2 && millis()-lastTX >= sb_min_interval) {
#ifdef SB_ALGO_KENWOOD
if (average_speed_final < sb_min_speed)
nextTX = sb_max_interval;
@ -5579,7 +5670,7 @@ invalid_packet:
// rate limit to 20s in SF12 CR4/5 aka lora_speed 300; 5s in lora_speed 1200 (SF9 CR4/7). -> 1200/lora_speed*5 seconds == 6000000 / lora_speed ms
// If special case nextTX <= 1: we already enforced rate-limiting (see course computation)
if (!fixed_beacon_enabled && !dont_send_own_position_packets && lora_tx_enabled && (lastTX+nextTX) < millis() && (nextTX <= 1 || (millis()-lastTX) >= (6000000L / lora_speed ))) {
if (!fixed_beacon_enabled && !dont_send_own_position_packets && lora_tx_enabled && (lastTX+nextTX) < millis() && (nextTX <= 2 || (millis()-lastTX) >= (6000000L / lora_speed ))) {
if (gps_isValid) {
enableOled(); // enable OLED
//writedisplaytext(" ((TX))","","LAT: "+LatShownP,"LON: "+LongShownP,"SPD: "+String(gps.speed.kmph(),1)+" CRS: "+String(gps.course.deg(),1),getSatAndBatInfo());

Wyświetl plik

@ -435,6 +435,7 @@ void refill_preferences_as_jsonData()
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_RELAY_PATH);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_SYMBOL_TABLE);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_SYMBOL);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_OBJECT_NAME);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_COMMENT);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_LATITUDE_PRESET);
s = s + "\n " + jsonLineFromPreferenceString(PREF_APRS_LONGITUDE_PRESET);
@ -680,7 +681,7 @@ boolean is_locator(String s) {
}
void compute_locator(String s)
void locator_to_lat_lon(String s)
{
float f_long, f_lat;
const char *p = s.c_str();
@ -765,12 +766,12 @@ void set_lat_long(String s_lat, String s_long) {
if (s_lat.isEmpty())
goto out;
if (is_locator(s_lat)) {
compute_locator(s_lat);
locator_to_lat_lon(s_lat);
return;
}
} else {
if (is_locator(s_long)) {
compute_locator(s_long);
locator_to_lat_lon(s_long);
return;
}
}
@ -918,34 +919,41 @@ void handle_SaveAPRSCfg() {
}
// APRS station settings
if (server.hasArg(PREF_APRS_CALLSIGN) && !server.arg(PREF_APRS_CALLSIGN).isEmpty()){
boolean is_valid = true;
uint8_t is_valid = 2;
const char *p;
const char *q;
String s = server.arg(PREF_APRS_CALLSIGN);
s.toUpperCase();
s.trim();
if (s.endsWith("-0"))
s.replace("-0", "");
p = s.c_str();
for (q = p; *q; q++) {
if (isalnum(*q) || *q == '-')
continue;
is_valid = false;
is_valid = 0;
break;
}
if (is_valid) {
is_valid = false;
is_valid = 0;
q = strchr(p, '-');
if (q) {
if (q > p && q-p <= 6 && strlen(q) > 1 && strlen(q) <= 3) {
q++;
if (q[1]) {
if (q[0] == '1' && q[1] >= '0' && q[1] <= '5') {
is_valid = true;
}
if ((q[0] >= 'A' && q[0] <= 'Z') || (q[1] >= 'A' && q[1] <= 'Z')) {
// non-conformal SSIDs like "-L4" are ok for aprs-is, but should not be sent on RF -> disable TX
is_valid = 1;
} else {
if (q[0] > '0' && q[0] <= '9') {
is_valid = true;
if (q[1]) {
if (q[0] == '1' && q[1] >= '0' && q[1] <= '5') {
is_valid = 2;
}
} else {
if (q[0] > '0' && q[0] <= '9') {
is_valid = 2;
}
}
}
}
@ -956,9 +964,12 @@ void handle_SaveAPRSCfg() {
}
}
if (is_valid) {
if (is_valid > 0) {
preferences.putString(PREF_APRS_CALLSIGN, s);
}
if (is_valid < 2) {
preferences.putBool(PREF_LORA_TX_ENABLE, false);
}
}
if (server.hasArg(PREF_APRS_SYMBOL_TABLE) && !server.arg(PREF_APRS_SYMBOL_TABLE).isEmpty()){
preferences.putString(PREF_APRS_SYMBOL_TABLE, server.arg(PREF_APRS_SYMBOL_TABLE));
@ -976,6 +987,14 @@ void handle_SaveAPRSCfg() {
if (! ( s.indexOf("WIDE1") > s.indexOf("WIDE") || s.indexOf("WIDE-") > -1 || s.startsWith("RFONLY,WIDE") || s.startsWith("NOGATE,WIDE") || s.indexOf("*") > -1 ))
preferences.putString(PREF_APRS_RELAY_PATH, s);
}
if (server.hasArg(PREF_APRS_OBJECT_NAME)){
String s = server.arg(PREF_APRS_OBJECT_NAME);
s.trim();
if (s == preferences.getString(PREF_APRS_CALLSIGN))
preferences.putString(PREF_APRS_OBJECT_NAME, "");
else
preferences.putString(PREF_APRS_OBJECT_NAME, s);
}
if (server.hasArg(PREF_APRS_COMMENT)){
preferences.putString(PREF_APRS_COMMENT, server.arg(PREF_APRS_COMMENT));
}