Files
ESPEasy/src/src/PluginStructs/P082_data_struct.h
T

275 lines
8.8 KiB
C

#ifndef PLUGINSTRUCTS_P082_DATA_STRUCT_H
#define PLUGINSTRUCTS_P082_DATA_STRUCT_H
#include "../../_Plugin_Helper.h"
#ifdef USES_P082
# include <TinyGPS++.h>
# include <ESPeasySerial.h>
# include "../Helpers/ModuloOversamplingHelper.h"
# ifndef BUILD_NO_DEBUG
# define P082_SEND_GPS_TO_LOG
// # define P082_USE_U_BLOX_SPECIFIC // TD-er: Disabled for now, as it is not working reliable/predictable
# endif // ifndef BUILD_NO_DEBUG
# define P082_TIMESTAMP_AGE 1000
# define P082_DEFAULT_FIX_TIMEOUT 2500 // TTL of fix status in ms since last update
# 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_CONFIG_POS 3
# define P082_QUERY1 PCONFIG(3) // P082_QUERY1_CONFIG_POS
# define P082_QUERY2 PCONFIG(4) // P082_QUERY1_CONFIG_POS + 1
# define P082_QUERY3 PCONFIG(5) // P082_QUERY1_CONFIG_POS + 2
# define P082_QUERY4 PCONFIG(6) // P082_QUERY1_CONFIG_POS + 3
# define P082_LONG_REF PCONFIG_FLOAT(0)
# define P082_LAT_REF PCONFIG_FLOAT(1)
# ifdef P082_USE_U_BLOX_SPECIFIC
# define P082_POWER_MODE PCONFIG(7)
# define P082_DYNAMIC_MODEL PCONFIG_LONG(0)
# endif // P082_USE_U_BLOX_SPECIFIC
# define P082_NR_OUTPUT_VALUES VARS_PER_TASK
# 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
enum class P082_query : uint8_t {
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_QUERY_COURSE = 12,
P082_NR_OUTPUT_OPTIONS
};
const __FlashStringHelper* Plugin_082_valuename(P082_query value_nr,
bool displayString);
P082_query Plugin_082_from_valuename(const String& valuename);
enum class P082_PowerMode : uint8_t {
Max_Performance = 0,
Power_Save = 1,
Eco = 2
};
const __FlashStringHelper* toString(P082_PowerMode mode);
enum class P082_DynamicModel : uint8_t {
Portable = 0,
Stationary = 2,
Pedestrian = 3,
Automotive = 4,
Sea = 5,
Airborne_1g = 6, // airborne with <1g acceleration
Airborne_2g = 7, // airborne with <2g acceleration
Airborne_4g = 8, // airborne with <4g acceleration
Wrist = 9, // Only recommended for wrist-worn applications. Receiver will filter out armmotion (just available for protocol version
// > 17).
Bike = 10 // Used for applications with equivalent dynamics to those of a motor bike. Lowvertical acceleration assumed. (supported
// in protocol versions 19.2)
};
const __FlashStringHelper* toString(P082_DynamicModel model);
// Class to help determine the most likely fraction of a second
// when the burst of messages starts
// This fraction is relative to the system micros.
struct P082_software_pps {
P082_software_pps();
// Keep track of fraction of second relative to the system micros
// when the start of the sentence ('$') was received.
void addStartOfSentence(uint32_t bytesAvailableInSerialBuffer);
// Commit the last recorded start of sentence time to the
// matching ModuloOversamplingHelper
void setSentenceType(TinyGPSPlus::GPS_Sentence_type sentenceType, uint32_t bytesAvailableInSerialBuffer);
void setBaudrate(uint32_t baudrate);
// Search for the second fraction of the sentence
// starting the burst of sentences, marking the start of a second.
bool getPPS(uint32_t& second_frac_in_usec) const;
#ifndef BUILD_NO_DEBUG
String getStats() const;
#endif
private:
uint64_t bytesToUsec(uint32_t bytes) const;
ModuloOversamplingHelper<uint32_t, uint32_t>_second_frac_in_usec[TinyGPSPlus::GPS_SENTENCE_OTHER]{};
uint64_t _cur_start_sentence_usec = 0;
int32_t _baudrate = 0;
};
struct P082_data_struct : public PluginTaskData_base {
// Enum is being stored, so don't change int values
P082_data_struct();
virtual ~P082_data_struct();
// void reset();
bool init(ESPEasySerialPort port,
const int16_t serial_rx,
const int16_t serial_tx,
const int8_t pps_pin);
bool isInitialized() const {
return gps != nullptr && easySerial != nullptr;
}
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.
ESPEASY_RULES_FLOAT_TYPE distanceSinceLast(unsigned int maxAge_msec);
private:
// 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,
uint8_t & centiseconds,
uint32_t & age,
bool & updated);
public:
bool getDateTime(struct tm& dateTime) const;
// Try to fetch 5 timestamps in a row, filter out the peaks and use the average to set the
bool tryUpdateSystemTime();
// Send command to GPS to put it in PMREQ backup mode (UBLOX only)
// @retval true when successful in sending command
bool powerDown();
// Send some characters to GPS to wake up
bool wakeUp();
# ifdef P082_USE_U_BLOX_SPECIFIC
bool setPowerMode(P082_PowerMode mode);
bool setDynamicModel(P082_DynamicModel model);
# endif // ifdef P082_USE_U_BLOX_SPECIFIC
# if FEATURE_PLUGIN_STATS
bool webformLoad_show_stats(struct EventStruct *event,
uint8_t var_index,
P082_query query_type) const;
# if FEATURE_CHART_JS
void webformLoad_show_position_scatterplot(struct EventStruct *event);
# endif // if FEATURE_CHART_JS
# endif // if FEATURE_PLUGIN_STATS
#ifndef BUILD_NO_DEBUG
String getPPSStats() const;
#endif
private:
# ifdef P082_USE_U_BLOX_SPECIFIC
// Compute checksum
// Caller should offset the data pointer to the correct start where the CRC should start.
// @param size The length over which the CRC should be computed
// @param CK_A, CK_B The 2 checksum bytes.
static void computeUbloxChecksum(const uint8_t *data,
size_t size,
uint8_t & CK_A,
uint8_t & CK_B);
// Set checksum.
// First 2 bytes of the array are skipped
static void setUbloxChecksum(uint8_t *data,
size_t size);
# endif // ifdef P082_USE_U_BLOX_SPECIFIC
bool writeToGPS(const uint8_t *data,
size_t size);
static void pps_interrupt(P082_data_struct *self);
public:
TinyGPSPlus *gps = nullptr;
ESPeasySerial *easySerial = nullptr;
ESPEASY_RULES_FLOAT_TYPE _last_lat{};
ESPEASY_RULES_FLOAT_TYPE _last_lng{};
ESPEASY_RULES_FLOAT_TYPE _ref_lat{};
ESPEASY_RULES_FLOAT_TYPE _ref_lng{};
ESPEASY_RULES_FLOAT_TYPE _distance{};
unsigned long _last_measurement = 0;
uint32_t _last_time = 0;
uint32_t _last_date = 0;
// uint32_t _start_sentence = 0;
// uint32_t _start_prev_sentence = 0;
// uint32_t _start_sequence = 0;
# ifdef P082_SEND_GPS_TO_LOG
String _lastSentence;
String _currentSentence;
# endif // ifdef P082_SEND_GPS_TO_LOG
float _cache[static_cast<uint8_t>(P082_query::P082_NR_OUTPUT_OPTIONS)]{};
OversamplingHelper<uint64_t, uint64_t>_oversampling_gps_time_offset_usec;
P082_software_pps _softwarePPS;
// When using PPS pin, we're only interested in the moment during a second when it triggers.
// So we keep only track of the micros() % 1000000 so we have some offset from the system micros counter.
// This will also be used to keep track of when the first sentence is received as the GPS will send those out in a burst at the start of a
// new second.
ESPEASY_VOLATILE(int64_t) _pps_time_micros = -1;
int8_t _ppsPin = -1;
};
#endif // ifdef USES_P082
#endif // ifndef PLUGINSTRUCTS_P082_DATA_STRUCT_H