mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-30 05:32:08 +00:00
add a .clang-format file (#9154)
This commit is contained in:
@@ -41,25 +41,24 @@ JSON::JSON() {}
|
||||
*
|
||||
* @return JSONValue* Returns a JSON Value representing the root, or NULL on error
|
||||
*/
|
||||
JSONValue *JSON::Parse(const char *data)
|
||||
{
|
||||
// Skip any preceding whitespace, end of data = no JSON = fail
|
||||
if (!SkipWhitespace(&data))
|
||||
return NULL;
|
||||
JSONValue *JSON::Parse(const char *data) {
|
||||
// Skip any preceding whitespace, end of data = no JSON = fail
|
||||
if (!SkipWhitespace(&data))
|
||||
return NULL;
|
||||
|
||||
// We need the start of a value here now...
|
||||
JSONValue *value = JSONValue::Parse(&data);
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
// We need the start of a value here now...
|
||||
JSONValue *value = JSONValue::Parse(&data);
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
|
||||
// Can be white space now and should be at the end of the string then...
|
||||
if (SkipWhitespace(&data)) {
|
||||
delete value;
|
||||
return NULL;
|
||||
}
|
||||
// Can be white space now and should be at the end of the string then...
|
||||
if (SkipWhitespace(&data)) {
|
||||
delete value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We're now at the end of the string
|
||||
return value;
|
||||
// We're now at the end of the string
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,12 +70,11 @@ JSONValue *JSON::Parse(const char *data)
|
||||
*
|
||||
* @return std::string Returns a JSON encoded string representation of the given value
|
||||
*/
|
||||
std::string JSON::Stringify(const JSONValue *value)
|
||||
{
|
||||
if (value != NULL)
|
||||
return value->Stringify();
|
||||
else
|
||||
return "";
|
||||
std::string JSON::Stringify(const JSONValue *value) {
|
||||
if (value != NULL)
|
||||
return value->Stringify();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,12 +86,11 @@ std::string JSON::Stringify(const JSONValue *value)
|
||||
*
|
||||
* @return bool Returns true if there is more data, or false if the end of the text was reached
|
||||
*/
|
||||
bool JSON::SkipWhitespace(const char **data)
|
||||
{
|
||||
while (**data != 0 && (**data == ' ' || **data == '\t' || **data == '\r' || **data == '\n'))
|
||||
(*data)++;
|
||||
bool JSON::SkipWhitespace(const char **data) {
|
||||
while (**data != 0 && (**data == ' ' || **data == '\t' || **data == '\r' || **data == '\n'))
|
||||
(*data)++;
|
||||
|
||||
return **data != 0;
|
||||
return **data != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,102 +104,101 @@ bool JSON::SkipWhitespace(const char **data)
|
||||
*
|
||||
* @return bool Returns true on success, false on failure
|
||||
*/
|
||||
bool JSON::ExtractString(const char **data, std::string &str)
|
||||
{
|
||||
str = "";
|
||||
bool JSON::ExtractString(const char **data, std::string &str) {
|
||||
str = "";
|
||||
|
||||
while (**data != 0) {
|
||||
// Save the char so we can change it if need be
|
||||
char next_char = **data;
|
||||
while (**data != 0) {
|
||||
// Save the char so we can change it if need be
|
||||
char next_char = **data;
|
||||
|
||||
// Escaping something?
|
||||
if (next_char == '\\') {
|
||||
// Move over the escape char
|
||||
(*data)++;
|
||||
// Escaping something?
|
||||
if (next_char == '\\') {
|
||||
// Move over the escape char
|
||||
(*data)++;
|
||||
|
||||
// Deal with the escaped char
|
||||
switch (**data) {
|
||||
case '"':
|
||||
next_char = '"';
|
||||
break;
|
||||
case '\\':
|
||||
next_char = '\\';
|
||||
break;
|
||||
case '/':
|
||||
next_char = '/';
|
||||
break;
|
||||
case 'b':
|
||||
next_char = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
next_char = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
next_char = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
next_char = '\r';
|
||||
break;
|
||||
case 't':
|
||||
next_char = '\t';
|
||||
break;
|
||||
case 'u': {
|
||||
// We need 5 chars (4 hex + the 'u') or its not valid
|
||||
if (!simplejson_csnlen(*data, 5))
|
||||
return false;
|
||||
// Deal with the escaped char
|
||||
switch (**data) {
|
||||
case '"':
|
||||
next_char = '"';
|
||||
break;
|
||||
case '\\':
|
||||
next_char = '\\';
|
||||
break;
|
||||
case '/':
|
||||
next_char = '/';
|
||||
break;
|
||||
case 'b':
|
||||
next_char = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
next_char = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
next_char = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
next_char = '\r';
|
||||
break;
|
||||
case 't':
|
||||
next_char = '\t';
|
||||
break;
|
||||
case 'u': {
|
||||
// We need 5 chars (4 hex + the 'u') or its not valid
|
||||
if (!simplejson_csnlen(*data, 5))
|
||||
return false;
|
||||
|
||||
// Deal with the chars
|
||||
next_char = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// Do it first to move off the 'u' and leave us on the
|
||||
// final hex digit as we move on by one later on
|
||||
(*data)++;
|
||||
// Deal with the chars
|
||||
next_char = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// Do it first to move off the 'u' and leave us on the
|
||||
// final hex digit as we move on by one later on
|
||||
(*data)++;
|
||||
|
||||
next_char <<= 4;
|
||||
next_char <<= 4;
|
||||
|
||||
// Parse the hex digit
|
||||
if (**data >= '0' && **data <= '9')
|
||||
next_char |= (**data - '0');
|
||||
else if (**data >= 'A' && **data <= 'F')
|
||||
next_char |= (10 + (**data - 'A'));
|
||||
else if (**data >= 'a' && **data <= 'f')
|
||||
next_char |= (10 + (**data - 'a'));
|
||||
else {
|
||||
// Invalid hex digit = invalid JSON
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// By the spec, only the above cases are allowed
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// End of the string?
|
||||
else if (next_char == '"') {
|
||||
(*data)++;
|
||||
str.shrink_to_fit(); // Remove unused capacity
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disallowed char?
|
||||
else if (next_char < ' ' && next_char != '\t') {
|
||||
// SPEC Violation: Allow tabs due to real world cases
|
||||
// Parse the hex digit
|
||||
if (**data >= '0' && **data <= '9')
|
||||
next_char |= (**data - '0');
|
||||
else if (**data >= 'A' && **data <= 'F')
|
||||
next_char |= (10 + (**data - 'A'));
|
||||
else if (**data >= 'a' && **data <= 'f')
|
||||
next_char |= (10 + (**data - 'a'));
|
||||
else {
|
||||
// Invalid hex digit = invalid JSON
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the next char
|
||||
str += next_char;
|
||||
|
||||
// Move on
|
||||
(*data)++;
|
||||
// By the spec, only the above cases are allowed
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're here, the string ended incorrectly
|
||||
return false;
|
||||
// End of the string?
|
||||
else if (next_char == '"') {
|
||||
(*data)++;
|
||||
str.shrink_to_fit(); // Remove unused capacity
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disallowed char?
|
||||
else if (next_char < ' ' && next_char != '\t') {
|
||||
// SPEC Violation: Allow tabs due to real world cases
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the next char
|
||||
str += next_char;
|
||||
|
||||
// Move on
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// If we're here, the string ended incorrectly
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,13 +210,12 @@ bool JSON::ExtractString(const char **data, std::string &str)
|
||||
*
|
||||
* @return double Returns the double value of the number found
|
||||
*/
|
||||
double JSON::ParseInt(const char **data)
|
||||
{
|
||||
double integer = 0;
|
||||
while (**data != 0 && **data >= '0' && **data <= '9')
|
||||
integer = integer * 10 + (*(*data)++ - '0');
|
||||
double JSON::ParseInt(const char **data) {
|
||||
double integer = 0;
|
||||
while (**data != 0 && **data >= '0' && **data <= '9')
|
||||
integer = integer * 10 + (*(*data)++ - '0');
|
||||
|
||||
return integer;
|
||||
return integer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,14 +227,13 @@ double JSON::ParseInt(const char **data)
|
||||
*
|
||||
* @return double Returns the double value of the decimal found
|
||||
*/
|
||||
double JSON::ParseDecimal(const char **data)
|
||||
{
|
||||
double decimal = 0.0;
|
||||
double factor = 0.1;
|
||||
while (**data != 0 && **data >= '0' && **data <= '9') {
|
||||
int digit = (*(*data)++ - '0');
|
||||
decimal = decimal + digit * factor;
|
||||
factor *= 0.1;
|
||||
}
|
||||
return decimal;
|
||||
double JSON::ParseDecimal(const char **data) {
|
||||
double decimal = 0.0;
|
||||
double factor = 0.1;
|
||||
while (**data != 0 && **data >= '0' && **data <= '9') {
|
||||
int digit = (*(*data)++ - '0');
|
||||
decimal = decimal + digit * factor;
|
||||
factor *= 0.1;
|
||||
}
|
||||
return decimal;
|
||||
}
|
||||
|
||||
@@ -31,18 +31,17 @@
|
||||
#include <vector>
|
||||
|
||||
// Simple function to check a string 's' has at least 'n' characters
|
||||
static inline bool simplejson_csnlen(const char *s, size_t n)
|
||||
{
|
||||
if (s == 0)
|
||||
return false;
|
||||
static inline bool simplejson_csnlen(const char *s, size_t n) {
|
||||
if (s == 0)
|
||||
return false;
|
||||
|
||||
const char *save = s;
|
||||
while (n-- > 0) {
|
||||
if (*(save++) == 0)
|
||||
return false;
|
||||
}
|
||||
const char *save = s;
|
||||
while (n-- > 0) {
|
||||
if (*(save++) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Custom types
|
||||
@@ -52,22 +51,21 @@ typedef std::map<std::string, JSONValue *> JSONObject;
|
||||
|
||||
#include "JSONValue.h"
|
||||
|
||||
class JSON
|
||||
{
|
||||
friend class JSONValue;
|
||||
class JSON {
|
||||
friend class JSONValue;
|
||||
|
||||
public:
|
||||
static JSONValue *Parse(const char *data);
|
||||
static std::string Stringify(const JSONValue *value);
|
||||
public:
|
||||
static JSONValue *Parse(const char *data);
|
||||
static std::string Stringify(const JSONValue *value);
|
||||
|
||||
protected:
|
||||
static bool SkipWhitespace(const char **data);
|
||||
static bool ExtractString(const char **data, std::string &str);
|
||||
static double ParseInt(const char **data);
|
||||
static double ParseDecimal(const char **data);
|
||||
protected:
|
||||
static bool SkipWhitespace(const char **data);
|
||||
static bool ExtractString(const char **data, std::string &str);
|
||||
static double ParseInt(const char **data);
|
||||
static double ParseDecimal(const char **data);
|
||||
|
||||
private:
|
||||
JSON();
|
||||
private:
|
||||
JSON();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,62 +34,61 @@ class JSON;
|
||||
|
||||
enum JSONType { JSONType_Null, JSONType_String, JSONType_Bool, JSONType_Number, JSONType_Array, JSONType_Object };
|
||||
|
||||
class JSONValue
|
||||
{
|
||||
friend class JSON;
|
||||
class JSONValue {
|
||||
friend class JSON;
|
||||
|
||||
public:
|
||||
JSONValue(/*NULL*/);
|
||||
explicit JSONValue(const char *m_char_value);
|
||||
explicit JSONValue(const std::string &m_string_value);
|
||||
explicit JSONValue(bool m_bool_value);
|
||||
explicit JSONValue(double m_number_value);
|
||||
explicit JSONValue(int m_integer_value);
|
||||
explicit JSONValue(unsigned int m_integer_value);
|
||||
explicit JSONValue(const JSONArray &m_array_value);
|
||||
explicit JSONValue(const JSONObject &m_object_value);
|
||||
explicit JSONValue(const JSONValue &m_source);
|
||||
~JSONValue();
|
||||
public:
|
||||
JSONValue(/*NULL*/);
|
||||
explicit JSONValue(const char *m_char_value);
|
||||
explicit JSONValue(const std::string &m_string_value);
|
||||
explicit JSONValue(bool m_bool_value);
|
||||
explicit JSONValue(double m_number_value);
|
||||
explicit JSONValue(int m_integer_value);
|
||||
explicit JSONValue(unsigned int m_integer_value);
|
||||
explicit JSONValue(const JSONArray &m_array_value);
|
||||
explicit JSONValue(const JSONObject &m_object_value);
|
||||
explicit JSONValue(const JSONValue &m_source);
|
||||
~JSONValue();
|
||||
|
||||
bool IsNull() const;
|
||||
bool IsString() const;
|
||||
bool IsBool() const;
|
||||
bool IsNumber() const;
|
||||
bool IsArray() const;
|
||||
bool IsObject() const;
|
||||
bool IsNull() const;
|
||||
bool IsString() const;
|
||||
bool IsBool() const;
|
||||
bool IsNumber() const;
|
||||
bool IsArray() const;
|
||||
bool IsObject() const;
|
||||
|
||||
const std::string &AsString() const;
|
||||
bool AsBool() const;
|
||||
double AsNumber() const;
|
||||
const JSONArray &AsArray() const;
|
||||
const JSONObject &AsObject() const;
|
||||
const std::string &AsString() const;
|
||||
bool AsBool() const;
|
||||
double AsNumber() const;
|
||||
const JSONArray &AsArray() const;
|
||||
const JSONObject &AsObject() const;
|
||||
|
||||
std::size_t CountChildren() const;
|
||||
bool HasChild(std::size_t index) const;
|
||||
JSONValue *Child(std::size_t index);
|
||||
bool HasChild(const char *name) const;
|
||||
JSONValue *Child(const char *name);
|
||||
std::vector<std::string> ObjectKeys() const;
|
||||
std::size_t CountChildren() const;
|
||||
bool HasChild(std::size_t index) const;
|
||||
JSONValue *Child(std::size_t index);
|
||||
bool HasChild(const char *name) const;
|
||||
JSONValue *Child(const char *name);
|
||||
std::vector<std::string> ObjectKeys() const;
|
||||
|
||||
std::string Stringify(bool const prettyprint = false) const;
|
||||
std::string Stringify(bool const prettyprint = false) const;
|
||||
|
||||
protected:
|
||||
static JSONValue *Parse(const char **data);
|
||||
protected:
|
||||
static JSONValue *Parse(const char **data);
|
||||
|
||||
private:
|
||||
static std::string StringifyString(const std::string &str);
|
||||
std::string StringifyImpl(size_t const indentDepth) const;
|
||||
static std::string Indent(size_t depth);
|
||||
private:
|
||||
static std::string StringifyString(const std::string &str);
|
||||
std::string StringifyImpl(size_t const indentDepth) const;
|
||||
static std::string Indent(size_t depth);
|
||||
|
||||
JSONType type;
|
||||
JSONType type;
|
||||
|
||||
union {
|
||||
bool bool_value;
|
||||
double number_value;
|
||||
std::string *string_value;
|
||||
JSONArray *array_value;
|
||||
JSONObject *object_value;
|
||||
};
|
||||
union {
|
||||
bool bool_value;
|
||||
double number_value;
|
||||
std::string *string_value;
|
||||
JSONArray *array_value;
|
||||
JSONObject *object_value;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -15,456 +15,447 @@
|
||||
|
||||
static const char *errStr = "Error decoding proto for %s message!";
|
||||
|
||||
std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog)
|
||||
{
|
||||
// the created jsonObj is immutable after creation, so
|
||||
// we need to do the heavy lifting before assembling it.
|
||||
std::string msgType;
|
||||
JSONObject jsonObj;
|
||||
std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog) {
|
||||
// the created jsonObj is immutable after creation, so
|
||||
// we need to do the heavy lifting before assembling it.
|
||||
std::string msgType;
|
||||
JSONObject jsonObj;
|
||||
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
JSONObject msgPayload;
|
||||
switch (mp->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
|
||||
msgType = "text";
|
||||
// convert bytes to string
|
||||
if (shouldLog)
|
||||
LOG_DEBUG("got text message of size %u", mp->decoded.payload.size);
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
JSONObject msgPayload;
|
||||
switch (mp->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
|
||||
msgType = "text";
|
||||
// convert bytes to string
|
||||
if (shouldLog)
|
||||
LOG_DEBUG("got text message of size %u", mp->decoded.payload.size);
|
||||
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
// check if this is a JSON payload
|
||||
JSONValue *json_value = JSON::Parse(payloadStr);
|
||||
if (json_value != NULL) {
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type json");
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
// check if this is a JSON payload
|
||||
JSONValue *json_value = JSON::Parse(payloadStr);
|
||||
if (json_value != NULL) {
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type json");
|
||||
|
||||
// if it is, then we can just use the json object
|
||||
jsonObj["payload"] = json_value;
|
||||
} else {
|
||||
// if it isn't, then we need to create a json object
|
||||
// with the string as the value
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type plaintext");
|
||||
// if it is, then we can just use the json object
|
||||
jsonObj["payload"] = json_value;
|
||||
} else {
|
||||
// if it isn't, then we need to create a json object
|
||||
// with the string as the value
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type plaintext");
|
||||
|
||||
msgPayload["text"] = new JSONValue(payloadStr);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
}
|
||||
break;
|
||||
msgPayload["text"] = new JSONValue(payloadStr);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_TELEMETRY_APP: {
|
||||
msgType = "telemetry";
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||
// If battery is present, encode the battery level value
|
||||
// TODO - Add a condition to send a code for a non-present value
|
||||
if (decoded->variant.device_metrics.has_battery_level) {
|
||||
msgPayload["battery_level"] = new JSONValue((int)decoded->variant.device_metrics.battery_level);
|
||||
}
|
||||
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
|
||||
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
|
||||
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
|
||||
msgPayload["uptime_seconds"] = new JSONValue((unsigned int)decoded->variant.device_metrics.uptime_seconds);
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
|
||||
// Avoid sending 0s for sensors that could be 0
|
||||
if (decoded->variant.environment_metrics.has_temperature) {
|
||||
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_relative_humidity) {
|
||||
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_barometric_pressure) {
|
||||
msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_gas_resistance) {
|
||||
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_voltage) {
|
||||
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_current) {
|
||||
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_lux) {
|
||||
msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_white_lux) {
|
||||
msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_iaq) {
|
||||
msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_distance) {
|
||||
msgPayload["distance"] = new JSONValue(decoded->variant.environment_metrics.distance);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_speed) {
|
||||
msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_direction) {
|
||||
msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_gust) {
|
||||
msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_lull) {
|
||||
msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_radiation) {
|
||||
msgPayload["radiation"] = new JSONValue(decoded->variant.environment_metrics.radiation);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_ir_lux) {
|
||||
msgPayload["ir_lux"] = new JSONValue(decoded->variant.environment_metrics.ir_lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_uv_lux) {
|
||||
msgPayload["uv_lux"] = new JSONValue(decoded->variant.environment_metrics.uv_lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_weight) {
|
||||
msgPayload["weight"] = new JSONValue(decoded->variant.environment_metrics.weight);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_rainfall_1h) {
|
||||
msgPayload["rainfall_1h"] = new JSONValue(decoded->variant.environment_metrics.rainfall_1h);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_rainfall_24h) {
|
||||
msgPayload["rainfall_24h"] = new JSONValue(decoded->variant.environment_metrics.rainfall_24h);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_soil_moisture) {
|
||||
msgPayload["soil_moisture"] = new JSONValue((uint)decoded->variant.environment_metrics.soil_moisture);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_soil_temperature) {
|
||||
msgPayload["soil_temperature"] = new JSONValue(decoded->variant.environment_metrics.soil_temperature);
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_standard) {
|
||||
msgPayload["pm10"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_standard);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_standard) {
|
||||
msgPayload["pm25"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_standard);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_standard) {
|
||||
msgPayload["pm100"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm100_standard);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_environmental) {
|
||||
msgPayload["pm10_e"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_environmental);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_environmental) {
|
||||
msgPayload["pm25_e"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_environmental);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_environmental) {
|
||||
msgPayload["pm100_e"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm100_environmental);
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
|
||||
if (decoded->variant.power_metrics.has_ch1_voltage) {
|
||||
msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch1_current) {
|
||||
msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_voltage) {
|
||||
msgPayload["voltage_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_voltage);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_current) {
|
||||
msgPayload["current_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_current);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_voltage) {
|
||||
msgPayload["voltage_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_voltage);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_current) {
|
||||
msgPayload["current_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_current);
|
||||
}
|
||||
}
|
||||
case meshtastic_PortNum_TELEMETRY_APP: {
|
||||
msgType = "telemetry";
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||
// If battery is present, encode the battery level value
|
||||
// TODO - Add a condition to send a code for a non-present value
|
||||
if (decoded->variant.device_metrics.has_battery_level) {
|
||||
msgPayload["battery_level"] = new JSONValue((int)decoded->variant.device_metrics.battery_level);
|
||||
}
|
||||
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
|
||||
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
|
||||
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
|
||||
msgPayload["uptime_seconds"] = new JSONValue((unsigned int)decoded->variant.device_metrics.uptime_seconds);
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
|
||||
// Avoid sending 0s for sensors that could be 0
|
||||
if (decoded->variant.environment_metrics.has_temperature) {
|
||||
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_relative_humidity) {
|
||||
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_barometric_pressure) {
|
||||
msgPayload["barometric_pressure"] =
|
||||
new JSONValue(decoded->variant.environment_metrics.barometric_pressure);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_gas_resistance) {
|
||||
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_voltage) {
|
||||
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_current) {
|
||||
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_lux) {
|
||||
msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_white_lux) {
|
||||
msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_iaq) {
|
||||
msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_distance) {
|
||||
msgPayload["distance"] = new JSONValue(decoded->variant.environment_metrics.distance);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_speed) {
|
||||
msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_direction) {
|
||||
msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_gust) {
|
||||
msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_lull) {
|
||||
msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_radiation) {
|
||||
msgPayload["radiation"] = new JSONValue(decoded->variant.environment_metrics.radiation);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_ir_lux) {
|
||||
msgPayload["ir_lux"] = new JSONValue(decoded->variant.environment_metrics.ir_lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_uv_lux) {
|
||||
msgPayload["uv_lux"] = new JSONValue(decoded->variant.environment_metrics.uv_lux);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_weight) {
|
||||
msgPayload["weight"] = new JSONValue(decoded->variant.environment_metrics.weight);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_rainfall_1h) {
|
||||
msgPayload["rainfall_1h"] = new JSONValue(decoded->variant.environment_metrics.rainfall_1h);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_rainfall_24h) {
|
||||
msgPayload["rainfall_24h"] = new JSONValue(decoded->variant.environment_metrics.rainfall_24h);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_soil_moisture) {
|
||||
msgPayload["soil_moisture"] = new JSONValue((uint)decoded->variant.environment_metrics.soil_moisture);
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_soil_temperature) {
|
||||
msgPayload["soil_temperature"] = new JSONValue(decoded->variant.environment_metrics.soil_temperature);
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_standard) {
|
||||
msgPayload["pm10"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_standard);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_standard) {
|
||||
msgPayload["pm25"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_standard);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_standard) {
|
||||
msgPayload["pm100"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm100_standard);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_environmental) {
|
||||
msgPayload["pm10_e"] =
|
||||
new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_environmental);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_environmental) {
|
||||
msgPayload["pm25_e"] =
|
||||
new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_environmental);
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_environmental) {
|
||||
msgPayload["pm100_e"] =
|
||||
new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm100_environmental);
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
|
||||
if (decoded->variant.power_metrics.has_ch1_voltage) {
|
||||
msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch1_current) {
|
||||
msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_voltage) {
|
||||
msgPayload["voltage_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_voltage);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_current) {
|
||||
msgPayload["current_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_current);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_voltage) {
|
||||
msgPayload["voltage_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_voltage);
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_current) {
|
||||
msgPayload["current_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_current);
|
||||
}
|
||||
}
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_NODEINFO_APP: {
|
||||
msgType = "nodeinfo";
|
||||
meshtastic_User scratch;
|
||||
meshtastic_User *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["id"] = new JSONValue(decoded->id);
|
||||
msgPayload["longname"] = new JSONValue(decoded->long_name);
|
||||
msgPayload["shortname"] = new JSONValue(decoded->short_name);
|
||||
msgPayload["hardware"] = new JSONValue(decoded->hw_model);
|
||||
msgPayload["role"] = new JSONValue((int)decoded->role);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_POSITION_APP: {
|
||||
msgType = "position";
|
||||
meshtastic_Position scratch;
|
||||
meshtastic_Position *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if ((int)decoded->time) {
|
||||
msgPayload["time"] = new JSONValue((unsigned int)decoded->time);
|
||||
}
|
||||
case meshtastic_PortNum_NODEINFO_APP: {
|
||||
msgType = "nodeinfo";
|
||||
meshtastic_User scratch;
|
||||
meshtastic_User *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["id"] = new JSONValue(decoded->id);
|
||||
msgPayload["longname"] = new JSONValue(decoded->long_name);
|
||||
msgPayload["shortname"] = new JSONValue(decoded->short_name);
|
||||
msgPayload["hardware"] = new JSONValue(decoded->hw_model);
|
||||
msgPayload["role"] = new JSONValue((int)decoded->role);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
if ((int)decoded->timestamp) {
|
||||
msgPayload["timestamp"] = new JSONValue((unsigned int)decoded->timestamp);
|
||||
}
|
||||
case meshtastic_PortNum_POSITION_APP: {
|
||||
msgType = "position";
|
||||
meshtastic_Position scratch;
|
||||
meshtastic_Position *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if ((int)decoded->time) {
|
||||
msgPayload["time"] = new JSONValue((unsigned int)decoded->time);
|
||||
}
|
||||
if ((int)decoded->timestamp) {
|
||||
msgPayload["timestamp"] = new JSONValue((unsigned int)decoded->timestamp);
|
||||
}
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
if ((int)decoded->altitude) {
|
||||
msgPayload["altitude"] = new JSONValue((int)decoded->altitude);
|
||||
}
|
||||
if ((int)decoded->ground_speed) {
|
||||
msgPayload["ground_speed"] = new JSONValue((unsigned int)decoded->ground_speed);
|
||||
}
|
||||
if (int(decoded->ground_track)) {
|
||||
msgPayload["ground_track"] = new JSONValue((unsigned int)decoded->ground_track);
|
||||
}
|
||||
if (int(decoded->sats_in_view)) {
|
||||
msgPayload["sats_in_view"] = new JSONValue((unsigned int)decoded->sats_in_view);
|
||||
}
|
||||
if ((int)decoded->PDOP) {
|
||||
msgPayload["PDOP"] = new JSONValue((int)decoded->PDOP);
|
||||
}
|
||||
if ((int)decoded->HDOP) {
|
||||
msgPayload["HDOP"] = new JSONValue((int)decoded->HDOP);
|
||||
}
|
||||
if ((int)decoded->VDOP) {
|
||||
msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP);
|
||||
}
|
||||
if ((int)decoded->precision_bits) {
|
||||
msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits);
|
||||
}
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
if ((int)decoded->altitude) {
|
||||
msgPayload["altitude"] = new JSONValue((int)decoded->altitude);
|
||||
}
|
||||
case meshtastic_PortNum_WAYPOINT_APP: {
|
||||
msgType = "waypoint";
|
||||
meshtastic_Waypoint scratch;
|
||||
meshtastic_Waypoint *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["id"] = new JSONValue((unsigned int)decoded->id);
|
||||
msgPayload["name"] = new JSONValue(decoded->name);
|
||||
msgPayload["description"] = new JSONValue(decoded->description);
|
||||
msgPayload["expire"] = new JSONValue((unsigned int)decoded->expire);
|
||||
msgPayload["locked_to"] = new JSONValue((unsigned int)decoded->locked_to);
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
if ((int)decoded->ground_speed) {
|
||||
msgPayload["ground_speed"] = new JSONValue((unsigned int)decoded->ground_speed);
|
||||
}
|
||||
case meshtastic_PortNum_NEIGHBORINFO_APP: {
|
||||
msgType = "neighborinfo";
|
||||
meshtastic_NeighborInfo scratch;
|
||||
meshtastic_NeighborInfo *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
|
||||
&scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["node_id"] = new JSONValue((unsigned int)decoded->node_id);
|
||||
msgPayload["node_broadcast_interval_secs"] = new JSONValue((unsigned int)decoded->node_broadcast_interval_secs);
|
||||
msgPayload["last_sent_by_id"] = new JSONValue((unsigned int)decoded->last_sent_by_id);
|
||||
msgPayload["neighbors_count"] = new JSONValue(decoded->neighbors_count);
|
||||
JSONArray neighbors;
|
||||
for (uint8_t i = 0; i < decoded->neighbors_count; i++) {
|
||||
JSONObject neighborObj;
|
||||
neighborObj["node_id"] = new JSONValue((unsigned int)decoded->neighbors[i].node_id);
|
||||
neighborObj["snr"] = new JSONValue((int)decoded->neighbors[i].snr);
|
||||
neighbors.push_back(new JSONValue(neighborObj));
|
||||
}
|
||||
msgPayload["neighbors"] = new JSONValue(neighbors);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
if (int(decoded->ground_track)) {
|
||||
msgPayload["ground_track"] = new JSONValue((unsigned int)decoded->ground_track);
|
||||
}
|
||||
case meshtastic_PortNum_TRACEROUTE_APP: {
|
||||
if (mp->decoded.request_id) { // Only report the traceroute response
|
||||
msgType = "traceroute";
|
||||
meshtastic_RouteDiscovery scratch;
|
||||
meshtastic_RouteDiscovery *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg,
|
||||
&scratch)) {
|
||||
decoded = &scratch;
|
||||
JSONArray route; // Route this message took
|
||||
JSONArray routeBack; // Route this message took back
|
||||
JSONArray snrTowards; // Snr for forward route
|
||||
JSONArray snrBack; // Snr for reverse route
|
||||
if (int(decoded->sats_in_view)) {
|
||||
msgPayload["sats_in_view"] = new JSONValue((unsigned int)decoded->sats_in_view);
|
||||
}
|
||||
if ((int)decoded->PDOP) {
|
||||
msgPayload["PDOP"] = new JSONValue((int)decoded->PDOP);
|
||||
}
|
||||
if ((int)decoded->HDOP) {
|
||||
msgPayload["HDOP"] = new JSONValue((int)decoded->HDOP);
|
||||
}
|
||||
if ((int)decoded->VDOP) {
|
||||
msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP);
|
||||
}
|
||||
if ((int)decoded->precision_bits) {
|
||||
msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits);
|
||||
}
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_WAYPOINT_APP: {
|
||||
msgType = "waypoint";
|
||||
meshtastic_Waypoint scratch;
|
||||
meshtastic_Waypoint *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["id"] = new JSONValue((unsigned int)decoded->id);
|
||||
msgPayload["name"] = new JSONValue(decoded->name);
|
||||
msgPayload["description"] = new JSONValue(decoded->description);
|
||||
msgPayload["expire"] = new JSONValue((unsigned int)decoded->expire);
|
||||
msgPayload["locked_to"] = new JSONValue((unsigned int)decoded->locked_to);
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_NEIGHBORINFO_APP: {
|
||||
msgType = "neighborinfo";
|
||||
meshtastic_NeighborInfo scratch;
|
||||
meshtastic_NeighborInfo *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["node_id"] = new JSONValue((unsigned int)decoded->node_id);
|
||||
msgPayload["node_broadcast_interval_secs"] = new JSONValue((unsigned int)decoded->node_broadcast_interval_secs);
|
||||
msgPayload["last_sent_by_id"] = new JSONValue((unsigned int)decoded->last_sent_by_id);
|
||||
msgPayload["neighbors_count"] = new JSONValue(decoded->neighbors_count);
|
||||
JSONArray neighbors;
|
||||
for (uint8_t i = 0; i < decoded->neighbors_count; i++) {
|
||||
JSONObject neighborObj;
|
||||
neighborObj["node_id"] = new JSONValue((unsigned int)decoded->neighbors[i].node_id);
|
||||
neighborObj["snr"] = new JSONValue((int)decoded->neighbors[i].snr);
|
||||
neighbors.push_back(new JSONValue(neighborObj));
|
||||
}
|
||||
msgPayload["neighbors"] = new JSONValue(neighbors);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_TRACEROUTE_APP: {
|
||||
if (mp->decoded.request_id) { // Only report the traceroute response
|
||||
msgType = "traceroute";
|
||||
meshtastic_RouteDiscovery scratch;
|
||||
meshtastic_RouteDiscovery *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
JSONArray route; // Route this message took
|
||||
JSONArray routeBack; // Route this message took back
|
||||
JSONArray snrTowards; // Snr for forward route
|
||||
JSONArray snrBack; // Snr for reverse route
|
||||
|
||||
// Lambda function for adding a long name to the route
|
||||
auto addToRoute = [](JSONArray *route, NodeNum num) {
|
||||
char long_name[40] = "Unknown";
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
|
||||
bool name_known = node ? node->has_user : false;
|
||||
if (name_known)
|
||||
memcpy(long_name, node->user.long_name, sizeof(long_name));
|
||||
route->push_back(new JSONValue(long_name));
|
||||
};
|
||||
addToRoute(&route, mp->to); // Started at the original transmitter (destination of response)
|
||||
for (uint8_t i = 0; i < decoded->route_count; i++) {
|
||||
addToRoute(&route, decoded->route[i]);
|
||||
}
|
||||
addToRoute(&route, mp->from); // Ended at the original destination (source of response)
|
||||
// Lambda function for adding a long name to the route
|
||||
auto addToRoute = [](JSONArray *route, NodeNum num) {
|
||||
char long_name[40] = "Unknown";
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
|
||||
bool name_known = node ? node->has_user : false;
|
||||
if (name_known)
|
||||
memcpy(long_name, node->user.long_name, sizeof(long_name));
|
||||
route->push_back(new JSONValue(long_name));
|
||||
};
|
||||
addToRoute(&route, mp->to); // Started at the original transmitter (destination of response)
|
||||
for (uint8_t i = 0; i < decoded->route_count; i++) {
|
||||
addToRoute(&route, decoded->route[i]);
|
||||
}
|
||||
addToRoute(&route, mp->from); // Ended at the original destination (source of response)
|
||||
|
||||
addToRoute(&routeBack, mp->from); // Started at the original destination (source of response)
|
||||
for (uint8_t i = 0; i < decoded->route_back_count; i++) {
|
||||
addToRoute(&routeBack, decoded->route_back[i]);
|
||||
}
|
||||
addToRoute(&routeBack, mp->to); // Ended at the original transmitter (destination of response)
|
||||
addToRoute(&routeBack, mp->from); // Started at the original destination (source of response)
|
||||
for (uint8_t i = 0; i < decoded->route_back_count; i++) {
|
||||
addToRoute(&routeBack, decoded->route_back[i]);
|
||||
}
|
||||
addToRoute(&routeBack, mp->to); // Ended at the original transmitter (destination of response)
|
||||
|
||||
for (uint8_t i = 0; i < decoded->snr_back_count; i++) {
|
||||
snrBack.push_back(new JSONValue((float)decoded->snr_back[i] / 4));
|
||||
}
|
||||
for (uint8_t i = 0; i < decoded->snr_back_count; i++) {
|
||||
snrBack.push_back(new JSONValue((float)decoded->snr_back[i] / 4));
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < decoded->snr_towards_count; i++) {
|
||||
snrTowards.push_back(new JSONValue((float)decoded->snr_towards[i] / 4));
|
||||
}
|
||||
for (uint8_t i = 0; i < decoded->snr_towards_count; i++) {
|
||||
snrTowards.push_back(new JSONValue((float)decoded->snr_towards[i] / 4));
|
||||
}
|
||||
|
||||
msgPayload["route"] = new JSONValue(route);
|
||||
msgPayload["route_back"] = new JSONValue(routeBack);
|
||||
msgPayload["snr_back"] = new JSONValue(snrBack);
|
||||
msgPayload["snr_towards"] = new JSONValue(snrTowards);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_DETECTION_SENSOR_APP: {
|
||||
msgType = "detection";
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
msgPayload["text"] = new JSONValue(payloadStr);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
break;
|
||||
msgPayload["route"] = new JSONValue(route);
|
||||
msgPayload["route_back"] = new JSONValue(routeBack);
|
||||
msgPayload["snr_back"] = new JSONValue(snrBack);
|
||||
msgPayload["snr_towards"] = new JSONValue(snrTowards);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_DETECTION_SENSOR_APP: {
|
||||
msgType = "detection";
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
msgPayload["text"] = new JSONValue(payloadStr);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
break;
|
||||
}
|
||||
#ifdef ARCH_ESP32
|
||||
case meshtastic_PortNum_PAXCOUNTER_APP: {
|
||||
msgType = "paxcounter";
|
||||
meshtastic_Paxcount scratch;
|
||||
meshtastic_Paxcount *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Paxcount_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["wifi_count"] = new JSONValue((unsigned int)decoded->wifi);
|
||||
msgPayload["ble_count"] = new JSONValue((unsigned int)decoded->ble);
|
||||
msgPayload["uptime"] = new JSONValue((unsigned int)decoded->uptime);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_PAXCOUNTER_APP: {
|
||||
msgType = "paxcounter";
|
||||
meshtastic_Paxcount scratch;
|
||||
meshtastic_Paxcount *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Paxcount_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload["wifi_count"] = new JSONValue((unsigned int)decoded->wifi);
|
||||
msgPayload["ble_count"] = new JSONValue((unsigned int)decoded->ble);
|
||||
msgPayload["uptime"] = new JSONValue((unsigned int)decoded->uptime);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, msgType.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case meshtastic_PortNum_REMOTE_HARDWARE_APP: {
|
||||
meshtastic_HardwareMessage scratch;
|
||||
meshtastic_HardwareMessage *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg,
|
||||
&scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) {
|
||||
msgType = "gpios_changed";
|
||||
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) {
|
||||
msgType = "gpios_read_reply";
|
||||
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
|
||||
msgPayload["gpio_mask"] = new JSONValue((unsigned int)decoded->gpio_mask);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, "RemoteHardware");
|
||||
}
|
||||
break;
|
||||
case meshtastic_PortNum_REMOTE_HARDWARE_APP: {
|
||||
meshtastic_HardwareMessage scratch;
|
||||
meshtastic_HardwareMessage *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) {
|
||||
msgType = "gpios_changed";
|
||||
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) {
|
||||
msgType = "gpios_read_reply";
|
||||
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
|
||||
msgPayload["gpio_mask"] = new JSONValue((unsigned int)decoded->gpio_mask);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
}
|
||||
// add more packet types here if needed
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON");
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR(errStr, "RemoteHardware");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
jsonObj["id"] = new JSONValue((unsigned int)mp->id);
|
||||
jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time);
|
||||
jsonObj["to"] = new JSONValue((unsigned int)mp->to);
|
||||
jsonObj["from"] = new JSONValue((unsigned int)mp->from);
|
||||
jsonObj["channel"] = new JSONValue((unsigned int)mp->channel);
|
||||
jsonObj["type"] = new JSONValue(msgType.c_str());
|
||||
jsonObj["sender"] = new JSONValue(nodeDB->getNodeId().c_str());
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
|
||||
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
||||
// add more packet types here if needed
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON");
|
||||
}
|
||||
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObj);
|
||||
std::string jsonStr = value->Stringify();
|
||||
jsonObj["id"] = new JSONValue((unsigned int)mp->id);
|
||||
jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time);
|
||||
jsonObj["to"] = new JSONValue((unsigned int)mp->to);
|
||||
jsonObj["from"] = new JSONValue((unsigned int)mp->from);
|
||||
jsonObj["channel"] = new JSONValue((unsigned int)mp->channel);
|
||||
jsonObj["type"] = new JSONValue(msgType.c_str());
|
||||
jsonObj["sender"] = new JSONValue(nodeDB->getNodeId().c_str());
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
|
||||
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
||||
}
|
||||
|
||||
if (shouldLog)
|
||||
LOG_INFO("serialized json message: %s", jsonStr.c_str());
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObj);
|
||||
std::string jsonStr = value->Stringify();
|
||||
|
||||
delete value;
|
||||
return jsonStr;
|
||||
if (shouldLog)
|
||||
LOG_INFO("serialized json message: %s", jsonStr.c_str());
|
||||
|
||||
delete value;
|
||||
return jsonStr;
|
||||
}
|
||||
|
||||
std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPacket *mp)
|
||||
{
|
||||
JSONObject jsonObj;
|
||||
std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPacket *mp) {
|
||||
JSONObject jsonObj;
|
||||
|
||||
jsonObj["id"] = new JSONValue((unsigned int)mp->id);
|
||||
jsonObj["time_ms"] = new JSONValue((double)millis());
|
||||
jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time);
|
||||
jsonObj["to"] = new JSONValue((unsigned int)mp->to);
|
||||
jsonObj["from"] = new JSONValue((unsigned int)mp->from);
|
||||
jsonObj["channel"] = new JSONValue((unsigned int)mp->channel);
|
||||
jsonObj["want_ack"] = new JSONValue(mp->want_ack);
|
||||
jsonObj["id"] = new JSONValue((unsigned int)mp->id);
|
||||
jsonObj["time_ms"] = new JSONValue((double)millis());
|
||||
jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time);
|
||||
jsonObj["to"] = new JSONValue((unsigned int)mp->to);
|
||||
jsonObj["from"] = new JSONValue((unsigned int)mp->from);
|
||||
jsonObj["channel"] = new JSONValue((unsigned int)mp->channel);
|
||||
jsonObj["want_ack"] = new JSONValue(mp->want_ack);
|
||||
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
|
||||
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
||||
}
|
||||
jsonObj["size"] = new JSONValue((unsigned int)mp->encrypted.size);
|
||||
auto encryptedStr = bytesToHex(mp->encrypted.bytes, mp->encrypted.size);
|
||||
jsonObj["bytes"] = new JSONValue(encryptedStr.c_str());
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
|
||||
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
||||
}
|
||||
jsonObj["size"] = new JSONValue((unsigned int)mp->encrypted.size);
|
||||
auto encryptedStr = bytesToHex(mp->encrypted.bytes, mp->encrypted.size);
|
||||
jsonObj["bytes"] = new JSONValue(encryptedStr.c_str());
|
||||
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObj);
|
||||
std::string jsonStr = value->Stringify();
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObj);
|
||||
std::string jsonStr = value->Stringify();
|
||||
|
||||
delete value;
|
||||
return jsonStr;
|
||||
delete value;
|
||||
return jsonStr;
|
||||
}
|
||||
#endif
|
||||
@@ -3,21 +3,19 @@
|
||||
|
||||
static const char hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
class MeshPacketSerializer
|
||||
{
|
||||
public:
|
||||
static std::string JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog = true);
|
||||
static std::string JsonSerializeEncrypted(const meshtastic_MeshPacket *mp);
|
||||
class MeshPacketSerializer {
|
||||
public:
|
||||
static std::string JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog = true);
|
||||
static std::string JsonSerializeEncrypted(const meshtastic_MeshPacket *mp);
|
||||
|
||||
private:
|
||||
static std::string bytesToHex(const uint8_t *bytes, int len)
|
||||
{
|
||||
std::string result = "";
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char const byte = bytes[i];
|
||||
result += hexChars[(byte & 0xF0) >> 4];
|
||||
result += hexChars[(byte & 0x0F) >> 0];
|
||||
}
|
||||
return result;
|
||||
private:
|
||||
static std::string bytesToHex(const uint8_t *bytes, int len) {
|
||||
std::string result = "";
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char const byte = bytes[i];
|
||||
result += hexChars[(byte & 0xF0) >> 4];
|
||||
result += hexChars[(byte & 0x0F) >> 0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -14,399 +14,394 @@
|
||||
StaticJsonDocument<1024> jsonObj;
|
||||
StaticJsonDocument<1024> arrayObj;
|
||||
|
||||
std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog)
|
||||
{
|
||||
// the created jsonObj is immutable after creation, so
|
||||
// we need to do the heavy lifting before assembling it.
|
||||
std::string msgType;
|
||||
jsonObj.clear();
|
||||
arrayObj.clear();
|
||||
std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog) {
|
||||
// the created jsonObj is immutable after creation, so
|
||||
// we need to do the heavy lifting before assembling it.
|
||||
std::string msgType;
|
||||
jsonObj.clear();
|
||||
arrayObj.clear();
|
||||
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
switch (mp->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
|
||||
msgType = "text";
|
||||
// convert bytes to string
|
||||
if (shouldLog)
|
||||
LOG_DEBUG("got text message of size %u", mp->decoded.payload.size);
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
switch (mp->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
|
||||
msgType = "text";
|
||||
// convert bytes to string
|
||||
if (shouldLog)
|
||||
LOG_DEBUG("got text message of size %u", mp->decoded.payload.size);
|
||||
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
// check if this is a JSON payload
|
||||
StaticJsonDocument<512> text_doc;
|
||||
DeserializationError error = deserializeJson(text_doc, payloadStr);
|
||||
if (error) {
|
||||
// if it isn't, then we need to create a json object
|
||||
// with the string as the value
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type plaintext");
|
||||
jsonObj["payload"]["text"] = payloadStr;
|
||||
} else {
|
||||
// if it is, then we can just use the json object
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type json");
|
||||
jsonObj["payload"] = text_doc;
|
||||
}
|
||||
break;
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
// check if this is a JSON payload
|
||||
StaticJsonDocument<512> text_doc;
|
||||
DeserializationError error = deserializeJson(text_doc, payloadStr);
|
||||
if (error) {
|
||||
// if it isn't, then we need to create a json object
|
||||
// with the string as the value
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type plaintext");
|
||||
jsonObj["payload"]["text"] = payloadStr;
|
||||
} else {
|
||||
// if it is, then we can just use the json object
|
||||
if (shouldLog)
|
||||
LOG_INFO("text message payload is of type json");
|
||||
jsonObj["payload"] = text_doc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_TELEMETRY_APP: {
|
||||
msgType = "telemetry";
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||
// If battery is present, encode the battery level value
|
||||
// TODO - Add a condition to send a code for a non-present value
|
||||
if (decoded->variant.device_metrics.has_battery_level) {
|
||||
jsonObj["payload"]["battery_level"] = (int)decoded->variant.device_metrics.battery_level;
|
||||
}
|
||||
jsonObj["payload"]["voltage"] = decoded->variant.device_metrics.voltage;
|
||||
jsonObj["payload"]["channel_utilization"] = decoded->variant.device_metrics.channel_utilization;
|
||||
jsonObj["payload"]["air_util_tx"] = decoded->variant.device_metrics.air_util_tx;
|
||||
jsonObj["payload"]["uptime_seconds"] = (unsigned int)decoded->variant.device_metrics.uptime_seconds;
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
|
||||
if (decoded->variant.environment_metrics.has_temperature) {
|
||||
jsonObj["payload"]["temperature"] = decoded->variant.environment_metrics.temperature;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_relative_humidity) {
|
||||
jsonObj["payload"]["relative_humidity"] = decoded->variant.environment_metrics.relative_humidity;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_barometric_pressure) {
|
||||
jsonObj["payload"]["barometric_pressure"] = decoded->variant.environment_metrics.barometric_pressure;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_gas_resistance) {
|
||||
jsonObj["payload"]["gas_resistance"] = decoded->variant.environment_metrics.gas_resistance;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_voltage) {
|
||||
jsonObj["payload"]["voltage"] = decoded->variant.environment_metrics.voltage;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_current) {
|
||||
jsonObj["payload"]["current"] = decoded->variant.environment_metrics.current;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_lux) {
|
||||
jsonObj["payload"]["lux"] = decoded->variant.environment_metrics.lux;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_white_lux) {
|
||||
jsonObj["payload"]["white_lux"] = decoded->variant.environment_metrics.white_lux;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_iaq) {
|
||||
jsonObj["payload"]["iaq"] = (uint)decoded->variant.environment_metrics.iaq;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_speed) {
|
||||
jsonObj["payload"]["wind_speed"] = decoded->variant.environment_metrics.wind_speed;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_direction) {
|
||||
jsonObj["payload"]["wind_direction"] = (uint)decoded->variant.environment_metrics.wind_direction;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_gust) {
|
||||
jsonObj["payload"]["wind_gust"] = decoded->variant.environment_metrics.wind_gust;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_lull) {
|
||||
jsonObj["payload"]["wind_lull"] = decoded->variant.environment_metrics.wind_lull;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_radiation) {
|
||||
jsonObj["payload"]["radiation"] = decoded->variant.environment_metrics.radiation;
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_standard) {
|
||||
jsonObj["payload"]["pm10"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_standard;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_standard) {
|
||||
jsonObj["payload"]["pm25"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_standard;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_standard) {
|
||||
jsonObj["payload"]["pm100"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_standard;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_environmental) {
|
||||
jsonObj["payload"]["pm10_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_environmental;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_environmental) {
|
||||
jsonObj["payload"]["pm25_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_environmental;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_environmental) {
|
||||
jsonObj["payload"]["pm100_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_environmental;
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
|
||||
if (decoded->variant.power_metrics.has_ch1_voltage) {
|
||||
jsonObj["payload"]["voltage_ch1"] = decoded->variant.power_metrics.ch1_voltage;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch1_current) {
|
||||
jsonObj["payload"]["current_ch1"] = decoded->variant.power_metrics.ch1_current;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_voltage) {
|
||||
jsonObj["payload"]["voltage_ch2"] = decoded->variant.power_metrics.ch2_voltage;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_current) {
|
||||
jsonObj["payload"]["current_ch2"] = decoded->variant.power_metrics.ch2_current;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_voltage) {
|
||||
jsonObj["payload"]["voltage_ch3"] = decoded->variant.power_metrics.ch3_voltage;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_current) {
|
||||
jsonObj["payload"]["current_ch3"] = decoded->variant.power_metrics.ch3_current;
|
||||
}
|
||||
}
|
||||
case meshtastic_PortNum_TELEMETRY_APP: {
|
||||
msgType = "telemetry";
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||
// If battery is present, encode the battery level value
|
||||
// TODO - Add a condition to send a code for a non-present value
|
||||
if (decoded->variant.device_metrics.has_battery_level) {
|
||||
jsonObj["payload"]["battery_level"] = (int)decoded->variant.device_metrics.battery_level;
|
||||
}
|
||||
jsonObj["payload"]["voltage"] = decoded->variant.device_metrics.voltage;
|
||||
jsonObj["payload"]["channel_utilization"] = decoded->variant.device_metrics.channel_utilization;
|
||||
jsonObj["payload"]["air_util_tx"] = decoded->variant.device_metrics.air_util_tx;
|
||||
jsonObj["payload"]["uptime_seconds"] = (unsigned int)decoded->variant.device_metrics.uptime_seconds;
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
|
||||
if (decoded->variant.environment_metrics.has_temperature) {
|
||||
jsonObj["payload"]["temperature"] = decoded->variant.environment_metrics.temperature;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_relative_humidity) {
|
||||
jsonObj["payload"]["relative_humidity"] = decoded->variant.environment_metrics.relative_humidity;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_barometric_pressure) {
|
||||
jsonObj["payload"]["barometric_pressure"] = decoded->variant.environment_metrics.barometric_pressure;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_gas_resistance) {
|
||||
jsonObj["payload"]["gas_resistance"] = decoded->variant.environment_metrics.gas_resistance;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_voltage) {
|
||||
jsonObj["payload"]["voltage"] = decoded->variant.environment_metrics.voltage;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_current) {
|
||||
jsonObj["payload"]["current"] = decoded->variant.environment_metrics.current;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_lux) {
|
||||
jsonObj["payload"]["lux"] = decoded->variant.environment_metrics.lux;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_white_lux) {
|
||||
jsonObj["payload"]["white_lux"] = decoded->variant.environment_metrics.white_lux;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_iaq) {
|
||||
jsonObj["payload"]["iaq"] = (uint)decoded->variant.environment_metrics.iaq;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_speed) {
|
||||
jsonObj["payload"]["wind_speed"] = decoded->variant.environment_metrics.wind_speed;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_direction) {
|
||||
jsonObj["payload"]["wind_direction"] = (uint)decoded->variant.environment_metrics.wind_direction;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_gust) {
|
||||
jsonObj["payload"]["wind_gust"] = decoded->variant.environment_metrics.wind_gust;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_wind_lull) {
|
||||
jsonObj["payload"]["wind_lull"] = decoded->variant.environment_metrics.wind_lull;
|
||||
}
|
||||
if (decoded->variant.environment_metrics.has_radiation) {
|
||||
jsonObj["payload"]["radiation"] = decoded->variant.environment_metrics.radiation;
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_standard) {
|
||||
jsonObj["payload"]["pm10"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_standard;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_standard) {
|
||||
jsonObj["payload"]["pm25"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_standard;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_standard) {
|
||||
jsonObj["payload"]["pm100"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_standard;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm10_environmental) {
|
||||
jsonObj["payload"]["pm10_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_environmental;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm25_environmental) {
|
||||
jsonObj["payload"]["pm25_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_environmental;
|
||||
}
|
||||
if (decoded->variant.air_quality_metrics.has_pm100_environmental) {
|
||||
jsonObj["payload"]["pm100_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_environmental;
|
||||
}
|
||||
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
|
||||
if (decoded->variant.power_metrics.has_ch1_voltage) {
|
||||
jsonObj["payload"]["voltage_ch1"] = decoded->variant.power_metrics.ch1_voltage;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch1_current) {
|
||||
jsonObj["payload"]["current_ch1"] = decoded->variant.power_metrics.ch1_current;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_voltage) {
|
||||
jsonObj["payload"]["voltage_ch2"] = decoded->variant.power_metrics.ch2_voltage;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch2_current) {
|
||||
jsonObj["payload"]["current_ch2"] = decoded->variant.power_metrics.ch2_current;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_voltage) {
|
||||
jsonObj["payload"]["voltage_ch3"] = decoded->variant.power_metrics.ch3_voltage;
|
||||
}
|
||||
if (decoded->variant.power_metrics.has_ch3_current) {
|
||||
jsonObj["payload"]["current_ch3"] = decoded->variant.power_metrics.ch3_current;
|
||||
}
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for telemetry message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_NODEINFO_APP: {
|
||||
msgType = "nodeinfo";
|
||||
meshtastic_User scratch;
|
||||
meshtastic_User *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
jsonObj["payload"]["id"] = decoded->id;
|
||||
jsonObj["payload"]["longname"] = decoded->long_name;
|
||||
jsonObj["payload"]["shortname"] = decoded->short_name;
|
||||
jsonObj["payload"]["hardware"] = decoded->hw_model;
|
||||
jsonObj["payload"]["role"] = (int)decoded->role;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for nodeinfo message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_POSITION_APP: {
|
||||
msgType = "position";
|
||||
meshtastic_Position scratch;
|
||||
meshtastic_Position *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if ((int)decoded->time) {
|
||||
jsonObj["payload"]["time"] = (unsigned int)decoded->time;
|
||||
}
|
||||
if ((int)decoded->timestamp) {
|
||||
jsonObj["payload"]["timestamp"] = (unsigned int)decoded->timestamp;
|
||||
}
|
||||
jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i;
|
||||
jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i;
|
||||
if ((int)decoded->altitude) {
|
||||
jsonObj["payload"]["altitude"] = (int)decoded->altitude;
|
||||
}
|
||||
if ((int)decoded->ground_speed) {
|
||||
jsonObj["payload"]["ground_speed"] = (unsigned int)decoded->ground_speed;
|
||||
}
|
||||
if (int(decoded->ground_track)) {
|
||||
jsonObj["payload"]["ground_track"] = (unsigned int)decoded->ground_track;
|
||||
}
|
||||
if (int(decoded->sats_in_view)) {
|
||||
jsonObj["payload"]["sats_in_view"] = (unsigned int)decoded->sats_in_view;
|
||||
}
|
||||
if ((int)decoded->PDOP) {
|
||||
jsonObj["payload"]["PDOP"] = (int)decoded->PDOP;
|
||||
}
|
||||
if ((int)decoded->HDOP) {
|
||||
jsonObj["payload"]["HDOP"] = (int)decoded->HDOP;
|
||||
}
|
||||
if ((int)decoded->VDOP) {
|
||||
jsonObj["payload"]["VDOP"] = (int)decoded->VDOP;
|
||||
}
|
||||
if ((int)decoded->precision_bits) {
|
||||
jsonObj["payload"]["precision_bits"] = (int)decoded->precision_bits;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for position message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_WAYPOINT_APP: {
|
||||
msgType = "position";
|
||||
meshtastic_Waypoint scratch;
|
||||
meshtastic_Waypoint *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
jsonObj["payload"]["id"] = (unsigned int)decoded->id;
|
||||
jsonObj["payload"]["name"] = decoded->name;
|
||||
jsonObj["payload"]["description"] = decoded->description;
|
||||
jsonObj["payload"]["expire"] = (unsigned int)decoded->expire;
|
||||
jsonObj["payload"]["locked_to"] = (unsigned int)decoded->locked_to;
|
||||
jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i;
|
||||
jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for position message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_NEIGHBORINFO_APP: {
|
||||
msgType = "neighborinfo";
|
||||
meshtastic_NeighborInfo scratch;
|
||||
meshtastic_NeighborInfo *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
|
||||
&scratch)) {
|
||||
decoded = &scratch;
|
||||
jsonObj["payload"]["node_id"] = (unsigned int)decoded->node_id;
|
||||
jsonObj["payload"]["node_broadcast_interval_secs"] = (unsigned int)decoded->node_broadcast_interval_secs;
|
||||
jsonObj["payload"]["last_sent_by_id"] = (unsigned int)decoded->last_sent_by_id;
|
||||
jsonObj["payload"]["neighbors_count"] = decoded->neighbors_count;
|
||||
|
||||
JsonObject neighbors_obj = arrayObj.to<JsonObject>();
|
||||
JsonArray neighbors = neighbors_obj.createNestedArray("neighbors");
|
||||
JsonObject neighbors_0 = neighbors.createNestedObject();
|
||||
|
||||
for (uint8_t i = 0; i < decoded->neighbors_count; i++) {
|
||||
neighbors_0["node_id"] = (unsigned int)decoded->neighbors[i].node_id;
|
||||
neighbors_0["snr"] = (int)decoded->neighbors[i].snr;
|
||||
neighbors[i + 1] = neighbors_0;
|
||||
neighbors_0.clear();
|
||||
}
|
||||
neighbors.remove(0);
|
||||
jsonObj["payload"]["neighbors"] = neighbors;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for neighborinfo message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_TRACEROUTE_APP: {
|
||||
if (mp->decoded.request_id) { // Only report the traceroute response
|
||||
msgType = "traceroute";
|
||||
meshtastic_RouteDiscovery scratch;
|
||||
meshtastic_RouteDiscovery *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg,
|
||||
&scratch)) {
|
||||
decoded = &scratch;
|
||||
JsonArray route = arrayObj.createNestedArray("route");
|
||||
|
||||
auto addToRoute = [](JsonArray *route, NodeNum num) {
|
||||
char long_name[40] = "Unknown";
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
|
||||
bool name_known = node ? node->has_user : false;
|
||||
if (name_known)
|
||||
memcpy(long_name, node->user.long_name, sizeof(long_name));
|
||||
route->add(long_name);
|
||||
};
|
||||
|
||||
addToRoute(&route, mp->to); // route.add(mp->to);
|
||||
for (uint8_t i = 0; i < decoded->route_count; i++) {
|
||||
addToRoute(&route, decoded->route[i]); // route.add(decoded->route[i]);
|
||||
}
|
||||
addToRoute(&route,
|
||||
mp->from); // route.add(mp->from); // Ended at the original destination (source of response)
|
||||
|
||||
jsonObj["payload"]["route"] = route;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for traceroute message!");
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("Traceroute response not reported");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_DETECTION_SENSOR_APP: {
|
||||
msgType = "detection";
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
jsonObj["payload"]["text"] = payloadStr;
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_REMOTE_HARDWARE_APP: {
|
||||
meshtastic_HardwareMessage scratch;
|
||||
meshtastic_HardwareMessage *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg,
|
||||
&scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) {
|
||||
msgType = "gpios_changed";
|
||||
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value;
|
||||
} else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) {
|
||||
msgType = "gpios_read_reply";
|
||||
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value;
|
||||
jsonObj["payload"]["gpio_mask"] = (unsigned int)decoded->gpio_mask;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for RemoteHardware message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
// add more packet types here if needed
|
||||
default:
|
||||
LOG_WARN("Unsupported packet type %d", mp->decoded.portnum);
|
||||
return "";
|
||||
break;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON");
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for telemetry message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
jsonObj["id"] = (unsigned int)mp->id;
|
||||
jsonObj["timestamp"] = (unsigned int)mp->rx_time;
|
||||
jsonObj["to"] = (unsigned int)mp->to;
|
||||
jsonObj["from"] = (unsigned int)mp->from;
|
||||
jsonObj["channel"] = (unsigned int)mp->channel;
|
||||
jsonObj["type"] = msgType.c_str();
|
||||
jsonObj["sender"] = nodeDB->getNodeId().c_str();
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = (int)mp->rx_rssi;
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = (float)mp->rx_snr;
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = (unsigned int)(hopsAway);
|
||||
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
||||
case meshtastic_PortNum_NODEINFO_APP: {
|
||||
msgType = "nodeinfo";
|
||||
meshtastic_User scratch;
|
||||
meshtastic_User *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
jsonObj["payload"]["id"] = decoded->id;
|
||||
jsonObj["payload"]["longname"] = decoded->long_name;
|
||||
jsonObj["payload"]["shortname"] = decoded->short_name;
|
||||
jsonObj["payload"]["hardware"] = decoded->hw_model;
|
||||
jsonObj["payload"]["role"] = (int)decoded->role;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for nodeinfo message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_POSITION_APP: {
|
||||
msgType = "position";
|
||||
meshtastic_Position scratch;
|
||||
meshtastic_Position *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if ((int)decoded->time) {
|
||||
jsonObj["payload"]["time"] = (unsigned int)decoded->time;
|
||||
}
|
||||
if ((int)decoded->timestamp) {
|
||||
jsonObj["payload"]["timestamp"] = (unsigned int)decoded->timestamp;
|
||||
}
|
||||
jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i;
|
||||
jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i;
|
||||
if ((int)decoded->altitude) {
|
||||
jsonObj["payload"]["altitude"] = (int)decoded->altitude;
|
||||
}
|
||||
if ((int)decoded->ground_speed) {
|
||||
jsonObj["payload"]["ground_speed"] = (unsigned int)decoded->ground_speed;
|
||||
}
|
||||
if (int(decoded->ground_track)) {
|
||||
jsonObj["payload"]["ground_track"] = (unsigned int)decoded->ground_track;
|
||||
}
|
||||
if (int(decoded->sats_in_view)) {
|
||||
jsonObj["payload"]["sats_in_view"] = (unsigned int)decoded->sats_in_view;
|
||||
}
|
||||
if ((int)decoded->PDOP) {
|
||||
jsonObj["payload"]["PDOP"] = (int)decoded->PDOP;
|
||||
}
|
||||
if ((int)decoded->HDOP) {
|
||||
jsonObj["payload"]["HDOP"] = (int)decoded->HDOP;
|
||||
}
|
||||
if ((int)decoded->VDOP) {
|
||||
jsonObj["payload"]["VDOP"] = (int)decoded->VDOP;
|
||||
}
|
||||
if ((int)decoded->precision_bits) {
|
||||
jsonObj["payload"]["precision_bits"] = (int)decoded->precision_bits;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for position message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_WAYPOINT_APP: {
|
||||
msgType = "position";
|
||||
meshtastic_Waypoint scratch;
|
||||
meshtastic_Waypoint *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
jsonObj["payload"]["id"] = (unsigned int)decoded->id;
|
||||
jsonObj["payload"]["name"] = decoded->name;
|
||||
jsonObj["payload"]["description"] = decoded->description;
|
||||
jsonObj["payload"]["expire"] = (unsigned int)decoded->expire;
|
||||
jsonObj["payload"]["locked_to"] = (unsigned int)decoded->locked_to;
|
||||
jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i;
|
||||
jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for position message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_NEIGHBORINFO_APP: {
|
||||
msgType = "neighborinfo";
|
||||
meshtastic_NeighborInfo scratch;
|
||||
meshtastic_NeighborInfo *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
jsonObj["payload"]["node_id"] = (unsigned int)decoded->node_id;
|
||||
jsonObj["payload"]["node_broadcast_interval_secs"] = (unsigned int)decoded->node_broadcast_interval_secs;
|
||||
jsonObj["payload"]["last_sent_by_id"] = (unsigned int)decoded->last_sent_by_id;
|
||||
jsonObj["payload"]["neighbors_count"] = decoded->neighbors_count;
|
||||
|
||||
// serialize and write it to the stream
|
||||
JsonObject neighbors_obj = arrayObj.to<JsonObject>();
|
||||
JsonArray neighbors = neighbors_obj.createNestedArray("neighbors");
|
||||
JsonObject neighbors_0 = neighbors.createNestedObject();
|
||||
|
||||
// Serial.printf("serialized json message: \r");
|
||||
// serializeJson(jsonObj, Serial);
|
||||
// Serial.println("");
|
||||
for (uint8_t i = 0; i < decoded->neighbors_count; i++) {
|
||||
neighbors_0["node_id"] = (unsigned int)decoded->neighbors[i].node_id;
|
||||
neighbors_0["snr"] = (int)decoded->neighbors[i].snr;
|
||||
neighbors[i + 1] = neighbors_0;
|
||||
neighbors_0.clear();
|
||||
}
|
||||
neighbors.remove(0);
|
||||
jsonObj["payload"]["neighbors"] = neighbors;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for neighborinfo message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_TRACEROUTE_APP: {
|
||||
if (mp->decoded.request_id) { // Only report the traceroute response
|
||||
msgType = "traceroute";
|
||||
meshtastic_RouteDiscovery scratch;
|
||||
meshtastic_RouteDiscovery *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
JsonArray route = arrayObj.createNestedArray("route");
|
||||
|
||||
std::string jsonStr = "";
|
||||
serializeJson(jsonObj, jsonStr);
|
||||
auto addToRoute = [](JsonArray *route, NodeNum num) {
|
||||
char long_name[40] = "Unknown";
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
|
||||
bool name_known = node ? node->has_user : false;
|
||||
if (name_known)
|
||||
memcpy(long_name, node->user.long_name, sizeof(long_name));
|
||||
route->add(long_name);
|
||||
};
|
||||
|
||||
if (shouldLog)
|
||||
LOG_INFO("serialized json message: %s", jsonStr.c_str());
|
||||
addToRoute(&route, mp->to); // route.add(mp->to);
|
||||
for (uint8_t i = 0; i < decoded->route_count; i++) {
|
||||
addToRoute(&route, decoded->route[i]); // route.add(decoded->route[i]);
|
||||
}
|
||||
addToRoute(&route,
|
||||
mp->from); // route.add(mp->from); // Ended at the original destination (source of response)
|
||||
|
||||
return jsonStr;
|
||||
jsonObj["payload"]["route"] = route;
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for traceroute message!");
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("Traceroute response not reported");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_DETECTION_SENSOR_APP: {
|
||||
msgType = "detection";
|
||||
char payloadStr[(mp->decoded.payload.size) + 1];
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
jsonObj["payload"]["text"] = payloadStr;
|
||||
break;
|
||||
}
|
||||
case meshtastic_PortNum_REMOTE_HARDWARE_APP: {
|
||||
meshtastic_HardwareMessage scratch;
|
||||
meshtastic_HardwareMessage *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) {
|
||||
msgType = "gpios_changed";
|
||||
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value;
|
||||
} else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) {
|
||||
msgType = "gpios_read_reply";
|
||||
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value;
|
||||
jsonObj["payload"]["gpio_mask"] = (unsigned int)decoded->gpio_mask;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_ERROR("Error decoding proto for RemoteHardware message!");
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
// add more packet types here if needed
|
||||
default:
|
||||
LOG_WARN("Unsupported packet type %d", mp->decoded.portnum);
|
||||
return "";
|
||||
break;
|
||||
}
|
||||
} else if (shouldLog) {
|
||||
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON");
|
||||
return "";
|
||||
}
|
||||
|
||||
jsonObj["id"] = (unsigned int)mp->id;
|
||||
jsonObj["timestamp"] = (unsigned int)mp->rx_time;
|
||||
jsonObj["to"] = (unsigned int)mp->to;
|
||||
jsonObj["from"] = (unsigned int)mp->from;
|
||||
jsonObj["channel"] = (unsigned int)mp->channel;
|
||||
jsonObj["type"] = msgType.c_str();
|
||||
jsonObj["sender"] = nodeDB->getNodeId().c_str();
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = (int)mp->rx_rssi;
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = (float)mp->rx_snr;
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = (unsigned int)(hopsAway);
|
||||
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
||||
}
|
||||
|
||||
// serialize and write it to the stream
|
||||
|
||||
// Serial.printf("serialized json message: \r");
|
||||
// serializeJson(jsonObj, Serial);
|
||||
// Serial.println("");
|
||||
|
||||
std::string jsonStr = "";
|
||||
serializeJson(jsonObj, jsonStr);
|
||||
|
||||
if (shouldLog)
|
||||
LOG_INFO("serialized json message: %s", jsonStr.c_str());
|
||||
|
||||
return jsonStr;
|
||||
}
|
||||
|
||||
std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPacket *mp)
|
||||
{
|
||||
jsonObj.clear();
|
||||
jsonObj["id"] = (unsigned int)mp->id;
|
||||
jsonObj["time_ms"] = (double)millis();
|
||||
jsonObj["timestamp"] = (unsigned int)mp->rx_time;
|
||||
jsonObj["to"] = (unsigned int)mp->to;
|
||||
jsonObj["from"] = (unsigned int)mp->from;
|
||||
jsonObj["channel"] = (unsigned int)mp->channel;
|
||||
jsonObj["want_ack"] = mp->want_ack;
|
||||
std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPacket *mp) {
|
||||
jsonObj.clear();
|
||||
jsonObj["id"] = (unsigned int)mp->id;
|
||||
jsonObj["time_ms"] = (double)millis();
|
||||
jsonObj["timestamp"] = (unsigned int)mp->rx_time;
|
||||
jsonObj["to"] = (unsigned int)mp->to;
|
||||
jsonObj["from"] = (unsigned int)mp->from;
|
||||
jsonObj["channel"] = (unsigned int)mp->channel;
|
||||
jsonObj["want_ack"] = mp->want_ack;
|
||||
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = (int)mp->rx_rssi;
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = (float)mp->rx_snr;
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = (unsigned int)(hopsAway);
|
||||
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
||||
}
|
||||
jsonObj["size"] = (unsigned int)mp->encrypted.size;
|
||||
auto encryptedStr = bytesToHex(mp->encrypted.bytes, mp->encrypted.size);
|
||||
jsonObj["bytes"] = encryptedStr.c_str();
|
||||
if (mp->rx_rssi != 0)
|
||||
jsonObj["rssi"] = (int)mp->rx_rssi;
|
||||
if (mp->rx_snr != 0)
|
||||
jsonObj["snr"] = (float)mp->rx_snr;
|
||||
const int8_t hopsAway = getHopsAway(*mp);
|
||||
if (hopsAway >= 0) {
|
||||
jsonObj["hops_away"] = (unsigned int)(hopsAway);
|
||||
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
||||
}
|
||||
jsonObj["size"] = (unsigned int)mp->encrypted.size;
|
||||
auto encryptedStr = bytesToHex(mp->encrypted.bytes, mp->encrypted.size);
|
||||
jsonObj["bytes"] = encryptedStr.c_str();
|
||||
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = "";
|
||||
serializeJson(jsonObj, jsonStr);
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = "";
|
||||
serializeJson(jsonObj, jsonStr);
|
||||
|
||||
return jsonStr;
|
||||
return jsonStr;
|
||||
}
|
||||
#endif
|
||||
@@ -3,127 +3,125 @@
|
||||
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
|
||||
cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len)
|
||||
{
|
||||
cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len) {
|
||||
|
||||
cobs_encode_result result = {0, COBS_ENCODE_OK};
|
||||
|
||||
if (!dst_buf_ptr || !src_ptr) {
|
||||
result.status = COBS_ENCODE_NULL_POINTER;
|
||||
return result;
|
||||
}
|
||||
|
||||
const uint8_t *src_read_ptr = src_ptr;
|
||||
const uint8_t *src_end_ptr = src_read_ptr + src_len;
|
||||
uint8_t *dst_buf_start_ptr = dst_buf_ptr;
|
||||
uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len;
|
||||
uint8_t *dst_code_write_ptr = dst_buf_ptr;
|
||||
uint8_t *dst_write_ptr = dst_code_write_ptr + 1;
|
||||
uint8_t search_len = 1;
|
||||
|
||||
if (src_len != 0) {
|
||||
for (;;) {
|
||||
if (dst_write_ptr >= dst_buf_end_ptr) {
|
||||
result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW);
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t src_byte = *src_read_ptr++;
|
||||
if (src_byte == 0) {
|
||||
*dst_code_write_ptr = search_len;
|
||||
dst_code_write_ptr = dst_write_ptr++;
|
||||
search_len = 1;
|
||||
if (src_read_ptr >= src_end_ptr) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*dst_write_ptr++ = src_byte;
|
||||
search_len++;
|
||||
if (src_read_ptr >= src_end_ptr) {
|
||||
break;
|
||||
}
|
||||
if (search_len == 0xFF) {
|
||||
*dst_code_write_ptr = search_len;
|
||||
dst_code_write_ptr = dst_write_ptr++;
|
||||
search_len = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dst_code_write_ptr >= dst_buf_end_ptr) {
|
||||
result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW);
|
||||
dst_write_ptr = dst_buf_end_ptr;
|
||||
} else {
|
||||
*dst_code_write_ptr = search_len;
|
||||
}
|
||||
|
||||
result.out_len = dst_write_ptr - dst_buf_start_ptr;
|
||||
cobs_encode_result result = {0, COBS_ENCODE_OK};
|
||||
|
||||
if (!dst_buf_ptr || !src_ptr) {
|
||||
result.status = COBS_ENCODE_NULL_POINTER;
|
||||
return result;
|
||||
}
|
||||
|
||||
const uint8_t *src_read_ptr = src_ptr;
|
||||
const uint8_t *src_end_ptr = src_read_ptr + src_len;
|
||||
uint8_t *dst_buf_start_ptr = dst_buf_ptr;
|
||||
uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len;
|
||||
uint8_t *dst_code_write_ptr = dst_buf_ptr;
|
||||
uint8_t *dst_write_ptr = dst_code_write_ptr + 1;
|
||||
uint8_t search_len = 1;
|
||||
|
||||
if (src_len != 0) {
|
||||
for (;;) {
|
||||
if (dst_write_ptr >= dst_buf_end_ptr) {
|
||||
result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW);
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t src_byte = *src_read_ptr++;
|
||||
if (src_byte == 0) {
|
||||
*dst_code_write_ptr = search_len;
|
||||
dst_code_write_ptr = dst_write_ptr++;
|
||||
search_len = 1;
|
||||
if (src_read_ptr >= src_end_ptr) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*dst_write_ptr++ = src_byte;
|
||||
search_len++;
|
||||
if (src_read_ptr >= src_end_ptr) {
|
||||
break;
|
||||
}
|
||||
if (search_len == 0xFF) {
|
||||
*dst_code_write_ptr = search_len;
|
||||
dst_code_write_ptr = dst_write_ptr++;
|
||||
search_len = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dst_code_write_ptr >= dst_buf_end_ptr) {
|
||||
result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW);
|
||||
dst_write_ptr = dst_buf_end_ptr;
|
||||
} else {
|
||||
*dst_code_write_ptr = search_len;
|
||||
}
|
||||
|
||||
result.out_len = dst_write_ptr - dst_buf_start_ptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len)
|
||||
{
|
||||
cobs_decode_result result = {0, COBS_DECODE_OK};
|
||||
|
||||
if (!dst_buf_ptr || !src_ptr) {
|
||||
result.status = COBS_DECODE_NULL_POINTER;
|
||||
return result;
|
||||
}
|
||||
|
||||
const uint8_t *src_read_ptr = src_ptr;
|
||||
const uint8_t *src_end_ptr = src_read_ptr + src_len;
|
||||
uint8_t *dst_buf_start_ptr = dst_buf_ptr;
|
||||
const uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len;
|
||||
uint8_t *dst_write_ptr = dst_buf_ptr;
|
||||
|
||||
if (src_len != 0) {
|
||||
for (;;) {
|
||||
uint8_t len_code = *src_read_ptr++;
|
||||
if (len_code == 0) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT);
|
||||
break;
|
||||
}
|
||||
len_code--;
|
||||
|
||||
size_t remaining_bytes = src_end_ptr - src_read_ptr;
|
||||
if (len_code > remaining_bytes) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_INPUT_TOO_SHORT);
|
||||
len_code = remaining_bytes;
|
||||
}
|
||||
|
||||
remaining_bytes = dst_buf_end_ptr - dst_write_ptr;
|
||||
if (len_code > remaining_bytes) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW);
|
||||
len_code = remaining_bytes;
|
||||
}
|
||||
|
||||
for (uint8_t i = len_code; i != 0; i--) {
|
||||
uint8_t src_byte = *src_read_ptr++;
|
||||
if (src_byte == 0) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT);
|
||||
}
|
||||
*dst_write_ptr++ = src_byte;
|
||||
}
|
||||
|
||||
if (src_read_ptr >= src_end_ptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (len_code != 0xFE) {
|
||||
if (dst_write_ptr >= dst_buf_end_ptr) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW);
|
||||
break;
|
||||
}
|
||||
*dst_write_ptr++ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.out_len = dst_write_ptr - dst_buf_start_ptr;
|
||||
cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len) {
|
||||
cobs_decode_result result = {0, COBS_DECODE_OK};
|
||||
|
||||
if (!dst_buf_ptr || !src_ptr) {
|
||||
result.status = COBS_DECODE_NULL_POINTER;
|
||||
return result;
|
||||
}
|
||||
|
||||
const uint8_t *src_read_ptr = src_ptr;
|
||||
const uint8_t *src_end_ptr = src_read_ptr + src_len;
|
||||
uint8_t *dst_buf_start_ptr = dst_buf_ptr;
|
||||
const uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len;
|
||||
uint8_t *dst_write_ptr = dst_buf_ptr;
|
||||
|
||||
if (src_len != 0) {
|
||||
for (;;) {
|
||||
uint8_t len_code = *src_read_ptr++;
|
||||
if (len_code == 0) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT);
|
||||
break;
|
||||
}
|
||||
len_code--;
|
||||
|
||||
size_t remaining_bytes = src_end_ptr - src_read_ptr;
|
||||
if (len_code > remaining_bytes) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_INPUT_TOO_SHORT);
|
||||
len_code = remaining_bytes;
|
||||
}
|
||||
|
||||
remaining_bytes = dst_buf_end_ptr - dst_write_ptr;
|
||||
if (len_code > remaining_bytes) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW);
|
||||
len_code = remaining_bytes;
|
||||
}
|
||||
|
||||
for (uint8_t i = len_code; i != 0; i--) {
|
||||
uint8_t src_byte = *src_read_ptr++;
|
||||
if (src_byte == 0) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT);
|
||||
}
|
||||
*dst_write_ptr++ = src_byte;
|
||||
}
|
||||
|
||||
if (src_read_ptr >= src_end_ptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (len_code != 0xFE) {
|
||||
if (dst_write_ptr >= dst_buf_end_ptr) {
|
||||
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW);
|
||||
break;
|
||||
}
|
||||
*dst_write_ptr++ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.out_len = dst_write_ptr - dst_buf_start_ptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,28 +12,24 @@
|
||||
#define COBS_DECODE_DST_BUF_LEN_MAX(SRC_LEN) (((SRC_LEN) == 0) ? 0u : ((SRC_LEN)-1u))
|
||||
#define COBS_ENCODE_SRC_OFFSET(SRC_LEN) (((SRC_LEN) + 253u) / 254u)
|
||||
|
||||
typedef enum {
|
||||
COBS_ENCODE_OK = 0x00,
|
||||
COBS_ENCODE_NULL_POINTER = 0x01,
|
||||
COBS_ENCODE_OUT_BUFFER_OVERFLOW = 0x02
|
||||
} cobs_encode_status;
|
||||
typedef enum { COBS_ENCODE_OK = 0x00, COBS_ENCODE_NULL_POINTER = 0x01, COBS_ENCODE_OUT_BUFFER_OVERFLOW = 0x02 } cobs_encode_status;
|
||||
|
||||
typedef struct {
|
||||
size_t out_len;
|
||||
cobs_encode_status status;
|
||||
size_t out_len;
|
||||
cobs_encode_status status;
|
||||
} cobs_encode_result;
|
||||
|
||||
typedef enum {
|
||||
COBS_DECODE_OK = 0x00,
|
||||
COBS_DECODE_NULL_POINTER = 0x01,
|
||||
COBS_DECODE_OUT_BUFFER_OVERFLOW = 0x02,
|
||||
COBS_DECODE_ZERO_BYTE_IN_INPUT = 0x04,
|
||||
COBS_DECODE_INPUT_TOO_SHORT = 0x08
|
||||
COBS_DECODE_OK = 0x00,
|
||||
COBS_DECODE_NULL_POINTER = 0x01,
|
||||
COBS_DECODE_OUT_BUFFER_OVERFLOW = 0x02,
|
||||
COBS_DECODE_ZERO_BYTE_IN_INPUT = 0x04,
|
||||
COBS_DECODE_INPUT_TOO_SHORT = 0x08
|
||||
} cobs_decode_status;
|
||||
|
||||
typedef struct {
|
||||
size_t out_len;
|
||||
cobs_decode_status status;
|
||||
size_t out_len;
|
||||
cobs_decode_status status;
|
||||
} cobs_decode_result;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user