[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.
This commit is contained in:
TD-er
2020-10-15 03:14:20 +02:00
parent d0cdf7de42
commit 1e02509a80
7 changed files with 410 additions and 279 deletions
+10 -2
View File
@@ -21,8 +21,16 @@ 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 (header.valuecount === 7) {
return decode(bytes, [header, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8],
['header', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked']);
} else if (header.valuecount === 8) {
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
+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);
+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
+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
+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