sforkowany z mirror/meshtastic-firmware
commit
30d7f188e2
|
@ -1,6 +1,6 @@
|
|||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[portduino_base]
|
||||
platform = https://github.com/meshtastic/platform-native.git#develop
|
||||
platform = https://github.com/meshtastic/platform-native.git#096b3c3e9c5c8e19d4c3b6cd803fffef2a9be4c5
|
||||
framework = arduino
|
||||
build_src_filter =
|
||||
${env.build_src_filter}
|
||||
|
@ -18,6 +18,4 @@ lib_deps =
|
|||
${env.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
rweather/Crypto@^0.4.0
|
||||
; jgromes/RadioLib@5.4.1
|
||||
https://github.com/jgromes/RadioLib.git#63208f1e89d4dac6eedaafbe234bf90f1fd5402b ; 5.4.1 with some fixes, remove when 5.4.2 is released
|
||||
build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino
|
||||
|
|
|
@ -42,7 +42,7 @@ build_flags = -Wno-missing-field-initializers
|
|||
-Wno-format
|
||||
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||
-DUSE_THREAD_NAMES
|
||||
; -DTINYGPS_OPTION_NO_CUSTOM_FIELDS // this should work now...
|
||||
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
-DPB_ENABLE_MALLOC=1
|
||||
-DRADIOLIB_EXCLUDE_CC1101
|
||||
-DRADIOLIB_EXCLUDE_NRF24
|
||||
|
@ -66,6 +66,7 @@ lib_deps =
|
|||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
nanopb/Nanopb@^0.4.6
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
jgromes/RadioLib@^5.5.0
|
||||
|
||||
; Used for the code analysis in PIO Home / Inspect
|
||||
check_tool = cppcheck
|
||||
|
@ -73,20 +74,17 @@ check_skip_packages = yes
|
|||
check_flags =
|
||||
-DAPP_VERSION=1.0.0
|
||||
--suppressions-list=suppressions.txt
|
||||
--inline-suppr
|
||||
|
||||
; Common settings for conventional (non Portduino) Arduino targets
|
||||
[arduino_base]
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
; Portduino is using meshtastic fork for now
|
||||
jgromes/RadioLib@5.4.1
|
||||
mprograms/QMC5883LCompass@^1.1.1
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
|
||||
|
||||
build_flags = ${env.build_flags} -Os
|
||||
-DRADIOLIB_SPI_PARANOID=0
|
||||
# -DRADIOLIB_GODMODE
|
||||
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
|
||||
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
|
||||
|
||||
; Common libs for communicating over TCP/IP networks such as MQTT
|
||||
|
@ -94,7 +92,6 @@ build_src_filter = ${env.build_src_filter} -<platform/portduino/>
|
|||
lib_deps =
|
||||
knolleary/PubSubClient@^2.8
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
meshtastic/json11@^1.0.2
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
; (not included in native / portduino)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 24874086e392b0ec504f9f89137e7b7f8b5bfcbd
|
||||
Subproject commit 3aca01ac82487de8aa3d5eefdd907b4d80714501
|
|
@ -2,22 +2,13 @@
|
|||
#include "configuration.h"
|
||||
#include "NodeDB.h"
|
||||
|
||||
#ifndef PIN_BUZZER
|
||||
|
||||
// Noop methods for boards w/o buzzer
|
||||
void playBeep(){};
|
||||
void playStartMelody(){};
|
||||
void playShutdownMelody(){};
|
||||
|
||||
#else
|
||||
#ifdef M5STACK
|
||||
#include "Speaker.h"
|
||||
TONE Tone;
|
||||
#else
|
||||
#if !defined(ARCH_ESP32) && !defined(ARCH_RP2040) && !defined(ARCH_PORTDUINO)
|
||||
#include "Tone.h"
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_PORTDUINO)
|
||||
extern "C" void delay(uint32_t dwMs);
|
||||
#endif
|
||||
|
||||
struct ToneDuration {
|
||||
int frequency_khz;
|
||||
|
@ -43,30 +34,25 @@ const int DURATION_1_8 = 125; // 1/8 note
|
|||
const int DURATION_1_4 = 250; // 1/4 note
|
||||
|
||||
void playTones(const ToneDuration *tone_durations, int size) {
|
||||
if (config.network.eth_enabled != true) {
|
||||
#ifdef PIN_BUZZER
|
||||
if (!config.device.buzzer_gpio)
|
||||
config.device.buzzer_gpio = PIN_BUZZER;
|
||||
#endif
|
||||
if (config.device.buzzer_gpio) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
const auto &tone_duration = tone_durations[i];
|
||||
#ifdef M5STACK
|
||||
Tone.tone(tone_duration.frequency_khz);
|
||||
delay(tone_duration.duration_ms);
|
||||
Tone.mute();
|
||||
#else
|
||||
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||
#endif
|
||||
tone(config.device.buzzer_gpio, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||
// to distinguish the notes, set a minimum time between them.
|
||||
delay(1.3 * tone_duration.duration_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef M5STACK
|
||||
|
||||
void playBeep() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#else
|
||||
void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
|
||||
#endif
|
||||
|
||||
void playStartMelody() {
|
||||
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8},
|
||||
|
@ -75,11 +61,9 @@ void playStartMelody() {
|
|||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
|
||||
void playShutdownMelody() {
|
||||
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8},
|
||||
{NOTE_AS3, DURATION_1_8},
|
||||
{NOTE_FS3, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#endif
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
void printATECCInfo()
|
||||
{
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
atecc.readConfigZone(false);
|
||||
|
||||
DEBUG_MSG("ATECC608B Serial Number: ");
|
||||
|
@ -114,7 +114,7 @@ void scanI2Cdevice()
|
|||
DEBUG_MSG("unknown display found\n");
|
||||
}
|
||||
}
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
if (addr == ATECC608B_ADDR) {
|
||||
keystore_found = addr;
|
||||
if (atecc.begin(keystore_found) == true) {
|
||||
|
|
|
@ -150,9 +150,21 @@ bool GPS::setupGPS()
|
|||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||
#endif
|
||||
|
||||
// if the overrides are not dialled in, set them from the board definitions, if they exist
|
||||
|
||||
#if defined(GPS_RX_PIN)
|
||||
if (!config.position.rx_gpio)
|
||||
config.position.rx_gpio = GPS_RX_PIN;
|
||||
#endif
|
||||
#if defined(GPS_TX_PIN)
|
||||
if (!config.position.tx_gpio)
|
||||
config.position.tx_gpio = GPS_TX_PIN;
|
||||
#endif
|
||||
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
#if defined(GPS_RX_PIN) && defined(ARCH_ESP32)
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||
#if defined(ARCH_ESP32)
|
||||
if(config.position.rx_gpio)
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, config.position.rx_gpio, config.position.tx_gpio);
|
||||
#else
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "PowerStatus.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "mesh/generated/telemetry.pb.h"
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
#include <SparkFun_ATECCX08a_Arduino_Library.h>
|
||||
#endif
|
||||
|
||||
|
@ -22,7 +22,7 @@ extern bool pmu_found;
|
|||
extern bool isCharging;
|
||||
extern bool isUSBPowered;
|
||||
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
extern ATECCX08A atecc;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -100,6 +100,8 @@ typedef struct _Config_DeviceConfig {
|
|||
Config_DeviceConfig_Role role;
|
||||
bool serial_enabled;
|
||||
bool debug_log_enabled;
|
||||
uint32_t button_gpio;
|
||||
uint32_t buzzer_gpio;
|
||||
} Config_DeviceConfig;
|
||||
|
||||
typedef struct _Config_DisplayConfig {
|
||||
|
@ -143,6 +145,8 @@ typedef struct _Config_PositionConfig {
|
|||
uint32_t gps_update_interval;
|
||||
uint32_t gps_attempt_time;
|
||||
uint32_t position_flags;
|
||||
uint32_t rx_gpio;
|
||||
uint32_t tx_gpio;
|
||||
} Config_PositionConfig;
|
||||
|
||||
typedef struct _Config_PowerConfig {
|
||||
|
@ -225,8 +229,8 @@ extern "C" {
|
|||
|
||||
/* Initializer values for message structs */
|
||||
#define Config_init_default {0, {Config_DeviceConfig_init_default}}
|
||||
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0}
|
||||
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
||||
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
||||
#define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||
|
@ -234,8 +238,8 @@ extern "C" {
|
|||
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
#define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
|
||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0}
|
||||
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
||||
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
||||
#define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||
|
@ -250,6 +254,8 @@ extern "C" {
|
|||
#define Config_DeviceConfig_role_tag 1
|
||||
#define Config_DeviceConfig_serial_enabled_tag 2
|
||||
#define Config_DeviceConfig_debug_log_enabled_tag 3
|
||||
#define Config_DeviceConfig_button_gpio_tag 4
|
||||
#define Config_DeviceConfig_buzzer_gpio_tag 5
|
||||
#define Config_DisplayConfig_screen_on_secs_tag 1
|
||||
#define Config_DisplayConfig_gps_format_tag 2
|
||||
#define Config_DisplayConfig_auto_screen_carousel_secs_tag 3
|
||||
|
@ -280,6 +286,8 @@ extern "C" {
|
|||
#define Config_PositionConfig_gps_update_interval_tag 5
|
||||
#define Config_PositionConfig_gps_attempt_time_tag 6
|
||||
#define Config_PositionConfig_position_flags_tag 7
|
||||
#define Config_PositionConfig_rx_gpio_tag 8
|
||||
#define Config_PositionConfig_tx_gpio_tag 9
|
||||
#define Config_PowerConfig_is_power_saving_tag 1
|
||||
#define Config_PowerConfig_on_battery_shutdown_after_secs_tag 2
|
||||
#define Config_PowerConfig_adc_multiplier_override_tag 3
|
||||
|
@ -325,7 +333,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,bluetooth,payload_variant.bl
|
|||
#define Config_DeviceConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, role, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, serial_enabled, 2) \
|
||||
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 3)
|
||||
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, button_gpio, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, buzzer_gpio, 5)
|
||||
#define Config_DeviceConfig_CALLBACK NULL
|
||||
#define Config_DeviceConfig_DEFAULT NULL
|
||||
|
||||
|
@ -336,7 +346,9 @@ X(a, STATIC, SINGULAR, BOOL, fixed_position, 3) \
|
|||
X(a, STATIC, SINGULAR, BOOL, gps_enabled, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_flags, 7)
|
||||
X(a, STATIC, SINGULAR, UINT32, position_flags, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, rx_gpio, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, tx_gpio, 9)
|
||||
#define Config_PositionConfig_CALLBACK NULL
|
||||
#define Config_PositionConfig_DEFAULT NULL
|
||||
|
||||
|
@ -429,12 +441,12 @@ extern const pb_msgdesc_t Config_BluetoothConfig_msg;
|
|||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define Config_BluetoothConfig_size 10
|
||||
#define Config_DeviceConfig_size 6
|
||||
#define Config_DeviceConfig_size 18
|
||||
#define Config_DisplayConfig_size 22
|
||||
#define Config_LoRaConfig_size 68
|
||||
#define Config_NetworkConfig_IpV4Config_size 20
|
||||
#define Config_NetworkConfig_size 161
|
||||
#define Config_PositionConfig_size 30
|
||||
#define Config_PositionConfig_size 42
|
||||
#define Config_PowerConfig_size 43
|
||||
#define Config_size 164
|
||||
|
||||
|
|
|
@ -150,8 +150,8 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
|
|||
#define LocalModuleConfig_fields &LocalModuleConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define LocalConfig_size 361
|
||||
#define LocalModuleConfig_size 294
|
||||
#define LocalConfig_size 385
|
||||
#define LocalModuleConfig_size 296
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
|
|
@ -90,6 +90,7 @@ typedef struct _ModuleConfig_ExternalNotificationConfig {
|
|||
bool active;
|
||||
bool alert_message;
|
||||
bool alert_bell;
|
||||
bool use_pwm;
|
||||
} ModuleConfig_ExternalNotificationConfig;
|
||||
|
||||
typedef struct _ModuleConfig_MQTTConfig {
|
||||
|
@ -184,7 +185,7 @@ extern "C" {
|
|||
#define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0}
|
||||
#define ModuleConfig_AudioConfig_init_default {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN}
|
||||
#define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
|
||||
#define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0}
|
||||
|
@ -193,7 +194,7 @@ extern "C" {
|
|||
#define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0}
|
||||
#define ModuleConfig_AudioConfig_init_zero {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN}
|
||||
#define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
|
||||
#define ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0}
|
||||
|
@ -222,6 +223,7 @@ extern "C" {
|
|||
#define ModuleConfig_ExternalNotificationConfig_active_tag 4
|
||||
#define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5
|
||||
#define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6
|
||||
#define ModuleConfig_ExternalNotificationConfig_use_pwm_tag 7
|
||||
#define ModuleConfig_MQTTConfig_enabled_tag 1
|
||||
#define ModuleConfig_MQTTConfig_address_tag 2
|
||||
#define ModuleConfig_MQTTConfig_username_tag 3
|
||||
|
@ -314,7 +316,8 @@ X(a, STATIC, SINGULAR, UINT32, output_ms, 2) \
|
|||
X(a, STATIC, SINGULAR, UINT32, output, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, active, 4) \
|
||||
X(a, STATIC, SINGULAR, BOOL, alert_message, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, alert_bell, 6)
|
||||
X(a, STATIC, SINGULAR, BOOL, alert_bell, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, use_pwm, 7)
|
||||
#define ModuleConfig_ExternalNotificationConfig_CALLBACK NULL
|
||||
#define ModuleConfig_ExternalNotificationConfig_DEFAULT NULL
|
||||
|
||||
|
@ -382,7 +385,7 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
|
|||
/* Maximum encoded size of messages (where known) */
|
||||
#define ModuleConfig_AudioConfig_size 22
|
||||
#define ModuleConfig_CannedMessageConfig_size 49
|
||||
#define ModuleConfig_ExternalNotificationConfig_size 20
|
||||
#define ModuleConfig_ExternalNotificationConfig_size 22
|
||||
#define ModuleConfig_MQTTConfig_size 105
|
||||
#define ModuleConfig_RangeTestConfig_size 10
|
||||
#define ModuleConfig_SerialConfig_size 26
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <HTTPBodyParser.hpp>
|
||||
#include <HTTPMultipartBodyParser.hpp>
|
||||
#include <HTTPURLEncodedBodyParser.hpp>
|
||||
#include <json11.hpp>
|
||||
#include "mqtt/JSON.h"
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
|
@ -246,15 +246,15 @@ void htmlDeleteDir(const char *dirname)
|
|||
root.close();
|
||||
}
|
||||
|
||||
std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *, char *>> *fileList, const char *dirname,
|
||||
uint8_t levels)
|
||||
JSONArray htmlListDir(const char *dirname, uint8_t levels)
|
||||
{
|
||||
File root = FSCom.open(dirname, FILE_O_READ);
|
||||
JSONArray fileList;
|
||||
if (!root) {
|
||||
return NULL;
|
||||
return fileList;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
return NULL;
|
||||
return fileList;
|
||||
}
|
||||
|
||||
// iterate over the file list
|
||||
|
@ -263,19 +263,19 @@ std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *,
|
|||
if (file.isDirectory() && !String(file.name()).endsWith(".")) {
|
||||
if (levels) {
|
||||
#ifdef ARCH_ESP32
|
||||
htmlListDir(fileList, file.path(), levels - 1);
|
||||
fileList.push_back(new JSONValue(htmlListDir(file.path(), levels - 1)));
|
||||
#else
|
||||
htmlListDir(fileList, file.name(), levels - 1);
|
||||
fileList.push_back(new JSONValue(htmlListDir(file.name(), levels - 1)));
|
||||
#endif
|
||||
file.close();
|
||||
}
|
||||
} else {
|
||||
std::map<char *, char *> thisFileMap;
|
||||
thisFileMap[strdup("size")] = strdup(String(file.size()).c_str());
|
||||
JSONObject thisFileMap;
|
||||
thisFileMap["size"] = new JSONValue((int)file.size());
|
||||
#ifdef ARCH_ESP32
|
||||
thisFileMap[strdup("name")] = strdup(String(file.path()).substring(1).c_str());
|
||||
thisFileMap["name"] = new JSONValue(String(file.path()).substring(1).c_str());
|
||||
#else
|
||||
thisFileMap[strdup("name")] = strdup(String(file.name()).substring(1).c_str());
|
||||
thisFileMap["name"] = new JSONValue(String(file.name()).substring(1).c_str());
|
||||
#endif
|
||||
if (String(file.name()).substring(1).endsWith(".gz")) {
|
||||
#ifdef ARCH_ESP32
|
||||
|
@ -284,9 +284,9 @@ std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *,
|
|||
String modifiedFile = String(file.name()).substring(1);
|
||||
#endif
|
||||
modifiedFile.remove((modifiedFile.length() - 3), 3);
|
||||
thisFileMap[strdup("nameModified")] = strdup(modifiedFile.c_str());
|
||||
thisFileMap["nameModified"] = new JSONValue(modifiedFile.c_str());
|
||||
}
|
||||
fileList->push_back(thisFileMap);
|
||||
fileList.push_back(new JSONValue(thisFileMap));
|
||||
}
|
||||
file.close();
|
||||
file = root.openNextFile();
|
||||
|
@ -301,29 +301,31 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
|||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||
|
||||
using namespace json11;
|
||||
auto fileList = htmlListDir(new std::vector<std::map<char *, char *>>(), "/static", 10);
|
||||
auto fileList = htmlListDir("/static", 10);
|
||||
|
||||
// create json output structure
|
||||
Json filesystemObj = Json::object{
|
||||
{"total", String(FSCom.totalBytes()).c_str()},
|
||||
{"used", String(FSCom.usedBytes()).c_str()},
|
||||
{"free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()},
|
||||
};
|
||||
JSONObject filesystemObj;
|
||||
filesystemObj["total"] = new JSONValue((int)FSCom.totalBytes());
|
||||
filesystemObj["used"] = new JSONValue((int)FSCom.usedBytes());
|
||||
filesystemObj["free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
|
||||
|
||||
Json jsonObjInner = Json::object{{"files", Json(*fileList)}, {"filesystem", filesystemObj}};
|
||||
JSONObject jsonObjInner;
|
||||
jsonObjInner["files"] = new JSONValue(fileList);
|
||||
jsonObjInner["filesystem"] = new JSONValue(filesystemObj);
|
||||
|
||||
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["data"] = new JSONValue(jsonObjInner);
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
|
||||
res->print(value->Stringify().c_str());
|
||||
|
||||
delete value;
|
||||
}
|
||||
|
||||
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
ResourceParameters *params = req->getParams();
|
||||
std::string paramValDelete;
|
||||
|
||||
|
@ -334,15 +336,19 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
|||
std::string pathDelete = "/" + paramValDelete;
|
||||
if (FSCom.remove(pathDelete.c_str())) {
|
||||
Serial.println(pathDelete.c_str());
|
||||
Json jsonObjOuter = Json::object{{"status", "ok"}};
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
return;
|
||||
} else {
|
||||
Serial.println(pathDelete.c_str());
|
||||
Json jsonObjOuter = Json::object{{"status", "Error"}};
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("Error");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -559,8 +565,6 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
|||
|
||||
void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
ResourceParameters *params = req->getParams();
|
||||
std::string content;
|
||||
|
||||
|
@ -579,81 +583,87 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
|||
}
|
||||
|
||||
// data->airtime->tx_log
|
||||
std::vector<String> txLogValues;
|
||||
JSONArray txLogValues;
|
||||
uint32_t *logArray;
|
||||
logArray = airTime->airtimeReport(TX_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
uint32_t tmp;
|
||||
tmp = *(logArray + i);
|
||||
txLogValues.push_back(String(tmp));
|
||||
txLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
// data->airtime->rx_log
|
||||
std::vector<String> rxLogValues;
|
||||
JSONArray rxLogValues;
|
||||
logArray = airTime->airtimeReport(RX_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
uint32_t tmp;
|
||||
tmp = *(logArray + i);
|
||||
rxLogValues.push_back(String(tmp));
|
||||
rxLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
// data->airtime->rx_all_log
|
||||
std::vector<String> rxAllLogValues;
|
||||
JSONArray rxAllLogValues;
|
||||
logArray = airTime->airtimeReport(RX_ALL_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
uint32_t tmp;
|
||||
tmp = *(logArray + i);
|
||||
rxAllLogValues.push_back(String(tmp));
|
||||
rxAllLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
Json jsonObjAirtime = Json::object{
|
||||
{"tx_log", Json(txLogValues)},
|
||||
{"rx_log", Json(rxLogValues)},
|
||||
{"rx_all_log", Json(rxAllLogValues)},
|
||||
{"channel_utilization", Json(airTime->channelUtilizationPercent())},
|
||||
{"utilization_tx", Json(airTime->utilizationTXPercent())},
|
||||
{"seconds_since_boot", Json(int(airTime->getSecondsSinceBoot()))},
|
||||
{"seconds_per_period", Json(int(airTime->getSecondsPerPeriod()))},
|
||||
{"periods_to_log", Json(airTime->getPeriodsToLog())},
|
||||
};
|
||||
// data->airtime
|
||||
JSONObject jsonObjAirtime;
|
||||
jsonObjAirtime["tx_log"] = new JSONValue(txLogValues);
|
||||
jsonObjAirtime["rx_log"] = new JSONValue(rxLogValues);
|
||||
jsonObjAirtime["rx_all_log"] = new JSONValue(rxAllLogValues);
|
||||
jsonObjAirtime["channel_utilization"] = new JSONValue(airTime->channelUtilizationPercent());
|
||||
jsonObjAirtime["utilization_tx"] = new JSONValue(airTime->utilizationTXPercent());
|
||||
jsonObjAirtime["seconds_since_boot"] = new JSONValue(int(airTime->getSecondsSinceBoot()));
|
||||
jsonObjAirtime["seconds_per_period"] = new JSONValue(int(airTime->getSecondsPerPeriod()));
|
||||
jsonObjAirtime["periods_to_log"] = new JSONValue(airTime->getPeriodsToLog());
|
||||
|
||||
// data->wifi
|
||||
String ipStr = String(WiFi.localIP().toString());
|
||||
|
||||
Json jsonObjWifi = Json::object{{"rssi", String(WiFi.RSSI())}, {"ip", ipStr.c_str()}};
|
||||
JSONObject jsonObjWifi;
|
||||
jsonObjWifi["rssi"] = new JSONValue(WiFi.RSSI());
|
||||
jsonObjWifi["ip"] = new JSONValue(WiFi.localIP().toString().c_str());
|
||||
|
||||
// data->memory
|
||||
Json jsonObjMemory = Json::object{{"heap_total", Json(int(ESP.getHeapSize()))},
|
||||
{"heap_free", Json(int(ESP.getFreeHeap()))},
|
||||
{"psram_total", Json(int(ESP.getPsramSize()))},
|
||||
{"psram_free", Json(int(ESP.getFreePsram()))},
|
||||
{"fs_total", String(FSCom.totalBytes()).c_str()},
|
||||
{"fs_used", String(FSCom.usedBytes()).c_str()},
|
||||
{"fs_free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()}};
|
||||
JSONObject jsonObjMemory;
|
||||
jsonObjMemory["heap_total"] = new JSONValue((int)ESP.getHeapSize());
|
||||
jsonObjMemory["heap_free"] = new JSONValue((int)ESP.getFreeHeap());
|
||||
jsonObjMemory["psram_total"] = new JSONValue((int)ESP.getPsramSize());
|
||||
jsonObjMemory["psram_free"] = new JSONValue((int)ESP.getFreePsram());
|
||||
jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes());
|
||||
jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes());
|
||||
jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
|
||||
|
||||
// data->power
|
||||
Json jsonObjPower = Json::object{{"battery_percent", Json(powerStatus->getBatteryChargePercent())},
|
||||
{"battery_voltage_mv", Json(powerStatus->getBatteryVoltageMv())},
|
||||
{"has_battery", BoolToString(powerStatus->getHasBattery())},
|
||||
{"has_usb", BoolToString(powerStatus->getHasUSB())},
|
||||
{"is_charging", BoolToString(powerStatus->getIsCharging())}};
|
||||
JSONObject jsonObjPower;
|
||||
jsonObjPower["battery_percent"] = new JSONValue(powerStatus->getBatteryChargePercent());
|
||||
jsonObjPower["battery_voltage_mv"] = new JSONValue(powerStatus->getBatteryVoltageMv());
|
||||
jsonObjPower["has_battery"] = new JSONValue(BoolToString(powerStatus->getHasBattery()));
|
||||
jsonObjPower["has_usb"] = new JSONValue(BoolToString(powerStatus->getHasUSB()));
|
||||
jsonObjPower["is_charging"] = new JSONValue(BoolToString(powerStatus->getIsCharging()));
|
||||
|
||||
// data->device
|
||||
Json jsonObjDevice = Json::object{{"reboot_counter", Json(int(myNodeInfo.reboot_count))}};
|
||||
JSONObject jsonObjDevice;
|
||||
jsonObjDevice["reboot_counter"] = new JSONValue((int)myNodeInfo.reboot_count);
|
||||
|
||||
// data->radio
|
||||
Json jsonObjRadio = Json::object{{"frequency", Json(RadioLibInterface::instance->getFreq())},
|
||||
{"lora_channel", Json(int(RadioLibInterface::instance->getChannelNum()))}};
|
||||
JSONObject jsonObjRadio;
|
||||
jsonObjRadio["frequency"] = new JSONValue(RadioLibInterface::instance->getFreq());
|
||||
jsonObjRadio["lora_channel"] = new JSONValue((int)RadioLibInterface::instance->getChannelNum());
|
||||
|
||||
// collect data to inner data object
|
||||
Json jsonObjInner = Json::object{{"airtime", jsonObjAirtime}, {"wifi", jsonObjWifi}, {"memory", jsonObjMemory},
|
||||
{"power", jsonObjPower}, {"device", jsonObjDevice}, {"radio", jsonObjRadio}};
|
||||
JSONObject jsonObjInner;
|
||||
jsonObjInner["airtime"] = new JSONValue(jsonObjAirtime);
|
||||
jsonObjInner["wifi"] = new JSONValue(jsonObjWifi);
|
||||
jsonObjInner["memory"] = new JSONValue(jsonObjMemory);
|
||||
jsonObjInner["power"] = new JSONValue(jsonObjPower);
|
||||
jsonObjInner["device"] = new JSONValue(jsonObjDevice);
|
||||
jsonObjInner["radio"] = new JSONValue(jsonObjRadio);
|
||||
|
||||
// create json output structure
|
||||
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["data"] = new JSONValue(jsonObjInner);
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -767,8 +777,6 @@ void handleRestart(HTTPRequest *req, HTTPResponse *res)
|
|||
|
||||
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
res->setHeader("Content-Type", "application/json");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "POST");
|
||||
|
@ -797,15 +805,15 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
|||
#endif
|
||||
}
|
||||
|
||||
Json jsonObjOuter = Json::object{{"status", "ok"}};
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
||||
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
res->setHeader("Content-Type", "application/json");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||
|
@ -814,7 +822,7 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
|||
int n = WiFi.scanNetworks();
|
||||
|
||||
// build list of network objects
|
||||
std::vector<Json> networkObjs;
|
||||
JSONArray networkObjs;
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
char ssidArray[50];
|
||||
|
@ -823,8 +831,10 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
|||
ssidString.toCharArray(ssidArray, 50);
|
||||
|
||||
if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) {
|
||||
Json thisNetwork = Json::object{{"ssid", ssidArray}, {"rssi", WiFi.RSSI(i)}};
|
||||
networkObjs.push_back(thisNetwork);
|
||||
JSONObject thisNetwork;
|
||||
thisNetwork["ssid"] = new JSONValue(ssidArray);
|
||||
thisNetwork["rssi"] = new JSONValue(WiFi.RSSI(i));
|
||||
networkObjs.push_back(new JSONValue(thisNetwork));
|
||||
}
|
||||
// Yield some cpu cycles to IP stack.
|
||||
// This is important in case the list is large and it takes us time to return
|
||||
|
@ -834,9 +844,12 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
|||
}
|
||||
|
||||
// build output structure
|
||||
Json jsonObjOuter = Json::object{{"data", networkObjs}, {"status", "ok"}};
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["data"] = new JSONValue(networkObjs);
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
|
|
@ -56,13 +56,28 @@ static int32_t reconnectWiFi()
|
|||
// Make sure we clear old connection credentials
|
||||
WiFi.disconnect(false, true);
|
||||
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point\n");
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point %s\n",wifiName);
|
||||
|
||||
int n = WiFi.scanNetworks();
|
||||
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
DEBUG_MSG("Found WiFi network %s, signal strength %d\n", WiFi.SSID(i).c_str(), WiFi.RSSI(i));
|
||||
yield();
|
||||
}
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
} else {
|
||||
DEBUG_MSG("No networks found during site survey. Rebooting MCU...\n");
|
||||
screen->startRebootScreen();
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifndef DISABLE_NTP
|
||||
if (WiFi.isConnected() && ((millis() - lastrun_ntp) > 43200000)) { // every 12 hours
|
||||
if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours
|
||||
DEBUG_MSG("Updating NTP time\n");
|
||||
if (timeClient.update()) {
|
||||
DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n");
|
||||
|
|
|
@ -76,7 +76,7 @@ int32_t ExternalNotificationModule::runOnce()
|
|||
// moduleConfig.external_notification.output_ms = 1000;
|
||||
// moduleConfig.external_notification.output = 13;
|
||||
|
||||
if (externalCurrentState) {
|
||||
if (externalCurrentState && !moduleConfig.external_notification.use_pwm) {
|
||||
|
||||
// If the output is turned on, turn it back off after the given period of time.
|
||||
if (externalTurnedOn + (moduleConfig.external_notification.output_ms
|
||||
|
@ -84,13 +84,13 @@ int32_t ExternalNotificationModule::runOnce()
|
|||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
|
||||
millis()) {
|
||||
DEBUG_MSG("Turning off external notification\n");
|
||||
if (output != PIN_BUZZER) {
|
||||
setExternalOff();
|
||||
}
|
||||
setExternalOff();
|
||||
}
|
||||
}
|
||||
|
||||
return (25);
|
||||
if (moduleConfig.external_notification.use_pwm)
|
||||
return INT32_MAX; // we don't need this thread here...
|
||||
else
|
||||
return 25;
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::setExternalOn()
|
||||
|
@ -129,11 +129,6 @@ ExternalNotificationModule::ExternalNotificationModule()
|
|||
// moduleConfig.external_notification.output_ms = 1000;
|
||||
// moduleConfig.external_notification.output = 13;
|
||||
|
||||
if (moduleConfig.external_notification.alert_message) {
|
||||
// restrict to the gpio channel for rx
|
||||
boundChannel = Channels::gpioChannel;
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
|
||||
DEBUG_MSG("Initializing External Notification Module\n");
|
||||
|
@ -142,14 +137,19 @@ ExternalNotificationModule::ExternalNotificationModule()
|
|||
? moduleConfig.external_notification.output
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT;
|
||||
|
||||
if (output != PIN_BUZZER) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
// Set the direction of a pin
|
||||
DEBUG_MSG("Using Pin %i in digital mode\n", output);
|
||||
pinMode(output, OUTPUT);
|
||||
// Turn off the pin
|
||||
setExternalOff();
|
||||
} else{
|
||||
DEBUG_MSG("Using Pin %i in PWM mode\n", output);
|
||||
} else {
|
||||
config.device.buzzer_gpio = config.device.buzzer_gpio
|
||||
? config.device.buzzer_gpio
|
||||
: PIN_BUZZER;
|
||||
|
||||
// in PWM Mode we force the buzzer pin if it is set
|
||||
DEBUG_MSG("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("External Notification Module Disabled\n");
|
||||
|
@ -170,7 +170,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
|||
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
|
||||
for (int i = 0; i < p.payload.size; i++) {
|
||||
if (p.payload.bytes[i] == ASCII_BELL) {
|
||||
if (output != PIN_BUZZER) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn();
|
||||
} else {
|
||||
playBeep();
|
||||
|
@ -181,7 +181,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
|||
|
||||
if (moduleConfig.external_notification.alert_message) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Module\n");
|
||||
if (output != PIN_BUZZER) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn();
|
||||
} else {
|
||||
playBeep();
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* File JSON.cpp part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "JSON.h"
|
||||
|
||||
/**
|
||||
* Blocks off the public constructor
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
*/
|
||||
JSON::JSON()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a complete JSON encoded string
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param char* data The JSON text
|
||||
*
|
||||
* @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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// We're now at the end of the string
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the passed in JSONValue into a JSON encode string
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONValue* value The root value
|
||||
*
|
||||
* @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 "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over any whitespace characters (space, tab, \r or \n) defined by the JSON spec
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
*
|
||||
* @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)++;
|
||||
|
||||
return **data != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a JSON String as defined by the spec - "<some chars>"
|
||||
* Any escaped characters are swapped out for their unescaped values
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
* @param std::string& str Reference to a std::string to receive the extracted string
|
||||
*
|
||||
* @return bool Returns true on success, false on failure
|
||||
*/
|
||||
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;
|
||||
|
||||
// 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 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;
|
||||
|
||||
// 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.reserve(); // 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses some text as though it is an integer
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
*
|
||||
* @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');
|
||||
|
||||
return integer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses some text as though it is a decimal
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
*
|
||||
* @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;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* File JSON.h part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _JSON_H_
|
||||
#define _JSON_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
|
||||
// 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;
|
||||
|
||||
const char *save = s;
|
||||
while (n-- > 0)
|
||||
{
|
||||
if (*(save++) == 0) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Custom types
|
||||
class JSONValue;
|
||||
typedef std::vector<JSONValue*> JSONArray;
|
||||
typedef std::map<std::string, JSONValue*> JSONObject;
|
||||
|
||||
#include "JSONValue.h"
|
||||
|
||||
class JSON
|
||||
{
|
||||
friend class JSONValue;
|
||||
|
||||
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);
|
||||
private:
|
||||
JSON();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,940 @@
|
|||
/*
|
||||
* File JSONValue.cpp part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
|
||||
#include "JSONValue.h"
|
||||
|
||||
// Macros to free an array/object
|
||||
#define FREE_ARRAY(x) { JSONArray::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete *iter; } }
|
||||
#define FREE_OBJECT(x) { JSONObject::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete (*iter).second; } }
|
||||
|
||||
/**
|
||||
* Parses a JSON encoded value to a JSONValue object
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the data
|
||||
*
|
||||
* @return JSONValue* Returns a pointer to a JSONValue object on success, NULL on error
|
||||
*/
|
||||
JSONValue *JSONValue::Parse(const char **data)
|
||||
{
|
||||
// Is it a string?
|
||||
if (**data == '"')
|
||||
{
|
||||
std::string str;
|
||||
if (!JSON::ExtractString(&(++(*data)), str))
|
||||
return NULL;
|
||||
else
|
||||
return new JSONValue(str);
|
||||
}
|
||||
|
||||
// Is it a boolean?
|
||||
else if ((simplejson_csnlen(*data, 4) && strncasecmp(*data, "true", 4) == 0) || (simplejson_csnlen(*data, 5) && strncasecmp(*data, "false", 5) == 0))
|
||||
{
|
||||
bool value = strncasecmp(*data, "true", 4) == 0;
|
||||
(*data) += value ? 4 : 5;
|
||||
return new JSONValue(value);
|
||||
}
|
||||
|
||||
// Is it a null?
|
||||
else if (simplejson_csnlen(*data, 4) && strncasecmp(*data, "null", 4) == 0)
|
||||
{
|
||||
(*data) += 4;
|
||||
return new JSONValue();
|
||||
}
|
||||
|
||||
// Is it a number?
|
||||
else if (**data == '-' || (**data >= '0' && **data <= '9'))
|
||||
{
|
||||
// Negative?
|
||||
bool neg = **data == '-';
|
||||
if (neg) (*data)++;
|
||||
|
||||
double number = 0.0;
|
||||
|
||||
// Parse the whole part of the number - only if it wasn't 0
|
||||
if (**data == '0')
|
||||
(*data)++;
|
||||
else if (**data >= '1' && **data <= '9')
|
||||
number = JSON::ParseInt(data);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
// Could be a decimal now...
|
||||
if (**data == '.')
|
||||
{
|
||||
(*data)++;
|
||||
|
||||
// Not get any digits?
|
||||
if (!(**data >= '0' && **data <= '9'))
|
||||
return NULL;
|
||||
|
||||
// Find the decimal and sort the decimal place out
|
||||
// Use ParseDecimal as ParseInt won't work with decimals less than 0.1
|
||||
// thanks to Javier Abadia for the report & fix
|
||||
double decimal = JSON::ParseDecimal(data);
|
||||
|
||||
// Save the number
|
||||
number += decimal;
|
||||
}
|
||||
|
||||
// Could be an exponent now...
|
||||
if (**data == 'E' || **data == 'e')
|
||||
{
|
||||
(*data)++;
|
||||
|
||||
// Check signage of expo
|
||||
bool neg_expo = false;
|
||||
if (**data == '-' || **data == '+')
|
||||
{
|
||||
neg_expo = **data == '-';
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// Not get any digits?
|
||||
if (!(**data >= '0' && **data <= '9'))
|
||||
return NULL;
|
||||
|
||||
// Sort the expo out
|
||||
double expo = JSON::ParseInt(data);
|
||||
for (double i = 0.0; i < expo; i++)
|
||||
number = neg_expo ? (number / 10.0) : (number * 10.0);
|
||||
}
|
||||
|
||||
// Was it neg?
|
||||
if (neg) number *= -1;
|
||||
|
||||
return new JSONValue(number);
|
||||
}
|
||||
|
||||
// An object?
|
||||
else if (**data == '{')
|
||||
{
|
||||
JSONObject object;
|
||||
|
||||
(*data)++;
|
||||
|
||||
while (**data != 0)
|
||||
{
|
||||
// Whitespace at the start?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Special case - empty object
|
||||
if (object.size() == 0 && **data == '}')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(object);
|
||||
}
|
||||
|
||||
// We want a string now...
|
||||
std::string name;
|
||||
if (!JSON::ExtractString(&(++(*data)), name))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Need a : now
|
||||
if (*((*data)++) != ':')
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The value is here
|
||||
JSONValue *value = Parse(data);
|
||||
if (value == NULL)
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add the name:value
|
||||
if (object.find(name) != object.end())
|
||||
delete object[name];
|
||||
object[name] = value;
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// End of object?
|
||||
if (**data == '}')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(object);
|
||||
}
|
||||
|
||||
// Want a , now
|
||||
if (**data != ',')
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// Only here if we ran out of data
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// An array?
|
||||
else if (**data == '[')
|
||||
{
|
||||
JSONArray array;
|
||||
|
||||
(*data)++;
|
||||
|
||||
while (**data != 0)
|
||||
{
|
||||
// Whitespace at the start?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Special case - empty array
|
||||
if (array.size() == 0 && **data == ']')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(array);
|
||||
}
|
||||
|
||||
// Get the value
|
||||
JSONValue *value = Parse(data);
|
||||
if (value == NULL)
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add the value
|
||||
array.push_back(value);
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// End of array?
|
||||
if (**data == ']')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(array);
|
||||
}
|
||||
|
||||
// Want a , now
|
||||
if (**data != ',')
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// Only here if we ran out of data
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ran out of possibilites, it's bad!
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type NULL
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
JSONValue::JSONValue(/*NULL*/)
|
||||
{
|
||||
type = JSONType_Null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type String
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param char* m_char_value The string to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const char *m_char_value)
|
||||
{
|
||||
type = JSONType_String;
|
||||
string_value = new std::string(std::string(m_char_value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type String
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param std::string m_string_value The string to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const std::string &m_string_value)
|
||||
{
|
||||
type = JSONType_String;
|
||||
string_value = new std::string(m_string_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Bool
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param bool m_bool_value The bool to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(bool m_bool_value)
|
||||
{
|
||||
type = JSONType_Bool;
|
||||
bool_value = m_bool_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Number
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param double m_number_value The number to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(double m_number_value)
|
||||
{
|
||||
type = JSONType_Number;
|
||||
number_value = m_number_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Number
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param int m_integer_value The number to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(int m_integer_value)
|
||||
{
|
||||
type = JSONType_Number;
|
||||
number_value = (double) m_integer_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Array
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONArray m_array_value The JSONArray to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const JSONArray &m_array_value)
|
||||
{
|
||||
type = JSONType_Array;
|
||||
array_value = new JSONArray(m_array_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Object
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONObject m_object_value The JSONObject to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const JSONObject &m_object_value)
|
||||
{
|
||||
type = JSONType_Object;
|
||||
object_value = new JSONObject(m_object_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor to perform a deep copy of array / object values
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONValue m_source The source JSONValue that is being copied
|
||||
*/
|
||||
JSONValue::JSONValue(const JSONValue &m_source)
|
||||
{
|
||||
type = m_source.type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case JSONType_String:
|
||||
string_value = new std::string(*m_source.string_value);
|
||||
break;
|
||||
|
||||
case JSONType_Bool:
|
||||
bool_value = m_source.bool_value;
|
||||
break;
|
||||
|
||||
case JSONType_Number:
|
||||
number_value = m_source.number_value;
|
||||
break;
|
||||
|
||||
case JSONType_Array:
|
||||
{
|
||||
JSONArray source_array = *m_source.array_value;
|
||||
JSONArray::iterator iter;
|
||||
array_value = new JSONArray();
|
||||
for (iter = source_array.begin(); iter != source_array.end(); iter++)
|
||||
array_value->push_back(new JSONValue(**iter));
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Object:
|
||||
{
|
||||
JSONObject source_object = *m_source.object_value;
|
||||
object_value = new JSONObject();
|
||||
JSONObject::iterator iter;
|
||||
for (iter = source_object.begin(); iter != source_object.end(); iter++)
|
||||
{
|
||||
std::string name = (*iter).first;
|
||||
(*object_value)[name] = new JSONValue(*((*iter).second));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Null:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The destructor for the JSON Value object
|
||||
* Handles deleting the objects in the array or the object value
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
JSONValue::~JSONValue()
|
||||
{
|
||||
if (type == JSONType_Array)
|
||||
{
|
||||
JSONArray::iterator iter;
|
||||
for (iter = array_value->begin(); iter != array_value->end(); iter++)
|
||||
delete *iter;
|
||||
delete array_value;
|
||||
}
|
||||
else if (type == JSONType_Object)
|
||||
{
|
||||
JSONObject::iterator iter;
|
||||
for (iter = object_value->begin(); iter != object_value->end(); iter++)
|
||||
{
|
||||
delete (*iter).second;
|
||||
}
|
||||
delete object_value;
|
||||
}
|
||||
else if (type == JSONType_String)
|
||||
{
|
||||
delete string_value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a NULL
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a NULL value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsNull() const
|
||||
{
|
||||
return type == JSONType_Null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a String
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a String value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsString() const
|
||||
{
|
||||
return type == JSONType_String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a Bool
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a Bool value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsBool() const
|
||||
{
|
||||
return type == JSONType_Bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a Number
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a Number value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsNumber() const
|
||||
{
|
||||
return type == JSONType_Number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is an Array
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is an Array value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsArray() const
|
||||
{
|
||||
return type == JSONType_Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is an Object
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is an Object value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsObject() const
|
||||
{
|
||||
return type == JSONType_Object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the String value of this JSONValue
|
||||
* Use IsString() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return std::string Returns the string value
|
||||
*/
|
||||
const std::string &JSONValue::AsString() const
|
||||
{
|
||||
return (*string_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Bool value of this JSONValue
|
||||
* Use IsBool() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns the bool value
|
||||
*/
|
||||
bool JSONValue::AsBool() const
|
||||
{
|
||||
return bool_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Number value of this JSONValue
|
||||
* Use IsNumber() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return double Returns the number value
|
||||
*/
|
||||
double JSONValue::AsNumber() const
|
||||
{
|
||||
return number_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Array value of this JSONValue
|
||||
* Use IsArray() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONArray Returns the array value
|
||||
*/
|
||||
const JSONArray &JSONValue::AsArray() const
|
||||
{
|
||||
return (*array_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Object value of this JSONValue
|
||||
* Use IsObject() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONObject Returns the object value
|
||||
*/
|
||||
const JSONObject &JSONValue::AsObject() const
|
||||
{
|
||||
return (*object_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of children of this JSONValue.
|
||||
* This number will be 0 or the actual number of children
|
||||
* if IsArray() or IsObject().
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return The number of children.
|
||||
*/
|
||||
std::size_t JSONValue::CountChildren() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case JSONType_Array:
|
||||
return array_value->size();
|
||||
case JSONType_Object:
|
||||
return object_value->size();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this JSONValue has a child at the given index.
|
||||
* Use IsArray() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if the array has a value at the given index.
|
||||
*/
|
||||
bool JSONValue::HasChild(std::size_t index) const
|
||||
{
|
||||
if (type == JSONType_Array)
|
||||
{
|
||||
return index < array_value->size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child of this JSONValue at the given index.
|
||||
* Use IsArray() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONValue* Returns JSONValue at the given index or NULL
|
||||
* if it doesn't exist.
|
||||
*/
|
||||
JSONValue *JSONValue::Child(std::size_t index)
|
||||
{
|
||||
if (index < array_value->size())
|
||||
{
|
||||
return (*array_value)[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this JSONValue has a child at the given key.
|
||||
* Use IsObject() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if the object has a value at the given key.
|
||||
*/
|
||||
bool JSONValue::HasChild(const char* name) const
|
||||
{
|
||||
if (type == JSONType_Object)
|
||||
{
|
||||
return object_value->find(name) != object_value->end();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child of this JSONValue at the given key.
|
||||
* Use IsObject() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONValue* Returns JSONValue for the given key in the object
|
||||
* or NULL if it doesn't exist.
|
||||
*/
|
||||
JSONValue* JSONValue::Child(const char* name)
|
||||
{
|
||||
JSONObject::const_iterator it = object_value->find(name);
|
||||
if (it != object_value->end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the keys of the JSON Object or an empty vector
|
||||
* if this value is not an object.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return std::vector<std::string> A vector containing the keys.
|
||||
*/
|
||||
std::vector<std::string> JSONValue::ObjectKeys() const
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
|
||||
if (type == JSONType_Object)
|
||||
{
|
||||
JSONObject::const_iterator iter = object_value->begin();
|
||||
while (iter != object_value->end())
|
||||
{
|
||||
keys.push_back(iter->first);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON encoded string for the value with all necessary characters escaped
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param bool prettyprint Enable prettyprint
|
||||
*
|
||||
* @return std::string Returns the JSON string
|
||||
*/
|
||||
std::string JSONValue::Stringify(bool const prettyprint) const
|
||||
{
|
||||
size_t const indentDepth = prettyprint ? 1 : 0;
|
||||
return StringifyImpl(indentDepth);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a JSON encoded string for the value with all necessary characters escaped
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param size_t indentDepth The prettyprint indentation depth (0 : no prettyprint)
|
||||
*
|
||||
* @return std::string Returns the JSON string
|
||||
*/
|
||||
std::string JSONValue::StringifyImpl(size_t const indentDepth) const
|
||||
{
|
||||
std::string ret_string;
|
||||
size_t const indentDepth1 = indentDepth ? indentDepth + 1 : 0;
|
||||
std::string const indentStr = Indent(indentDepth);
|
||||
std::string const indentStr1 = Indent(indentDepth1);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case JSONType_Null:
|
||||
ret_string = "null";
|
||||
break;
|
||||
|
||||
case JSONType_String:
|
||||
ret_string = StringifyString(*string_value);
|
||||
break;
|
||||
|
||||
case JSONType_Bool:
|
||||
ret_string = bool_value ? "true" : "false";
|
||||
break;
|
||||
|
||||
case JSONType_Number:
|
||||
{
|
||||
if (isinf(number_value) || isnan(number_value))
|
||||
ret_string = "null";
|
||||
else
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.precision(15);
|
||||
ss << number_value;
|
||||
ret_string = ss.str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Array:
|
||||
{
|
||||
ret_string = indentDepth ? "[\n" + indentStr1 : "[";
|
||||
JSONArray::const_iterator iter = array_value->begin();
|
||||
while (iter != array_value->end())
|
||||
{
|
||||
ret_string += (*iter)->StringifyImpl(indentDepth1);
|
||||
|
||||
// Not at the end - add a separator
|
||||
if (++iter != array_value->end())
|
||||
ret_string += ",";
|
||||
}
|
||||
ret_string += indentDepth ? "\n" + indentStr + "]" : "]";
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Object:
|
||||
{
|
||||
ret_string = indentDepth ? "{\n" + indentStr1 : "{";
|
||||
JSONObject::const_iterator iter = object_value->begin();
|
||||
while (iter != object_value->end())
|
||||
{
|
||||
ret_string += StringifyString((*iter).first);
|
||||
ret_string += ":";
|
||||
ret_string += (*iter).second->StringifyImpl(indentDepth1);
|
||||
|
||||
// Not at the end - add a separator
|
||||
if (++iter != object_value->end())
|
||||
ret_string += ",";
|
||||
}
|
||||
ret_string += indentDepth ? "\n" + indentStr + "}" : "}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON encoded string with all required fields escaped
|
||||
* Works from http://www.ecma-internationl.org/publications/files/ECMA-ST/ECMA-262.pdf
|
||||
* Section 15.12.3.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param std::string str The string that needs to have the characters escaped
|
||||
*
|
||||
* @return std::string Returns the JSON string
|
||||
*/
|
||||
std::string JSONValue::StringifyString(const std::string &str)
|
||||
{
|
||||
std::string str_out = "\"";
|
||||
|
||||
std::string::const_iterator iter = str.begin();
|
||||
while (iter != str.end())
|
||||
{
|
||||
char chr = *iter;
|
||||
|
||||
if (chr == '"' || chr == '\\' || chr == '/')
|
||||
{
|
||||
str_out += '\\';
|
||||
str_out += chr;
|
||||
}
|
||||
else if (chr == '\b')
|
||||
{
|
||||
str_out += "\\b";
|
||||
}
|
||||
else if (chr == '\f')
|
||||
{
|
||||
str_out += "\\f";
|
||||
}
|
||||
else if (chr == '\n')
|
||||
{
|
||||
str_out += "\\n";
|
||||
}
|
||||
else if (chr == '\r')
|
||||
{
|
||||
str_out += "\\r";
|
||||
}
|
||||
else if (chr == '\t')
|
||||
{
|
||||
str_out += "\\t";
|
||||
}
|
||||
else if (chr < ' ' || chr > 126)
|
||||
{
|
||||
str_out += "\\u";
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int value = (chr >> 12) & 0xf;
|
||||
if (value >= 0 && value <= 9)
|
||||
str_out += (char)('0' + value);
|
||||
else if (value >= 10 && value <= 15)
|
||||
str_out += (char)('A' + (value - 10));
|
||||
chr <<= 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str_out += chr;
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
str_out += "\"";
|
||||
return str_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the indentation string for the depth given
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param size_t indent The prettyprint indentation depth (0 : no indentation)
|
||||
*
|
||||
* @return std::string Returns the string
|
||||
*/
|
||||
std::string JSONValue::Indent(size_t depth)
|
||||
{
|
||||
const size_t indent_step = 2;
|
||||
depth ? --depth : 0;
|
||||
std::string indentStr(depth * indent_step, ' ');
|
||||
return indentStr;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* File JSONValue.h part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _JSONVALUE_H_
|
||||
#define _JSONVALUE_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "JSON.h"
|
||||
|
||||
class JSON;
|
||||
|
||||
enum JSONType { JSONType_Null, JSONType_String, JSONType_Bool, JSONType_Number, JSONType_Array, JSONType_Object };
|
||||
|
||||
class JSONValue
|
||||
{
|
||||
friend class JSON;
|
||||
|
||||
public:
|
||||
JSONValue(/*NULL*/);
|
||||
JSONValue(const char *m_char_value);
|
||||
JSONValue(const std::string &m_string_value);
|
||||
JSONValue(bool m_bool_value);
|
||||
JSONValue(double m_number_value);
|
||||
JSONValue(int m_integer_value);
|
||||
JSONValue(const JSONArray &m_array_value);
|
||||
JSONValue(const JSONObject &m_object_value);
|
||||
JSONValue(const JSONValue &m_source);
|
||||
~JSONValue();
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
JSONType type;
|
||||
|
||||
union
|
||||
{
|
||||
bool bool_value;
|
||||
double number_value;
|
||||
std::string *string_value;
|
||||
JSONArray *array_value;
|
||||
JSONObject *object_value;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -12,7 +12,7 @@
|
|||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <json11.hpp>
|
||||
#include "mqtt/JSON.h"
|
||||
|
||||
MQTT *mqtt;
|
||||
|
||||
|
@ -32,19 +32,19 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
|
|||
|
||||
if (moduleConfig.mqtt.json_enabled && (strncmp(topic, jsonTopic.c_str(), jsonTopic.length()) == 0)) {
|
||||
// check if this is a json payload message by comparing the topic start
|
||||
using namespace json11;
|
||||
char payloadStr[length + 1];
|
||||
memcpy(payloadStr, payload, length);
|
||||
payloadStr[length] = 0; // null terminated string
|
||||
std::string err;
|
||||
auto json = Json::parse(payloadStr, err);
|
||||
if (err.empty()) {
|
||||
JSONValue *json_value = JSON::Parse(payloadStr);
|
||||
if (json_value != NULL) {
|
||||
DEBUG_MSG("JSON Received on MQTT, parsing..\n");
|
||||
// check if it is a valid envelope
|
||||
if (json.object_items().count("sender") != 0 && json.object_items().count("payload") != 0 && json["type"].string_value().compare("sendtext") == 0) {
|
||||
JSONObject json;
|
||||
json = json_value->AsObject();
|
||||
if ((json.find("sender") != json.end()) && (json.find("payload") != json.end()) && (json.find("type") != json.end()) && json["type"]->IsString() && (json["type"]->AsString().compare("sendtext") == 0)) {
|
||||
// this is a valid envelope
|
||||
if (json["sender"].string_value().compare(owner.id) != 0) {
|
||||
std::string jsonPayloadStr = json["payload"].dump();
|
||||
if (json["payload"]->IsString() && json["type"]->IsString() && (json["sender"]->AsString().compare(owner.id) != 0)) {
|
||||
std::string jsonPayloadStr = json["payload"]->AsString();
|
||||
DEBUG_MSG("JSON payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length());
|
||||
|
||||
// construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
|
||||
|
@ -68,6 +68,7 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
|
|||
// no json, this is an invalid payload
|
||||
DEBUG_MSG("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length);
|
||||
}
|
||||
delete json_value;
|
||||
} else {
|
||||
if (!pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e)) {
|
||||
DEBUG_MSG("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length);
|
||||
|
@ -250,7 +251,6 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
|
|||
|
||||
if (moduleConfig.mqtt.json_enabled) {
|
||||
// handle json topic
|
||||
using namespace json11;
|
||||
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
|
||||
if (jsonString.length() != 0) {
|
||||
String topicJson = jsonTopic + channelId + "/" + owner.id;
|
||||
|
@ -264,12 +264,11 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
|
|||
// converts a downstream packet into a json message
|
||||
std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
// the created jsonObj is immutable after creation, so
|
||||
// we need to do the heavy lifting before assembling it.
|
||||
String msgType;
|
||||
Json msgPayload;
|
||||
JSONObject msgPayload;
|
||||
JSONObject jsonObj;
|
||||
|
||||
switch (mp->decoded.portnum) {
|
||||
case PortNum_TEXT_MESSAGE_APP: {
|
||||
|
@ -280,17 +279,17 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
|||
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
|
||||
std::string err;
|
||||
auto json = Json::parse(payloadStr, err);
|
||||
if (err.empty()) {
|
||||
JSONValue *json_value = JSON::Parse(payloadStr);
|
||||
if (json_value != NULL) {
|
||||
DEBUG_MSG("text message payload is of type json\n");
|
||||
// if it is, then we can just use the json object
|
||||
msgPayload = json;
|
||||
jsonObj["payload"] = json_value;
|
||||
} else {
|
||||
// if it isn't, then we need to create a json object
|
||||
// with the string as the value
|
||||
DEBUG_MSG("text message payload is of type plaintext\n");
|
||||
msgPayload = Json::object{{"text", payloadStr}};
|
||||
msgPayload["text"] = new JSONValue(payloadStr);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -303,22 +302,19 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
|||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->which_variant == Telemetry_device_metrics_tag) {
|
||||
msgPayload = Json::object{
|
||||
{"battery_level", (int)decoded->variant.device_metrics.battery_level},
|
||||
{"voltage", decoded->variant.device_metrics.voltage},
|
||||
{"channel_utilization", decoded->variant.device_metrics.channel_utilization},
|
||||
{"air_util_tx", decoded->variant.device_metrics.air_util_tx},
|
||||
};
|
||||
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);
|
||||
} else if (decoded->which_variant == Telemetry_environment_metrics_tag) {
|
||||
msgPayload = Json::object{
|
||||
{"temperature", decoded->variant.environment_metrics.temperature},
|
||||
{"relative_humidity", decoded->variant.environment_metrics.relative_humidity},
|
||||
{"barometric_pressure", decoded->variant.environment_metrics.barometric_pressure},
|
||||
{"gas_resistance", decoded->variant.environment_metrics.gas_resistance},
|
||||
{"voltage", decoded->variant.environment_metrics.voltage},
|
||||
{"current", decoded->variant.environment_metrics.current},
|
||||
};
|
||||
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
|
||||
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
|
||||
msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure);
|
||||
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
|
||||
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
|
||||
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
|
||||
}
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else
|
||||
DEBUG_MSG("Error decoding protobuf for telemetry message!\n");
|
||||
};
|
||||
|
@ -332,13 +328,11 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
|||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &User_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload = Json::object{
|
||||
{"id", decoded->id},
|
||||
{"longname", decoded->long_name},
|
||||
{"shortname", decoded->short_name},
|
||||
{"hardware", decoded->hw_model}
|
||||
};
|
||||
|
||||
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);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else
|
||||
DEBUG_MSG("Error decoding protobuf for nodeinfo message!\n");
|
||||
};
|
||||
|
@ -352,13 +346,12 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
|||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Position_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload = Json::object{
|
||||
{"time", (int)decoded->time},
|
||||
{"pos_timestamp", (int)decoded->timestamp},
|
||||
{"latitude_i", (int)decoded->latitude_i},
|
||||
{"longitude_i", (int)decoded->longitude_i},
|
||||
{"altitude", (int)decoded->altitude}
|
||||
};
|
||||
msgPayload["time"] = new JSONValue((int)decoded->time);
|
||||
msgPayload["timestamp"] = new JSONValue((int)decoded->timestamp);
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
msgPayload["altitude"] = new JSONValue((int)decoded->altitude);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else {
|
||||
DEBUG_MSG("Error decoding protobuf for position message!\n");
|
||||
}
|
||||
|
@ -374,15 +367,14 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
|||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Waypoint_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload = Json::object{
|
||||
{"id", (int)decoded->id},
|
||||
{"name", decoded->name},
|
||||
{"description", decoded->description},
|
||||
{"expire", (int)decoded->expire},
|
||||
{"locked", decoded->locked},
|
||||
{"latitude_i", (int)decoded->latitude_i},
|
||||
{"longitude_i", (int)decoded->longitude_i},
|
||||
};
|
||||
msgPayload["id"] = new JSONValue((int)decoded->id);
|
||||
msgPayload["name"] = new JSONValue(decoded->name);
|
||||
msgPayload["description"] = new JSONValue(decoded->description);
|
||||
msgPayload["expire"] = new JSONValue((int)decoded->expire);
|
||||
msgPayload["locked"] = new JSONValue(decoded->locked);
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else {
|
||||
DEBUG_MSG("Error decoding protobuf for position message!\n");
|
||||
}
|
||||
|
@ -394,21 +386,20 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
|||
break;
|
||||
}
|
||||
|
||||
// assemble the final jsonObj
|
||||
Json jsonObj = Json::object{
|
||||
{"id", Json((int)mp->id)},
|
||||
{"timestamp", Json((int)mp->rx_time)},
|
||||
{"to", Json((int)mp->to)},
|
||||
{"from", Json((int)mp->from)},
|
||||
{"channel", Json((int)mp->channel)},
|
||||
{"type", msgType.c_str()},
|
||||
{"sender", owner.id},
|
||||
{"payload", msgPayload}
|
||||
};
|
||||
jsonObj["id"] = new JSONValue((int)mp->id);
|
||||
jsonObj["timestamp"] = new JSONValue((int)mp->rx_time);
|
||||
jsonObj["to"] = new JSONValue((int)mp->to);
|
||||
jsonObj["from"] = new JSONValue((int)mp->from);
|
||||
jsonObj["channel"] = new JSONValue((int)mp->channel);
|
||||
jsonObj["type"] = new JSONValue(msgType.c_str());
|
||||
jsonObj["sender"] = new JSONValue(owner.id);
|
||||
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObj);
|
||||
std::string jsonStr = value->Stringify();
|
||||
|
||||
// serialize and return it
|
||||
std::string jsonStr = jsonObj.dump();
|
||||
DEBUG_MSG("serialized json message: %s\n", jsonStr.c_str());
|
||||
|
||||
delete value;
|
||||
return jsonStr;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,10 @@ cstyleCast
|
|||
// ignore stuff that is not ours
|
||||
*:.pio/*
|
||||
*:*/libdeps/*
|
||||
noExplicitConstructor:*/mqtt/*
|
||||
postfixOperator:*/mqtt/*
|
||||
|
||||
// these two caused issues
|
||||
missingOverride
|
||||
virtualCallInConstructor
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
#include "Speaker.h"
|
||||
|
||||
TONE::TONE(void) {
|
||||
_volume = 5;
|
||||
_begun = false;
|
||||
}
|
||||
|
||||
void TONE::begin() {
|
||||
_begun = true;
|
||||
ledcSetup(TONE_PIN_CHANNEL, 0, 13);
|
||||
ledcAttachPin(PIN_BUZZER, TONE_PIN_CHANNEL);
|
||||
}
|
||||
|
||||
void TONE::end() {
|
||||
mute();
|
||||
ledcDetachPin(PIN_BUZZER);
|
||||
_begun = false;
|
||||
}
|
||||
|
||||
void TONE::tone(uint16_t frequency) {
|
||||
if(!_begun) begin();
|
||||
ledcWriteTone(TONE_PIN_CHANNEL, frequency);
|
||||
ledcWrite(TONE_PIN_CHANNEL, 0x400 >> _volume);
|
||||
}
|
||||
|
||||
void TONE::setVolume(uint8_t volume) {
|
||||
_volume = 11 - volume;
|
||||
}
|
||||
|
||||
void TONE::mute() {
|
||||
ledcWriteTone(TONE_PIN_CHANNEL, 0);
|
||||
digitalWrite(PIN_BUZZER, 0);
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#ifndef _SPEAKER_H_
|
||||
#define _SPEAKER_H_
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
#include "esp32-hal-dac.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
class TONE {
|
||||
public:
|
||||
TONE(void);
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
void mute();
|
||||
void tone(uint16_t frequency);
|
||||
void setVolume(uint8_t volume);
|
||||
|
||||
private:
|
||||
uint8_t _volume;
|
||||
bool _begun;
|
||||
bool speaker_on;
|
||||
};
|
||||
#endif
|
|
@ -6,7 +6,6 @@ monitor_port = COM8
|
|||
monitor_filters = esp32_exception_decoder
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter}
|
||||
+<../variants/m5stack_core>
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -I variants/m5stack_core
|
||||
-DILI9341_DRIVER
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#define BUTTON_PIN 38
|
||||
|
||||
#define PIN_BUZZER 25
|
||||
#define TONE_PIN_CHANNEL 0
|
||||
|
||||
#undef RF95_SCK
|
||||
#undef RF95_MISO
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
#include "Speaker.h"
|
||||
|
||||
TONE::TONE(void) {
|
||||
_volume = 5;
|
||||
_begun = false;
|
||||
}
|
||||
|
||||
void TONE::begin() {
|
||||
_begun = true;
|
||||
ledcSetup(TONE_PIN_CHANNEL, 0, 13);
|
||||
ledcAttachPin(PIN_BUZZER, TONE_PIN_CHANNEL);
|
||||
}
|
||||
|
||||
void TONE::end() {
|
||||
mute();
|
||||
ledcDetachPin(PIN_BUZZER);
|
||||
_begun = false;
|
||||
}
|
||||
|
||||
void TONE::tone(uint16_t frequency) {
|
||||
if(!_begun) begin();
|
||||
ledcWriteTone(TONE_PIN_CHANNEL, frequency);
|
||||
ledcWrite(TONE_PIN_CHANNEL, 0x400 >> _volume);
|
||||
}
|
||||
|
||||
void TONE::setVolume(uint8_t volume) {
|
||||
_volume = 11 - volume;
|
||||
}
|
||||
|
||||
void TONE::mute() {
|
||||
ledcWriteTone(TONE_PIN_CHANNEL, 0);
|
||||
digitalWrite(PIN_BUZZER, 0);
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#ifndef _SPEAKER_H_
|
||||
#define _SPEAKER_H_
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
#include "esp32-hal-dac.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
class TONE {
|
||||
public:
|
||||
TONE(void);
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
void mute();
|
||||
void tone(uint16_t frequency);
|
||||
void setVolume(uint8_t volume);
|
||||
|
||||
private:
|
||||
uint8_t _volume;
|
||||
bool _begun;
|
||||
bool speaker_on;
|
||||
};
|
||||
#endif
|
|
@ -3,7 +3,6 @@ extends = esp32_base
|
|||
board = m5stack-coreink
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter}
|
||||
+<../variants/m5stack_coreink>
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -I variants/m5stack_coreink
|
||||
;-D RADIOLIB_VERBOSE
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
//BUZZER
|
||||
#define PIN_BUZZER 2
|
||||
#define TONE_PIN_CHANNEL 0
|
||||
|
||||
#undef RF95_SCK
|
||||
#undef RF95_MISO
|
||||
|
|
|
@ -205,7 +205,8 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
|||
#define RV3028_RTC (uint8_t) 0b1010010
|
||||
|
||||
// RAK18001 Buzzer in Slot C
|
||||
#define PIN_BUZZER 21 // IO3 is PWM2
|
||||
// #define PIN_BUZZER 21 // IO3 is PWM2
|
||||
// NEW: set this via protobuf instead!
|
||||
|
||||
// Battery
|
||||
// The battery sense is hooked to pin A0 (5)
|
||||
|
|
Ładowanie…
Reference in New Issue