Compare commits

...
Author SHA1 Message Date
TD-er 1a7f662e66 automatically updated release notes for mega-20201016 2020-10-16 23:26:50 +02:00
TD-erandGitHub 7bf6aa06c7 Merge pull request #3319 from TD-er/bugfix/LoRa_set_SF
LoRaWAN dynamic send interval + syslog fix
2020-10-15 14:20:28 +02:00
TD-er 6aca592049 [LoRa TTN] Fix decoder issue in GPS data
Now with support for Total Distance and distance from reference point.
2020-10-15 03:32:22 +02:00
TD-er 1e02509a80 [GPS] Add distance counter + distance from ref point
Also updated float form fields to allow upto 6 decimals as those were only used for GPS coordinates.
2020-10-15 03:14:20 +02:00
TD-er d0cdf7de42 [Docs] Document LoRaWAN TTN dynamic send interval setting 2020-10-14 22:32:08 +02:00
TD-er c15379887a [Syslog] Fix syslog name does not include unit number (#3288)
Fixes: #3288
2020-10-14 17:28:05 +02:00
TD-erandGitHub 354e8af0c1 Merge pull request #3293 from uwekaditz/UweKaditz
[P092_DLBus] Exception solved
2020-10-13 19:46:39 +02:00
uwekaditzandGitHub aa226174b9 Merge branch 'mega' into UweKaditz 2020-10-13 19:35:22 +02:00
TD-erandGitHub cd26623b2a Merge pull request #3313 from TD-er/bugfix/WiFi_connect_issues
[WiFi] Fix WiFi (re)connect issues caused by new WiFi timers
2020-10-13 17:28:07 +02:00
TD-er 0100d26080 [Timing Stats] Add duty cycle column + LoRa TTN on air timings 2020-10-13 02:08:23 +02:00
TD-er 29abb5dbba [WiFi] Fix WiFi (re)connect issues caused by new WiFi timers
In a quite recent commit, a fix was made for devices connected over 2^31 msec (close to 25 days)
But this also introduced some new issues which could manifest itself if the initial WiFi connect wasn't immediate.

Symptoms:
- Connect to fallback WiFi may take several minutes (sometimes > 10 minutes)
- Connect to hidden AP during setup may not work or take minutes to complete
- Reconnect to AP may fail if the AP wasn't found on initial scan at boot of ESP.
- MQTT may not always reconnect or web page may only react after several minutes if there has been a WiFi reconnect (or just 2nd attempt)
2020-10-12 21:44:06 +02:00
TD-erandGitHub 0e5b73be42 Merge pull request #3303 from TD-er/feature/LoRa_RAWdata_plugins
[LoRaTTN] Add encoder/decoder for unit of measure for AcuDC243
2020-10-12 15:32:09 +02:00
uwekaditz 2571783139 Merge remote-tracking branch 'upstream/mega' into UweKaditz 2020-10-11 21:21:46 +02:00
uwekaditz a664199224 Merge branch 'mega' into UweKaditz 2020-10-11 21:18:33 +02:00
uwekaditz 2b0b11033a Merge branch 'UweKaditz' into mega 2020-10-11 21:17:28 +02:00
TD-erandGitHub 69178038d6 Merge pull request #3310 from tonhuisman/bugfix/check_4th_varname
[Checks] Check all 4 variable names
2020-10-10 21:47:20 +02:00
Ton Huisman b44553c34b [Checks] Check all 4 variable names 2020-10-10 21:41:24 +02:00
TD-er e07f93fce6 [LoRaTTN] Add encoder/decoder for unit of measure for AcuDC243
Since the outputs can be selected, it is important to also know the unit of measure per value.
2020-10-09 12:37:49 +02:00
uwekaditz d6ce926b95 [P092] Exception solved
CHG: Interrupt will be only enabled after network is connected
CHG: usecPassedSince() not longer used in ISR_PinChanged(), caused the exception ???
CHG: in case no DLbus is connected, the next reading attempt happens only after the next PLUGIN_092_READ was called (reduces load and log messages)
2020-10-05 19:44:44 +02:00
uwekaditz 5d27748232 Merge remote-tracking branch 'upstream/mega' into UweKaditz 2020-10-05 15:32:03 +02:00
uwekaditz f141c9dbf1 Merge remote-tracking branch 'upstream/mega' into UweKaditz 2020-09-28 17:05:41 +02:00
uwekaditz a5f4f04f25 Merge remote-tracking branch 'upstream/mega' into UweKaditz 2020-09-20 17:39:52 +02:00
uwekaditz befa29b1b0 Merge remote-tracking branch 'upstream/mega' into UweKaditz 2020-08-30 16:59:26 +02:00
uwekaditz bd9018b01e Merge tag 'mega-20200829' into UweKaditz 2020-08-30 16:59:01 +02:00
uwekaditz 28dc6b3694 Merge remote-tracking branch 'upstream/mega' into UweKaditz 2020-08-24 19:52:37 +02:00
31 changed files with 838 additions and 347 deletions
+22
View File
@@ -1,3 +1,25 @@
-------------------------------------------------
Changes in release mega-20201016 (since mega-20201009)
-------------------------------------------------
Release date: vr 16 okt 2020 23:26:50 CEST
TD-er (7):
[LoRaTTN] Add encoder/decoder for unit of measure for AcuDC243
[WiFi] Fix WiFi (re)connect issues caused by new WiFi timers
[Timing Stats] Add duty cycle column + LoRa TTN on air timings
[Syslog] Fix syslog name does not include unit number (#3288)
[Docs] Document LoRaWAN TTN dynamic send interval setting
[GPS] Add distance counter + distance from ref point
[LoRa TTN] Fix decoder issue in GPS data
Ton Huisman (1):
[Checks] Check all 4 variable names
uwekaditz (1):
[P092] Exception solved
-------------------------------------------------
Changes in release mega-20201009 (since mega-20200929)
-------------------------------------------------
+34
View File
@@ -153,5 +153,39 @@ Decoding Data
Controller Settings
-------------------
Since there are legal limitations on the amount of time you are allowed to send,
it is even more important to understand what effect the Controller Queue parameters may have on the reliability of data transmission.
You are allowed to send only 1% of the time.
Meaning if your message takes 100 msec to send, you can only send a message every 10 seconds.
As a rule of thumb, the time needed to send a message of N bytes doubles for every step up in the Spreading Factor.
For example, a message sent at SF7 may take 100 msec to send.
The same message sent at SF8, will take 200 msec.
At SF9 takes 400 msec, etc. The slowest is SF12.
The RN2483 module does keep track of the used air time, per channel.
Meaning it is possible to send a burst of upto 8 messages (since we have 8 channels) after which we have to wait for a free channel to send out a new one.
As with any other ESPEasy controller, there is a queue mechanism to manage the messages ready to be sent and also allow for a number of retries.
This number of retries is even more important on this LoRaWAN TTN controller.
If sending a message fails due to no free channels, the minimum send interval will be dynamically increased, based on the air time of the message to be sent.
The dynamic adjustment is 10x the expected air time. So by setting the number of retries to 10, it is almost guaranteed the message will eventually be sent.
10 retries with 10x the expected air time equals a maximum of 100x the expected air time, which eventually will be as low as 1% of the time sending.
N.B. This expected air time is dependant on the set Spread Factor and the length of the message.
In practice the messages will be sent in bursts, and thus the extra wait time is often 2 - 3x the expected air time of the message.
So on setups with a large variation in message sizes, it makes sense to send the large ones at the start of a message burst.
Setting the number of retries high (e.g. 10x), may be useful to make sure a sequence of messages in a burst will all get sent.
But it may also lead to a large number of messages to be lost as the queue is full.
So it depends on the use case what will be the best strategy here.
At least the Minimum Send Interval can be kept low (e.g. the default 100 msec) to allow for quickly sending out a burst of upto 8 messages.
@@ -242,6 +242,11 @@ String rn2xx3::peekLastError() const
return _rn2xx3_handler.peekLastError();
}
float rn2xx3::getLoRaAirTime(uint8_t pl) const
{
return _rn2xx3_handler.getLoRaAirTime(pl);
}
String rn2xx3::getLastError()
{
return _rn2xx3_handler.getLastError();
+41
View File
@@ -221,6 +221,42 @@ public:
* This can be overwritten by the network when using OTAA.
* So to force a datarate, call this function after initOTAA().
*/
/*
EU / CN
Frequencies:
EU 863-870 MHz (LoRaWAN Specification (2015), Page 35, Table 14)
CN 779-787 MHz (LoRaWAN Specification (2015), Page 44, Table 25)
EU 433 MHz (LoRaWAN Specification (2015), Page 48, Table 31)
DataRate Modulation SF BW bit/s
0 LoRa 12 125 250
1 LoRa 11 125 440
2 LoRa 10 125 980
3 LoRa 9 125 1'760
4 LoRa 8 125 3'125
5 LoRa 7 125 5'470
6 LoRa 7 250 11'000
7 FSK 50 kbps 50'000
Data rates 8-15 are reserved.
US
Frequencies:
US 902-928 MHz (LoRaWAN Specification (2015), Page 40, Table 18)
DataRate Modulation SF BW bit/s
0 LoRa 10 125 980
1 LoRa 9 125 1'760
2 LoRa 8 125 3'125
3 LoRa 7 125 5'470
4 LoRa 8 500 12'500
8 LoRa 12 500 980
9 LoRa 11 500 1'760
10 LoRa 10 500 3'900
11 LoRa 9 500 7'000
12 LoRa 8 500 12'500
13 LoRa 7 500 21'900
Data rates 5-7 and 14-15 are reserved.
*/
bool setDR(int dr);
/*
@@ -287,6 +323,11 @@ public:
String peekLastError() const;
// Compute the air time for a packet in msec.
// Formula used from https://www.loratools.nl/#/airtime
// @param pl Payload length in bytes
float getLoRaAirTime(uint8_t pl) const;
bool hasJoined() const {
return _rn2xx3_handler.Status.Joined;
}
@@ -441,6 +441,7 @@ bool rn2xx3_handler::setSF(uint8_t sf)
if (dr >= 0)
{
_sf = sf;
_dr = dr;
return setDR(dr);
}
}
@@ -590,10 +591,10 @@ bool rn2xx3_handler::setFrequencyPlan(RN2xx3_datatypes::Freq_plan fp)
default:
{
// set default channels 868.1, 868.3 and 868.5?
returnValue = false; // well we didn't do anything, so yes, false
break;
return false; // well we didn't do anything, so yes, false
}
}
_fp = fp;
return returnValue;
}
@@ -697,6 +698,56 @@ bool rn2xx3_handler::getRxDelayValues(uint32_t& rxdelay1,
return _rxdelay1 != 0 && _rxdelay2 != 0;
}
float rn2xx3_handler::getLoRaAirTime(uint8_t pl) const
{
uint8_t sf = _sf; // Spreading factor 7 - 12
uint16_t bw = 125; // Bandwidth 125 kHz default for LoRaWAN. 250 kHz also supported.
uint8_t cr = 1; // Code Rate 4 / (CR + 4) = 4/5. 4/5 default for LoRaWAN
uint8_t n_preamble = 8; // Preamble length Default for frame = 8, beacon = 10
bool header = true; // Explicit header Default on for LoRaWAN
bool crc = true; // CRC Default on for LoRaWAN
if (sf > 12) {
sf = 12;
} else if (sf < 7) {
sf = 7;
}
if (cr > 4) {
cr = 4;
} else if (cr < 1) {
cr = 1;
}
// Symbols in frame
int payload_length = 8;
{
int beta_offset = 28;
if (crc) { beta_offset += 16; }
if (!header) { beta_offset -= 20; }
float beta_f = 8.0f * pl - 4.0f * sf + beta_offset;
bool lowDataRateOptimization = (bw == 125 && sf >= 11);
if (lowDataRateOptimization) {
beta_f = beta_f / (4.0f * (sf - 2));
} else {
beta_f = beta_f / (4.0f * sf);
}
int beta = static_cast<int>(beta_f + 1.0f); // ceil
if (beta > 0) {
payload_length += (beta * (cr + 4));
}
}
// t_symbol and t_air in msec
float t_symbol = static_cast<float>(1 << sf) / bw;
float t_air = ((n_preamble + 4.25f) + payload_length) * t_symbol;
return t_air;
}
void rn2xx3_handler::set_state(rn2xx3_handler::RN_state state) {
const bool was_processing_cmd = _processing_cmd != Active_cmd::none;
@@ -189,6 +189,12 @@ public:
bool getRxDelayValues(uint32_t& rxdelay1,
uint32_t& rxdelay2);
// Compute the air time for a packet in msec.
// Formula used from https://www.loratools.nl/#/airtime
// @param pl Payload length in bytes
float getLoRaAirTime(uint8_t pl) const;
private:
RN2xx3_datatypes::Model configureModuleType();
@@ -259,6 +265,7 @@ private:
RN2xx3_datatypes::Model _moduleType = RN2xx3_datatypes::Model::RN_NA;
RN2xx3_datatypes::Freq_plan _fp = RN2xx3_datatypes::Freq_plan::TTN_EU;
uint8_t _sf = 7;
uint8_t _dr = 5;
bool _otaa = true; // Switch between OTAA or ABP activation (default OTAA)
bool _asyncMode = false; // When set, the user must call async_loop() frequently
+35 -11
View File
@@ -544,13 +544,9 @@ function Converter(decoded, port) {
case 82:
converted.name = "GPS";
// The GPS plugin must be set first to output like this.
// GPS data is already decoded in packed_decoder.js
// HDOP is needed by TTN mapper to weigh the quality of the data.
// When using TTN mapper, make sure to output these values.
// converted.longitude = converted.val_1;
// converted.latitude = converted.val_2;
// converted.altitude = converted.val_3;
// converted.hdop = converted.val_4;
break;
case 83:
@@ -568,12 +564,16 @@ function Converter(decoded, port) {
case 85:
converted.name = "AcuDC243";
// This plugin can output any value, just using the default settings here.
// TODO TD-er: Must add binary representation of all values
converted.volt = converted.val_1;
converted.current = converted.val_2;
converted.watt = converted.val_3;
converted.wh_total = converted.val_4;
// This plugin can output any value, so show string representation
// of the unit of measure
converted.unit1 = getAcuDC243Unit(converted.unit1);
converted.unit2 = getAcuDC243Unit(converted.unit2);
converted.unit3 = getAcuDC243Unit(converted.unit3);
converted.unit4 = getAcuDC243Unit(converted.unit4);
converted.v1 = converted.val_1;
converted.v2 = converted.val_2;
converted.v3 = converted.val_3;
converted.v4 = converted.val_4;
break;
case 86:
@@ -668,4 +668,28 @@ function Converter(decoded, port) {
}
return converted;
}
function getAcuDC243Unit(unit_id) {
switch (unit_id) {
case 0: // P085_QUERY_V 0
return "V";
case 1: // P085_QUERY_A 1
return "A";
case 2: // P085_QUERY_W 2
return "W";
case 3: // P085_QUERY_Wh_imp 3
return "Wh imp";
case 4: // P085_QUERY_Wh_exp 4
return "Wh exp";
case 5: // P085_QUERY_Wh_tot 5
return "Wh total";
case 6: // P085_QUERY_Wh_net 6
return "Wh net";
case 7: // P085_QUERY_h_tot 7
return "hours tot";
case 8: // P085_QUERY_h_load 8
return "hours load";
}
return "unknown" + unit_id;
}
+16 -2
View File
@@ -21,8 +21,22 @@ function Decoder(bytes, port) {
case 82:
// GPS
return decode(bytes, [header, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8],
['header', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked']);
if (bytes.length === 18) {
return decode(bytes, [header, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8],
['header', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked']);
} else if (bytes.length === 21) {
return decode(bytes, [header, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8, uint24_1e2],
['header', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked', 'distance_total_km']);
} else {
return decode(bytes, [header, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8, uint24_1e2, uint24_1e1],
['header', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked', 'distance_total_km', 'distance_ref']);
}
case 85:
// AcuDC243
return decode(bytes, [header, uint8, int32_1e4, uint8, int32_1e4, uint8, int32_1e4, uint8, int32_1e4],
['header', 'unit1', 'val_1', 'unit2', 'val_2', 'unit3', 'val_3', 'unit4', 'val_4']);
}
+5 -4
View File
@@ -161,17 +161,18 @@ String NetworkGetHostname() {
// ********************************************************************************
// Determine Wifi AP name to set. (also used for mDNS)
// ********************************************************************************
String NetworkGetHostNameFromSettings()
String NetworkGetHostNameFromSettings(bool force_add_unitnr)
{
if (force_add_unitnr) return Settings.getHostname(true);
return Settings.getHostname();
}
String NetworkCreateRFCCompliantHostname() {
return createRFCCompliantHostname(NetworkGetHostNameFromSettings());
String NetworkCreateRFCCompliantHostname(bool force_add_unitnr) {
return createRFCCompliantHostname(NetworkGetHostNameFromSettings(force_add_unitnr));
}
// Create hostname with - instead of spaces
String createRFCCompliantHostname(String oldString) {
String createRFCCompliantHostname(const String& oldString) {
String result(oldString);
result.replace(" ", "-");
+3 -3
View File
@@ -11,10 +11,10 @@ IPAddress NetworkGatewayIP();
IPAddress NetworkDnsIP (uint8_t dns_no);
uint8_t * NetworkMacAddressAsBytes(uint8_t* mac);
String NetworkMacAddress();
String NetworkGetHostNameFromSettings();
String NetworkGetHostNameFromSettings(bool force_add_unitnr = false);
String NetworkGetHostname();
String NetworkCreateRFCCompliantHostname();
String createRFCCompliantHostname(String oldString);
String NetworkCreateRFCCompliantHostname(bool force_add_unitnr = false);
String createRFCCompliantHostname(const String& oldString);
String WifiSoftAPmacAddress();
+2 -4
View File
@@ -71,7 +71,6 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) {
ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier
last_ssid = (const char*) ssid_copy;
lastConnectMoment.setNow();
wifi_considered_stable = false;
processedConnect = false;
break;
}
@@ -82,7 +81,7 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) {
WiFi.persistent(false);
WiFi.disconnect(true);
if (last_wifi_connect_attempt_moment.isSet() && (lastConnectMoment > last_wifi_connect_attempt_moment)) {
if (last_wifi_connect_attempt_moment.isSet() && (!lastConnectMoment.isSet())) {
// There was an unsuccessful connection attempt
lastConnectedDuration_us = last_wifi_connect_attempt_moment.timeDiff(lastDisconnectMoment);
} else {
@@ -169,7 +168,6 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) {
void onConnected(const WiFiEventStationModeConnected& event) {
lastConnectMoment.setNow();
wifi_considered_stable = false;
processedConnect = false;
channel_changed = RTC.lastWiFiChannel != event.channel;
RTC.lastWiFiChannel = event.channel;
@@ -187,7 +185,7 @@ void onConnected(const WiFiEventStationModeConnected& event) {
void onDisconnect(const WiFiEventStationModeDisconnected& event) {
lastDisconnectMoment.setNow();
if (lastConnectMoment > last_wifi_connect_attempt_moment) {
if (last_wifi_connect_attempt_moment.isSet() && !lastConnectMoment.isSet()) {
// There was an unsuccessful connection attempt
lastConnectedDuration_us = last_wifi_connect_attempt_moment.timeDiff(lastDisconnectMoment);
} else {
+15 -4
View File
@@ -213,7 +213,11 @@ void WiFiConnectRelaxed() {
log += wifi_connect_attempt + 1;
addLog(LOG_LEVEL_INFO, log);
}
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
lastDisconnectMoment.clear();
lastConnectMoment.clear();
lastGetIPmoment.clear();
wifi_considered_stable = false;
last_wifi_connect_attempt_moment.setNow();
wifiConnectInProgress = true;
@@ -258,7 +262,9 @@ bool prepareWiFi() {
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
#endif // if defined(ESP32)
if (RTC.lastWiFiChannel == 0 && wifi_connect_attempt <= 1) {
const bool canSkipScan = RTC.lastWiFiChannel != 0 && wifi_connect_attempt <= 1;
if (!canSkipScan) {
WifiScan(false, true);
}
setConnectionSpeed();
@@ -322,7 +328,7 @@ void resetWiFi() {
// Don't reset WiFi too often
return;
}
lastDisconnectMoment.setNow();
lastDisconnectMoment.clear();
lastWiFiResetMoment.setNow();
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
lastConnectMoment.clear();
@@ -645,7 +651,12 @@ bool wifiConnectTimeoutReached() {
// For the first attempt, do not wait to start connecting.
if (wifi_connect_attempt == 0) { return true; }
if (lastDisconnectMoment.isSet() && (last_wifi_connect_attempt_moment > lastDisconnectMoment)) {
if (!last_wifi_connect_attempt_moment.isSet()) {
// No attempt made
return true;
}
if (lastDisconnectMoment.isSet()) {
// Connection attempt was already ended.
return true;
}
@@ -656,7 +667,7 @@ bool wifiConnectTimeoutReached() {
}
// wait until it connects + add some device specific random offset to prevent
// all nodes overloading the accesspoint when turning on at the same time.
// all nodes overloading the access point when turning on at the same time.
#if defined(ESP8266)
const unsigned int randomOffset_in_msec = (wifi_connect_attempt == 1) ? 0 : 1000 * ((ESP.getChipId() & 0xF));
#endif // if defined(ESP8266)
+1 -1
View File
@@ -128,7 +128,7 @@ void handle_unprocessedWiFiEvents()
if (wifi_connect_attempt > 0) {
// We only want to clear this counter if the connection is currently stable.
if (bitRead(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED)) {
if (lastConnectMoment.timeoutReached(WIFI_CONNECTION_CONSIDERED_STABLE)) {
if (lastConnectMoment.isSet() && lastConnectMoment.timeoutReached(WIFI_CONNECTION_CONSIDERED_STABLE)) {
// Connection considered stable
wifi_connect_attempt = 0;
wifi_considered_stable = true;
+1 -1
View File
@@ -85,7 +85,7 @@ void syslog(byte logLevel, const char *message)
// Using Settings.Name as the Hostname (Hostname must NOT content space)
{
String header;
String hostname = Settings.Name;
String hostname = NetworkCreateRFCCompliantHostname(true);
hostname.trim();
hostname.replace(' ', '_');
header.reserve(16 + hostname.length());
+6 -5
View File
@@ -349,12 +349,13 @@ void addFloatNumberBox(const String& id, float value, float min, float max)
html += id;
html += '\'';
html += F(" min=");
html += min;
html += String(min, 6);
html += F(" max=");
html += max;
html += F(" step=0.01");
html += F(" style='width:5em;' value=");
html += value;
html += String(max, 6);
html += F(" step=0.000001");
html += F(" style='width:7em;' value=");
html += String(value, 6);
html += '>';
addHtml(html);
+23 -3
View File
@@ -18,6 +18,7 @@ void handle_timingstats() {
html_table_header(F("Function"));
html_table_header(F("#calls"));
html_table_header(F("call/sec"));
html_table_header(F("duty (%)"));
html_table_header(F("min (ms)"));
html_table_header(F("Avg (ms)"));
html_table_header(F("max (ms)"));
@@ -35,6 +36,8 @@ void handle_timingstats() {
addRowLabel(F("Time span"));
addHtml(String(timespan));
addHtml(F(" sec"));
addRowLabel(F("*"));
addHtml(F("Duty cycle based on average < 1 msec is highly unreliable"));
html_end_table();
sendHeadandTail_stdtemplate(_TAIL);
@@ -56,17 +59,34 @@ void format_using_threshhold(unsigned long value) {
void stream_html_timing_stats(const TimingStats& stats, long timeSinceLastReset) {
unsigned long minVal, maxVal;
unsigned int c = stats.getMinMax(minVal, maxVal);
const unsigned int c = stats.getMinMax(minVal, maxVal);
html_TD();
addHtml(String(c));
html_TD();
float call_per_sec = static_cast<float>(c) / static_cast<float>(timeSinceLastReset) * 1000.0f;
const float call_per_sec = static_cast<float>(c) / static_cast<float>(timeSinceLastReset) * 1000.0f;
const float avg = stats.getAvg();
addHtml(String(call_per_sec, 2));
html_TD();
{
const float duty = (call_per_sec * avg / 10000.0f);
String duty_str = String(duty, 2);
if (avg < 1000) {
// Unreliable as average is below 1 msec
duty_str += '*';
html_I(duty_str);
} else if (duty > 10.0f) {
// Over 10% of the time
html_B(duty_str);
} else {
addHtml(duty_str);
}
}
html_TD();
format_using_threshhold(minVal);
html_TD();
format_using_threshhold(stats.getAvg());
format_using_threshhold(avg);
html_TD();
format_using_threshhold(maxVal);
}
+62 -6
View File
@@ -105,6 +105,10 @@ struct C018_data_struct {
return res;
}
bool command_finished() const {
return myLora->command_finished();
}
bool txUncnfBytes(const byte *data, uint8_t size, uint8_t port) {
bool res = myLora->txBytes(data, size, port) != RN2xx3_datatypes::TX_return_type::TX_FAIL;
@@ -268,9 +272,17 @@ struct C018_data_struct {
return sampleSetCounter;
}
float getLoRaAirTime(uint8_t pl) const {
if (isInitialized()) {
return myLora->getLoRaAirTime(pl + 13); // We have a LoRaWAN header of 13 bytes.
}
return -1.0;
}
void async_loop() {
if (isInitialized()) {
rn2xx3_handler::RN_state state = myLora->async_loop();
if (rn2xx3_handler::RN_state::must_perform_init == state) {
if (myLora->get_busy_count() > 10) {
if (_resetPin != -1) {
@@ -281,7 +293,8 @@ struct C018_data_struct {
delay(200);
}
autobaud_success = false;
// triggerAutobaud();
// triggerAutobaud();
}
}
}
@@ -749,10 +762,10 @@ bool C018_init(struct EventStruct *event) {
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
C018_DelayHandler->configureControllerSettings(ControllerSettings);
AppEUI = getControllerUser(event->ControllerIndex, ControllerSettings);
AppKey = getControllerPass(event->ControllerIndex, ControllerSettings);
AppEUI = getControllerUser(event->ControllerIndex, ControllerSettings);
AppKey = getControllerPass(event->ControllerIndex, ControllerSettings);
SampleSetInitiator = ControllerSettings.SampleSetInitiator;
Port = ControllerSettings.Port;
Port = ControllerSettings.Port;
}
std::shared_ptr<C018_ConfigStruct> customConfig(new C018_ConfigStruct);
@@ -808,8 +821,36 @@ bool do_process_c018_delay_queue(int controller_number, const C018_queue_element
// *INDENT-ON*
bool do_process_c018_delay_queue(int controller_number, const C018_queue_element& element, ControllerSettingsStruct& ControllerSettings) {
bool success = C018_data.txHexBytes(element.packed, ControllerSettings.Port);
String error = C018_data.getLastError(); // Clear the error string.
uint8_t pl = (element.packed.length() / 2);
float airtime_ms = C018_data.getLoRaAirTime(pl);
bool mustSetDelay = false;
bool success = false;
if (!C018_data.command_finished()) {
mustSetDelay = true;
} else {
success = C018_data.txHexBytes(element.packed, ControllerSettings.Port);
if (success) {
if (airtime_ms > 0.0) {
ADD_TIMER_STAT(C018_AIR_TIME, static_cast<unsigned long>(airtime_ms * 1000));
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("LoRaWAN : Payload Length: ");
log += pl + 13; // We have a LoRaWAN header of 13 bytes.
log += F(" Air Time: ");
log += String(airtime_ms, 3);
log += F(" ms");
addLog(LOG_LEVEL_INFO, log);
}
}
}
}
String error = C018_data.getLastError(); // Clear the error string.
if (error.indexOf(F("no_free_ch")) != -1) {
mustSetDelay = true;
}
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("C018 : Sent: ");
@@ -823,6 +864,21 @@ bool do_process_c018_delay_queue(int controller_number, const C018_queue_element
log += error;
addLog(LOG_LEVEL_INFO, log);
}
if (mustSetDelay) {
// Module is still sending, delay for 10x expected air time, which is equivalent of 10% air time duty cycle.
// This can be retried a few times, so at most 10 retries like these are needed to get below 1% air time again.
// Very likely only 2 - 3 of these delays are needed, as we have 8 channels to send from and messages are likely sent in bursts.
C018_DelayHandler->setAdditionalDelay(10 * airtime_ms);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("LoRaWAN : Unable to send. Delay for ");
log += 10 * airtime_ms;
log += F(" ms");
addLog(LOG_LEVEL_INFO, log);
}
}
return success;
}
+131 -270
View File
@@ -1,3 +1,5 @@
#include "_Plugin_Helper.h"
#ifdef USES_P082
// #######################################################################################################
@@ -10,215 +12,45 @@
//
//
#include <ESPeasySerial.h>
#include <TinyGPS++.h>
#include "_Plugin_Helper.h"
#include "ESPEasy_packed_raw_data.h"
# include "ESPEasy_packed_raw_data.h"
#include "src/Globals/ESPEasy_time.h"
#include "src/Helpers/ESPEasy_time_calc.h"
# include "src/Globals/ESPEasy_time.h"
# include "src/Helpers/ESPEasy_time_calc.h"
#define PLUGIN_082
#define PLUGIN_ID_082 82
#define PLUGIN_NAME_082 "Position - GPS [TESTING]"
#define PLUGIN_VALUENAME1_082 "Longitude"
#define PLUGIN_VALUENAME2_082 "Latitude"
#define PLUGIN_VALUENAME3_082 "Altitude"
#define PLUGIN_VALUENAME4_082 "Speed"
# include "src/PluginStructs/P082_data_struct.h"
# define PLUGIN_082
# define PLUGIN_ID_082 82
# define PLUGIN_NAME_082 "Position - GPS [TESTING]"
# define PLUGIN_VALUENAME1_082 "Longitude"
# define PLUGIN_VALUENAME2_082 "Latitude"
# define PLUGIN_VALUENAME3_082 "Altitude"
# define PLUGIN_VALUENAME4_082 "Speed"
#define P082_TIMEOUT PCONFIG(0)
#define P082_TIMEOUT_LABEL PCONFIG_LABEL(0)
#define P082_BAUDRATE PCONFIG(1)
#define P082_BAUDRATE_LABEL PCONFIG_LABEL(1)
#define P082_DISTANCE PCONFIG(2)
#define P082_DISTANCE_LABEL PCONFIG_LABEL(2)
#define P082_QUERY1 PCONFIG(3)
#define P082_QUERY2 PCONFIG(4)
#define P082_QUERY3 PCONFIG(5)
#define P082_QUERY4 PCONFIG(6)
# define P082_TIMEOUT PCONFIG(0)
# define P082_TIMEOUT_LABEL PCONFIG_LABEL(0)
# define P082_BAUDRATE PCONFIG(1)
# define P082_BAUDRATE_LABEL PCONFIG_LABEL(1)
# define P082_DISTANCE PCONFIG(2)
# define P082_DISTANCE_LABEL PCONFIG_LABEL(2)
# define P082_QUERY1 PCONFIG(3)
# define P082_QUERY2 PCONFIG(4)
# define P082_QUERY3 PCONFIG(5)
# define P082_QUERY4 PCONFIG(6)
# define P082_LONG_REF PCONFIG_FLOAT(0)
# define P082_LAT_REF PCONFIG_FLOAT(1)
#define P082_NR_OUTPUT_VALUES VARS_PER_TASK
#define P082_QUERY1_CONFIG_POS 3
# define P082_NR_OUTPUT_VALUES VARS_PER_TASK
# define P082_QUERY1_CONFIG_POS 3
#define P082_QUERY_LONG 0
#define P082_QUERY_LAT 1
#define P082_QUERY_ALT 2
#define P082_QUERY_SPD 3
#define P082_QUERY_SATVIS 4
#define P082_QUERY_SATUSE 5
#define P082_QUERY_HDOP 6
#define P082_QUERY_FIXQ 7
#define P082_QUERY_DB_MAX 8
#define P082_QUERY_CHKSUM_FAIL 9
#define P082_NR_OUTPUT_OPTIONS 10
# define P082_DISTANCE_DFLT 0 // Disable update per distance travelled.
# define P082_QUERY1_DFLT P082_query::P082_QUERY_LONG
# define P082_QUERY2_DFLT P082_query::P082_QUERY_LAT
# define P082_QUERY3_DFLT P082_query::P082_QUERY_ALT
# define P082_QUERY4_DFLT P082_query::P082_QUERY_SPD
#define P082_TIMESTAMP_AGE 1500
#define P082_DEFAULT_FIX_TIMEOUT 2500 // TTL of fix status in ms since last update
#define P082_DISTANCE_DFLT 0 // Disable update per distance travelled.
#define P082_QUERY1_DFLT P082_QUERY_LONG
#define P082_QUERY2_DFLT P082_QUERY_LAT
#define P082_QUERY3_DFLT P082_QUERY_ALT
#define P082_QUERY4_DFLT P082_QUERY_SPD
#define P082_SEND_GPS_TO_LOG
struct P082_data_struct : public PluginTaskData_base {
P082_data_struct() : gps(nullptr), P082_easySerial(nullptr) {}
~P082_data_struct() {
reset();
}
void reset() {
if (gps != nullptr) {
delete gps;
gps = nullptr;
}
if (P082_easySerial != nullptr) {
delete P082_easySerial;
P082_easySerial = nullptr;
}
}
bool init(ESPEasySerialPort port, const int16_t serial_rx, const int16_t serial_tx) {
if (serial_rx < 0) {
return false;
}
reset();
gps = new (std::nothrow) TinyGPSPlus();
P082_easySerial = new (std::nothrow) ESPeasySerial(port, serial_rx, serial_tx);
if (P082_easySerial != nullptr) {
P082_easySerial->begin(9600);
}
return isInitialized();
}
bool isInitialized() const {
return gps != nullptr && P082_easySerial != nullptr;
}
bool loop() {
if (!isInitialized()) {
return false;
}
bool completeSentence = false;
if (P082_easySerial != nullptr) {
int available = P082_easySerial->available();
unsigned long startLoop = millis();
while (available > 0 && timePassedSince(startLoop) < 10) {
--available;
char c = P082_easySerial->read();
#ifdef P082_SEND_GPS_TO_LOG
currentSentence += c;
#endif // ifdef P082_SEND_GPS_TO_LOG
if (gps->encode(c)) {
// Full sentence received
#ifdef P082_SEND_GPS_TO_LOG
lastSentence = currentSentence;
currentSentence = "";
#endif // ifdef P082_SEND_GPS_TO_LOG
completeSentence = true;
}
}
}
return completeSentence;
}
bool hasFix(unsigned int maxAge_msec) {
if (!isInitialized()) {
return false;
}
return gps->location.isValid() && gps->location.age() < maxAge_msec;
}
bool storeCurPos(unsigned int maxAge_msec) {
if (!hasFix(maxAge_msec)) {
return false;
}
last_lat = gps->location.lat();
last_lng = gps->location.lng();
return true;
}
// Return the distance in meters compared to last stored position.
// @retval -1 when no fix.
double distanceSinceLast(unsigned int maxAge_msec) {
if (!hasFix(maxAge_msec)) {
return -1.0;
}
if ((last_lat < 0.0001 && last_lat > -0.0001) || (last_lng < 0.0001 && last_lng > -0.0001)) {
return -1.0;
}
return gps->distanceBetween(last_lat, last_lng, gps->location.lat(), gps->location.lng());
}
// Return the GPS time stamp, which is in UTC.
// @param age is the time in msec since the last update of the time +
// additional centiseconds given by the GPS.
bool getDateTime(struct tm& dateTime, uint32_t& age, bool& pps_sync) {
if (!isInitialized()) {
return false;
}
if (pps_time != 0) {
age = timePassedSince(pps_time);
pps_time = 0;
pps_sync = true;
if ((age > 1000) || (gps->time.age() > age)) {
return false;
}
} else {
age = gps->time.age();
pps_sync = false;
}
if (age > P082_TIMESTAMP_AGE) {
return false;
}
if (gps->date.age() > P082_TIMESTAMP_AGE) {
return false;
}
if (!gps->date.isValid() || !gps->time.isValid()) {
return false;
}
dateTime.tm_year = gps->date.year() - 1970;
dateTime.tm_mon = gps->date.month();
dateTime.tm_mday = gps->date.day();
dateTime.tm_hour = gps->time.hour();
dateTime.tm_min = gps->time.minute();
dateTime.tm_sec = gps->time.second();
// FIXME TD-er: Must the offset in centisecond be added when pps_sync active?
if (!pps_sync) {
age += (gps->time.centisecond() * 10);
}
return true;
}
TinyGPSPlus *gps = nullptr;
ESPeasySerial *P082_easySerial = nullptr;
double last_lat = 0.0;
double last_lng = 0.0;
unsigned long pps_time = 0;
unsigned long last_measurement = 0;
#ifdef P082_SEND_GPS_TO_LOG
String lastSentence;
String currentSentence;
#endif // ifdef P082_SEND_GPS_TO_LOG
float cache[P082_NR_OUTPUT_OPTIONS] = {0};
};
// Must use volatile declared variable (which will end up in iRAM)
volatile unsigned long P082_pps_time = 0;
@@ -252,15 +84,15 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
for (byte i = 0; i < VARS_PER_TASK; ++i) {
if (i < P082_NR_OUTPUT_VALUES) {
const byte pconfigIndex = i + P082_QUERY1_CONFIG_POS;
byte choice = PCONFIG(pconfigIndex);
P082_query choice = static_cast<P082_query>(PCONFIG(pconfigIndex));
safe_strncpy(
ExtraTaskSettings.TaskDeviceValueNames[i],
Plugin_082_valuename(choice, false),
sizeof(ExtraTaskSettings.TaskDeviceValueNames[i]));
switch (choice) {
case P082_QUERY_LONG:
case P082_QUERY_LAT:
case P082_query::P082_QUERY_LONG:
case P082_query::P082_QUERY_LAT:
ExtraTaskSettings.TaskDeviceValueDecimals[i] = 6;
break;
default:
@@ -301,10 +133,10 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
{
P082_TIMEOUT = P082_DEFAULT_FIX_TIMEOUT;
P082_DISTANCE = P082_DISTANCE_DFLT;
P082_QUERY1 = P082_QUERY1_DFLT;
P082_QUERY2 = P082_QUERY2_DFLT;
P082_QUERY3 = P082_QUERY3_DFLT;
P082_QUERY4 = P082_QUERY4_DFLT;
P082_QUERY1 = static_cast<byte>(P082_QUERY1_DFLT);
P082_QUERY2 = static_cast<byte>(P082_QUERY2_DFLT);
P082_QUERY3 = static_cast<byte>(P082_QUERY3_DFLT);
P082_QUERY4 = static_cast<byte>(P082_QUERY4_DFLT);
success = true;
break;
@@ -318,19 +150,20 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
}
case PLUGIN_WEBFORM_LOAD: {
/*
P082_data_struct *P082_data =
static_cast<P082_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr != P082_data && P082_data->isInitialized()) {
String detectedString = F("Detected: ");
detectedString += String(P082_data->P082_easySerial->baudRate());
detectedString += String(P082_data->easySerial->baudRate());
addUnit(detectedString);
*/
addFormNumericBox(F("Fix Timeout"), P082_TIMEOUT_LABEL, P082_TIMEOUT, 100, 10000);
addUnit(F("ms"));
addFormSubHeader(F("Current Sensor Data"));
P082_html_show_stats(event);
// Settings to add:
@@ -348,18 +181,25 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
// fixQuality, fixMode
// statistics (chars processed, failed checksum)
{
addFormSubHeader(F("Reference Point"));
addFormFloatNumberBox(F("Latitude"), F("lat_ref"), P082_LAT_REF, -90.0f, 90.0f);
addFormFloatNumberBox(F("Longitude"), F("lng_ref"), P082_LONG_REF, -180.0f, 180.0f);
}
{
// In a separate scope to free memory of String array as soon as possible
sensorTypeHelper_webformLoad_header();
String options[P082_NR_OUTPUT_OPTIONS];
String options[static_cast<byte>(P082_query::P082_NR_OUTPUT_OPTIONS)];
for (int i = 0; i < P082_NR_OUTPUT_OPTIONS; ++i) {
options[i] = Plugin_082_valuename(i, true);
for (byte i = 0; i < static_cast<byte>(P082_query::P082_NR_OUTPUT_OPTIONS); ++i) {
options[i] = Plugin_082_valuename(static_cast<P082_query>(i), true);
}
for (byte i = 0; i < P082_NR_OUTPUT_VALUES; ++i) {
const byte pconfigIndex = i + P082_QUERY1_CONFIG_POS;
sensorTypeHelper_loadOutputSelector(event, pconfigIndex, i, P082_NR_OUTPUT_OPTIONS, options);
sensorTypeHelper_loadOutputSelector(event, pconfigIndex, i, static_cast<int>(P082_query::P082_NR_OUTPUT_OPTIONS), options);
}
}
@@ -375,10 +215,13 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
P082_TIMEOUT = getFormItemInt(P082_TIMEOUT_LABEL);
P082_DISTANCE = getFormItemInt(P082_DISTANCE_LABEL);
P082_LONG_REF = getFormItemFloat(F("lng_ref"));
P082_LAT_REF = getFormItemFloat(F("lat_ref"));
// Save output selector parameters.
for (byte i = 0; i < P082_NR_OUTPUT_VALUES; ++i) {
for (int i = 0; i < P082_NR_OUTPUT_VALUES; ++i) {
const byte pconfigIndex = i + P082_QUERY1_CONFIG_POS;
const byte choice = PCONFIG(pconfigIndex);
const P082_query choice = static_cast<P082_query>(PCONFIG(pconfigIndex));
sensorTypeHelper_saveOutputSelector(event, pconfigIndex, i, Plugin_082_valuename(choice, false));
}
@@ -391,9 +234,9 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
P082_TIMEOUT = P082_DEFAULT_FIX_TIMEOUT;
}
const ESPEasySerialPort port = static_cast<ESPEasySerialPort>(CONFIG_PORT);
const int16_t serial_rx = CONFIG_PIN1;
const int16_t serial_tx = CONFIG_PIN2;
const int16_t pps_pin = CONFIG_PIN3;
const int16_t serial_rx = CONFIG_PIN1;
const int16_t serial_tx = CONFIG_PIN2;
const int16_t pps_pin = CONFIG_PIN3;
initPluginTaskData(event->TaskIndex, new (std::nothrow) P082_data_struct());
P082_data_struct *P082_data =
static_cast<P082_data_struct *>(getPluginTaskData(event->TaskIndex));
@@ -431,9 +274,9 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
static_cast<P082_data_struct *>(getPluginTaskData(event->TaskIndex));
if ((nullptr != P082_data) && P082_data->loop()) {
#ifdef P082_SEND_GPS_TO_LOG
addLog(LOG_LEVEL_DEBUG, P082_data->lastSentence);
#endif // ifdef P082_SEND_GPS_TO_LOG
# ifdef P082_SEND_GPS_TO_LOG
addLog(LOG_LEVEL_DEBUG, P082_data->_lastSentence);
# endif // ifdef P082_SEND_GPS_TO_LOG
Scheduler.schedule_task_device_timer(event->TaskIndex, millis() + 10);
delay(0); // Processing a full sentence may take a while, run some
// background tasks.
@@ -460,8 +303,15 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
if (curFixStatus) {
if (P082_data->gps->location.isUpdated()) {
P082_setOutputValue(event, P082_QUERY_LONG, P082_data->gps->location.lng());
P082_setOutputValue(event, P082_QUERY_LAT, P082_data->gps->location.lat());
const float lng = P082_data->gps->location.lng();
const float lat = P082_data->gps->location.lat();
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_LONG), lng);
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_LAT), lat);
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_DISTANCE), P082_data->_distance);
const float dist_ref = P082_data->gps->distanceBetween(P082_LAT_REF, P082_LONG_REF, lat, lng);
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_DIST_REF), dist_ref);
if (P082_DISTANCE > 0) {
distance = P082_data->distanceSinceLast(P082_TIMEOUT);
@@ -472,24 +322,25 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
if (P082_data->gps->altitude.isUpdated()) {
// ToDo make unit selectable
P082_setOutputValue(event, P082_QUERY_ALT, P082_data->gps->altitude.meters());
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_ALT), P082_data->gps->altitude.meters());
success = true;
addLog(LOG_LEVEL_DEBUG, F("GPS: Altitude update."));
}
if (P082_data->gps->speed.isUpdated()) {
// ToDo make unit selectable
P082_setOutputValue(event, P082_QUERY_SPD, P082_data->gps->speed.mps());
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_SPD), P082_data->gps->speed.mps());
addLog(LOG_LEVEL_DEBUG, F("GPS: Speed update."));
success = true;
}
}
P082_setOutputValue(event, P082_QUERY_SATVIS, P082_data->gps->satellitesStats.nrSatsVisible());
P082_setOutputValue(event, P082_QUERY_SATUSE, P082_data->gps->satellitesStats.nrSatsTracked());
P082_setOutputValue(event, P082_QUERY_HDOP, P082_data->gps->hdop.value() / 100.0f);
P082_setOutputValue(event, P082_QUERY_FIXQ, P082_data->gps->location.Quality());
P082_setOutputValue(event, P082_QUERY_DB_MAX, P082_data->gps->satellitesStats.getBestSNR());
P082_setOutputValue(event, P082_QUERY_CHKSUM_FAIL, P082_data->gps->failedChecksum());
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_SATVIS), P082_data->gps->satellitesStats.nrSatsVisible());
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_SATUSE), P082_data->gps->satellitesStats.nrSatsTracked());
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_HDOP), P082_data->gps->hdop.value() / 100.0f);
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_FIXQ), P082_data->gps->location.Quality());
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_DB_MAX), P082_data->gps->satellitesStats.getBestSNR());
P082_setOutputValue(event, static_cast<byte>(P082_query::P082_QUERY_CHKSUM_FAIL), P082_data->gps->failedChecksum());
if (curFixStatus) {
P082_setSystemTime(event);
@@ -502,7 +353,7 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
if (P082_DISTANCE > 0) {
// Check travelled distance.
if (distance > static_cast<double>(P082_DISTANCE) || distance < 0.0) {
if ((distance > static_cast<double>(P082_DISTANCE)) || (distance < 0.0)) {
if (P082_data->storeCurPos(P082_TIMEOUT)) {
distance_passed = true;
@@ -523,21 +374,21 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
}
}
if (P082_data->last_measurement == 0) {
if (P082_data->_last_measurement == 0) {
interval_passed = true;
} else if (timeOutReached(P082_data->last_measurement + (Settings.TaskDeviceTimer[event->TaskIndex] * 1000))) {
} else if (timeOutReached(P082_data->_last_measurement + (Settings.TaskDeviceTimer[event->TaskIndex] * 1000))) {
interval_passed = true;
}
success = (distance_passed || interval_passed);
if (success) {
P082_data->last_measurement = millis();
P082_data->_last_measurement = millis();
}
}
}
break;
}
#ifdef USES_PACKED_RAW_DATA
# ifdef USES_PACKED_RAW_DATA
case PLUGIN_GET_PACKED_RAW_DATA:
{
P082_data_struct *P082_data =
@@ -545,28 +396,37 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
if ((nullptr != P082_data) && P082_data->isInitialized()) {
// Matching JS code:
// return decode(bytes, [header, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8],
// ['header', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked']);
// return decode(bytes, [header, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8, uint24, uint24_1e1],
// ['header', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked', 'distance_total', 'distance_ref']);
// altitude type: return +(int16(bytes) / 4 - 1000).toFixed(1);
string += LoRa_addFloat(P082_data->cache[P082_QUERY_LAT], PackedData_latLng);
string += LoRa_addFloat(P082_data->cache[P082_QUERY_LONG], PackedData_latLng);
string += LoRa_addFloat(P082_data->cache[P082_QUERY_ALT], PackedData_altitude);
string += LoRa_addFloat(P082_data->cache[P082_QUERY_SPD], PackedData_uint16_1e2);
string += LoRa_addFloat(P082_data->cache[P082_QUERY_HDOP], PackedData_hdop);
string += LoRa_addFloat(P082_data->cache[P082_QUERY_DB_MAX], PackedData_uint8);
string += LoRa_addFloat(P082_data->cache[P082_QUERY_SATUSE], PackedData_uint8);
event->Par1 = 7; // valuecount 7
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_LAT)], PackedData_latLng);
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_LONG)], PackedData_latLng);
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_ALT)], PackedData_altitude);
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_SPD)], PackedData_uint16_1e2);
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_HDOP)], PackedData_hdop);
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_DB_MAX)], PackedData_uint8);
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_SATUSE)], PackedData_uint8);
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_DISTANCE)] / 1000, PackedData_uint24_1e2); // Max 167772.16 km
event->Par1 = 8;
if (P082_referencePointSet(event)) {
string += LoRa_addFloat(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_DIST_REF)], PackedData_uint24_1e1); // Max 1677.7216 km
event->Par1 = 9;
}
success = true;
}
break;
}
#endif // USES_PACKED_RAW_DATA
# endif // USES_PACKED_RAW_DATA
}
return success;
}
bool P082_referencePointSet(struct EventStruct *event) {
return ! ((P082_LONG_REF < 0.1) && (P082_LONG_REF > -0.1)
&& (P082_LAT_REF < 0.1) && (P082_LAT_REF > -0.1) );
}
void P082_setOutputValue(struct EventStruct *event, byte outputType, float value) {
P082_data_struct *P082_data =
static_cast<P082_data_struct *>(getPluginTaskData(event->TaskIndex));
@@ -574,8 +434,10 @@ void P082_setOutputValue(struct EventStruct *event, byte outputType, float value
if ((nullptr == P082_data) || !P082_data->isInitialized()) {
return;
}
if (outputType < P082_NR_OUTPUT_OPTIONS)
P082_data->cache[outputType] = value;
if (outputType < static_cast<byte>(P082_query::P082_NR_OUTPUT_OPTIONS)) {
P082_data->_cache[outputType] = value;
}
for (byte i = 0; i < P082_NR_OUTPUT_VALUES; ++i) {
const byte pconfigIndex = i + P082_QUERY1_CONFIG_POS;
@@ -595,6 +457,7 @@ void P082_logStats(struct EventStruct *event) {
return;
}
String log;
log.reserve(128);
log = F("GPS:");
log += F(" Fix: ");
@@ -654,9 +517,9 @@ void P082_html_show_satStats(struct EventStruct *event, bool tracked, bool onlyG
addHtml(String(id));
if (tracked) {
addHtml( " (");
addHtml(" (");
addHtml(String(snr));
addHtml( ")");
addHtml(")");
}
}
}
@@ -705,7 +568,7 @@ void P082_html_show_stats(struct EventStruct *event) {
addRowLabel(F("Best SNR"));
addHtml(String(P082_data->gps->satellitesStats.getBestSNR()));
addHtml( F(" dBHz"));
addHtml(F(" dBHz"));
// Satellites tracked or in view.
P082_html_show_satStats(event, true, true);
@@ -728,8 +591,19 @@ void P082_html_show_stats(struct EventStruct *event) {
addHtml(F("-"));
}
addRowLabel(F("Distance Travelled"));
addHtml(String(static_cast<int>(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_DISTANCE)])));
addUnit(F("m"));
if (P082_referencePointSet(event)) {
addRowLabel(F("Distance from Ref. Point"));
addHtml(String(static_cast<int>(P082_data->_cache[static_cast<byte>(P082_query::P082_QUERY_DIST_REF)])));
addUnit(F("m"));
}
addRowLabel(F("Checksum (pass/fail/invalid)"));
String chksumStats;
chksumStats = P082_data->gps->passedChecksum();
chksumStats += '/';
chksumStats += P082_data->gps->failedChecksum();
@@ -755,7 +629,8 @@ void P082_setSystemTime(struct EventStruct *event) {
struct tm dateTime;
uint32_t age;
bool pps_sync;
P082_data->pps_time = P082_pps_time; // Must copy the interrupt gathered time first.
P082_data->_pps_time = P082_pps_time; // Must copy the interrupt gathered time first.
if (P082_data->getDateTime(dateTime, age, pps_sync)) {
// Use floating point precision to use the time since last update from GPS
@@ -772,19 +647,5 @@ void Plugin_082_interrupt() {
P082_pps_time = millis();
}
String Plugin_082_valuename(byte value_nr, bool displayString) {
switch (value_nr) {
case P082_QUERY_LONG: return displayString ? F("Longitude") : F("long");
case P082_QUERY_LAT: return displayString ? F("Latitude") : F("lat");
case P082_QUERY_ALT: return displayString ? F("Altitude") : F("alt");
case P082_QUERY_SPD: return displayString ? F("Speed (m/s)") : F("spd");
case P082_QUERY_SATVIS: return displayString ? F("Satellites Visible") : F("sat_vis");
case P082_QUERY_SATUSE: return displayString ? F("Satellites Tracked") : F("sat_tr");
case P082_QUERY_HDOP: return displayString ? F("HDOP") : F("hdop");
case P082_QUERY_FIXQ: return displayString ? F("Fix Quality") : F("fix_qual");
case P082_QUERY_DB_MAX: return displayString ? F("Max SNR in dBHz") : F("snr_max");
}
return "";
}
#endif // USES_P082
+25
View File
@@ -360,6 +360,31 @@ boolean Plugin_085(byte function, struct EventStruct *event, String& string) {
}
break;
}
#ifdef USES_PACKED_RAW_DATA
case PLUGIN_GET_PACKED_RAW_DATA:
{
P085_data_struct *P085_data =
static_cast<P085_data_struct *>(getPluginTaskData(event->TaskIndex));
if ((nullptr != P085_data) && P085_data->isInitialized()) {
// Matching JS code:
// return decode(bytes, [header, uint8, int32_1e4, uint8, int32_1e4, uint8, int32_1e4, uint8, int32_1e4],
// ['header', 'unit1', 'val_1', 'unit2', 'val_2', 'unit3', 'val_3', 'unit4', 'val_4']);
for (byte i = 0; i < VARS_PER_TASK; ++i) {
const byte pconfigIndex = i + P085_QUERY1_CONFIG_POS;
const byte choice = PCONFIG(pconfigIndex);
string += LoRa_addInt(choice, PackedData_uint8);
string += LoRa_addFloat(UserVar[event->BaseVarIndex + i], PackedData_int32_1e4);
}
event->Par1 = 8; // valuecount
success = true;
}
break;
}
#endif // USES_PACKED_RAW_DATA
}
return success;
}
+34 -5
View File
@@ -21,6 +21,12 @@
For following devices just a pull up resistor is needed if the device is used stand alone:
UVR1611, UVR61-3 and ESR21
@uwekaditz 2020-10-05 Exception solved
CHG: Interrupt will be only enabled after network is connected
CHG: usecPassedSince() not longer used in ISR_PinChanged(), caused the exception ???
CHG: in case no DLbus is connected, the next reading attempt happens only after the next PLUGIN_092_READ was called
(reduces load and log messages)
@uwekaditz 2020-03-01 Memory usage optimized
CHG: Moved arrays into the class DLBus
CHG: Moved arrays to PLUGIN_092_DEBUG
@@ -435,12 +441,12 @@ boolean Plugin_092(uint8_t function, struct EventStruct *event, String& string)
}
P092_init = true;
P092_ReceivedOK = false;
addLog(LOG_LEVEL_INFO, F("P092_init: attachInterrupt"));
addLog(LOG_LEVEL_INFO, F("P092_init: Set pin"));
DLbus_Data->ISR_DLB_Pin = CONFIG_PIN1;
pinMode(CONFIG_PIN1, INPUT_PULLUP);
// on a CHANGE on the data pin P092_Pin_changed is called
DLbus_Data->attachDLBusInterrupt();
// // on a CHANGE on the data pin P092_Pin_changed is called
// DLbus_Data->attachDLBusInterrupt();
UserVar[event->BaseVarIndex] = NAN;
}
success = true;
@@ -461,9 +467,16 @@ boolean Plugin_092(uint8_t function, struct EventStruct *event, String& string)
return false;
}
if (!DLbus_Data->IsISRset) {
// on a CHANGE on the data pin P092_Pin_changed is called
DLbus_Data->attachDLBusInterrupt();
addLog(LOG_LEVEL_INFO, F("P092 ISR set"));
}
if (DLbus_Data->ISR_Receiving) {
return false;
}
Plugin_092_SetIndices(PCONFIG(0));
if (DLbus_Data->ISR_AllBitsReceived) {
@@ -488,8 +501,9 @@ boolean Plugin_092(uint8_t function, struct EventStruct *event, String& string)
success = P092_ReceivedOK;
}
if ((P092_ReceivedOK == false) ||
(timePassedSince(P092_LastReceived) > (static_cast<long>(Settings.TaskDeviceTimer[event->TaskIndex] * 1000 / 2)))) {
if ((DLbus_Data->IsNoData == false) &&
((P092_ReceivedOK == false) ||
(timePassedSince(P092_LastReceived) > (static_cast<long>(Settings.TaskDeviceTimer[event->TaskIndex] * 1000 / 2))))) {
Plugin_092_StartReceiving();
success = true;
}
@@ -525,10 +539,24 @@ boolean Plugin_092(uint8_t function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_ERROR, log);
return false;
}
if (!DLbus_Data->IsISRset) {
// on a CHANGE on the data pin P092_Pin_changed is called
addLog(LOG_LEVEL_ERROR, F("## P092_read: Error DL-Bus: ISR not set"));
return false;
}
if (DLbus_Data->IsNoData) {
// start new receiving attempt
DLbus_Data->IsNoData = false;
return true;
}
success = P092_ReceivedOK;
if (P092_ReceivedOK == false) {
addLog(LOG_LEVEL_INFO, F("P092_read: Still receiving DL-Bus bits!"));
return true;
}
else {
sP092_ReadData P092_ReadData;
@@ -723,6 +751,7 @@ void Plugin_092_StartReceiving(void) {
if (DLbus_Data->ISR_PulseCount == 0) {
// nothing received
DLbus_Data->ISR_Receiving = false;
DLbus_Data->IsNoData = true; // stop receiving until next PLUGIN_092_READ
addLog(LOG_LEVEL_ERROR, F("## StartReceiving: Error: Nothing received! No DL bus connected!"));
}
}
@@ -160,6 +160,13 @@ struct ControllerDelayHandlerStruct {
return nextTime;
}
// Set the "lastSend" to "now" + some additional delay.
// This will cause the next schedule time to be delayed to
// msecFromNow + minTimeBetweenMessages
void setAdditionalDelay(unsigned long msecFromNow) {
lastSend = millis() + msecFromNow;
}
size_t getQueueMemorySize() const {
size_t totalSize = 0;
@@ -84,7 +84,7 @@ bool ExtraTaskSettingsStruct::checkInvalidCharInNames(const char *name) const {
bool ExtraTaskSettingsStruct::checkInvalidCharInNames() const {
if (!checkInvalidCharInNames(&TaskDeviceName[0])) { return false; }
for (int i = 0; i < (VARS_PER_TASK - 1); ++i) {
for (int i = 0; i < VARS_PER_TASK; ++i) {
if (!checkInvalidCharInNames(&TaskDeviceValueNames[i][0])) { return false; }
}
return true;
+1
View File
@@ -228,6 +228,7 @@ String getMiscStatsName(int stat) {
case PARSE_SYSVAR: return F("parseSystemVariables()");
case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change");
case HANDLE_SERVING_WEBPAGE: return F("handle webpage");
case C018_AIR_TIME: return F("C018 LoRa TTN - Air Time");
case C001_DELAY_QUEUE:
case C002_DELAY_QUEUE:
case C003_DELAY_QUEUE:
+32 -21
View File
@@ -54,26 +54,33 @@
# define C018_DELAY_QUEUE 33
# define C019_DELAY_QUEUE 34
# define C020_DELAY_QUEUE 35
# define TRY_CONNECT_HOST_TCP 36
# define TRY_CONNECT_HOST_UDP 37
# define HOST_BY_NAME_STATS 38
# define CONNECT_CLIENT_STATS 39
# define LOAD_CUSTOM_TASK_STATS 40
# define WIFI_ISCONNECTED_STATS 41
# define WIFI_NOTCONNECTED_STATS 42
# define LOAD_TASK_SETTINGS 43
# define TRY_OPEN_FILE 44
# define FS_GC_SUCCESS 45
# define FS_GC_FAIL 46
# define PARSE_SYSVAR 47
# define PARSE_SYSVAR_NOCHANGE 48
# define PARSE_TEMPLATE_PADDED 49
# define RULES_PROCESSING 50
# define GRAT_ARP_STATS 51
# define BACKGROUND_TASKS 52
# define HANDLE_SCHEDULER_IDLE 53
# define HANDLE_SCHEDULER_TASK 54
# define HANDLE_SERVING_WEBPAGE 55
# define C021_DELAY_QUEUE 36
# define C022_DELAY_QUEUE 37
# define C023_DELAY_QUEUE 38
# define C024_DELAY_QUEUE 39
# define C025_DELAY_QUEUE 40
# define C018_AIR_TIME 41
# define TRY_CONNECT_HOST_TCP 42
# define TRY_CONNECT_HOST_UDP 43
# define HOST_BY_NAME_STATS 44
# define CONNECT_CLIENT_STATS 45
# define LOAD_CUSTOM_TASK_STATS 46
# define WIFI_ISCONNECTED_STATS 47
# define WIFI_NOTCONNECTED_STATS 48
# define LOAD_TASK_SETTINGS 49
# define TRY_OPEN_FILE 50
# define FS_GC_SUCCESS 51
# define FS_GC_FAIL 52
# define PARSE_SYSVAR 53
# define PARSE_SYSVAR_NOCHANGE 54
# define PARSE_TEMPLATE_PADDED 55
# define RULES_PROCESSING 56
# define GRAT_ARP_STATS 57
# define BACKGROUND_TASKS 58
# define HANDLE_SCHEDULER_IDLE 59
# define HANDLE_SCHEDULER_TASK 60
# define HANDLE_SERVING_WEBPAGE 61
class TimingStats {
public:
@@ -109,7 +116,7 @@ extern std::map<int, TimingStats> controllerStats;
extern std::map<int, TimingStats> miscStats;
extern unsigned long timingstats_last_reset;
# define START_TIMER const unsigned statisticsTimerStart(micros());
# define START_TIMER const unsigned long statisticsTimerStart(micros());
# define STOP_TIMER_TASK(T, F) \
if (mustLogFunction(F)) pluginStats[(T) * 256 + (F)].add(usecPassedSince(statisticsTimerStart));
# define STOP_TIMER_CONTROLLER(T, F) \
@@ -118,12 +125,16 @@ extern unsigned long timingstats_last_reset;
// #define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince(statisticsTimerStart));
# define STOP_TIMER(L) miscStats[L].add(usecPassedSince(statisticsTimerStart));
// Add a timer statistic value in usec.
# define ADD_TIMER_STAT(L, T) miscStats[L].add(T);
#else // ifdef USES_TIMING_STATS
# define START_TIMER
# define STOP_TIMER_TASK(T, F) ;
# define STOP_TIMER_CONTROLLER(T, F) ;
# define STOP_TIMER(L) ;
# define ADD_TIMER_STAT(L, T) ;
// FIXME TD-er: This class is used as a parameter in functions defined in .ino files.
+4
View File
@@ -10,6 +10,10 @@ public:
LongTermTimer() {}
explicit LongTermTimer(bool usenow) : _timer_usec(0ull) {
if (usenow) setNow();
}
//explicit LongTermTimer(uint64_t start_time) : _timer_usec(start_time) {}
inline bool operator<(const LongTermTimer& rhs) const
+170
View File
@@ -0,0 +1,170 @@
#include "P082_data_struct.h"
#ifdef USES_P082
String Plugin_082_valuename(P082_query value_nr, bool displayString) {
switch (value_nr) {
case P082_query::P082_QUERY_LONG: return displayString ? F("Longitude") : F("long");
case P082_query::P082_QUERY_LAT: return displayString ? F("Latitude") : F("lat");
case P082_query::P082_QUERY_ALT: return displayString ? F("Altitude") : F("alt");
case P082_query::P082_QUERY_SPD: return displayString ? F("Speed (m/s)") : F("spd");
case P082_query::P082_QUERY_SATVIS: return displayString ? F("Satellites Visible") : F("sat_vis");
case P082_query::P082_QUERY_SATUSE: return displayString ? F("Satellites Tracked") : F("sat_tr");
case P082_query::P082_QUERY_HDOP: return displayString ? F("HDOP") : F("hdop");
case P082_query::P082_QUERY_FIXQ: return displayString ? F("Fix Quality") : F("fix_qual");
case P082_query::P082_QUERY_DB_MAX: return displayString ? F("Max SNR in dBHz") : F("snr_max");
case P082_query::P082_QUERY_CHKSUM_FAIL: return displayString ? F("Checksum Fail") : F("chksum_fail");
case P082_query::P082_QUERY_DISTANCE: return displayString ? F("Distance (ODO)") : F("dist");
case P082_query::P082_QUERY_DIST_REF: return displayString ? F("Distance from Reference Point") : F("dist_ref");
case P082_query::P082_NR_OUTPUT_OPTIONS: break;
}
return "";
}
P082_data_struct::P082_data_struct() : gps(nullptr), easySerial(nullptr) {}
P082_data_struct::~P082_data_struct() {
reset();
}
void P082_data_struct::reset() {
if (gps != nullptr) {
delete gps;
gps = nullptr;
}
if (easySerial != nullptr) {
delete easySerial;
easySerial = nullptr;
}
}
bool P082_data_struct::init(ESPEasySerialPort port, const int16_t serial_rx, const int16_t serial_tx) {
if (serial_rx < 0) {
return false;
}
reset();
gps = new (std::nothrow) TinyGPSPlus();
easySerial = new (std::nothrow) ESPeasySerial(port, serial_rx, serial_tx);
if (easySerial != nullptr) {
easySerial->begin(9600);
}
return isInitialized();
}
bool P082_data_struct::isInitialized() const {
return gps != nullptr && easySerial != nullptr;
}
bool P082_data_struct::loop() {
if (!isInitialized()) {
return false;
}
bool completeSentence = false;
if (easySerial != nullptr) {
int available = easySerial->available();
unsigned long startLoop = millis();
while (available > 0 && timePassedSince(startLoop) < 10) {
--available;
char c = easySerial->read();
# ifdef P082_SEND_GPS_TO_LOG
_currentSentence += c;
# endif // ifdef P082_SEND_GPS_TO_LOG
if (gps->encode(c)) {
// Full sentence received
# ifdef P082_SEND_GPS_TO_LOG
_lastSentence = _currentSentence;
_currentSentence = "";
# endif // ifdef P082_SEND_GPS_TO_LOG
completeSentence = true;
}
}
}
return completeSentence;
}
bool P082_data_struct::hasFix(unsigned int maxAge_msec) {
if (!isInitialized()) {
return false;
}
return gps->location.isValid() && gps->location.age() < maxAge_msec;
}
bool P082_data_struct::storeCurPos(unsigned int maxAge_msec) {
if (!hasFix(maxAge_msec)) {
return false;
}
_distance += distanceSinceLast(maxAge_msec);
_last_lat = gps->location.lat();
_last_lng = gps->location.lng();
return true;
}
// Return the distance in meters compared to last stored position.
// @retval -1 when no fix.
double P082_data_struct::distanceSinceLast(unsigned int maxAge_msec) {
if (!hasFix(maxAge_msec)) {
return -1.0;
}
if (((_last_lat < 0.0001) && (_last_lat > -0.0001)) || ((_last_lng < 0.0001) && (_last_lng > -0.0001))) {
return -1.0;
}
return gps->distanceBetween(_last_lat, _last_lng, gps->location.lat(), gps->location.lng());
}
// Return the GPS time stamp, which is in UTC.
// @param age is the time in msec since the last update of the time +
// additional centiseconds given by the GPS.
bool P082_data_struct::getDateTime(struct tm& dateTime, uint32_t& age, bool& pps_sync) {
if (!isInitialized()) {
return false;
}
if (_pps_time != 0) {
age = timePassedSince(_pps_time);
_pps_time = 0;
pps_sync = true;
if ((age > 1000) || (gps->time.age() > age)) {
return false;
}
} else {
age = gps->time.age();
pps_sync = false;
}
if (age > P082_TIMESTAMP_AGE) {
return false;
}
if (gps->date.age() > P082_TIMESTAMP_AGE) {
return false;
}
if (!gps->date.isValid() || !gps->time.isValid()) {
return false;
}
dateTime.tm_year = gps->date.year() - 1970;
dateTime.tm_mon = gps->date.month();
dateTime.tm_mday = gps->date.day();
dateTime.tm_hour = gps->time.hour();
dateTime.tm_min = gps->time.minute();
dateTime.tm_sec = gps->time.second();
// FIXME TD-er: Must the offset in centisecond be added when pps_sync active?
if (!pps_sync) {
age += (gps->time.centisecond() * 10);
}
return true;
}
#endif // ifdef USES_P082
+91
View File
@@ -0,0 +1,91 @@
#ifndef PLUGINSTRUCTS_P082_DATA_STRUCT_H
#define PLUGINSTRUCTS_P082_DATA_STRUCT_H
#include "../../_Plugin_Helper.h"
#include "../../ESPEasy_common.h"
#ifdef USES_P082
# include <TinyGPS++.h>
# include <ESPeasySerial.h>
# define P082_SEND_GPS_TO_LOG
# define P082_TIMESTAMP_AGE 1500
# define P082_DEFAULT_FIX_TIMEOUT 2500 // TTL of fix status in ms since last update
enum class P082_query : byte {
P082_QUERY_LONG = 0,
P082_QUERY_LAT = 1,
P082_QUERY_ALT = 2,
P082_QUERY_SPD = 3,
P082_QUERY_SATVIS = 4,
P082_QUERY_SATUSE = 5,
P082_QUERY_HDOP = 6,
P082_QUERY_FIXQ = 7,
P082_QUERY_DB_MAX = 8,
P082_QUERY_CHKSUM_FAIL = 9,
P082_QUERY_DISTANCE = 10,
P082_QUERY_DIST_REF = 11,
P082_NR_OUTPUT_OPTIONS
};
String Plugin_082_valuename(P082_query value_nr, bool displayString);
struct P082_data_struct : public PluginTaskData_base {
P082_data_struct();
~P082_data_struct();
void reset();
bool init(ESPEasySerialPort port,
const int16_t serial_rx,
const int16_t serial_tx);
bool isInitialized() const;
bool loop();
bool hasFix(unsigned int maxAge_msec);
bool storeCurPos(unsigned int maxAge_msec);
// Return the distance in meters compared to last stored position.
// @retval -1 when no fix.
double distanceSinceLast(unsigned int maxAge_msec);
// Return the GPS time stamp, which is in UTC.
// @param age is the time in msec since the last update of the time +
// additional centiseconds given by the GPS.
bool getDateTime(struct tm& dateTime,
uint32_t & age,
bool & pps_sync);
TinyGPSPlus *gps = nullptr;
ESPeasySerial *easySerial = nullptr;
double _last_lat = 0.0;
double _last_lng = 0.0;
double _ref_lat = 0.0;
double _ref_lng = 0.0;
double _distance = 0.0;
unsigned long _pps_time = 0;
unsigned long _last_measurement = 0;
# ifdef P082_SEND_GPS_TO_LOG
String _lastSentence;
String _currentSentence;
# endif // ifdef P082_SEND_GPS_TO_LOG
float _cache[static_cast<byte>(P082_query::P082_NR_OUTPUT_OPTIONS)] = { 0 };
};
#endif // ifdef USES_P082
#endif // ifndef PLUGINSTRUCTS_P082_DATA_STRUCT_H
+7 -2
View File
@@ -58,6 +58,8 @@ void DLBus::AddToErrorLog(const String& string)
void DLBus::attachDLBusInterrupt(void)
{
ISR_Receiving = false;
IsISRset = true;
IsNoData = false;
attachInterrupt(digitalPinToInterrupt(ISR_DLB_Pin), ISR, CHANGE);
}
@@ -80,9 +82,12 @@ void ICACHE_RAM_ATTR DLBus::ISR(void)
void ICACHE_RAM_ATTR DLBus::ISR_PinChanged(void)
{
long TimeDiff = usecPassedSince(ISR_TimeLastBitChange); // time difference to previous pulse in µs
// long TimeDiff = usecPassedSince(ISR_TimeLastBitChange); // time difference to previous pulse in µs
uint32_t _now = micros();
int32_t TimeDiff = (int32_t)(_now - ISR_TimeLastBitChange);
ISR_TimeLastBitChange = micros(); // save last pin change time
// ISR_TimeLastBitChange = micros(); // save last pin change time
ISR_TimeLastBitChange = _now; // save last pin change time
if (ISR_Receiving) {
uint8_t val = digitalRead(ISR_DLB_Pin); // read state
+2
View File
@@ -42,6 +42,8 @@ public:
uint8_t DeviceBytes[2] = { 0 };
uint8_t ByteStream[DLbus_MaxDataBits / 8 + 1]; // every bit gets sorted into a bitmap
boolean IsLogLevelInfo = false;
boolean IsNoData = false;
boolean IsISRset = false; // ISR set flag
uint8_t LogLevelInfo = 0xff;
uint8_t LogLevelError = 0xFF;
void attachDLBusInterrupt(void);
+1 -1
View File
@@ -91,7 +91,7 @@ input.wide, select.wide{
}
.widenumber{
max-width:500px;
width:100px
width:7em
}
.container,.container2{
font-size:12pt;
+1 -1
View File
File diff suppressed because one or more lines are too long