diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini
index fb1e45af..cd962b67 100644
--- a/arch/portduino/portduino.ini
+++ b/arch/portduino/portduino.ini
@@ -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
diff --git a/platformio.ini b/platformio.ini
index 94e3e9f5..dbddf753 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -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} -
; Common libs for communicating over TCP/IP networks such as MQTT
@@ -94,7 +92,6 @@ build_src_filter = ${env.build_src_filter} -
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)
diff --git a/protobufs b/protobufs
index 24874086..3aca01ac 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 24874086e392b0ec504f9f89137e7b7f8b5bfcbd
+Subproject commit 3aca01ac82487de8aa3d5eefdd907b4d80714501
diff --git a/src/buzz/buzz.cpp b/src/buzz/buzz.cpp
index f8314fe5..262cd20b 100644
--- a/src/buzz/buzz.cpp
+++ b/src/buzz/buzz.cpp
@@ -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
\ No newline at end of file
diff --git a/src/detect/i2cScan.h b/src/detect/i2cScan.h
index 19e40513..4eac50f0 100644
--- a/src/detect/i2cScan.h
+++ b/src/detect/i2cScan.h
@@ -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) {
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index 534a0ebe..54dc59cb 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -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
diff --git a/src/main.h b/src/main.h
index b7b41c25..89a6bd05 100644
--- a/src/main.h
+++ b/src/main.h
@@ -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
#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
diff --git a/src/mesh/generated/config.pb.h b/src/mesh/generated/config.pb.h
index 9748383c..2d6f3a1d 100644
--- a/src/mesh/generated/config.pb.h
+++ b/src/mesh/generated/config.pb.h
@@ -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
diff --git a/src/mesh/generated/localonly.pb.h b/src/mesh/generated/localonly.pb.h
index 783c523c..f2c12b10 100644
--- a/src/mesh/generated/localonly.pb.h
+++ b/src/mesh/generated/localonly.pb.h
@@ -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" */
diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h
index af4d4dce..d4e54642 100644
--- a/src/mesh/generated/module_config.pb.h
+++ b/src/mesh/generated/module_config.pb.h
@@ -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
diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp
index 82ac8fee..d01f3c4a 100644
--- a/src/mesh/http/ContentHandler.cpp
+++ b/src/mesh/http/ContentHandler.cpp
@@ -12,7 +12,7 @@
#include
#include
#include
-#include
+#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> *htmlListDir(std::vector> *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> *htmlListDir(std::vector 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> *htmlListDir(std::vectorpush_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>(), "/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 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 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 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 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;
}
diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp
index c00738d1..bb454246 100644
--- a/src/mesh/http/WiFiAPClient.cpp
+++ b/src/mesh/http/WiFiAPClient.cpp
@@ -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");
diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp
index e5d371c1..5a95ceec 100644
--- a/src/modules/ExternalNotificationModule.cpp
+++ b/src/modules/ExternalNotificationModule.cpp
@@ -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();
diff --git a/src/mqtt/JSON.cpp b/src/mqtt/JSON.cpp
new file mode 100644
index 00000000..65bff304
--- /dev/null
+++ b/src/mqtt/JSON.cpp
@@ -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 - ""
+ * 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;
+}
diff --git a/src/mqtt/JSON.h b/src/mqtt/JSON.h
new file mode 100644
index 00000000..d6532d69
--- /dev/null
+++ b/src/mqtt/JSON.h
@@ -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
+#include
+#include