diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..361a3c85 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "test/googletest"] + path = test/googletest + url = https://github.com/google/googletest.git +[submodule "test/arduino-mock"] + path = test/arduino-mock + url = https://github.com/ed7coyne/arduino-mock.git diff --git a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino index 3584102e..5dcb80e1 100644 --- a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino +++ b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino @@ -17,11 +17,13 @@ // FirebasePush_ESP8266 is a sample that push a new timestamp to firebase // on each reset. +#include + #include // create firebase client. -Firebase fbase = Firebase("example.firebaseio.com") - .auth("secret_or_token"); +Firebase fbase("example.firebaseio.com") + .auth("secret_or_token"); void setup() { Serial.begin(9600); @@ -46,7 +48,7 @@ void setup() { } // print key. - Serial.println(push.name()); + Serial.println("Name: " + push.name()); // get all entries. FirebaseGet get = fbase.get("/logs"); @@ -55,8 +57,9 @@ void setup() { Serial.println(push.error().message()); return; } - // print json. - Serial.println(get.json()); + // Print written timestamp. + String data = get.json()[push.name()]; + Serial.println("Timestamp:" + data); } void loop() { diff --git a/examples/FirebaseSerialHost_ESP8266/FirebaseSerialHost_ESP8266.ino b/examples/FirebaseSerialHost_ESP8266/FirebaseSerialHost_ESP8266.ino new file mode 100644 index 00000000..62bd6121 --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/FirebaseSerialHost_ESP8266.ino @@ -0,0 +1,67 @@ +// +// Copyright 2015 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +// A sample that will start our serial transciever listening on a software +// port and allow debug over the main serial port. +// +// A suggested setup for testing this example would be a USB to TTL cable +// with the green wire connected to pin 5 and the white wire connected to +// pin 4 (on the huzzah feather esp8266). +// First edit begin.txt and put in your host and secret. +// Then run the following commands to setup the serial port in linux: +// stty -F /dev/ttyUSB0 9600 raw -echo -echoe -echok +// Then on one console do: +// cat /dev/ttyUSB0 & +// This console will now read all responses from the modem. Then do: +// cat begin.txt > /dev/ttyUSB0 +// You should see +OK and you can now feed in the other example commmands. + +#include +#include + +#include +#include + +SoftwareSerial data_serial(5 /*RX*/, 4/*TX*/); +firebase::modem::SerialTransceiver transceiver; + +void setup() { + Serial.begin(9600); + + // connect to wifi. + WiFi.begin("SSID", "PASSWORD"); + Serial.print("connecting"); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + Serial.println(); + Serial.print("connected: "); + Serial.println(WiFi.localIP()); + + data_serial.begin(9600); + while (!data_serial) { + Serial.println("Error initilizing serial."); + delay(5000); + } + + transceiver.begin(&data_serial); +} + +void loop() { + transceiver.loop(); +} diff --git a/examples/FirebaseSerialHost_ESP8266/begin.txt b/examples/FirebaseSerialHost_ESP8266/begin.txt new file mode 100644 index 00000000..d0b9a4a9 --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/begin.txt @@ -0,0 +1,2 @@ +BEGIN $YOUR_HOST $YOUR_SECRET + diff --git a/examples/FirebaseSerialHost_ESP8266/begin_stream.txt b/examples/FirebaseSerialHost_ESP8266/begin_stream.txt new file mode 100644 index 00000000..54cf97b3 --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/begin_stream.txt @@ -0,0 +1,2 @@ +BEGIN_STREAM /serial/test + diff --git a/examples/FirebaseSerialHost_ESP8266/end_stream.txt b/examples/FirebaseSerialHost_ESP8266/end_stream.txt new file mode 100644 index 00000000..173d7c2c --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/end_stream.txt @@ -0,0 +1,2 @@ +END_STREAM + diff --git a/examples/FirebaseSerialHost_ESP8266/get.txt b/examples/FirebaseSerialHost_ESP8266/get.txt new file mode 100644 index 00000000..067a78ce --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/get.txt @@ -0,0 +1,2 @@ +GET /serial/test + diff --git a/examples/FirebaseSerialHost_ESP8266/get_push.txt b/examples/FirebaseSerialHost_ESP8266/get_push.txt new file mode 100644 index 00000000..f7eba497 --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/get_push.txt @@ -0,0 +1 @@ +GET /serial/push_test diff --git a/examples/FirebaseSerialHost_ESP8266/push.txt b/examples/FirebaseSerialHost_ESP8266/push.txt new file mode 100644 index 00000000..9878dd3c --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/push.txt @@ -0,0 +1 @@ +PUSH /seria/push_test "this is a test string \ " diff --git a/examples/FirebaseSerialHost_ESP8266/remove.txt b/examples/FirebaseSerialHost_ESP8266/remove.txt new file mode 100644 index 00000000..911f86a3 --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/remove.txt @@ -0,0 +1 @@ +REMOVE /serial/test diff --git a/examples/FirebaseSerialHost_ESP8266/set.txt b/examples/FirebaseSerialHost_ESP8266/set.txt new file mode 100644 index 00000000..8810bf0f --- /dev/null +++ b/examples/FirebaseSerialHost_ESP8266/set.txt @@ -0,0 +1,2 @@ +SET /serial/test this is a test string \ " + diff --git a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino index e4f10e64..4e0729c4 100644 --- a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino +++ b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino @@ -18,11 +18,12 @@ // public Firebase and optionally display them on a OLED i2c screen. #include +#include #include #include #include -#define OLED_RESET 10 +#define OLED_RESET 3 Adafruit_SSD1306 display(OLED_RESET); Firebase fbase("publicdata-cryptocurrency.firebaseio.com"); @@ -44,7 +45,7 @@ void setup() { Serial.println(); Serial.print("connected: "); Serial.println(WiFi.localIP()); - stream = fbase.stream("/bitcoin"); + stream = fbase.stream("/bitcoin/last"); } @@ -65,7 +66,7 @@ void loop() { Serial.println(event); JsonObject& json = buf.parseObject((char*)event.c_str()); String path = json["path"]; - float data = json["data"]; + float data = json["data"]["last"]; // TODO(proppy): parse JSON object. display.clearDisplay(); diff --git a/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/.gitignore b/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/.gitignore new file mode 100644 index 00000000..fd5106ff --- /dev/null +++ b/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/.gitignore @@ -0,0 +1 @@ +.DS_STORE diff --git a/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/Firebase_ESP8266_Neopixel.ino b/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/Firebase_ESP8266_Neopixel.ino new file mode 100644 index 00000000..89b35351 --- /dev/null +++ b/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/Firebase_ESP8266_Neopixel.ino @@ -0,0 +1,99 @@ +// +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Firebase_ESP8266-Neopixel is a sample that demonstrates how +// to set pixel data using a firebase stream. +#include +#include + +#include +#include "colors_ext.h" + +const int PIN=13; +Adafruit_NeoPixel strip = Adafruit_NeoPixel(32, PIN, NEO_GRB + NEO_KHZ800); + +#define JSON_BUFFER_SIZE 10*4 + +// TODO: Replace with your own credentials and keep these safe. +Firebase fbase = Firebase("YOUR-PROJECT.firebaseio.com") + .auth("YOUR_AUTH_SECRET"); + +void setup() { + Serial.begin(9600); + + strip.begin(); + strip.setBrightness(25); // 0 ... 255 + strip.show(); // Initialize all pixels to 'off' + + // Not connected, set the LEDs red + colorWipe(&strip, 0xFF0000, 50); + + // connect to wifi. + WiFi.begin("GoogleGuest", ""); + Serial.print("connecting"); + + int count = 0; + while (WiFi.status() != WL_CONNECTED) { + // Draw rainbows while connecting + Serial.print("."); + if (count < strip.numPixels()){ + strip.setPixelColor(count++, Wheel(&strip, count * 8)); + strip.show(); + } + delay(20); + } + Serial.println(); + Serial.print("connected: "); + Serial.println(WiFi.localIP()); + + // Connected, set the LEDs green + colorWipe(&strip, 0x00FF00, 50); +} + + +void loop() { + // Get all entries. + // TODO: Replace with streaming + FirebaseGet get = fbase.get("/rgbdata"); + if (get.error()) { + Serial.println("Firebase get failed"); + Serial.println(get.error().message()); + return; + } + + // Use dynamic for large JSON objects + // DynamicJsonBuffer jsonBuffer; + StaticJsonBuffer jsonBuffer; + + // create an empty object + String ref = get.json(); + Serial.println(ref); + JsonObject& pixelJSON = jsonBuffer.parseObject((char*)ref.c_str()); + + if(pixelJSON.success()){ + for (int i=0; i < strip.numPixels(); i++) { + String pixelAddress = "pixel" + String(i); + String pixelVal = pixelJSON[pixelAddress]; + Serial.println(pixelVal); + strip.setPixelColor(i, pixelVal.toInt()); + } + strip.show(); + } else { + Serial.println("Parse fail."); + Serial.println(get.json()); + } +} + diff --git a/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/colors_ext.h b/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/colors_ext.h new file mode 100644 index 00000000..5b78674e --- /dev/null +++ b/examples/Firebase_ESP8266_LEDs/Firebase_ESP8266_Neopixel/colors_ext.h @@ -0,0 +1,93 @@ +// The following methods are extracted from the Adafruit Neopixel example, strandtest. +// https://github.com/adafruit/Adafruit_NeoPixel + +#ifndef COLORS_EXT_H +#define COLORS_EXT_H + +// Input a value 0 to 255 to get a color value. +// The colours are a transition r - g - b - back to r. +uint32_t Wheel(Adafruit_NeoPixel* strip, byte WheelPos) { + WheelPos = 255 - WheelPos; + if(WheelPos < 85) { + return strip->Color(255 - WheelPos * 3, 0, WheelPos * 3); + } + if(WheelPos < 170) { + WheelPos -= 85; + return strip->Color(0, WheelPos * 3, 255 - WheelPos * 3); + } + WheelPos -= 170; + return strip->Color(WheelPos * 3, 255 - WheelPos * 3, 0); +} + + + +// Fill the dots one after the other with a color +void colorWipe(Adafruit_NeoPixel* strip, uint32_t c, uint8_t wait) { + for(uint16_t i=0; inumPixels(); i++) { + strip->setPixelColor(i, c); + strip->show(); + delay(wait); + } +} + +void rainbow(Adafruit_NeoPixel* strip, uint8_t wait) { + uint16_t i, j; + + for(j=0; j<256; j++) { + for(i=0; inumPixels(); i++) { + strip->setPixelColor(i, Wheel(strip, (i+j) & 255)); + } + strip->show(); + delay(wait); + } +} + +// Slightly different, this makes the rainbow equally distributed throughout +void rainbowCycle(Adafruit_NeoPixel* strip, uint8_t wait) { + uint16_t i, j; + + for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel + for(i=0; i< strip->numPixels(); i++) { + strip->setPixelColor(i, Wheel(strip, ((i * 256 / strip->numPixels()) + j) & 255)); + } + strip->show(); + delay(wait); + } +} + +//Theatre-style crawling lights. +void theaterChase(Adafruit_NeoPixel* strip, uint32_t c, uint8_t wait) { + for (int j=0; j<10; j++) { //do 10 cycles of chasing + for (int q=0; q < 3; q++) { + for (int i=0; i < strip->numPixels(); i=i+3) { + strip->setPixelColor(i+q, c); //turn every third pixel on + } + strip->show(); + + delay(wait); + + for (int i=0; i < strip->numPixels(); i=i+3) { + strip->setPixelColor(i+q, 0); //turn every third pixel off + } + } + } +} + +//Theatre-style crawling lights with rainbow effect +void theaterChaseRainbow(Adafruit_NeoPixel* strip, uint8_t wait) { + for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel + for (int q=0; q < 3; q++) { + for (int i=0; i < strip->numPixels(); i=i+3) { + strip->setPixelColor(i+q, Wheel(strip, (i+j) % 255)); //turn every third pixel on + } + strip->show(); + + delay(wait); + + for (int i=0; i < strip->numPixels(); i=i+3) { + strip->setPixelColor(i+q, 0); //turn every third pixel off + } + } + } +} +#endif diff --git a/examples/Firebase_ESP8266_LEDs/www/.gitignore b/examples/Firebase_ESP8266_LEDs/www/.gitignore new file mode 100644 index 00000000..c346b134 --- /dev/null +++ b/examples/Firebase_ESP8266_LEDs/www/.gitignore @@ -0,0 +1,2 @@ +bower_components/ +node_modules/ diff --git a/examples/Firebase_ESP8266_LEDs/www/README.md b/examples/Firebase_ESP8266_LEDs/www/README.md new file mode 100644 index 00000000..d42490bd --- /dev/null +++ b/examples/Firebase_ESP8266_LEDs/www/README.md @@ -0,0 +1,26 @@ +# Firebase Neopixel Web demo # + +This demo console shows you how to synchronize data from the web to a device. + +## Installation ## +The demo uses [Bower](http://bower.io/) and +[Polymer](http://www.polymer-project.org/) to simplify the UI and dependencies +of the project. + +For Bower, you need to install [Node.js](http://nodejs.org/). After node is +installed, install the Bower package by calling: + +`npm install -g bower` + +After Bower is installed, you are ready to update the project dependencies with +Bower by running: + +`bower install` + +With the dependencies set, serve the www folder from a web server. For example, +you can use the Python Simple HTTP server module by running: + +`python -m SimpleHTTPServer [port]` + +With the web server running, navigate to /web-demo.html and you should see +the demo load. diff --git a/examples/Firebase_ESP8266_LEDs/www/bower.json b/examples/Firebase_ESP8266_LEDs/www/bower.json new file mode 100644 index 00000000..996e0e06 --- /dev/null +++ b/examples/Firebase_ESP8266_LEDs/www/bower.json @@ -0,0 +1,23 @@ +{ + "name": "web", + "homepage": "https://github.com/gguuss/firebase-arduino", + "authors": [ + "Gus Class " + ], + "description": "", + "main": "", + "moduleType": [], + "license": "MIT", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "polymer": "^1.2.0", + "polymer-color-picker": "^1.0.1" + } +} diff --git a/examples/Firebase_ESP8266_LEDs/www/web-demo.html b/examples/Firebase_ESP8266_LEDs/www/web-demo.html new file mode 100644 index 00000000..42c7dbc2 --- /dev/null +++ b/examples/Firebase_ESP8266_LEDs/www/web-demo.html @@ -0,0 +1,226 @@ + + + + + + + + + + +

Paint Demo

+ + Pick a color then click a cell. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+





+

Debugger / tester

+
+ + + +
+Examples:
+
+Boring RGB pixels
+
+{ + "pixel0":16711680, "pixel1":255, "pixel2":65280, "pixel3":16711680, "pixel4":255, "pixel5":65280, "pixel6":16711680, "pixel7":16711680, + "pixel8":16711680, "pixel9":255, "pixel10":65280, "pixel11":16711680, "pixel12":255, "pixel13":65280, "pixel14":16711680, "pixel15":16711680, + "pixel16":16711680, "pixel17":255, "pixel18":65280, "pixel19":16711680, "pixel20":255, "pixel21":65280, "pixel22":16711680, "pixel23":16711680, + "pixel24":16711680, "pixel25":255, "pixel26":65280, "pixel27":16711680, "pixel28":255, "pixel29":65280, "pixel30":16711680, "pixel31":16711680 +} +
+Charlie +
+{ + "pixel0":0, "pixel1":16776960, "pixel2":16776960, "pixel3":16776960, "pixel4":0, "pixel5":16776960, "pixel6":16776960, "pixel7":16776960, + "pixel8":0, "pixel9":0, "pixel10":16776960, "pixel11":0, "pixel12":0, "pixel13":0, "pixel14":16776960, "pixel15":16776960, + "pixel16":16776960, "pixel17":0, "pixel18":0, "pixel19":0, "pixel20":16776960, "pixel21":0, "pixel22":0, "pixel23":0, + "pixel24":16776960, "pixel25":16776960, "pixel26":0, "pixel27":16776960, "pixel28":16776960, "pixel29":16776960, "pixel30":0, "pixel31":16776960 +} +
+Proppy +
+{ + "pixel0":16748288,"pixel1":16748288,"pixel10":236517,"pixel11":236517,"pixel12":16748288,"pixel13":16748288,"pixel14":236517,"pixel15":236517, + "pixel16":16748288,"pixel17":16748288,"pixel18":236517,"pixel19":236517,"pixel2":236517,"pixel20":16748288,"pixel21":16748288,"pixel22":236517, + "pixel23":236517,"pixel24":16748288,"pixel25":16748288,"pixel26":236517,"pixel27":236517,"pixel28":16748288,"pixel29":16748288,"pixel3":236517, + "pixel30":236517,"pixel31":236517,"pixel4":16748288,"pixel5":16748288,"pixel6":236517,"pixel7":236517,"pixel8":16748288,"pixel9":16748288 +} +
+ + + diff --git a/hardware/FireboyYun/bom.txt b/hardware/FireboyYun/bom.txt new file mode 100644 index 00000000..60c5de8d --- /dev/null +++ b/hardware/FireboyYun/bom.txt @@ -0,0 +1,7 @@ +Partlist exported from fireboy_yun.sch at 4/7/16 10:39 AM + +Qty Value Device Package Parts Description +13 1X2-3.5MM 1X2-3.5MM 1X2-3.5MM DC_5V_8A, L1_IO, L1_PWR, L2_IO, L2_PWR, L3_IO, L3_PWR, L4_IO, L4_PWR, SW_P1, SW_P2, SW_RST, SW_UND 3.5mm Terminal block +1 1X4-BIG 1X4-BIG 1X04-BIG DISPLAY 4-pin connector +1 220 100OHM-1/4W-5%(PTH) AXIAL-0.3 PWR_LED_R1 RES-08059 +1 Blue LED3MM LED3MM PWR_LED LED diff --git a/hardware/FireboyYun/eagle.epf b/hardware/FireboyYun/eagle.epf new file mode 100644 index 00000000..df73b350 --- /dev/null +++ b/hardware/FireboyYun/eagle.epf @@ -0,0 +1,2 @@ +[Eagle] +Version="07 05 00" \ No newline at end of file diff --git a/hardware/FireboyYun/fireboy_yun.brd b/hardware/FireboyYun/fireboy_yun.brd new file mode 100644 index 00000000..c7091fac --- /dev/null +++ b/hardware/FireboyYun/fireboy_yun.brd @@ -0,0 +1,870 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fireboy, powered by Firebase +Semper Legitimi +GND +GND +GND +GND +GND +VCC +Fireboy, powered by Firebase +Semper Legitimi +VCC +VCC +VCC +VCC +VCC +DAT +DAT +DAT +DAT +Gower +Gower + + + + + + + + + + + + + + +>NAME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<B>LED</B><p> +3 mm, round + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RST +3v +5v +Gnd +Vin +Analog In +0 +1 +2 +3 +4 +5 +12 +11 +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 +Digital I/O +Digital I/O + + + + + + + + +<h3>SparkFun Electronics' preferred foot prints</h3> +In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> +We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. +<br><br> +<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ +<br><br> +You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. + + + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + + +<b>EAGLE Design Rules</b> +<p> +Die Standard-Design-Rules sind so gewählt, dass sie für +die meisten Anwendungen passen. Sollte ihre Platine +besondere Anforderungen haben, treffen Sie die erforderlichen +Einstellungen hier und speichern die Design Rules unter +einem neuen Namen ab. +<b>EAGLE Design Rules</b> +<p> +The default Design Rules have been set to cover +a wide range of applications. Your particular design +may have different requirements, so please make the +necessary adjustments and save your customized +design rules under a new name. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hardware/FireboyYun/fireboy_yun.sch b/hardware/FireboyYun/fireboy_yun.sch new file mode 100644 index 00000000..30516b91 --- /dev/null +++ b/hardware/FireboyYun/fireboy_yun.sch @@ -0,0 +1,2376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME + + + + + + + + + + + + + + + + + + + +>NAME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME + + + + + + + + +<b>CHICAGO MINIATURE LAMP, INC.</b><p> +7022X Series SMT LEDs 1206 Package Size + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + +<B>LED</B><p> +5 mm, square, Siemens + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<B>LED</B><p> +2 x 5 mm, rectangle + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + +<B>LED</B><p> +3 mm, round + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<B>LED</B><p> +5 mm, round + + + + + + + + + + + +>NAME +>VALUE + + +<B>LED</B><p> +1 mm, round, Siemens + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<B>LED BLOCK</B><p> +1 LED, Siemens + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>LED HOLDER</b><p> +Siemens + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>LED HOLDER</b><p> +Siemens + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>LED HOLDER</b><p> +Siemens + + + + + + + + + + + + + + + + + +A+ +K- +>NAME +>VALUE + + + + + +<b>LED HOLDER</b><p> +Siemens + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE ++ +- + + +<B>IR LED</B><p> +infrared emitting diode, Infineon +TO-18, lead spacing 2.54 mm, cathode marking<p> +Inifineon + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<B>IR LED</B><p> +infrared emitting diode, Infineon +TO-18, lead spacing 2.54 mm, cathode marking<p> +Inifineon + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<B>LED</B><p> +rectangle, 5.7 x 3.2 mm + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<B>IR LED</B><p> +IR transmitter Siemens + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>TOPLED® High-optical Power LED (HOP)</b><p> +Source: http://www.osram.convergy.de/ ... ls_t675.pdf + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +A +C + + + + + + + +<b>BLUE LINETM Hyper Mini TOPLED® Hyper-Bright LED</b><p> +Source: http://www.osram.convergy.de/ ... LB M676.pdf + + + + + + + + + + + + + + +A +C +>NAME +>VALUE + + + + + + + +<b>Super SIDELED® High-Current LED</b><p> +LG A672, LP A672 <br> +Source: http://www.osram.convergy.de/ ... LG_LP_A672.pdf (2004.05.13) + + + + + + + + + + + + + + + + + + + +C +A +>NAME +>VALUE + + + + + + + +<b>SmartLEDTM Hyper-Bright LED</b><p> +Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY L896.pdf + + + + + + + +>NAME +>VALUE + + + + + +<b>Hyper TOPLED® RG Hyper-Bright LED</b><p> +Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY T776.pdf + + + + + + + + + + + + + + + + +>NAME +>VALUE +A +C + + + + + + + + + + +<b>Hyper Micro SIDELED®</b><p> +Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY Y876.pdf + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +<b>Power TOPLED®</b><p> +Source: http://www.osram.convergy.de/ ... LA_LO_LA_LY E67B.pdf + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +C +A +C +C + + + + + + + + + + + +<b>Hyper CHIPLED Hyper-Bright LED</b><p> +LB Q993<br> +Source: http://www.osram.convergy.de/ ... Lb_q993.pdf + + + + +>NAME +>VALUE + + + + + + + +<b>Hyper CHIPLED Hyper-Bright LED</b><p> +LB R99A<br> +Source: http://www.osram.convergy.de/ ... lb_r99a.pdf + + + + +>NAME +>VALUE ++ + + + + + + + +<b>Mini TOPLED Santana®</b><p> +Source: http://www.osram.convergy.de/ ... LG M470.pdf + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +<b>CHIPLED</b><p> +Source: http://www.osram.convergy.de/ ... LG_R971.pdf + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + +<b>CHIPLED</b><p> +Source: http://www.osram.convergy.de/ ... LG_LY N971.pdf + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +<b>CHIPLED</b><p> +Source: http://www.osram.convergy.de/ ... LG_LY Q971.pdf + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +<b>CHIPLED-0603</b><p> +Recommended Solder Pad useable for SmartLEDTM and Chipled - Package 0603<br> +Package able to withstand TTW-soldering heat<br> +Package suitable for TTW-soldering<br> +Source: http://www.osram.convergy.de/ ... LO_LS_LY L89K.pdf + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +<b>SmartLED TTW</b><p> +Recommended Solder Pad useable for SmartLEDTM and Chipled - Package 0603<br> +Package able to withstand TTW-soldering heat<br> +Package suitable for TTW-soldering<br> +Source: http://www.osram.convergy.de/ ... LO_LS_LY L89K.pdf + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +A +K + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +3.5mm Terminal block +<p>http://www.ladyada.net/library/pcb/eaglelibrary.html<p> + + + + + + + + + + + + + + + + +4-pin connector + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>LED</b><p> +<u>OSRAM</u>:<br> + +- <u>CHIPLED</u><br> +LG R971, LG N971, LY N971, LG Q971, LY Q971, LO R971, LY R971 +LH N974, LH R974<br> +LS Q976, LO Q976, LY Q976<br> +LO Q996<br> + + +- <u>Hyper CHIPLED</u><br> +LW Q18S<br> +LB Q993, LB Q99A, LB R99A<br> + +- <u>SideLED</u><br> +LS A670, LO A670, LY A670, LG A670, LP A670<br> +LB A673, LV A673, LT A673, LW A673<br> +LH A674<br> +LY A675<br> +LS A676, LA A676, LO A676, LY A676, LW A676<br> +LS A679, LY A679, LG A679<br> + +- <u>Hyper Micro SIDELED®</u><br> +LS Y876, LA Y876, LO Y876, LY Y876<br> +LT Y87S<br> + +- <u>SmartLED</u><br> +LW L88C, LW L88S<br> +LB L89C, LB L89S, LG L890<br> +LS L89K, LO L89K, LY L89K<br> +LS L896, LA L896, LO L896, LY L896<br> + +- <u>TOPLED</u><br> +LS T670, LO T670, LY T670, LG T670, LP T670<br> +LSG T670, LSP T670, LSY T670, LOP T670, LYG T670<br> +LG T671, LOG T671, LSG T671<br> +LB T673, LV T673, LT T673, LW T673<br> +LH T674<br> +LS T676, LA T676, LO T676, LY T676, LB T676, LH T676, LSB T676, LW T676<br> +LB T67C, LV T67C, LT T67C, LS T67K, LO T67K, LY T67K, LW E67C<br> +LS E67B, LA E67B, LO E67B, LY E67B, LB E67C, LV E67C, LT E67C<br> +LW T67C<br> +LS T679, LY T679, LG T679<br> +LS T770, LO T770, LY T770, LG T770, LP T770<br> +LB T773, LV T773, LT T773, LW T773<br> +LH T774<br> +LS E675, LA E675, LY E675, LS T675<br> +LS T776, LA T776, LO T776, LY T776, LB T776<br> +LHGB T686<br> +LT T68C, LB T68C<br> + +- <u>Hyper Mini TOPLED®</u><br> +LB M676<br> + +- <u>Mini TOPLED Santana®</u><br> +LG M470<br> +LS M47K, LO M47K, LY M47K<br> + +<p> +Source: http://www.osram.convergy.de/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RST +3v +5v +Gnd +Vin +Analog In +0 +1 +2 +3 +4 +5 +12 +11 +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 +Digital I/O +Digital I/O + + + + + + + + +Limited YUN Pin out. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Arduino YUN mini shield. Originally taken from Adafruit's UNO R3 shield. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<h3>SparkFun Electronics' preferred foot prints</h3> +In this library you'll find non-functional items- supply symbols, logos, notations, frame blocks, etc.<br><br> +We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. +<br><br> +<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ +<br><br> +You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. + + + + + +>VALUE + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + +<b>Frames for Sheet and Layout</b> + + + + + + + + + + + + + + + + + + + + + + + + + + +Date: +>LAST_DATE_TIME +Sheet: +>SHEET +REV: +TITLE: +Document Number: +>DRAWING_NAME + + + + +<b>FRAME</b> A Size , 8 1/2 x 11 INCH, Landscape<p> + + + + + + + + + + + + + + + +<h3>SparkFun Electronics' preferred foot prints</h3> +In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> +We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. +<br><br> +<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ +<br><br> +You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. + + + + + + + + + + + + +>Name +>Value + + +This is the "EZ" version of the standard .3" spaced resistor package.<br> +It has a reduced top mask to make it harder to install upside-down. + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + +>Name +>Value + + + + + + + + +>Name +>Value + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +RES-08059 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Arduino Yun +LEDs +DC Power +Display +Switches +Power LED + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library.properties b/library.properties new file mode 100644 index 00000000..cb67fa8b --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=firebase-arduino +version=0.5 +author= +maintainer= +sentence=Fill in later +paragraph=Fill in later +category=Communication +url=http://example.com/ +architectures=esp8266 diff --git a/serial_protocol.md b/serial_protocol.md new file mode 100644 index 00000000..41888faf --- /dev/null +++ b/serial_protocol.md @@ -0,0 +1,188 @@ +#Protocol: +During the first use, or when the chiplet changes environments a “NETWORK” call is expected to initialize the wifi parameters. + +Every time a serial connection is established we will expect a “BEGIN” call after which any subsequent calls can be made, until the connection is closed. + +In the following examples we use %% to represent variables. For example %Host% represents your firebase host. + +##Response Format Byte +All responses will be prefixed with one of the following bytes signifying the response type. +``` + + If response is ok and a raw string value. + $ If response is ok, raw string value will be json formatted and prefixed by the byte count and a new line. + : If response is ok and a number, this could be float or int. + ? If response is ok and a boolean value. + - If response is an error +``` +##NETWORK +Only needs to be called when the chiplet is in a new environment and needs to connect to a new network. This setting will be stored by the chiplet and persisted through power cycles. +###Usage + NETWORK %SSID% + NETWORK %SSID% %PASSWORD% +###Response + +CONNECTED - When connected to new network + -UNABLE_TO_CONNECT - When unable to connect +###Examples + >> NETWORK home-guest + << +CONNECTED + >> NETWORK home-private MySecretPassword + << +CONNECTED + >> NETWORK home-guest + << -UNABLE_TO_CONNECT + +##BEGIN +Must be called after creating a Serial connection, it can take either just a host for accessing public variables or you may also provide a secret for accessing protected variables in the database. +###Usage + BEGIN %Host% + BEGIN %Host% %Secret% +###Response + +OK - Accepted initialization parameters +###Examples + >> BEGIN https://samplechat.firebaseio-demo.com + << +OK + >> BEGIN https://samplechat.firebaseio-demo.com nnz...sdf + << +OK +##GET +Fetches the value at %PATH% and returns it on the serial line. If %PATH% points to a leaf node you will get the raw value back, if it points to an internal node you will get a JSON string with all children. +###Usage + GET %PATH% +###Response + %DATA_AT_PATH% + $%JSON_DATA_BYTE_COUNT% \r\n %JSON_DATA +###Examples + >>GET /user/aturing/first + <<+Alan + >>GET /user/aturing + <<$39 + <<{ "first" : "Alan", "last" : "Turing" } + +##GET{+,*,#,.,?,$} +Same as GET but will either return the value in the format specified (by the format byte) or return an error. +###Usage + GET+ %PATH% + GET: %PATH% + GET? %PATH% + GET$ %PATH% +###Response + %FORMATED_RESPONSE% +###Examples + >>GET? /user/aturing/was_human + <>GET? /user/aturing/first + <<-ERROR_INCORRECT_FORMAT +##SET +Store the data provided at the path provided. This method should be used for simple strings and will assume the first newline is the end of the data. +###Usage + SET %PATH% %DATA% +###Response + +OK + -FAIL +###Examples + >>SET /user/aturing/first Alan + <<+OK +##SET$ +Similar to SET above but used to write multiline strings or raw binary data. Data format is similar to the batch string ($) return type, we specify the $DATA_BYTE_COUNT on the same line as SET$ then a newline and all data. However which the batch string ($) return type returns data json escaped and quoted you may provide raw data and we will handle the escaping. + +Receiver will wait until a timeout for client to send %DATA_BYTE_COUNT% worth of data before becoming responsive again. +###Usage + SET$ %PATH% + %DATA_BYTE_COUNT% + %DATA% +###Response + +OK + -FAIL + -FAIL_TIMEOUT +###Examples + >>SET /user/aturing/address + >>24 + >>78 High Street, + >>Hampton + <<+OK + +##SET{+,*,#,.,?} +Same as SET but will force the value to be stored in the given type or return an error if we cannot parse it as that type. +###Usage + SET+ %PATH% %VALUE% + SET: %PATH% %VALUE% + SET? %PATH% %VALUE% +###Response + +OK + -INCORRECT_TYPE +###Examples + >>SET? /user/aturing/was_human true + <<+OK + >>SET? /user/aturing/was_human He was not a computer. + <<-INCORRECT_TYPE + +##REMOVE +Deletes the value located at the path provided. +###Usage + REMOVE %PATH% +###Response + +OK + -FAIL +###Examples + >>REMOVE /user/aturing + <<+OK + +##PUSH +Adds a value to the list located at the path provided and returns the key at which the new object is located. +###Usage + PUSH %PATH% %DATA% +###Response + %KEY% +###Examples + >>PUSH /user/aturing/login_timestamps 1455052043 + <<+-K94eLnB0rAAvfkh_WC2 + +##PUSH$ +Similar to PUSH but used to write multiline strings or raw binary data. Data format is similar to the batch string ($) return type, we specify the $DATA_BYTE_COUNT on the same line as SET$ then a newline and all data. However you are not required to json escape all of your data, that will be handled for you. + +Receiver will wait until a timeout for client to send $DATA_BYTE_COUNT worth of data before becoming responsive again. +###Usage + PUSH$ %PATH% %DATA_BYTE_COUNT% + %DATA% +###Response + %KEY% +###Examples + >>PUSH$ /user/aturing/quotes 91 + >>We can only see a short distance ahead, + >>but we can see plenty there that needs to be done. + <<+-K94eLnB0rAAvfkh_WC3 + +##BEGIN_STREAM +Used to register to receive a stream of events that occur to the object at the provided path. + +After registering you will start receiving events on the response line. They will be formatted as one line with the event type {PUT,PATCH,etc..} followed by the sub_path that changed and the other line with the data associated with that event type. This data will be formatted similar to GET results and can have multi-line batch strings (*) or json strings (&). + +The event stream will continue until you send END_STREAM. + +When there is an ongoing event stream no other commands can be processed until you call END_STREAM as the event stream owns the return line. +###Usage + BEGIN_STREAM %PATH% +###Response + %EVENT_NAME% %SUB_PATH% + %DATA% + +OK +###Examples + >>BEGIN_STREAM /user/aturing + <<+PUT /last_login + <<:1455052043 + <<+PUT /address + <<$24 + <<"78 High Street,\r\nHampton" + +##END_STREAM +Used to stop listening to events at a given path. This must be the same path provided to a previous BEGIN_STREAM call. + +###Usage + END_STREAM %PATH% +###Response + +OK + -NOT_STREAMING_PATH +###Examples + >>END_STREAM /user/aturing + <<-NOT_STREAMING_PATH + >>BEGIN_STREAM /user/aturing + >>END_STREAM /user/aturing + <<+OK diff --git a/Firebase.cpp b/src/Firebase.cpp similarity index 58% rename from Firebase.cpp rename to src/Firebase.cpp index 154a72f3..08c2ebbe 100644 --- a/Firebase.cpp +++ b/src/Firebase.cpp @@ -15,17 +15,9 @@ // #include "Firebase.h" -// Detect whether stable version of HTTP library is installed instead of -// master branch and patch in missing status and methods. -#ifndef HTTP_CODE_TEMPORARY_REDIRECT -#define HTTP_CODE_TEMPORARY_REDIRECT 307 -#define USE_ESP_ARDUINO_CORE_2_0_0 -#endif +using std::unique_ptr; namespace { -const char* kFirebaseFingerprint = "7A 54 06 9B DC 7A 25 B3 86 8D 66 53 48 2C 0B 96 42 C7 B3 0A"; -const uint16_t kFirebasePort = 443; - String makeFirebaseURL(const String& path, const String& auth) { String url; if (path[0] != '/') { @@ -41,7 +33,8 @@ String makeFirebaseURL(const String& path, const String& auth) { } // namespace Firebase::Firebase(const String& host) : host_(host) { - http_.setReuse(true); + http_.reset(FirebaseHttpClient::create()); + http_->setReuseConnection(true); } Firebase& Firebase::auth(const String& auth) { @@ -49,37 +42,66 @@ Firebase& Firebase::auth(const String& auth) { return *this; } +const String& Firebase::auth() { + return auth_; +} + FirebaseGet Firebase::get(const String& path) { - return FirebaseGet(host_, auth_, path, &http_); + return FirebaseGet(host_, auth_, path, http_.get()); +} + +unique_ptr Firebase::getPtr(const String& path) { + return unique_ptr(new FirebaseGet(host_, auth_, path, http_.get())); } FirebaseSet Firebase::set(const String& path, const String& value) { - return FirebaseSet(host_, auth_, path, value, &http_); + return FirebaseSet(host_, auth_, path, value, http_.get()); +} + +unique_ptr Firebase::setPtr(const String& path, + const String& value) { + return unique_ptr( + new FirebaseSet(host_, auth_, path, value, http_.get())); } FirebasePush Firebase::push(const String& path, const String& value) { - return FirebasePush(host_, auth_, path, value, &http_); + return FirebasePush(host_, auth_, path, value, http_.get()); +} +unique_ptr Firebase::pushPtr(const String& path, const String& value) { + return unique_ptr( + new FirebasePush(host_, auth_, path, value, http_.get())); } FirebaseRemove Firebase::remove(const String& path) { - return FirebaseRemove(host_, auth_, path, &http_); + return FirebaseRemove(host_, auth_, path, http_.get()); +} + +unique_ptr Firebase::removePtr(const String& path) { + return unique_ptr( + new FirebaseRemove(host_, auth_, path, http_.get())); } FirebaseStream Firebase::stream(const String& path) { // TODO: create new client dedicated to stream. - return FirebaseStream(host_, auth_, path, &http_); + return FirebaseStream(host_, auth_, path, http_.get()); +} + +unique_ptr Firebase::streamPtr(const String& path) { + // TODO: create new client dedicated to stream. + return unique_ptr( + new FirebaseStream(host_, auth_, path, http_.get())); } // FirebaseCall FirebaseCall::FirebaseCall(const String& host, const String& auth, const char* method, const String& path, - const String& data, HTTPClient* http) : http_(http) { - String url = makeFirebaseURL(path, auth); - http_->setReuse(true); - http_->begin(host, kFirebasePort, url, true, kFirebaseFingerprint); + const String& data, FirebaseHttpClient* http) : http_(http) { + String path_with_auth = makeFirebaseURL(path, auth); + http_->setReuseConnection(true); + http_->begin(host, path_with_auth); bool followRedirect = false; - if (method == "STREAM") { + if (String(method) == "STREAM") { method = "GET"; http_->addHeader("Accept", "text/event-stream"); followRedirect = true; @@ -90,26 +112,24 @@ FirebaseCall::FirebaseCall(const String& host, const String& auth, http_->collectHeaders(headers, 1); } - int status = http_->sendRequest(method, (uint8_t*)data.c_str(), data.length()); + int status = http_->sendRequest(method, data); // TODO: Add a max redirect check if (followRedirect) { - while (status == HTTP_CODE_TEMPORARY_REDIRECT) { + while (status == HttpStatus::TEMPORARY_REDIRECT) { String location = http_->header("Location"); - http_->setReuse(false); + http_->setReuseConnection(false); http_->end(); - http_->setReuse(true); - http_->begin(location, kFirebaseFingerprint); - status = http_->sendRequest("GET", (uint8_t*)NULL, 0); + http_->setReuseConnection(true); + http_->begin(location); + status = http_->sendRequest("GET", String()); } } if (status != 200) { -#ifdef USE_ESP_ARDUINO_CORE_2_0_0 - error_ = FirebaseError(status, String(method) + " " + url + ": " + status); -#else - error_ = FirebaseError(status, String(method) + " " + url + ": " + HTTPClient::errorToString(status)); -#endif + error_ = FirebaseError(status, + String(method) + " " + path_with_auth + + ": " + http_->errorToString(status)); } // if not streaming. @@ -118,21 +138,24 @@ FirebaseCall::FirebaseCall(const String& host, const String& auth, } } +const JsonObject& FirebaseCall::json() { + //TODO(edcoyne): This is not efficient, we should do something smarter with + //the buffers. + buffer_ = DynamicJsonBuffer(); + return buffer_.parseObject(response()); +} + // FirebaseGet FirebaseGet::FirebaseGet(const String& host, const String& auth, const String& path, - HTTPClient* http) + FirebaseHttpClient* http) : FirebaseCall(host, auth, "GET", path, "", http) { - if (!error()) { - // TODO: parse json - json_ = response(); - } } // FirebaseSet FirebaseSet::FirebaseSet(const String& host, const String& auth, const String& path, const String& value, - HTTPClient* http) + FirebaseHttpClient* http) : FirebaseCall(host, auth, "PUT", path, value, http) { if (!error()) { // TODO: parse json @@ -142,25 +165,24 @@ FirebaseSet::FirebaseSet(const String& host, const String& auth, // FirebasePush FirebasePush::FirebasePush(const String& host, const String& auth, const String& path, const String& value, - HTTPClient* http) + FirebaseHttpClient* http) : FirebaseCall(host, auth, "POST", path, value, http) { if (!error()) { - // TODO: parse name - name_ = response(); + //name_ = json()["name"].as(); } } // FirebasePush FirebaseRemove::FirebaseRemove(const String& host, const String& auth, const String& path, - HTTPClient* http) + FirebaseHttpClient* http) : FirebaseCall(host, auth, "DELETE", path, "", http) { } // FirebaseStream FirebaseStream::FirebaseStream(const String& host, const String& auth, const String& path, - HTTPClient* http) + FirebaseHttpClient* http) : FirebaseCall(host, auth, "STREAM", path, "", http) { } diff --git a/Firebase.h b/src/Firebase.h similarity index 63% rename from Firebase.h rename to src/Firebase.h index 5691038d..68423c37 100644 --- a/Firebase.h +++ b/src/Firebase.h @@ -21,9 +21,9 @@ #define firebase_h #include -#include -#include -#include +#include +#include "FirebaseHttpClient.h" +#include "third-party/arduino-json-5.1.1/include/ArduinoJson.h" class FirebaseGet; class FirebaseSet; @@ -34,26 +34,41 @@ class FirebaseStream; // Firebase REST API client. class Firebase { public: - Firebase(const String& host); + explicit Firebase(const String& host); Firebase& auth(const String& auth); + virtual ~Firebase() = default; + + Firebase(const Firebase&) = delete; + + // Fetch auth string back. + const String& auth(); // Fetch json encoded `value` at `path`. FirebaseGet get(const String& path); + virtual std::unique_ptr getPtr(const String& path); // Set json encoded `value` at `path`. FirebaseSet set(const String& path, const String& json); + virtual std::unique_ptr setPtr(const String& path, const String& json); // Add new json encoded `value` to list at `path`. FirebasePush push(const String& path, const String& json); + virtual std::unique_ptr pushPtr(const String& path, const String& json); // Delete value at `path`. FirebaseRemove remove(const String& path); + virtual std::unique_ptr removePtr(const String& path); // Start a stream of events that affect value at `path`. FirebaseStream stream(const String& path); + virtual std::unique_ptr streamPtr(const String& path); + + protected: + // Used for testing. + Firebase() {} private: - HTTPClient http_; + std::unique_ptr http_; String host_; String auth_; }; @@ -76,29 +91,30 @@ class FirebaseCall { FirebaseCall() {} FirebaseCall(const String& host, const String& auth, const char* method, const String& path, - const String& data = "", - HTTPClient* http = NULL); - const FirebaseError& error() const { + const String& data = "", + FirebaseHttpClient* http = NULL); + virtual const FirebaseError& error() const { return error_; } - const String& response() { + + virtual const String& response() { return response_; } + + const JsonObject& json(); + protected: - HTTPClient* http_; + FirebaseHttpClient* http_; FirebaseError error_; String response_; + DynamicJsonBuffer buffer_; }; class FirebaseGet : public FirebaseCall { public: FirebaseGet() {} FirebaseGet(const String& host, const String& auth, - const String& path, HTTPClient* http = NULL); - - const String& json() const { - return json_; - } + const String& path, FirebaseHttpClient* http = NULL); private: String json_; @@ -108,11 +124,8 @@ class FirebaseSet: public FirebaseCall { public: FirebaseSet() {} FirebaseSet(const String& host, const String& auth, - const String& path, const String& value, HTTPClient* http = NULL); + const String& path, const String& value, FirebaseHttpClient* http = NULL); - const String& json() const { - return json_; - } private: String json_; @@ -122,9 +135,9 @@ class FirebasePush : public FirebaseCall { public: FirebasePush() {} FirebasePush(const String& host, const String& auth, - const String& path, const String& value, HTTPClient* http = NULL); + const String& path, const String& value, FirebaseHttpClient* http = NULL); - const String& name() const { + virtual const String& name() const { return name_; } @@ -136,7 +149,7 @@ class FirebaseRemove : public FirebaseCall { public: FirebaseRemove() {} FirebaseRemove(const String& host, const String& auth, - const String& path, HTTPClient* http = NULL); + const String& path, FirebaseHttpClient* http = NULL); }; @@ -144,10 +157,10 @@ class FirebaseStream : public FirebaseCall { public: FirebaseStream() {} FirebaseStream(const String& host, const String& auth, - const String& path, HTTPClient* http = NULL); - + const String& path, FirebaseHttpClient* http = NULL); + // Return if there is any event available to read. - bool available(); + virtual bool available(); // Event type. enum Event { @@ -156,13 +169,26 @@ class FirebaseStream : public FirebaseCall { PATCH }; + static inline String EventToName(Event event) { + switch(event) { + case UNKNOWN: + return "UNKNOWN"; + case PUT: + return "PUT"; + case PATCH: + return "PATCH"; + default: + return "INVALID_EVENT_" + event; + } + } + // Read next json encoded `event` from stream. - Event read(String& event); + virtual Event read(String& event); const FirebaseError& error() const { return _error; } - + private: FirebaseError _error; }; diff --git a/src/FirebaseHttpClient.h b/src/FirebaseHttpClient.h new file mode 100644 index 00000000..326c7410 --- /dev/null +++ b/src/FirebaseHttpClient.h @@ -0,0 +1,41 @@ +#ifndef FIREBASE_HTTP_CLIENT_H +#define FIREBASE_HTTP_CLIENT_H + +#include "Arduino.h" +#include "Stream.h" + +struct HttpStatus { + static const int TEMPORARY_REDIRECT = 307; +}; + +class FirebaseHttpClient { + public: + static FirebaseHttpClient* create(); + + virtual void setReuseConnection(bool reuse) = 0; + virtual void begin(const String& url) = 0; + virtual void begin(const String& host, const String& path) = 0; + + virtual void end() = 0; + + virtual void addHeader(const String& name, const String& value) = 0; + virtual void collectHeaders(const char* header_keys[], + const int header_key_count) = 0; + virtual String header(const String& name) = 0; + + virtual int sendRequest(const String& method, const String& data) = 0; + + virtual String getString() = 0; + + virtual Stream* getStreamPtr() = 0; + + virtual String errorToString(int error_code) = 0; + + protected: + static const uint16_t kFirebasePort = 443; +}; + +static const String kFirebaseFingerprint = + "7A 54 06 9B DC 7A 25 B3 86 8D 66 53 48 2C 0B 96 42 C7 B3 0A"; + +#endif // FIREBASE_HTTP_CLIENT_H diff --git a/src/FirebaseHttpClient_Esp8266.cpp b/src/FirebaseHttpClient_Esp8266.cpp new file mode 100644 index 00000000..145afa9a --- /dev/null +++ b/src/FirebaseHttpClient_Esp8266.cpp @@ -0,0 +1,75 @@ + +#include "FirebaseHttpClient.h" + +// The ordering of these includes matters greatly. +#include +#include +#include + +// Detect whether stable version of HTTP library is installed instead of +// master branch and patch in missing status and methods. +#ifndef HTTP_CODE_TEMPORARY_REDIRECT +#define HTTP_CODE_TEMPORARY_REDIRECT 307 +#define USE_ESP_ARDUINO_CORE_2_0_0 +#endif + +class FirebaseHttpClientEsp8266 : public FirebaseHttpClient { + public: + FirebaseHttpClientEsp8266() {} + + void setReuseConnection(bool reuse) override { + http_.setReuse(reuse); + } + + void begin(const String& url) override { + http_.begin(url, kFirebaseFingerprint); + } + + void begin(const String& host, const String& path) override { + http_.begin(host, kFirebasePort, path, true, kFirebaseFingerprint); + } + + void end() override { + http_.end(); + } + + void addHeader(const String& name, const String& value) override { + http_.addHeader(name, value); + } + + void collectHeaders(const char* header_keys[], const int count) override { + http_.collectHeaders(header_keys, count); + } + + String header(const String& name) override { + return http_.header(name.c_str()); + } + + int sendRequest(const String& method, const String& data) override { + return http_.sendRequest(method.c_str(), (uint8_t*)data.c_str(), data.length()); + } + + String getString() override { + return http_.getString(); + } + + Stream* getStreamPtr() override { + return http_.getStreamPtr(); + } + + String errorToString(int error_code) override { +#ifdef USE_ESP_ARDUINO_CORE_2_0_0 + return String(error_code); +#else + return HTTPClient::errorToString(error_code); +#endif + } + + private: + HTTPClient http_; +}; + +FirebaseHttpClient* FirebaseHttpClient::create() { + return new FirebaseHttpClientEsp8266(); +} + diff --git a/src/SerialTransceiver.h b/src/SerialTransceiver.h new file mode 100644 index 00000000..45ae91cf --- /dev/null +++ b/src/SerialTransceiver.h @@ -0,0 +1,3 @@ +#include "modem/SerialTransceiver.h" +// Bring them into the base namespace for easier use in arduino ide. +using firebase::modem::SerialTransceiver; diff --git a/src/modem/SerialTransceiver.cpp b/src/modem/SerialTransceiver.cpp new file mode 100644 index 00000000..a5947d46 --- /dev/null +++ b/src/modem/SerialTransceiver.cpp @@ -0,0 +1,61 @@ +#include "SerialTransceiver.h" + +namespace firebase { +namespace modem { + +void SerialTransceiver::begin(Stream* serial) { + std::unique_ptr fbase; + + in_.reset(new ArduinoInputStream(serial)); + out_.reset(new ArduinoOutputStream(serial)); +} + +void SerialTransceiver::loop() { + String command_name = in_->readStringUntil(' '); + + if (command_name.length() == 0 // Generally means a timeout has occured. + || command_name == "\n") { + return; + } + + if (command_name == "BEGIN") { + BeginCommand command; + if (command.execute(command_name, in_.get(), out_.get())) { + fbase_ = std::move(command.firebase()); + } + return; + } else if (!fbase_) { + in_->drain(); + out_->println("-FAIL Must call BEGIN before anything else."); + return; + } + + std::unique_ptr command = CreateCommand(command_name, fbase_.get()); + if (!command) { + in_->drain(); + out_->println(String("-FAIL Invalid command '") + command_name + "'." ); + return; + } + + command->execute(command_name, in_.get(), out_.get()); +} + +std::unique_ptr SerialTransceiver::CreateCommand(const String& text, + Firebase* fbase) { + std::unique_ptr command; + if (text == "GET") { + command.reset(new GetCommand(fbase)); + } else if (text == "SET") { + command.reset(new SetCommand(fbase)); + } else if (text == "PUSH") { + command.reset(new PushCommand(fbase)); + } else if (text == "REMOVE") { + command.reset(new RemoveCommand(fbase)); + } else if (text == "BEGIN_STREAM") { + command.reset(new StreamCommand(fbase)); + } + return command; +} + +} // modem +} // firebase diff --git a/src/modem/SerialTransceiver.h b/src/modem/SerialTransceiver.h new file mode 100644 index 00000000..f2b3f671 --- /dev/null +++ b/src/modem/SerialTransceiver.h @@ -0,0 +1,28 @@ +#ifndef MODEM_SERIAL_TRANSCIEVER_H +#define MODEM_SERIAL_TRANSCIEVER_H + +#include + +#include "Firebase.h" +#include "modem/commands.h" + +namespace firebase { +namespace modem { + +class SerialTransceiver { + public: + void begin(Stream* serial); + void loop(); + + private: + std::unique_ptr CreateCommand(const String& name, Firebase* fbase); + + std::unique_ptr fbase_; + std::unique_ptr in_; + std::unique_ptr out_; +}; + +} // modem +} // firebase + +#endif // MODEM_SERIAL_TRANSCIEVER_H diff --git a/src/modem/begin-command.cpp b/src/modem/begin-command.cpp new file mode 100644 index 00000000..4f7cb34d --- /dev/null +++ b/src/modem/begin-command.cpp @@ -0,0 +1,50 @@ +#include "modem/commands.h" + +namespace firebase { +namespace modem { + +bool BeginCommand::execute(const String& command, + InputStream* in, OutputStream* out) { + if (in == nullptr || out == nullptr) { + return false; + } + + if (command != "BEGIN") { + return false; + } + + String host; + String auth; + + String data(in->readLine()); + + int space_index = data.indexOf(' '); + if (space_index == -1) { + // host only. + host = data; + } else { + // host and auth. + host = data.substring(0, space_index); + auth = data.substring(space_index + 1); + } + + if (host.length() == 0) { + out->println("-FAIL Missing host"); + return false; + } + + new_firebase_.reset(new Firebase(host)); + if (auth.length() != 0) { + new_firebase_->auth(auth); + } + + out->println("+OK"); + return true; +} + +std::unique_ptr BeginCommand::firebase() { + return std::move(new_firebase_); +} + +} // modem +} // firebase diff --git a/src/modem/commands.h b/src/modem/commands.h new file mode 100644 index 00000000..77ff1053 --- /dev/null +++ b/src/modem/commands.h @@ -0,0 +1,79 @@ +#ifndef MODEM_COMMAND_H +#define MODEM_COMMAND_H + +#include "Firebase.h" +#include "modem/output-stream.h" +#include "modem/input-stream.h" + +namespace firebase { +namespace modem { + +class Command { + public: + Command(Firebase* fbase) : fbase_(fbase) {} + + // Execute command, reading any additional data needed from stream. + // Return false if execution failed. + virtual bool execute(const String& command, + InputStream* in, OutputStream* out) = 0; + protected: + Firebase& fbase() { + return *fbase_; + } + + private: + Firebase* fbase_; +}; + +class GetCommand : public Command { + public: + GetCommand(Firebase* fbase) : Command(fbase) {} + + bool execute(const String& command, InputStream* in, OutputStream* out); +}; + +class SetCommand : public Command { + public: + SetCommand(Firebase* fbase) : Command(fbase) {} + + bool execute(const String& command, InputStream* in, OutputStream* out); +}; + +class RemoveCommand : public Command { + public: + RemoveCommand(Firebase* fbase) : Command(fbase) {} + + bool execute(const String& command, InputStream* in, OutputStream* out); +}; + +class PushCommand : public Command { + public: + PushCommand(Firebase* fbase) : Command(fbase) {} + + bool execute(const String& command, InputStream* in, OutputStream* out); +}; + +class BeginCommand : public Command { + public: + BeginCommand() : Command(nullptr) {} + + bool execute(const String& command, InputStream* in, OutputStream* out); + + // This can only be called once. + std::unique_ptr firebase(); + + private: + std::unique_ptr new_firebase_; +}; + +class StreamCommand : public Command { + public: + StreamCommand(Firebase* fbase) : Command(fbase) {} + + bool execute(const String& command, InputStream* in, OutputStream* out); +}; + +} // modem +} // firebase + +#endif //MODEM_COMMAND_H diff --git a/src/modem/design.md b/src/modem/design.md new file mode 100644 index 00000000..fea7487b --- /dev/null +++ b/src/modem/design.md @@ -0,0 +1,10 @@ +Overview: + +![Design diagram](diagram.png) + +We create a SerialTransceiver object that will manage the serial connection. It will read the first word on a line to determine which command is being called and construct the appropriate Command subclass to handle the interaction. Commands will be short lived objects with no state between calls, they will own the serial connection until they hand it back and are responsible for handling all necessary input and leaving the input line in a clean state for the next command. + +We will aim to keep the Transceiver/Command interaction generic enough to enable creating additional Protocol Transceivers in the future. + +The Transceiver object will also own the Firebase object and present it to each command during construction. The Firebase object is our link to the firebase backend. + diff --git a/src/modem/diagram.png b/src/modem/diagram.png new file mode 100644 index 00000000..ea5407a9 Binary files /dev/null and b/src/modem/diagram.png differ diff --git a/src/modem/get-command.cpp b/src/modem/get-command.cpp new file mode 100644 index 00000000..0ee19299 --- /dev/null +++ b/src/modem/get-command.cpp @@ -0,0 +1,33 @@ +#include "modem/commands.h" + +namespace firebase { +namespace modem { + +bool GetCommand::execute(const String& command, + InputStream* in, OutputStream* out) { + if (in == nullptr || out == nullptr) { + return false; + } + + if (command != "GET") { + return false; + } + + String path = in->readLine(); + std::unique_ptr get(fbase().getPtr(path)); + + if (get->error()) { + out->print("-FAIL "); + out->println(get->error().message()); + return false; + } + + String value(get->response()); + // TODO implement json parsing to pull and process value. + out->print("+"); + out->println(value); + return true; +} + +} // modem +} // firebase diff --git a/src/modem/input-stream.h b/src/modem/input-stream.h new file mode 100644 index 00000000..9340552d --- /dev/null +++ b/src/modem/input-stream.h @@ -0,0 +1,51 @@ +#ifndef MODEM_INPUT_STREAM_H +#define MODEM_INPUT_STREAM_H + +#include + +namespace firebase { +namespace modem { + +class InputStream { + public: + virtual String readLine() = 0; + // This call consumes the terminator. + virtual String readStringUntil(const char terminator) = 0; + virtual void drain() = 0; + virtual bool available() = 0; +}; + +class ArduinoInputStream : public InputStream { + public: + ArduinoInputStream(Stream* stream) : stream_(stream) {} + String readLine() { + String out = stream_->readStringUntil('\n'); + if (out[out.length()-1] == '\r') { + out.remove(out.length()-1); + } + return out; + } + + String readStringUntil(const char terminator) { + return stream_->readStringUntil(terminator); + } + + void drain() { + while(stream_->available()) { + stream_->read(); + } + } + + bool available() { + return stream_->available(); + } + + private: + Stream* stream_; +}; + +} // modem +} // firebase + +#endif // MODEM_INPUT_STREAM_H + diff --git a/src/modem/json_util.h b/src/modem/json_util.h new file mode 100644 index 00000000..544120a1 --- /dev/null +++ b/src/modem/json_util.h @@ -0,0 +1,17 @@ +#ifndef MODEM_JSON_UTIL_H +#define MODEM_JSON_UTIL_H + +namespace firebase { +namespace modem { + +// TODO(edcoyne): We should use a json library to escape. +inline String EncodeForJson(String input) { + input.replace("\\", "\\\\"); + input.replace("\"", "\\\""); + return "\"" + input + "\""; +} + +} // modem +} // firebase + +#endif // MODEM_JSON_UTIL_H diff --git a/src/modem/output-stream.h b/src/modem/output-stream.h new file mode 100644 index 00000000..010adb6b --- /dev/null +++ b/src/modem/output-stream.h @@ -0,0 +1,39 @@ +#ifndef MODEM_OUTPUT_STREAM_H +#define MODEM_OUTPUT_STREAM_H + +#include +#include + +namespace firebase { +namespace modem { + +class OutputStream { + public: + virtual int println(const String& string) = 0; + virtual int println(const int value) = 0; + virtual int print(const String& string) = 0; +}; + +class ArduinoOutputStream : public OutputStream { + public: + ArduinoOutputStream(Stream* stream) : stream_(stream) {} + + int println(const String& string) override { + return stream_->println(string.c_str()); + } + + int println(const int value) override { + return stream_->println(value); + } + + int print(const String& string) override { + return stream_->print(string.c_str()); + } + private: + Stream* stream_; +}; + +} // modem +} // firebase + +#endif // MODEM_OUTPUT_STREAM diff --git a/src/modem/push-command.cpp b/src/modem/push-command.cpp new file mode 100644 index 00000000..73d0f7ef --- /dev/null +++ b/src/modem/push-command.cpp @@ -0,0 +1,34 @@ +#include "modem/commands.h" +#include "modem/json_util.h" + +namespace firebase { +namespace modem { + +bool PushCommand::execute(const String& command, + InputStream* in, OutputStream* out) { + if (in == nullptr || out == nullptr) { + return false; + } + + if (command != "PUSH") { + return false; + } + + String path(in->readStringUntil(' ')); + String data(in->readLine()); + + std::unique_ptr push( + fbase().pushPtr(path, EncodeForJson(data))); + + if (push->error()) { + out->print("-FAIL "); + out->println(push->error().message()); + return false; + } else { + out->println("+OK"); + return true; + } +} + +} // modem +} // firebase diff --git a/src/modem/remove-command.cpp b/src/modem/remove-command.cpp new file mode 100644 index 00000000..5026d25b --- /dev/null +++ b/src/modem/remove-command.cpp @@ -0,0 +1,30 @@ +#include "modem/commands.h" + +namespace firebase { +namespace modem { + +bool RemoveCommand::execute(const String& command, + InputStream* in, OutputStream* out) { + if (in == nullptr || out == nullptr) { + return false; + } + + if (command != "REMOVE") { + return false; + } + + String path = in->readLine(); + std::unique_ptr get(fbase().removePtr(path)); + + if (get->error()) { + out->print("-FAIL "); + out->println(get->error().message()); + return false; + } + + out->println("+OK"); + return true; +} + +} // modem +} // firebase diff --git a/src/modem/set-command.cpp b/src/modem/set-command.cpp new file mode 100644 index 00000000..35b53040 --- /dev/null +++ b/src/modem/set-command.cpp @@ -0,0 +1,34 @@ +#include "modem/commands.h" +#include "modem/json_util.h" + +namespace firebase { +namespace modem { + +bool SetCommand::execute(const String& command, + InputStream* in, OutputStream* out) { + if (in == nullptr || out == nullptr) { + return false; + } + + if (command != "SET") { + return false; + } + + String path(in->readStringUntil(' ')); + String data(in->readLine()); + + std::unique_ptr set(fbase().setPtr(path, + EncodeForJson(data))); + + if (set->error()) { + out->print("-FAIL "); + out->println(set->error().message()); + return false; + } else { + out->println("+OK"); + return true; + } +} + +} // modem +} // firebase diff --git a/src/modem/stream-command.cpp b/src/modem/stream-command.cpp new file mode 100644 index 00000000..b3b1c649 --- /dev/null +++ b/src/modem/stream-command.cpp @@ -0,0 +1,51 @@ +#include "modem/commands.h" + +namespace firebase { +namespace modem { + +bool StreamCommand::execute(const String& command, + InputStream* in, OutputStream* out) { + if (in == nullptr || out == nullptr) { + return false; + } + + if (command != "BEGIN_STREAM") { + return false; + } + + String path = in->readLine(); + std::unique_ptr stream(fbase().streamPtr(path)); + + if (stream->error()) { + out->print("-FAIL "); + out->println(stream->error().message()); + return false; + } + + bool running = true; + while(running) { + if (stream->available()) { + String json; + FirebaseStream::Event event = stream->read(json); + out->print("+"); + out->print(FirebaseStream::EventToName(event) + " "); + // TODO(edcoyne): add json parsing and get real path. + out->println("/dummy/path"); + out->println(json.length()); + out->println(json); + } else if (in->available()) { + String command = in->readLine(); + if (command == "END_STREAM") { + out->println("+OK"); + running = false; + } else { + out->println("-FAIL Cannot call any command but END_STREAM."); + } + } + } + + return true; +} + +} // modem +} // firebase diff --git a/src/third-party/README.md b/src/third-party/README.md new file mode 100644 index 00000000..76816743 --- /dev/null +++ b/src/third-party/README.md @@ -0,0 +1,2 @@ +These are packages that we depend upon. They may need to be trimmed, all .cpp +files in them will be compiled by the arduino IDE. diff --git a/src/third-party/arduino-json-5.1.1/CHANGELOG.md b/src/third-party/arduino-json-5.1.1/CHANGELOG.md new file mode 100644 index 00000000..7ea8888c --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/CHANGELOG.md @@ -0,0 +1,244 @@ +ArduinoJson: change log +======================= + +v5.1.1 +------ + +* Removed `String` duplication when one replaces a value in a `JsonObject` (PR #232 by @ulion) + +v5.1.0 +------ + +* Added support of `long long` (issue #171) +* Moved all build settings to `ArduinoJson/Configuration.hpp` + +**BREAKING CHANGE**: +If you defined `ARDUINOJSON_ENABLE_STD_STREAM`, you now need to define it to `1`. + +v5.0.8 +------ + +* Made the library compatible with [PlatformIO](http://platformio.org/) (issue #181) +* Fixed `JsonVariant::is()` that was incorrectly returning false (issue #214) + +v5.0.7 +------ + +* Made library easier to use from a CMake project: simply `add_subdirectory(ArduinoJson/src)` +* Changed `String` to be a `typedef` of `std::string` (issues #142 and #161) + +**BREAKING CHANGES**: +- `JsonVariant(true).as()` now returns `"true"` instead of `"1"` +- `JsonVariant(false).as()` now returns `"false"` instead of `"0"` + +v5.0.6 +------ + +* Added parameter to `DynamicJsonBuffer` constructor to set initial size (issue #152) +* Fixed warning about library category in Arduino 1.6.6 (issue #147) +* Examples: Added a loop to wait for serial port to be ready (issue #156) + +v5.0.5 +------ + +* Added overload `JsonObjectSuscript::set(value, decimals)` (issue #143) +* Use `float` instead of `double` to reduce the size of `JsonVariant` (issue #134) + +v5.0.4 +------ + +* Fixed ambiguous overload with `JsonArraySubscript` and `JsonObjectSubscript` (issue #122) + +v5.0.3 +------ + +* Fixed `printTo(String)` which wrote numbers instead of strings (issue #120) +* Fixed return type of `JsonArray::is()` and some others (issue #121) + +v5.0.2 +------ + +* Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the + `StaticJsonBuffer` is too small to hold a copy of the string +* Fixed Clang warning "register specifier is deprecated" (issue #102) +* Fixed GCC warning "declaration shadows a member" (issue #103) +* Fixed memory alignment, which made ESP8266 crash (issue #104) +* Fixed compilation on Visual Studio 2010 and 2012 (issue #107) + +v5.0.1 +------ + +* Fixed compilation with Arduino 1.0.6 (issue #99) + +v5.0.0 +------ + +* Added support of `String` class (issues #55, #56, #70, #77) +* Added `JsonBuffer::strdup()` to make a copy of a string (issues #10, #57) +* Implicitly call `strdup()` for `String` but not for `char*` (issues #84, #87) +* Added support of non standard JSON input (issue #44) +* Added support of comments in JSON input (issue #88) +* Added implicit cast between numerical types (issues #64, #69, #93) +* Added ability to read number values as string (issue #90) +* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66) +* Switched to new the library layout (requires Arduino 1.0.6 or above) + +**BREAKING CHANGES**: +- `JsonObject::add()` was renamed to `set()` +- `JsonArray::at()` and `JsonObject::at()` were renamed to `get()` +- Number of digits of floating point value are now set with `double_with_n_digits()` + +**Personal note about the `String` class**: +Support of the `String` class has been added to the library because many people use it in their programs. +However, you should not see this as an invitation to use the `String` class. +The `String` class is **bad** because it uses dynamic memory allocation. +Compared to static allocation, it compiles to a bigger, slower program, and is less predictable. +You certainly don't want that in an embedded environment! + +v4.6 +---- + +* Fixed segmentation fault in `DynamicJsonBuffer` when memory allocation fails (issue #92) + +v4.5 +---- + +* Fixed buffer overflow when input contains a backslash followed by a terminator (issue #81) + +**Upgrading is recommended** since previous versions contain a potential security risk. + +Special thanks to [Giancarlo Canales Barreto](https://github.com/gcanalesb) for finding this nasty bug. + +v4.4 +---- + +* Added `JsonArray::measureLength()` and `JsonObject::measureLength()` (issue #75) + +v4.3 +---- + +* Added `JsonArray::removeAt()` to remove an element of an array (issue #58) +* Fixed stack-overflow in `DynamicJsonBuffer` when parsing huge JSON files (issue #65) +* Fixed wrong return value of `parseArray()` and `parseObject()` when allocation fails (issue #68) + +v4.2 +---- + +* Switched back to old library layout (issues #39, #43 and #45) +* Removed global new operator overload (issue #40, #45 and #46) +* Added an example with EthernetServer + +v4.1 +---- + +* Added DynamicJsonBuffer (issue #19) + +v4.0 +---- + +* Unified parser and generator API (issue #23) +* Updated library layout, now requires Arduino 1.0.6 or newer + +**BREAKING CHANGE**: API changed significantly, see [Migrating code to the new API](https://github.com/bblanchon/ArduinoJson/wiki/Migrating-code-to-the-new-API). + + +v3.4 +---- + +* Fixed escaped char parsing (issue #16) + + +v3.3 +---- + +* Added indented output for the JSON generator (issue #11), see example bellow. +* Added `IndentedPrint`, a decorator for `Print` to allow indented output + +Example: + + JsonOject<2> json; + json["key"] = "value"; + json.prettyPrintTo(Serial); + +v3.2 +---- + +* Fixed a bug when adding nested object in `JsonArray` (bug introduced in v3.1). + +v3.1 +---- + +* Calling `Generator::JsonObject::add()` twice with the same `key` now replaces the `value` +* Added `Generator::JsonObject::operator[]`, see bellow the new API +* Added `Generator::JsonObject::remove()` (issue #9) + +Old generator API: + + JsonObject<3> root; + root.add("sensor", "gps"); + root.add("time", 1351824120); + root.add("data", array); + +New generator API: + + JsonObject<3> root; + root["sensor"] = "gps"; + root["time"] = 1351824120; + root["data"] = array; + +v3.0 +---- + +* New parser API, see bellow +* Renamed `JsonHashTable` into `JsonObject` +* Added iterators for `JsonArray` and `JsonObject` (issue #4) + +Old parser API: + + JsonHashTable root = parser.parseHashTable(json); + + char* sensor = root.getString("sensor"); + long time = root.getLong("time"); + double latitude = root.getArray("data").getDouble(0); + double longitude = root.getArray("data").getDouble(1); + +New parser API: + + JsonObject root = parser.parse(json); + + char* sensor = root["sensor"]; + long time = root["time"]; + double latitude = root["data"][0]; + double longitude = root["data"][1]; + +v2.1 +---- + +* Fixed case `#include "jsmn.cpp"` which caused an error in Linux (issue #6) +* Fixed a buffer overrun in JSON Parser (issue #5) + +v2.0 +---- + +* Added JSON encoding (issue #2) +* Renamed the library `ArduinoJsonParser` becomes `ArduinoJson` + +**Breaking change**: you need to add the following line at the top of your program. + + using namespace ArduinoJson::Parser; + +v1.2 +---- + +* Fixed error in JSON parser example (issue #1) + +v1.1 +---- + +* Example: changed `char* json` into `char[] json` so that the bytes are not write protected +* Fixed parsing bug when the JSON contains multi-dimensional arrays + +v1.0 +---- + +Initial release diff --git a/src/third-party/arduino-json-5.1.1/LICENSE.md b/src/third-party/arduino-json-5.1.1/LICENSE.md new file mode 100644 index 00000000..fea79d80 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/LICENSE.md @@ -0,0 +1,10 @@ +The MIT License (MIT) +--------------------- + +Copyright © 2014-2016 Benoit BLANCHON + +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. diff --git a/src/third-party/arduino-json-5.1.1/README.md b/src/third-party/arduino-json-5.1.1/README.md new file mode 100644 index 00000000..6a560077 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/README.md @@ -0,0 +1,122 @@ +Arduino JSON library +==================== + +[![Build status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/master?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/master) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=master)](https://travis-ci.org/bblanchon/ArduinoJson) [![Coverage Status](https://img.shields.io/coveralls/bblanchon/ArduinoJson.svg)](https://coveralls.io/r/bblanchon/ArduinoJson?branch=master) [![Star this project](http://githubbadges.com/star.svg?user=bblanchon&repo=ArduinoJson&style=flat&color=fff&background=007ec6)](https://github.com/bblanchon/ArduinoJson) + +*An elegant and efficient JSON library for embedded systems.* + +It's designed to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc). + +It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project. + +Features +-------- + +* JSON decoding (comments are supported) +* JSON encoding (with optional indentation) +* Elegant API, very easy to use +* Efficient (no malloc, nor copy) +* Portable (written in C++98) +* Self-contained (no external dependency) +* Small footprint +* MIT License + +Works on +-------- + +* All Arduino boards (Uno, Due, Mini, Micro, Yun...) +* ESP8266 +* Teensy +* Intel Edison +* PlatformIO +* Energia +* RedBearLab boards (BLE Nano...) +* Computers (Windows, Linux, OSX...) + +See [FAQ: Compatibility issues](https://github.com/bblanchon/ArduinoJson/wiki/Compatibility-issues) + +Quick start +----------- + +#### Decoding / Parsing + +```c++ +char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; + +StaticJsonBuffer<200> jsonBuffer; + +JsonObject& root = jsonBuffer.parseObject(json); + +const char* sensor = root["sensor"]; +long time = root["time"]; +double latitude = root["data"][0]; +double longitude = root["data"][1]; +``` + +#### Encoding / Generating + +```c++ +StaticJsonBuffer<200> jsonBuffer; + +JsonObject& root = jsonBuffer.createObject(); +root["sensor"] = "gps"; +root["time"] = 1351824120; + +JsonArray& data = root.createNestedArray("data"); +data.add(48.756080, 6); // 6 is the number of decimals to print +data.add(2.302038, 6); // if not specified, 2 digits are printed + +root.printTo(Serial); +// This prints: +// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]} +``` + + +Documentation +------------- + +The documentation is available online in the [Arduino JSON wiki](https://github.com/bblanchon/ArduinoJson/wiki) + +Testimonials +------------ + +From Arduino's Forum user `jflaplante`: +> I tried aJson json-arduino before trying your library. I always ran into memory problem after a while. +> I have no such problem so far with your library. It is working perfectly with my web services. + +From Arduino's Forum user `gbathree`: +> Thanks so much - this is an awesome library! If you want to see what we're doing with it - the project is located at www.photosynq.org. + +From StackOverflow user `thegreendroid`: +> It has a really elegant, simple API and it works like a charm on embedded and Windows/Linux platforms. We recently started using this on an embedded project and I can vouch for its quality. + +From GitHub user `zacsketches`: + +> Thanks for a great library!!! +> I've been watching you consistently develop this library over the past six months, and I used it today for a publish and subscribe architecture designed to help hobbyists move into more advanced robotics. Your library allowed me to implement remote subscription in order to facilitate multi-processor robots. +> ArduinoJson saved me a week's worth of time!! + +[From Reddit user `erm_what_`](https://www.reddit.com/r/arduino/comments/3jj6ep/announcing_arduinojson_50/cusjk8c): + +> This is a great library and I wouldn't be able to do the project I'm doing without it. I completely recommend it. + +[From Reddit user `makerhacks`](https://www.reddit.com/r/arduino/comments/3jj6ep/announcing_arduinojson_50/cusqg7b): + +> I am just starting an ESP8266 clock project and now I can output JSON from my server script and interpret it painlessly. + +Donators +-------- + +Special thanks to the following persons and companies who made generous donations to the library author: + +* Robert Murphy +* Surge Communications +* Alex Scott +* Firepick Services LLC +* A B Doodkorte +* Scott Smith +* Johann Stieger + +--- + +Found this library useful? Please star this project or [help me back with a donation!](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=donate%40benoitblanchon%2efr&lc=GB&item_name=Benoit%20Blanchon&item_number=Arduino%20JSON¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) :smile: diff --git a/src/third-party/arduino-json-5.1.1/examples/IndentedPrintExample/IndentedPrintExample.ino b/src/third-party/arduino-json-5.1.1/examples/IndentedPrintExample/IndentedPrintExample.ino new file mode 100644 index 00000000..9e86f0f5 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/examples/IndentedPrintExample/IndentedPrintExample.ino @@ -0,0 +1,35 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include + +using namespace ArduinoJson::Internals; + +void setup() { + Serial.begin(9600); + while (!Serial) { + // wait serial port initialization + } + + IndentedPrint serial(Serial); + serial.setTabSize(4); + + serial.println("This is at indentation 0"); + serial.indent(); + serial.println("This is at indentation 1"); + serial.println("This is also at indentation 1"); + serial.indent(); + serial.println("This is at indentation 2"); + + serial.unindent(); + serial.unindent(); + serial.println("This is back at indentation 0"); +} + +void loop() { + // not used in this example +} diff --git a/src/third-party/arduino-json-5.1.1/examples/JsonGeneratorExample/JsonGeneratorExample.ino b/src/third-party/arduino-json-5.1.1/examples/JsonGeneratorExample/JsonGeneratorExample.ino new file mode 100644 index 00000000..717a2276 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/examples/JsonGeneratorExample/JsonGeneratorExample.ino @@ -0,0 +1,70 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include + +void setup() { + Serial.begin(9600); + while (!Serial) { + // wait serial port initialization + } + + // Memory pool for JSON object tree. + // + // Inside the brackets, 200 is the size of the pool in bytes. + // If the JSON object is more complex, you need to increase that value. + StaticJsonBuffer<200> jsonBuffer; + + // StaticJsonBuffer allocates memory on the stack, it can be + // replaced by DynamicJsonBuffer which allocates in the heap. + // It's simpler but less efficient. + // + // DynamicJsonBuffer jsonBuffer; + + // Create the root of the object tree. + // + // It's a reference to the JsonObject, the actual bytes are inside the + // JsonBuffer with all the other nodes of the object tree. + // Memory is freed when jsonBuffer goes out of scope. + JsonObject& root = jsonBuffer.createObject(); + + // Add values in the object + // + // Most of the time, you can rely on the implicit casts. + // In other case, you can do root.set("time", 1351824120); + root["sensor"] = "gps"; + root["time"] = 1351824120; + + // Add a nested array. + // + // It's also possible to create the array separately and add it to the + // JsonObject but it's less efficient. + JsonArray& data = root.createNestedArray("data"); + data.add(double_with_n_digits(48.756080, 6)); + data.add(double_with_n_digits(2.302038, 6)); + + root.printTo(Serial); + // This prints: + // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]} + + Serial.println(); + + root.prettyPrintTo(Serial); + // This prints: + // { + // "sensor": "gps", + // "time": 1351824120, + // "data": [ + // 48.756080, + // 2.302038 + // ] + // } +} + +void loop() { + // not used in this example +} diff --git a/src/third-party/arduino-json-5.1.1/examples/JsonParserExample/JsonParserExample.ino b/src/third-party/arduino-json-5.1.1/examples/JsonParserExample/JsonParserExample.ino new file mode 100644 index 00000000..13536019 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/examples/JsonParserExample/JsonParserExample.ino @@ -0,0 +1,67 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include + +void setup() { + Serial.begin(9600); + while (!Serial) { + // wait serial port initialization + } + + // Memory pool for JSON object tree. + // + // Inside the brackets, 200 is the size of the pool in bytes, + // If the JSON object is more complex, you need to increase that value. + StaticJsonBuffer<200> jsonBuffer; + + // StaticJsonBuffer allocates memory on the stack, it can be + // replaced by DynamicJsonBuffer which allocates in the heap. + // It's simpler but less efficient. + // + // DynamicJsonBuffer jsonBuffer; + + // JSON input string. + // + // It's better to use a char[] as shown here. + // If you use a const char* or a String, ArduinoJson will + // have to make a copy of the input in the JsonBuffer. + char json[] = + "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; + + // Root of the object tree. + // + // It's a reference to the JsonObject, the actual bytes are inside the + // JsonBuffer with all the other nodes of the object tree. + // Memory is freed when jsonBuffer goes out of scope. + JsonObject& root = jsonBuffer.parseObject(json); + + // Test if parsing succeeds. + if (!root.success()) { + Serial.println("parseObject() failed"); + return; + } + + // Fetch values. + // + // Most of the time, you can rely on the implicit casts. + // In other case, you can do root["time"].as(); + const char* sensor = root["sensor"]; + long time = root["time"]; + double latitude = root["data"][0]; + double longitude = root["data"][1]; + + // Print values. + Serial.println(sensor); + Serial.println(time); + Serial.println(latitude, 6); + Serial.println(longitude, 6); +} + +void loop() { + // not used in this example +} diff --git a/src/third-party/arduino-json-5.1.1/examples/JsonServer/JsonServer.ino b/src/third-party/arduino-json-5.1.1/examples/JsonServer/JsonServer.ino new file mode 100644 index 00000000..895b6729 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/examples/JsonServer/JsonServer.ino @@ -0,0 +1,74 @@ +// Sample Arduino Json Web Server +// Created by Benoit Blanchon. +// Heavily inspired by "Web Server" from David A. Mellis and Tom Igoe + +#include +#include +#include + +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +IPAddress ip(192, 168, 0, 177); +EthernetServer server(80); + +bool readRequest(EthernetClient& client) { + bool currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + if (c == '\n' && currentLineIsBlank) { + return true; + } else if (c == '\n') { + currentLineIsBlank = true; + } else if (c != '\r') { + currentLineIsBlank = false; + } + } + } + return false; +} + +JsonObject& prepareResponse(JsonBuffer& jsonBuffer) { + JsonObject& root = jsonBuffer.createObject(); + + JsonArray& analogValues = root.createNestedArray("analog"); + for (int pin = 0; pin < 6; pin++) { + int value = analogRead(pin); + analogValues.add(value); + } + + JsonArray& digitalValues = root.createNestedArray("digital"); + for (int pin = 0; pin < 14; pin++) { + int value = digitalRead(pin); + digitalValues.add(value); + } + + return root; +} + +void writeResponse(EthernetClient& client, JsonObject& json) { + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: application/json"); + client.println("Connection: close"); + client.println(); + + json.prettyPrintTo(client); +} + +void setup() { + Ethernet.begin(mac, ip); + server.begin(); +} + +void loop() { + EthernetClient client = server.available(); + if (client) { + bool success = readRequest(client); + if (success) { + StaticJsonBuffer<500> jsonBuffer; + JsonObject& json = prepareResponse(jsonBuffer); + writeResponse(client, json); + } + delay(1); + client.stop(); + } +} diff --git a/src/third-party/arduino-json-5.1.1/examples/JsonUdpBeacon/JsonUdpBeacon.ino b/src/third-party/arduino-json-5.1.1/examples/JsonUdpBeacon/JsonUdpBeacon.ino new file mode 100644 index 00000000..7d0fa38a --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/examples/JsonUdpBeacon/JsonUdpBeacon.ino @@ -0,0 +1,55 @@ +// Send a JSON object on UDP at regular interval +// +// You can easily test this program with netcat: +// $ nc -ulp 8888 +// +// by Benoit Blanchon, MIT License 2015-2016 + +#include +#include +#include + +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +IPAddress localIp(192, 168, 0, 177); +IPAddress remoteIp(192, 168, 0, 109); +unsigned int remotePort = 8888; +unsigned localPort = 8888; +EthernetUDP udp; + +JsonObject& buildJson(JsonBuffer& jsonBuffer) { + JsonObject& root = jsonBuffer.createObject(); + + JsonArray& analogValues = root.createNestedArray("analog"); + for (int pin = 0; pin < 6; pin++) { + int value = analogRead(pin); + analogValues.add(value); + } + + JsonArray& digitalValues = root.createNestedArray("digital"); + for (int pin = 0; pin < 14; pin++) { + int value = digitalRead(pin); + digitalValues.add(value); + } + + return root; +} + +void sendJson(JsonObject& json) { + udp.beginPacket(remoteIp, remotePort); + json.printTo(udp); + udp.println(); + udp.endPacket(); +} + +void setup() { + Ethernet.begin(mac, localIp); + udp.begin(localPort); +} + +void loop() { + delay(1000); + + StaticJsonBuffer<300> jsonBuffer; + JsonObject& json = buildJson(jsonBuffer); + sendJson(json); +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson.h b/src/third-party/arduino-json-5.1.1/include/ArduinoJson.h new file mode 100644 index 00000000..0a3f49a9 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson.h @@ -0,0 +1,13 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "ArduinoJson/DynamicJsonBuffer.hpp" +#include "ArduinoJson/JsonArray.hpp" +#include "ArduinoJson/JsonObject.hpp" +#include "ArduinoJson/StaticJsonBuffer.hpp" + +using namespace ArduinoJson; diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Arduino/Print.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Arduino/Print.hpp new file mode 100644 index 00000000..ab1b0e8c --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Arduino/Print.hpp @@ -0,0 +1,89 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#ifndef ARDUINO + +#include "../Internals/JsonFloat.hpp" +#include "../Internals/JsonInteger.hpp" + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +// snprintf has been added in Visual Studio 2015 +#define ARDUINOJSON_SNPRINTF _snprintf +#else +#define ARDUINOJSON_SNPRINTF snprintf +#endif + +// This class reproduces Arduino's Print class +class Print { + public: + virtual ~Print() {} + + virtual size_t write(uint8_t) = 0; + + size_t print(const char* s) { + size_t n = 0; + while (*s) { + n += write(*s++); + } + return n; + } + + size_t print(ArduinoJson::Internals::JsonFloat value, int digits = 2) { + char tmp[32]; + + // https://github.com/arduino/Arduino/blob/db8cbf24c99dc930b9ccff1a43d018c81f178535/hardware/arduino/sam/cores/arduino/Print.cpp#L220 + bool isBigDouble = value > 4294967040.0 || value < -4294967040.0; + + if (isBigDouble) { + // Arduino's implementation prints "ovf" + // We prefer using the scientific notation, since we have sprintf + ARDUINOJSON_SNPRINTF(tmp, sizeof(tmp), "%g", value); + } else { + // Here we have the exact same output as Arduino's implementation + ARDUINOJSON_SNPRINTF(tmp, sizeof(tmp), "%.*f", digits, value); + } + + return print(tmp); + } + + size_t print(ArduinoJson::Internals::JsonInteger value) { + // see http://clc-wiki.net/wiki/K%26R2_solutions:Chapter_3:Exercise_4 + char buffer[22]; + + size_t n = 0; + if (value < 0) { + value = -value; + n += write('-'); + } + uint8_t i = 0; + do { + ArduinoJson::Internals::JsonInteger digit = value % 10; + value /= 10; + buffer[i++] = static_cast(digit >= 0 ? '0' + digit : '0' - digit); + } while (value); + + while (i > 0) { + n += write(buffer[--i]); + } + + return n; + } + + size_t println() { return write('\r') + write('\n'); } +}; + +#else + +#include + +#endif diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Arduino/String.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Arduino/String.hpp new file mode 100644 index 00000000..9e631d3d --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Arduino/String.hpp @@ -0,0 +1,19 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#ifndef ARDUINO + +#include +//typedef std::string String; + +#else + +#include + +#endif diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Configuration.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Configuration.hpp new file mode 100644 index 00000000..9b37548e --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Configuration.hpp @@ -0,0 +1,79 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#ifdef ARDUINO // assume this is an embedded platform + +// store using float instead of double to reduce the memory usage (issue #134) +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 0 +#endif + +// store using a long because it usually match the size of a float. +#ifndef ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif +#ifndef ARDUINOJSON_USE_INT64 +#define ARDUINOJSON_USE_INT64 0 +#endif + +// arduino doesn't support STL stream +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 0 +#endif + +#ifndef ARDUINOJSON_ENABLE_ALIGNMENT +#ifdef ARDUINO_ARCH_AVR +// alignment isn't needed for 8-bit AVR +#define ARDUINOJSON_ENABLE_ALIGNMENT 0 +#else +// but must processor needs pointer to be align on word size +#define ARDUINOJSON_ENABLE_ALIGNMENT 1 +#endif +#endif + +#else // assume this is a computer + +// on a computer we have plenty of memory so we can use doubles +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 1 +#endif + +// use long long when available +#ifndef ARDUINOJSON_USE_LONG_LONG +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) +#define ARDUINOJSON_USE_LONG_LONG 1 +#else +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif +#endif + +// use _int64 on old versions of Visual Studio +#ifndef ARDUINOJSON_USE_INT64 +#if defined(_MSC_VER) && _MSC_VER <= 1700 +#define ARDUINOJSON_USE_INT64 1 +#else +#define ARDUINOJSON_USE_INT64 0 +#endif +#endif + +// on a computer, we can assume that the STL is there +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 1 +#endif + +#ifndef ARDUINOJSON_ENABLE_ALIGNMENT +// even if not required, most cpu's are faster with aligned pointers +#define ARDUINOJSON_ENABLE_ALIGNMENT 1 +#endif + +#endif + +#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64 +#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together +#endif diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/DynamicJsonBuffer.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/DynamicJsonBuffer.hpp new file mode 100644 index 00000000..2e02b097 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/DynamicJsonBuffer.hpp @@ -0,0 +1,18 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Internals/BlockJsonBuffer.hpp" + +namespace ArduinoJson { +// Implements a JsonBuffer with dynamic memory allocation. +// You are strongly encouraged to consider using StaticJsonBuffer which is much +// more suitable for embedded systems. +typedef Internals::BlockJsonBuffer + DynamicJsonBuffer; +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/BlockJsonBuffer.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/BlockJsonBuffer.hpp new file mode 100644 index 00000000..4fa5a26f --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/BlockJsonBuffer.hpp @@ -0,0 +1,94 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../JsonBuffer.hpp" + +#include + +namespace ArduinoJson { +namespace Internals { +class DefaultAllocator { + public: + void* allocate(size_t size) { return malloc(size); } + void deallocate(void* pointer) { free(pointer); } +}; + +template +class BlockJsonBuffer : public JsonBuffer { + struct Block; + struct EmptyBlock { + Block* next; + size_t capacity; + size_t size; + }; + struct Block : EmptyBlock { + uint8_t data[1]; + }; + + public: + BlockJsonBuffer(size_t initialSize = 256) + : _head(NULL), _nextBlockSize(initialSize) {} + + ~BlockJsonBuffer() { + Block* currentBlock = _head; + + while (currentBlock != NULL) { + Block* nextBlock = currentBlock->next; + _allocator.deallocate(currentBlock); + currentBlock = nextBlock; + } + } + + size_t size() const { + size_t total = 0; + for (const Block* b = _head; b; b = b->next) total += b->size; + return total; + } + + protected: + virtual void* alloc(size_t bytes) { + return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); + } + + private: + bool canAllocInHead(size_t bytes) const { + return _head != NULL && _head->size + bytes <= _head->capacity; + } + + void* allocInHead(size_t bytes) { + void* p = _head->data + _head->size; + _head->size += round_size_up(bytes); + return p; + } + + void* allocInNewBlock(size_t bytes) { + size_t capacity = _nextBlockSize; + if (bytes > capacity) capacity = bytes; + if (!addNewBlock(capacity)) return NULL; + _nextBlockSize *= 2; + return allocInHead(bytes); + } + + bool addNewBlock(size_t capacity) { + size_t bytes = sizeof(EmptyBlock) + capacity; + Block* block = static_cast(_allocator.allocate(bytes)); + if (block == NULL) return false; + block->capacity = capacity; + block->size = 0; + block->next = _head; + _head = block; + return true; + } + + TAllocator _allocator; + Block* _head; + size_t _nextBlockSize; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Comments.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Comments.hpp new file mode 100644 index 00000000..21763cc3 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Comments.hpp @@ -0,0 +1,14 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace Internals { +const char *skipSpacesAndComments(const char *ptr); +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/DummyPrint.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/DummyPrint.hpp new file mode 100644 index 00000000..7ab82b6b --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/DummyPrint.hpp @@ -0,0 +1,21 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Arduino/Print.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A dummy Print implementation used in JsonPrintable::measureLength() +class DummyPrint : public Print { + public: + virtual size_t write(uint8_t) { return 1; } +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/DynamicStringBuilder.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/DynamicStringBuilder.hpp new file mode 100644 index 00000000..6225ad94 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/DynamicStringBuilder.hpp @@ -0,0 +1,33 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Arduino/Print.hpp" +#include "../Arduino/String.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A Print implementation that allows to write in a String +class DynamicStringBuilder : public Print { + public: + DynamicStringBuilder(String &str) : _str(str) {} + + virtual size_t write(uint8_t c) { + // Need to cast to char, otherwise String will print a number (issue #120) + _str += static_cast(c); + return 1; + } + + private: + DynamicStringBuilder &operator=(const DynamicStringBuilder &); + + String &_str; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Encoding.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Encoding.hpp new file mode 100644 index 00000000..b31f7e43 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Encoding.hpp @@ -0,0 +1,40 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Arduino/Print.hpp" + +namespace ArduinoJson { +namespace Internals { + +class Encoding { + public: + // Optimized for code size on a 8-bit AVR + static char escapeChar(char c) { + const char *p = _escapeTable; + while (p[0] && p[1] != c) { + p += 2; + } + return p[0]; + } + + // Optimized for code size on a 8-bit AVR + static char unescapeChar(char c) { + const char *p = _escapeTable + 4; + for (;;) { + if (p[0] == '\0') return c; + if (p[0] == c) return p[1]; + p += 2; + } + } + + private: + static const char _escapeTable[]; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ForceInline.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ForceInline.hpp new file mode 100644 index 00000000..37aad136 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ForceInline.hpp @@ -0,0 +1,14 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#ifdef _MSC_VER +#define FORCE_INLINE __forceinline +#else +#define FORCE_INLINE __attribute__((always_inline)) +#endif diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/IndentedPrint.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/IndentedPrint.hpp new file mode 100644 index 00000000..f0a9c1e8 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/IndentedPrint.hpp @@ -0,0 +1,55 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Arduino/Print.hpp" + +namespace ArduinoJson { +namespace Internals { + +// Decorator on top of Print to allow indented output. +// This class is used by JsonPrintable::prettyPrintTo() but can also be used +// for your own purpose, like logging. +class IndentedPrint : public Print { + public: + explicit IndentedPrint(Print &p) : sink(&p) { + level = 0; + tabSize = 2; + isNewLine = true; + } + + virtual size_t write(uint8_t); + + // Adds one level of indentation + void indent() { + if (level < MAX_LEVEL) level++; + } + + // Removes one level of indentation + void unindent() { + if (level > 0) level--; + } + + // Set the number of space printed for each level of indentation + void setTabSize(uint8_t n) { + if (n < MAX_TAB_SIZE) tabSize = n & MAX_TAB_SIZE; + } + + private: + Print *sink; + uint8_t level : 4; + uint8_t tabSize : 3; + bool isNewLine : 1; + + size_t writeTabs(); + + static const int MAX_LEVEL = 15; // because it's only 4 bits + static const int MAX_TAB_SIZE = 7; // because it's only 3 bits +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonBufferAllocated.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonBufferAllocated.hpp new file mode 100644 index 00000000..97328faf --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonBufferAllocated.hpp @@ -0,0 +1,25 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../JsonBuffer.hpp" + +namespace ArduinoJson { +namespace Internals { + +class JsonBufferAllocated { + public: + void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() { + if (!jsonBuffer) return NULL; + return jsonBuffer->alloc(n); + } + + void operator delete(void *, JsonBuffer *) throw() {} +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonFloat.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonFloat.hpp new file mode 100644 index 00000000..b6dc20f0 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonFloat.hpp @@ -0,0 +1,21 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Configuration.hpp" + +namespace ArduinoJson { +namespace Internals { + +#if ARDUINOJSON_USE_DOUBLE +typedef double JsonFloat; +#else +typedef float JsonFloat; +#endif +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonInteger.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonInteger.hpp new file mode 100644 index 00000000..8db05992 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonInteger.hpp @@ -0,0 +1,23 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Configuration.hpp" + +namespace ArduinoJson { +namespace Internals { + +#if ARDUINOJSON_USE_LONG_LONG +typedef long long JsonInteger; +#elif ARDUINOJSON_USE_INT64 +typedef __int64 JsonInteger; +#else +typedef long JsonInteger; +#endif +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonParser.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonParser.hpp new file mode 100644 index 00000000..001326dc --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonParser.hpp @@ -0,0 +1,47 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../JsonBuffer.hpp" +#include "../JsonVariant.hpp" + +namespace ArduinoJson { +namespace Internals { + +// Parse JSON string to create JsonArrays and JsonObjects +// This internal class is not indended to be used directly. +// Instead, use JsonBuffer.parseArray() or .parseObject() +class JsonParser { + public: + JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit) + : _buffer(buffer), + _readPtr(json ? json : ""), + _writePtr(json), + _nestingLimit(nestingLimit) {} + + JsonArray &parseArray(); + JsonObject &parseObject(); + + private: + bool skip(char charToSkip); + + const char *parseString(); + bool parseAnythingTo(JsonVariant *destination); + FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); + + inline bool parseArrayTo(JsonVariant *destination); + inline bool parseObjectTo(JsonVariant *destination); + inline bool parseStringTo(JsonVariant *destination); + + JsonBuffer *_buffer; + const char *_readPtr; + char *_writePtr; + uint8_t _nestingLimit; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonPrintable.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonPrintable.hpp new file mode 100644 index 00000000..95e6201b --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonPrintable.hpp @@ -0,0 +1,97 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Configuration.hpp" +#include "DummyPrint.hpp" +#include "IndentedPrint.hpp" +#include "JsonWriter.hpp" +#include "Prettyfier.hpp" +#include "StaticStringBuilder.hpp" +#include "DynamicStringBuilder.hpp" + +#if ARDUINOJSON_ENABLE_STD_STREAM +#include "StreamPrintAdapter.hpp" +#endif + +namespace ArduinoJson { +namespace Internals { + +// Implements all the overloads of printTo() and prettyPrintTo() +// Caution: this class use a template parameter to avoid virtual methods. +// This is a bit curious but allows to reduce the size of JsonVariant, JsonArray +// and JsonObject. +template +class JsonPrintable { + public: + size_t printTo(Print &print) const { + JsonWriter writer(print); + downcast().writeTo(writer); + return writer.bytesWritten(); + } + +#if ARDUINOJSON_ENABLE_STD_STREAM + std::ostream &printTo(std::ostream &os) const { + StreamPrintAdapter adapter(os); + printTo(adapter); + return os; + } +#endif + + size_t printTo(char *buffer, size_t bufferSize) const { + StaticStringBuilder sb(buffer, bufferSize); + return printTo(sb); + } + + size_t printTo(String &str) const { + DynamicStringBuilder sb(str); + return printTo(sb); + } + + size_t prettyPrintTo(IndentedPrint &print) const { + Prettyfier p(print); + return printTo(p); + } + + size_t prettyPrintTo(char *buffer, size_t bufferSize) const { + StaticStringBuilder sb(buffer, bufferSize); + return prettyPrintTo(sb); + } + + size_t prettyPrintTo(Print &print) const { + IndentedPrint indentedPrint = IndentedPrint(print); + return prettyPrintTo(indentedPrint); + } + + size_t prettyPrintTo(String &str) const { + DynamicStringBuilder sb(str); + return prettyPrintTo(sb); + } + + size_t measureLength() const { + DummyPrint dp; + return printTo(dp); + } + + size_t measurePrettyLength() const { + DummyPrint dp; + return prettyPrintTo(dp); + } + + private: + const T &downcast() const { return *static_cast(this); } +}; + +#if ARDUINOJSON_ENABLE_STD_STREAM +template +inline std::ostream &operator<<(std::ostream &os, const JsonPrintable &v) { + return v.printTo(os); +} +#endif +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonVariantContent.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonVariantContent.hpp new file mode 100644 index 00000000..14d0eed9 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonVariantContent.hpp @@ -0,0 +1,30 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "JsonFloat.hpp" +#include "JsonInteger.hpp" + +namespace ArduinoJson { + +// Forward declarations +class JsonArray; +class JsonObject; + +namespace Internals { +// A union that defines the actual content of a JsonVariant. +// The enum JsonVariantType determines which member is in use. +union JsonVariantContent { + JsonFloat asFloat; // used for double and float + JsonInteger asInteger; // used for bool, char, short, int and longs + const char* asString; // asString can be null + JsonArray* asArray; // asArray cannot be null + JsonObject* asObject; // asObject cannot be null +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonVariantType.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonVariantType.hpp new file mode 100644 index 00000000..418b0e6b --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonVariantType.hpp @@ -0,0 +1,37 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +class JsonArray; +class JsonObject; + +namespace Internals { + +// Enumerated type to know the current type of a JsonVariant. +// The value determines which member of JsonVariantContent is used. +enum JsonVariantType { + JSON_UNDEFINED, // the JsonVariant has not been initialized + JSON_UNPARSED, // the JsonVariant contains an unparsed string + JSON_STRING, // the JsonVariant stores a const char* + JSON_BOOLEAN, // the JsonVariant stores a bool + JSON_INTEGER, // the JsonVariant stores an integer + JSON_ARRAY, // the JsonVariant stores a pointer to a JsonArray + JSON_OBJECT, // the JsonVariant stores a pointer to a JsonObject + + // The following values are reserved for float values + // Multiple values are used for double, depending on the number of decimal + // digits that must be printed in the JSON output. + // This little trick allow to save one extra member in JsonVariant + JSON_FLOAT_0_DECIMALS + // JSON_FLOAT_1_DECIMAL + // JSON_FLOAT_2_DECIMALS + // ... +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonWriter.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonWriter.hpp new file mode 100644 index 00000000..8cdf848a --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/JsonWriter.hpp @@ -0,0 +1,85 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Arduino/Print.hpp" +#include "Encoding.hpp" +#include "ForceInline.hpp" +#include "JsonFloat.hpp" +#include "JsonInteger.hpp" + +namespace ArduinoJson { +namespace Internals { + +// Writes the JSON tokens to a Print implementation +// This class is used by: +// - JsonArray::writeTo() +// - JsonObject::writeTo() +// - JsonVariant::writeTo() +// Its derived by PrettyJsonWriter that overrides some members to add +// indentation. +class JsonWriter { + public: + explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {} + + // Returns the number of bytes sent to the Print implementation. + // This is very handy for implementations of printTo() that must return the + // number of bytes written. + size_t bytesWritten() const { return _length; } + + void beginArray() { write('['); } + void endArray() { write(']'); } + + void beginObject() { write('{'); } + void endObject() { write('}'); } + + void writeColon() { write(':'); } + void writeComma() { write(','); } + + void writeBoolean(bool value) { write(value ? "true" : "false"); } + + void writeString(const char *value) { + if (!value) { + write("null"); + } else { + write('\"'); + while (*value) writeChar(*value++); + write('\"'); + } + } + + void writeChar(char c) { + char specialChar = Encoding::escapeChar(c); + if (specialChar) { + write('\\'); + write(specialChar); + } else { + write(c); + } + } + + void writeInteger(JsonInteger value) { _length += _sink.print(value); } + + void writeFloat(JsonFloat value, uint8_t decimals) { + _length += _sink.print(value, decimals); + } + + void writeRaw(const char *s) { return write(s); } + + protected: + void write(char c) { _length += _sink.write(c); } + FORCE_INLINE void write(const char *s) { _length += _sink.print(s); } + + Print &_sink; + size_t _length; + + private: + JsonWriter &operator=(const JsonWriter &); // cannot be assigned +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/List.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/List.hpp new file mode 100644 index 00000000..7746f106 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/List.hpp @@ -0,0 +1,59 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../JsonBuffer.hpp" +#include "ListConstIterator.hpp" +#include "ListIterator.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A singly linked list of T. +// The linked list is composed of ListNode. +// It is derived by JsonArray and JsonObject +template +class List { + public: + typedef T value_type; + typedef ListNode node_type; + typedef ListIterator iterator; + typedef ListConstIterator const_iterator; + + // Creates an empty List attached to a JsonBuffer. + // The JsonBuffer allows to allocate new nodes. + // When buffer is NULL, the List is not able to grow and success() returns + // false. This is used to identify bad memory allocations and parsing + // failures. + explicit List(JsonBuffer *buffer) : _buffer(buffer), _firstNode(NULL) {} + + // Returns true if the object is valid + // Would return false in the following situation: + // - the memory allocation failed (StaticJsonBuffer was too small) + // - the JSON parsing failed + bool success() const { return _buffer != NULL; } + + // Returns the numbers of elements in the list. + // For a JsonObject, it would return the number of key-value pairs + size_t size() const; + + iterator begin() { return iterator(_firstNode); } + iterator end() { return iterator(NULL); } + + const_iterator begin() const { return const_iterator(_firstNode); } + const_iterator end() const { return const_iterator(NULL); } + + protected: + node_type *addNewNode(); + void removeNode(node_type *nodeToRemove); + + JsonBuffer *_buffer; + node_type *_firstNode; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListConstIterator.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListConstIterator.hpp new file mode 100644 index 00000000..f6b7ca53 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListConstIterator.hpp @@ -0,0 +1,41 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "ListNode.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A read-only forward itertor for List +template +class ListConstIterator { + public: + explicit ListConstIterator(const ListNode *node = NULL) : _node(node) {} + + const T &operator*() const { return _node->content; } + const T *operator->() { return &_node->content; } + + bool operator==(const ListConstIterator &other) const { + return _node == other._node; + } + + bool operator!=(const ListConstIterator &other) const { + return _node != other._node; + } + + ListConstIterator &operator++() { + if (_node) _node = _node->next; + return *this; + } + + private: + const ListNode *_node; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListIterator.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListIterator.hpp new file mode 100644 index 00000000..17342971 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListIterator.hpp @@ -0,0 +1,44 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "ListNode.hpp" +#include "ListConstIterator.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A read-write forward iterator for List +template +class ListIterator { + public: + explicit ListIterator(ListNode *node = NULL) : _node(node) {} + + T &operator*() const { return _node->content; } + T *operator->() { return &_node->content; } + + bool operator==(const ListIterator &other) const { + return _node == other._node; + } + + bool operator!=(const ListIterator &other) const { + return _node != other._node; + } + + ListIterator &operator++() { + if (_node) _node = _node->next; + return *this; + } + + operator ListConstIterator() const { return ListConstIterator(_node); } + + private: + ListNode *_node; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListNode.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListNode.hpp new file mode 100644 index 00000000..3c94662d --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ListNode.hpp @@ -0,0 +1,27 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include // for NULL + +#include "JsonBufferAllocated.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A node for a singly-linked list. +// Used by List and its iterators. +template +struct ListNode : public Internals::JsonBufferAllocated { + ListNode() : next(NULL) {} + + ListNode *next; + T content; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Parse.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Parse.hpp new file mode 100644 index 00000000..adbd7a50 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Parse.hpp @@ -0,0 +1,51 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include + +namespace ArduinoJson { +namespace Internals { +template +TFloat parse(const char *); + +template <> +inline float parse(const char *s) { + return static_cast(strtod(s, NULL)); +} + +template <> +inline double parse(const char *s) { + return strtod(s, NULL); +} + +template <> +inline long parse(const char *s) { + return strtol(s, NULL, 10); +} + +template <> +inline int parse(const char *s) { + return atoi(s); +} + +#if ARDUINOJSON_USE_LONG_LONG +template <> +inline long long parse(const char *s) { + return strtoll(s, NULL, 10); +} +#endif + +#if ARDUINOJSON_USE_INT64 +template <> +inline __int64 parse<__int64>(const char *s) { + return _strtoi64(s, NULL, 10); +} +#endif +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Prettyfier.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Prettyfier.hpp new file mode 100644 index 00000000..8f320d91 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Prettyfier.hpp @@ -0,0 +1,47 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "IndentedPrint.hpp" + +namespace ArduinoJson { +namespace Internals { + +// Converts a compact JSON string into an indented one. +class Prettyfier : public Print { + public: + explicit Prettyfier(IndentedPrint& p) : _sink(p) { + _previousChar = 0; + _inString = false; + } + + virtual size_t write(uint8_t); + + private: + Prettyfier& operator=(const Prettyfier&); // cannot be assigned + + bool inEmptyBlock() { return _previousChar == '{' || _previousChar == '['; } + + size_t handleStringChar(uint8_t); + size_t handleMarkupChar(uint8_t); + + size_t handleBlockClose(uint8_t); + size_t handleBlockOpen(uint8_t); + size_t handleColon(); + size_t handleComma(); + size_t handleQuoteOpen(); + size_t handleNormalChar(uint8_t); + size_t indentIfNeeded(); + size_t unindentIfNeeded(); + + uint8_t _previousChar; + IndentedPrint& _sink; + bool _inString; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ReferenceType.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ReferenceType.hpp new file mode 100644 index 00000000..a5cf507a --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/ReferenceType.hpp @@ -0,0 +1,35 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace Internals { + +// A type that is meant to be used by reference only (JsonArray and JsonObject) +class ReferenceType { + public: + bool operator==(const ReferenceType& other) const { + // two JsonArray are equal if they are the same instance + // (we don't compare the content) + return this == &other; + } + + bool operator!=(const ReferenceType& other) const { return this != &other; } + + protected: + ReferenceType() {} + + private: + // copy constructor is private + ReferenceType(const ReferenceType&); + + // copy operator is private + ReferenceType& operator=(const ReferenceType&); +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/StaticStringBuilder.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/StaticStringBuilder.hpp new file mode 100644 index 00000000..df1ceecf --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/StaticStringBuilder.hpp @@ -0,0 +1,31 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Arduino/Print.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A Print implementation that allows to write in a char[] +class StaticStringBuilder : public Print { + public: + StaticStringBuilder(char *buf, size_t size) + : buffer(buf), capacity(size - 1), length(0) { + buffer[0] = '\0'; + } + + virtual size_t write(uint8_t c); + + private: + char *buffer; + size_t capacity; + size_t length; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/StreamPrintAdapter.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/StreamPrintAdapter.hpp new file mode 100644 index 00000000..ace1d9ed --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/StreamPrintAdapter.hpp @@ -0,0 +1,39 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Configuration.hpp" + +#if ARDUINOJSON_ENABLE_STD_STREAM + +#include "../Arduino/Print.hpp" + +#include + +namespace ArduinoJson { +namespace Internals { + +class StreamPrintAdapter : public Print { + public: + explicit StreamPrintAdapter(std::ostream& os) : _os(os) {} + + virtual size_t write(uint8_t c) { + _os << static_cast(c); + return 1; + } + + private: + // cannot be assigned + StreamPrintAdapter& operator=(const StreamPrintAdapter&); + + std::ostream& _os; +}; +} +} + +#endif // ARDUINOJSON_ENABLE_STD_STREAM diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Unparsed.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Unparsed.hpp new file mode 100644 index 00000000..a01508b1 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/Internals/Unparsed.hpp @@ -0,0 +1,21 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace Internals { +class Unparsed { + public: + explicit Unparsed(const char* str) : _str(str) {} + operator const char*() const { return _str; } + + private: + const char* _str; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArray.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArray.hpp new file mode 100644 index 00000000..d478ab52 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArray.hpp @@ -0,0 +1,181 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Internals/JsonBufferAllocated.hpp" +#include "Internals/JsonPrintable.hpp" +#include "Internals/List.hpp" +#include "Internals/ReferenceType.hpp" +#include "JsonVariant.hpp" +#include "TypeTraits/EnableIf.hpp" +#include "TypeTraits/IsFloatingPoint.hpp" +#include "TypeTraits/IsReference.hpp" +#include "TypeTraits/IsSame.hpp" + +// Returns the size (in bytes) of an array with n elements. +// Can be very handy to determine the size of a StaticJsonBuffer. +#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ + (sizeof(JsonArray) + (NUMBER_OF_ELEMENTS) * sizeof(JsonArray::node_type)) + +namespace ArduinoJson { + +// Forward declarations +class JsonObject; +class JsonBuffer; +class JsonArraySubscript; + +// An array of JsonVariant. +// +// The constructor is private, instances must be created via +// JsonBuffer::createArray() or JsonBuffer::parseArray(). +// A JsonArray can be serialized to a JSON string via JsonArray::printTo(). +// It can also be deserialized from a JSON string via JsonBuffer::parseArray(). +class JsonArray : public Internals::JsonPrintable, + public Internals::ReferenceType, + public Internals::List, + public Internals::JsonBufferAllocated { + public: + // A meta-function that returns true if type T can be used in + // JsonArray::set() + template + struct CanSet { + static const bool value = JsonVariant::IsConstructibleFrom::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value; + }; + + // Create an empty JsonArray attached to the specified JsonBuffer. + // You should not call this constructor directly. + // Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray(). + explicit JsonArray(JsonBuffer *buffer) + : Internals::List(buffer) {} + + // Gets the value at the specified index + FORCE_INLINE JsonVariant operator[](size_t index) const; + + // Gets or sets the value at specified index + FORCE_INLINE JsonArraySubscript operator[](size_t index); + + // Adds the specified value at the end of the array. + // + // bool add(bool); + // bool add(char); + // bool add(long); + // bool add(int); + // bool add(short); + // bool add(float value); + // bool add(double value); + // bool add(const char*); + template + FORCE_INLINE bool add( + T value, + typename TypeTraits::EnableIf< + CanSet::value && !TypeTraits::IsReference::value>::type * = 0) { + return addNode(value); + } + // bool add(const String&) + // bool add(const JsonVariant&); + // bool add(JsonArray&); + // bool add(JsonObject&); + template + FORCE_INLINE bool add( + const T &value, + typename TypeTraits::EnableIf::value>::type * = 0) { + return addNode(const_cast(value)); + } + // bool add(float value, uint8_t decimals); + // bool add(double value, uint8_t decimals); + template + FORCE_INLINE bool add( + T value, uint8_t decimals, + typename TypeTraits::EnableIf::value>::type + * = 0) { + return addNode(JsonVariant(value, decimals)); + } + + // Sets the value at specified index. + // + // bool set(size_t index, bool value); + // bool set(size_t index, long value); + // bool set(size_t index, int value); + // bool set(size_t index, short value); + template + FORCE_INLINE bool set( + size_t index, T value, + typename TypeTraits::EnableIf< + CanSet::value && !TypeTraits::IsReference::value>::type * = 0) { + return setNodeAt(index, value); + } + // bool set(size_t index, const String&) + // bool set(size_t index, const JsonVariant&); + // bool set(size_t index, JsonArray&); + // bool set(size_t index, JsonObject&); + template + FORCE_INLINE bool set( + size_t index, const T &value, + typename TypeTraits::EnableIf::value>::type * = 0) { + return setNodeAt(index, const_cast(value)); + } + // bool set(size_t index, float value, uint8_t decimals = 2); + // bool set(size_t index, double value, uint8_t decimals = 2); + template + FORCE_INLINE bool set( + size_t index, T value, uint8_t decimals, + typename TypeTraits::EnableIf::value>::type + * = 0) { + return setNodeAt(index, JsonVariant(value, decimals)); + } + + // Gets the value at the specified index. + FORCE_INLINE JsonVariant get(size_t index) const; + + // Gets the value at the specified index. + template + FORCE_INLINE T get(size_t index) const; + + // Check the type of the value at specified index. + template + FORCE_INLINE bool is(size_t index) const; + + // Creates a JsonArray and adds a reference at the end of the array. + // It's a shortcut for JsonBuffer::createArray() and JsonArray::add() + JsonArray &createNestedArray(); + + // Creates a JsonObject and adds a reference at the end of the array. + // It's a shortcut for JsonBuffer::createObject() and JsonArray::add() + JsonObject &createNestedObject(); + + // Removes element at specified index. + void removeAt(size_t index); + + // Returns a reference an invalid JsonArray. + // This object is meant to replace a NULL pointer. + // This is used when memory allocation or JSON parsing fail. + static JsonArray &invalid() { return _invalid; } + + // Serialize the array to the specified JsonWriter. + void writeTo(Internals::JsonWriter &writer) const; + + private: + node_type *getNodeAt(size_t index) const; + + template + bool setNodeAt(size_t index, TValue value); + + template + bool addNode(TValue); + + template + FORCE_INLINE bool setNodeValue(node_type *, T value); + + // The instance returned by JsonArray::invalid() + static JsonArray _invalid; +}; +} + +#include "JsonArray.ipp" diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArray.ipp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArray.ipp new file mode 100644 index 00000000..2881ed25 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArray.ipp @@ -0,0 +1,101 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "JsonArray.hpp" +#include "JsonObject.hpp" +#include "JsonArraySubscript.hpp" + +namespace ArduinoJson { + +inline JsonArraySubscript JsonArray::operator[](size_t index) { + return JsonArraySubscript(*this, index); +} + +inline JsonVariant JsonArray::operator[](size_t index) const { + return get(index); +} + +template +inline bool JsonArray::addNode(TValue value) { + node_type *node = addNewNode(); + return node != NULL && setNodeValue(node, value); +} + +template +inline bool JsonArray::setNodeAt(size_t index, TValue value) { + node_type *node = getNodeAt(index); + return node != NULL && setNodeValue(node, value); +} + +template +inline bool JsonArray::setNodeValue(node_type *node, TValue value) { + node->content = value; + return true; +} + +template <> +inline bool JsonArray::setNodeValue(node_type *node, String &value) { + const char *copy = _buffer->strdup(value); + if (!copy) return false; + node->content = copy; + return true; +} + +inline JsonVariant JsonArray::get(size_t index) const { + node_type *node = getNodeAt(index); + return node ? node->content : JsonVariant(); +} + +template +inline T JsonArray::get(size_t index) const { + node_type *node = getNodeAt(index); + return node ? node->content.as() : JsonVariant::invalid(); +} + +template +inline bool JsonArray::is(size_t index) const { + node_type *node = getNodeAt(index); + return node ? node->content.is() : false; +} + +template +inline const JsonArraySubscript JsonVariantBase::operator[]( + int index) const { + return asArray()[index]; +} + +template <> +inline JsonArray &JsonVariant::invalid() { + return JsonArray::invalid(); +} + +template <> +inline JsonArray const &JsonVariant::invalid() { + return JsonArray::invalid(); +} + +inline JsonArray &JsonVariant::asArray() const { + if (_type == Internals::JSON_ARRAY) return *_content.asArray; + return JsonArray::invalid(); +} + +inline JsonArray &JsonArray::createNestedArray() { + if (!_buffer) return JsonArray::invalid(); + JsonArray &array = _buffer->createArray(); + add(array); + return array; +} + +inline JsonArray &JsonObject::createNestedArray(JsonObjectKey key) { + if (!_buffer) return JsonArray::invalid(); + JsonArray &array = _buffer->createArray(); + setNodeAt(key, array); + return array; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArraySubscript.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArraySubscript.hpp new file mode 100644 index 00000000..57e55ebf --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonArraySubscript.hpp @@ -0,0 +1,84 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Configuration.hpp" +#include "JsonVariantBase.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif + +namespace ArduinoJson { +class JsonArraySubscript : public JsonVariantBase { + public: + FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) + : _array(array), _index(index) {} + + JsonArraySubscript& operator=(const JsonArraySubscript& src) { + _array.set(_index, src); + return *this; + } + + template + typename TypeTraits::EnableIf::value, + JsonArraySubscript>::type& + operator=(const T& src) { + _array.set(_index, const_cast(src)); + return *this; + } + + template + typename TypeTraits::EnableIf::value, + JsonArraySubscript>::type& + operator=(T src) { + _array.set(_index, src); + return *this; + } + + FORCE_INLINE bool success() const { return _index < _array.size(); } + + FORCE_INLINE operator JsonVariant() const { return _array.get(_index); } + + template + FORCE_INLINE T as() const { + return _array.get(_index); + } + + template + FORCE_INLINE bool is() const { + return _array.is(_index); + } + + void writeTo(Internals::JsonWriter& writer) const { + _array.get(_index).writeTo(writer); + } + + template + void set(TValue value) { + _array.set(_index, value); + } + + private: + JsonArray& _array; + const size_t _index; +}; + +#if ARDUINOJSON_ENABLE_STD_STREAM +inline std::ostream& operator<<(std::ostream& os, + const JsonArraySubscript& source) { + return source.printTo(os); +} +#endif + +} // namespace ArduinoJson + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonBuffer.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonBuffer.hpp new file mode 100644 index 00000000..4ff05aa4 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonBuffer.hpp @@ -0,0 +1,136 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include // for size_t +#include // for uint8_t +#include + +#include "Arduino/String.hpp" +#include "JsonVariant.hpp" + +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +namespace ArduinoJson { +class JsonArray; +class JsonObject; + +// Entry point for using the library. +// +// Handle the memory management (done in derived classes) and calls the parser. +// This abstract class is implemented by StaticJsonBuffer which implements a +// fixed memory allocation. +class JsonBuffer { + public: + // CAUTION: NO VIRTUAL DESTRUCTOR! + // If we add a virtual constructor the Arduino compiler will add malloc() and + // free() to the binary, adding 706 useless bytes. + // virtual ~JsonBuffer() {} + + // Allocates an empty JsonArray. + // + // Returns a reference to the new JsonArray or JsonArray::invalid() if the + // allocation fails. + JsonArray &createArray(); + + // Allocates an empty JsonObject. + // + // Returns a reference to the new JsonObject or JsonObject::invalid() if the + // allocation fails. + JsonObject &createObject(); + + // Allocates and populate a JsonArray from a JSON string. + // + // The First argument is a pointer to the JSON string, the memory must be + // writable + // because the parser will insert null-terminators and replace escaped chars. + // + // The second argument set the nesting limit (see comment on DEFAULT_LIMIT) + // + // Returns a reference to the new JsonObject or JsonObject::invalid() if the + // allocation fails. + JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); + + // Same with a const char*. + // With this overload, the JsonBuffer will make a copy of the string + JsonArray &parseArray(const char *json, uint8_t nesting = DEFAULT_LIMIT) { + return parseArray(strdup(json), nesting); + } + + // Same as above with a String class + JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) { + return parseArray(json.c_str(), nesting); + } + + // Allocates and populate a JsonObject from a JSON string. + // + // The First argument is a pointer to the JSON string, the memory must be + // writable + // because the parser will insert null-terminators and replace escaped chars. + // + // The second argument set the nesting limit (see comment on DEFAULT_LIMIT) + // + // Returns a reference to the new JsonObject or JsonObject::invalid() if the + // allocation fails. + JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); + + // Same with a const char*. + // With this overload, the JsonBuffer will make a copy of the string + JsonObject &parseObject(const char *json, uint8_t nesting = DEFAULT_LIMIT) { + return parseObject(strdup(json), nesting); + } + + // Same as above with a String class + JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) { + return parseObject(json.c_str(), nesting); + } + + // Duplicate a string + char *strdup(const char *src) { + return src ? strdup(src, strlen(src)) : NULL; + } + char *strdup(const String &src) { return strdup(src.c_str(), src.length()); } + + // Allocates n bytes in the JsonBuffer. + // Return a pointer to the allocated memory or NULL if allocation fails. + virtual void *alloc(size_t size) = 0; + + protected: + // Preserve aligment if nessary + static FORCE_INLINE size_t round_size_up(size_t bytes) { +#if ARDUINOJSON_ENABLE_ALIGNMENT + const size_t x = sizeof(void *) - 1; + return (bytes + x) & ~x; +#else + return bytes; +#endif + } + + private: + char *strdup(const char *, size_t); + + // Default value of nesting limit of parseArray() and parseObject(). + // + // The nesting limit is a contain on the level of nesting allowed in the + // JSON + // string. + // If set to 0, only a flat array or objects can be parsed. + // If set to 1, the object can contain nested arrays or objects but only 1 + // level deep. + // And bigger values will allow more level of nesting. + // + // The purpose of this feature is to prevent stack overflow that could + // lead to + // a security risk. + static const uint8_t DEFAULT_LIMIT = 10; +}; +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObject.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObject.hpp new file mode 100644 index 00000000..9f4a061f --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObject.hpp @@ -0,0 +1,153 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Arduino/String.hpp" +#include "Internals/JsonBufferAllocated.hpp" +#include "Internals/JsonPrintable.hpp" +#include "Internals/List.hpp" +#include "Internals/ReferenceType.hpp" +#include "JsonPair.hpp" +#include "TypeTraits/EnableIf.hpp" +#include "TypeTraits/IsFloatingPoint.hpp" +#include "TypeTraits/IsReference.hpp" +#include "TypeTraits/IsSame.hpp" + +// Returns the size (in bytes) of an object with n elements. +// Can be very handy to determine the size of a StaticJsonBuffer. +#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ + (sizeof(JsonObject) + (NUMBER_OF_ELEMENTS) * sizeof(JsonObject::node_type)) + +namespace ArduinoJson { + +// Forward declarations +class JsonArray; +class JsonBuffer; + +// A dictionary of JsonVariant indexed by string (char*) +// +// The constructor is private, instances must be created via +// JsonBuffer::createObject() or JsonBuffer::parseObject(). +// A JsonObject can be serialized to a JSON string via JsonObject::printTo(). +// It can also be deserialized from a JSON string via JsonBuffer::parseObject(). +class JsonObject : public Internals::JsonPrintable, + public Internals::ReferenceType, + public Internals::List, + public Internals::JsonBufferAllocated { + public: + // A meta-function that returns true if type T can be used in + // JsonObject::set() + template + struct CanSet { + static const bool value = JsonVariant::IsConstructibleFrom::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value; + }; + + // Create an empty JsonArray attached to the specified JsonBuffer. + // You should not use this constructor directly. + // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject(). + FORCE_INLINE explicit JsonObject(JsonBuffer* buffer) + : Internals::List(buffer) {} + + // Gets or sets the value associated with the specified key. + FORCE_INLINE JsonObjectSubscript operator[](const char* key); + FORCE_INLINE JsonObjectSubscript operator[](const String& key); + + // Gets the value associated with the specified key. + FORCE_INLINE JsonVariant operator[](JsonObjectKey key) const; + + // Sets the specified key with the specified value. + // bool set(TKey key, bool value); + // bool set(TKey key, char value); + // bool set(TKey key, long value); + // bool set(TKey key, int value); + // bool set(TKey key, short value); + // bool set(TKey key, float value); + // bool set(TKey key, double value); + // bool set(TKey key, const char* value); + template + FORCE_INLINE bool set( + JsonObjectKey key, T value, + typename TypeTraits::EnableIf< + CanSet::value && !TypeTraits::IsReference::value>::type* = 0) { + return setNodeAt(key, value); + } + // bool set(Key, String&); + // bool set(Key, JsonArray&); + // bool set(Key, JsonObject&); + // bool set(Key, JsonVariant&); + template + FORCE_INLINE bool set( + JsonObjectKey key, const T& value, + typename TypeTraits::EnableIf::value>::type* = 0) { + return setNodeAt(key, const_cast(value)); + } + // bool set(Key, float value, uint8_t decimals); + // bool set(Key, double value, uint8_t decimals); + template + FORCE_INLINE bool set( + JsonObjectKey key, TValue value, uint8_t decimals, + typename TypeTraits::EnableIf< + TypeTraits::IsFloatingPoint::value>::type* = 0) { + return setNodeAt(key, JsonVariant(value, decimals)); + } + + // Gets the value associated with the specified key. + FORCE_INLINE JsonVariant get(JsonObjectKey) const; + + // Gets the value associated with the specified key. + template + FORCE_INLINE T get(JsonObjectKey) const; + + // Checks the type of the value associated with the specified key. + template + FORCE_INLINE bool is(JsonObjectKey) const; + + // Creates and adds a JsonArray. + // This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). + FORCE_INLINE JsonArray& createNestedArray(JsonObjectKey key); + + // Creates and adds a JsonObject. + // This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). + FORCE_INLINE JsonObject& createNestedObject(JsonObjectKey key); + + // Tells weither the specified key is present and associated with a value. + FORCE_INLINE bool containsKey(JsonObjectKey key) const; + + // Removes the specified key and the associated value. + void remove(JsonObjectKey key); + + // Returns a reference an invalid JsonObject. + // This object is meant to replace a NULL pointer. + // This is used when memory allocation or JSON parsing fail. + static JsonObject& invalid() { return _invalid; } + + // Serialize the object to the specified JsonWriter + void writeTo(Internals::JsonWriter& writer) const; + + private: + // Returns the list node that matches the specified key. + node_type* getNodeAt(const char* key) const; + + node_type* getOrCreateNodeAt(const char* key); + + template + FORCE_INLINE bool setNodeAt(JsonObjectKey key, T value); + + FORCE_INLINE bool setNodeKey(node_type*, JsonObjectKey key); + + template + FORCE_INLINE bool setNodeValue(node_type*, T value); + + // The instance returned by JsonObject::invalid() + static JsonObject _invalid; +}; +} + +#include "JsonObject.ipp" diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObject.ipp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObject.ipp new file mode 100644 index 00000000..b8fc87ff --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObject.ipp @@ -0,0 +1,134 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "JsonArray.hpp" +#include "JsonObject.hpp" +#include "JsonObjectSubscript.hpp" + +namespace ArduinoJson { + +inline JsonVariant JsonObject::get(JsonObjectKey key) const { + node_type *node = getNodeAt(key.c_str()); + return node ? node->content.value : JsonVariant(); +} + +template +inline T JsonObject::get(JsonObjectKey key) const { + node_type *node = getNodeAt(key.c_str()); + return node ? node->content.value.as() : JsonVariant::invalid(); +} + +template +inline bool JsonObject::is(JsonObjectKey key) const { + node_type *node = getNodeAt(key.c_str()); + return node ? node->content.value.is() : false; +} + +inline JsonObjectSubscript JsonObject::operator[]( + const char *key) { + return JsonObjectSubscript(*this, key); +} + +inline JsonObjectSubscript JsonObject::operator[]( + const String &key) { + return JsonObjectSubscript(*this, key); +} + +inline JsonVariant JsonObject::operator[](JsonObjectKey key) const { + return get(key); +} + +inline bool JsonObject::containsKey(JsonObjectKey key) const { + return getNodeAt(key.c_str()) != NULL; +} + +inline void JsonObject::remove(JsonObjectKey key) { + removeNode(getNodeAt(key.c_str())); +} + +template +inline bool JsonObject::setNodeAt(JsonObjectKey key, T value) { + node_type *node = getNodeAt(key.c_str()); + if (!node) { + node = addNewNode(); + if (!node || !setNodeKey(node, key)) + return false; + } + return setNodeValue(node, value); +} + +inline bool JsonObject::setNodeKey(node_type *node, JsonObjectKey key) { + if (key.needs_copy()) { + node->content.key = _buffer->strdup(key.c_str()); + if (node->content.key == NULL) return false; + } else { + node->content.key = key.c_str(); + } + return true; +} + +template +inline bool JsonObject::setNodeValue(node_type *node, TValue value) { + node->content.value = value; + return true; +} + +template <> +inline bool JsonObject::setNodeValue(node_type *node, String &value) { + node->content.value = _buffer->strdup(value); + return node->content.value; +} + +template <> +inline bool JsonObject::setNodeValue(node_type *node, const String &value) { + node->content.value = _buffer->strdup(value); + return node->content.value; +} + +template +inline const JsonObjectSubscript JsonVariantBase:: +operator[](const char *key) const { + return asObject()[key]; +} + +template +inline const JsonObjectSubscript JsonVariantBase:: +operator[](const String &key) const { + return asObject()[key]; +} + +template <> +inline JsonObject const &JsonVariant::invalid() { + return JsonObject::invalid(); +} + +template <> +inline JsonObject &JsonVariant::invalid() { + return JsonObject::invalid(); +} + +inline JsonObject &JsonVariant::asObject() const { + if (_type == Internals::JSON_OBJECT) return *_content.asObject; + return JsonObject::invalid(); +} + +inline JsonObject &JsonObject::createNestedObject(JsonObjectKey key) { + if (!_buffer) return JsonObject::invalid(); + JsonObject &array = _buffer->createObject(); + setNodeAt(key, array); + return array; +} + +inline JsonObject &JsonArray::createNestedObject() { + if (!_buffer) return JsonObject::invalid(); + JsonObject &object = _buffer->createObject(); + add(object); + return object; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObjectKey.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObjectKey.hpp new file mode 100644 index 00000000..5390b426 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObjectKey.hpp @@ -0,0 +1,27 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Arduino/String.hpp" + +namespace ArduinoJson { + +// Represents a key in a JsonObject +class JsonObjectKey { + public: + JsonObjectKey(const char* key) : _value(key), _needs_copy(false) {} + JsonObjectKey(const String& key) : _value(key.c_str()), _needs_copy(true) {} + + const char* c_str() const { return _value; } + bool needs_copy() const { return _needs_copy; } + + private: + const char* _value; + bool _needs_copy; +}; +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObjectSubscript.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObjectSubscript.hpp new file mode 100644 index 00000000..70b6a642 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonObjectSubscript.hpp @@ -0,0 +1,99 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Configuration.hpp" +#include "JsonVariantBase.hpp" +#include "TypeTraits/EnableIf.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif + +namespace ArduinoJson { + +template +class JsonObjectSubscript : public JsonVariantBase > { + public: + FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key) + : _object(object), _key(key) {} + + JsonObjectSubscript& operator=(const JsonObjectSubscript& src) { + _object.set(_key, src); + return *this; + } + + template + typename TypeTraits::EnableIf::value, + JsonObjectSubscript >::type& + operator=(const T& src) { + _object.set(_key, const_cast(src)); + return *this; + } + + template + typename TypeTraits::EnableIf::value, + JsonObjectSubscript >::type& + operator=(T src) { + _object.set(_key, src); + return *this; + } + + FORCE_INLINE bool success() const { return _object.containsKey(_key); } + + FORCE_INLINE operator JsonVariant() const { return _object.get(_key); } + + template + FORCE_INLINE TValue as() const { + return _object.get(_key); + } + + template + FORCE_INLINE bool is() const { + return _object.is(_key); + } + + template + FORCE_INLINE bool set(TValue value) { + return _object.set(_key, value); + } + + template + FORCE_INLINE bool set(TValue value, uint8_t decimals) { + return _object.set(_key, value, decimals); + } + + FORCE_INLINE JsonVariant get() { return _object.get(_key); } + + void writeTo(Internals::JsonWriter& writer) const { + _object.get(_key).writeTo(writer); + } + + private: + JsonObject& _object; + TKey _key; +}; + +#if ARDUINOJSON_ENABLE_STD_STREAM +inline std::ostream& operator<<( + std::ostream& os, const JsonObjectSubscript& source) { + return source.printTo(os); +} + +inline std::ostream& operator<<( + std::ostream& os, const JsonObjectSubscript& source) { + return source.printTo(os); +} +#endif + +} // namespace ArduinoJson + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonPair.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonPair.hpp new file mode 100644 index 00000000..49ebed8d --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonPair.hpp @@ -0,0 +1,20 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "JsonObjectKey.hpp" +#include "JsonVariant.hpp" + +namespace ArduinoJson { + +// A key value pair for JsonObject. +struct JsonPair { + const char* key; + JsonVariant value; +}; +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariant.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariant.hpp new file mode 100644 index 00000000..f570c96f --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariant.hpp @@ -0,0 +1,217 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include +#include // for uint8_t + +#include "Internals/JsonPrintable.hpp" +#include "Internals/JsonVariantContent.hpp" +#include "Internals/JsonVariantType.hpp" +#include "Internals/Unparsed.hpp" +#include "JsonVariantBase.hpp" +#include "TypeTraits/EnableIf.hpp" +#include "TypeTraits/IsFloatingPoint.hpp" +#include "TypeTraits/IsIntegral.hpp" +#include "TypeTraits/IsSame.hpp" +#include "TypeTraits/RemoveConst.hpp" +#include "TypeTraits/RemoveReference.hpp" + +namespace ArduinoJson { + +// Forward declarations. +class JsonArray; +class JsonObject; + +// A variant that can be a any value serializable to a JSON value. +// +// It can be set to: +// - a boolean +// - a char, short, int or a long (signed or unsigned) +// - a string (const char*) +// - a reference to a JsonArray or JsonObject +class JsonVariant : public JsonVariantBase { + public: + template + struct IsConstructibleFrom; + + // Creates an uninitialized JsonVariant + FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} + + // Create a JsonVariant containing a boolean value. + // It will be serialized as "true" or "false" in JSON. + FORCE_INLINE JsonVariant(bool value); + + // Create a JsonVariant containing a floating point value. + // The second argument specifies the number of decimal digits to write in + // the JSON string. + // JsonVariant(double value, uint8_t decimals); + // JsonVariant(float value, uint8_t decimals); + template + FORCE_INLINE JsonVariant( + T value, uint8_t decimals = 2, + typename TypeTraits::EnableIf::value>::type + * = 0) { + using namespace Internals; + _type = static_cast(JSON_FLOAT_0_DECIMALS + decimals); + _content.asFloat = static_cast(value); + } + + // Create a JsonVariant containing an integer value. + // JsonVariant(short) + // JsonVariant(int) + // JsonVariant(long) + template + FORCE_INLINE JsonVariant( + T value, + typename TypeTraits::EnableIf::value>::type * = + 0) { + using namespace Internals; + _type = JSON_INTEGER; + _content.asInteger = static_cast(value); + } + + // Create a JsonVariant containing a string. + FORCE_INLINE JsonVariant(const char *value); + + // Create a JsonVariant containing an unparsed string + FORCE_INLINE JsonVariant(Internals::Unparsed value); + + // Create a JsonVariant containing a reference to an array. + FORCE_INLINE JsonVariant(JsonArray &array); + + // Create a JsonVariant containing a reference to an object. + FORCE_INLINE JsonVariant(JsonObject &object); + + // Get the variant as the specified type. + // short as() const; + // int as() const; + // long as() const; + template + const typename TypeTraits::EnableIf::value, T>::type + as() const { + return static_cast(asInteger()); + } + // double as() const; + // float as() const; + template + const typename TypeTraits::EnableIf::value, + T>::type + as() const { + return static_cast(asFloat()); + } + // const String as() const; + template + const typename TypeTraits::EnableIf::value, + T>::type + as() const { + return toString(); + } + // const char* as() const; + // const char* as() const; + template + typename TypeTraits::EnableIf::value, + const char *>::type + as() const { + return asString(); + } + // const bool as() const + template + const typename TypeTraits::EnableIf::value, + T>::type + as() const { + return asInteger() != 0; + } + // JsonArray& as const; + // JsonArray& as const; + // JsonArray& as const; + template + typename TypeTraits::EnableIf< + TypeTraits::IsSame< + typename TypeTraits::RemoveConst< + typename TypeTraits::RemoveReference::type>::type, + JsonArray>::value, + JsonArray &>::type + as() const { + return asArray(); + } + // JsonObject& as const; + // JsonObject& as const; + // JsonObject& as const; + template + typename TypeTraits::EnableIf< + TypeTraits::IsSame< + typename TypeTraits::RemoveConst< + typename TypeTraits::RemoveReference::type>::type, + JsonObject>::value, + JsonObject &>::type + as() const { + return asObject(); + } + + // Tells weither the variant has the specified type. + // Returns true if the variant has type type T, false otherwise. + template + bool is() const; + + // Serialize the variant to a JsonWriter + void writeTo(Internals::JsonWriter &writer) const; + + // TODO: rename + template + static T invalid(); + + const char *asString() const; + JsonArray &asArray() const; + JsonObject &asObject() const; + + private: + String toString() const; + Internals::JsonFloat asFloat() const; + Internals::JsonInteger asInteger() const; + + // The current type of the variant + Internals::JsonVariantType _type; + + // The various alternatives for the value of the variant. + Internals::JsonVariantContent _content; +}; + +inline JsonVariant float_with_n_digits(float value, uint8_t digits) { + return JsonVariant(value, digits); +} + +inline JsonVariant double_with_n_digits(double value, uint8_t digits) { + return JsonVariant(value, digits); +} + +template +struct JsonVariant::IsConstructibleFrom { + static const bool value = + TypeTraits::IsIntegral::value || + TypeTraits::IsFloatingPoint::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame &>::value || + TypeTraits::IsSame &>::value || + TypeTraits::IsSame &>::value || + TypeTraits::IsSame &>::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value; +}; +} + +// Include inline implementations +#include "JsonVariant.ipp" diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariant.ipp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariant.ipp new file mode 100644 index 00000000..c9fb3b71 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariant.ipp @@ -0,0 +1,150 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Configuration.hpp" +#include "JsonVariant.hpp" +#include "Internals/Parse.hpp" + +#include + +namespace ArduinoJson { + +inline JsonVariant::JsonVariant(bool value) { + using namespace Internals; + _type = JSON_BOOLEAN; + _content.asInteger = static_cast(value); +} + +inline JsonVariant::JsonVariant(const char *value) { + _type = Internals::JSON_STRING; + _content.asString = value; +} + +inline JsonVariant::JsonVariant(Internals::Unparsed value) { + _type = Internals::JSON_UNPARSED; + _content.asString = value; +} + +inline JsonVariant::JsonVariant(JsonArray &array) { + _type = Internals::JSON_ARRAY; + _content.asArray = &array; +} + +inline JsonVariant::JsonVariant(JsonObject &object) { + _type = Internals::JSON_OBJECT; + _content.asObject = &object; +} + +template +inline T JsonVariant::invalid() { + return T(); +} + +template +inline bool JsonVariant::is() const { + return false; +} + +template <> // in .cpp +bool JsonVariant::is() const; + +template <> // in .cpp +bool JsonVariant::is() const; + +template <> // int .cpp +bool JsonVariant::is() const; + +template <> +inline bool JsonVariant::is() const { + return _type == Internals::JSON_STRING; +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +template <> +inline bool JsonVariant::is() const { + return _type == Internals::JSON_ARRAY; +} + +template <> +inline bool JsonVariant::is() const { + return _type == Internals::JSON_ARRAY; +} + +template <> +inline bool JsonVariant::is() const { + return _type == Internals::JSON_OBJECT; +} + +template <> +inline bool JsonVariant::is() const { + return _type == Internals::JSON_OBJECT; +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +template <> +inline bool JsonVariant::is() const { + return is(); +} + +inline Internals::JsonInteger JsonVariant::asInteger() const { + if (_type == Internals::JSON_INTEGER || _type == Internals::JSON_BOOLEAN) + return _content.asInteger; + + if (_type >= Internals::JSON_FLOAT_0_DECIMALS) + return static_cast(_content.asFloat); + + if ((_type == Internals::JSON_STRING || _type == Internals::JSON_UNPARSED) && + _content.asString) { + if (!strcmp("true", _content.asString)) return 1; + return Internals::parse(_content.asString); + } + + return 0L; +} + +#if ARDUINOJSON_ENABLE_STD_STREAM +inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) { + return source.printTo(os); +} +#endif + +} // namespace ArduinoJson diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariantBase.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariantBase.hpp new file mode 100644 index 00000000..7ca0919f --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/JsonVariantBase.hpp @@ -0,0 +1,133 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "Internals/ForceInline.hpp" +#include "JsonObjectKey.hpp" + +namespace ArduinoJson { + +// Forward declarations. +class JsonArraySubscript; +template +class JsonObjectSubscript; + +template +class JsonVariantBase : public Internals::JsonPrintable { + public: + FORCE_INLINE const char *asString() const { return as(); } + + // Gets the variant as an array. + // Returns a reference to the JsonArray or JsonArray::invalid() if the + // variant + // is not an array. + FORCE_INLINE operator JsonArray &() const { return as(); } + FORCE_INLINE JsonArray &asArray() const { return as(); } + + // Gets the variant as an object. + // Returns a reference to the JsonObject or JsonObject::invalid() if the + // variant is not an object. + FORCE_INLINE operator JsonObject &() const { return as(); } + FORCE_INLINE JsonObject &asObject() const { return as(); } + + template + FORCE_INLINE operator T() const { + return as(); + } + + template + FORCE_INLINE const T as() const { + return impl()->template as(); + } + + // Mimics an array or an object. + // Returns the size of the array or object if the variant has that type. + // Returns 0 if the variant is neither an array nor an object + size_t size() const { return asArray().size() + asObject().size(); } + + // Mimics an array. + // Returns the element at specified index if the variant is an array. + // Returns JsonVariant::invalid() if the variant is not an array. + FORCE_INLINE const JsonArraySubscript operator[](int index) const; + + // Mimics an object. + // Returns the value associated with the specified key if the variant is + // an object. + // Return JsonVariant::invalid() if the variant is not an object. + FORCE_INLINE const JsonObjectSubscript operator[]( + const char *key) const; + FORCE_INLINE const JsonObjectSubscript operator[]( + const String &key) const; + + // Serialize the variant to a JsonWriter + void writeTo(Internals::JsonWriter &writer) const; + + private: + const TImpl *impl() const { return static_cast(this); } +}; + +template +inline bool operator==(const JsonVariantBase &left, TComparand right) { + return left.template as() == right; +} + +template +inline bool operator==(TComparand left, const JsonVariantBase &right) { + return left == right.template as(); +} + +template +inline bool operator!=(const JsonVariantBase &left, TComparand right) { + return left.template as() != right; +} + +template +inline bool operator!=(TComparand left, const JsonVariantBase &right) { + return left != right.template as(); +} + +template +inline bool operator<=(const JsonVariantBase &left, TComparand right) { + return left.template as() <= right; +} + +template +inline bool operator<=(TComparand left, const JsonVariantBase &right) { + return left <= right.template as(); +} + +template +inline bool operator>=(const JsonVariantBase &left, TComparand right) { + return left.template as() >= right; +} + +template +inline bool operator>=(TComparand left, const JsonVariantBase &right) { + return left >= right.template as(); +} + +template +inline bool operator<(const JsonVariantBase &left, TComparand right) { + return left.template as() < right; +} + +template +inline bool operator<(TComparand left, const JsonVariantBase &right) { + return left < right.template as(); +} + +template +inline bool operator>(const JsonVariantBase &left, TComparand right) { + return left.template as() > right; +} + +template +inline bool operator>(TComparand left, const JsonVariantBase &right) { + return left > right.template as(); +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/StaticJsonBuffer.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/StaticJsonBuffer.hpp new file mode 100644 index 00000000..c1473e7f --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/StaticJsonBuffer.hpp @@ -0,0 +1,36 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "JsonBuffer.hpp" + +namespace ArduinoJson { + +// Implements a JsonBuffer with fixed memory allocation. +// The template paramenter CAPACITY specifies the capacity of the buffer in +// bytes. +template +class StaticJsonBuffer : public JsonBuffer { + public: + explicit StaticJsonBuffer() : _size(0) {} + + size_t capacity() const { return CAPACITY; } + size_t size() const { return _size; } + + virtual void* alloc(size_t bytes) { + if (_size + bytes > CAPACITY) return NULL; + void* p = &_buffer[_size]; + _size += round_size_up(bytes); + return p; + } + + private: + uint8_t _buffer[CAPACITY]; + size_t _size; +}; +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/EnableIf.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/EnableIf.hpp new file mode 100644 index 00000000..408e8bb0 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/EnableIf.hpp @@ -0,0 +1,22 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that return the type T if Condition is true. +template +struct EnableIf {}; + +template +struct EnableIf { + typedef T type; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsFloatingPoint.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsFloatingPoint.hpp new file mode 100644 index 00000000..42a13ec6 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsFloatingPoint.hpp @@ -0,0 +1,21 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "IsSame.hpp" + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that returns true if T is a floating point type +template +struct IsFloatingPoint { + static const bool value = IsSame::value || IsSame::value; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsIntegral.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsIntegral.hpp new file mode 100644 index 00000000..b2e75ee6 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsIntegral.hpp @@ -0,0 +1,41 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Configuration.hpp" +#include "IsSame.hpp" + +#include + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that returns true if T is an integral type. +template +struct IsIntegral { + static const bool value = TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || +#if ARDUINOJSON_USE_LONG_LONG + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || +#endif + +#if ARDUINOJSON_USE_INT64 + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || +#endif + TypeTraits::IsSame::value; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsReference.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsReference.hpp new file mode 100644 index 00000000..436a25db --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsReference.hpp @@ -0,0 +1,24 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that returns true if T is a reference +template +struct IsReference { + static const bool value = false; +}; + +template +struct IsReference { + static const bool value = true; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsSame.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsSame.hpp new file mode 100644 index 00000000..0b68d3c3 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/IsSame.hpp @@ -0,0 +1,24 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that returns true if types T and U are the same. +template +struct IsSame { + static const bool value = false; +}; + +template +struct IsSame { + static const bool value = true; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/RemoveConst.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/RemoveConst.hpp new file mode 100644 index 00000000..cf7b3af2 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/RemoveConst.hpp @@ -0,0 +1,23 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that return the type T without the const modifier +template +struct RemoveConst { + typedef T type; +}; +template +struct RemoveConst { + typedef T type; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/RemoveReference.hpp b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/RemoveReference.hpp new file mode 100644 index 00000000..d77eb85e --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/include/ArduinoJson/TypeTraits/RemoveReference.hpp @@ -0,0 +1,23 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that return the type T without the reference modifier. +template +struct RemoveReference { + typedef T type; +}; +template +struct RemoveReference { + typedef T type; +}; +} +} diff --git a/src/third-party/arduino-json-5.1.1/keywords.txt b/src/third-party/arduino-json-5.1.1/keywords.txt new file mode 100644 index 00000000..913b6aa6 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/keywords.txt @@ -0,0 +1,14 @@ +JsonArray KEYWORD1 +JsonObject KEYWORD1 +JsonVariant KEYWORD1 +StaticJsonBuffer KEYWORD1 +add KEYWORD2 +createArray KEYWORD2 +createNestedArray KEYWORD2 +createNestedObject KEYWORD2 +createObject KEYWORD2 +parseArray KEYWORD2 +parseObject KEYWORD2 +prettyPrintTo KEYWORD2 +printTo KEYWORD2 +success KEYWORD2 diff --git a/src/third-party/arduino-json-5.1.1/library.properties b/src/third-party/arduino-json-5.1.1/library.properties new file mode 100644 index 00000000..5b0ae67b --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/library.properties @@ -0,0 +1,9 @@ +name=ArduinoJson +version=5.1.1 +author=Benoit Blanchon +maintainer=Benoit Blanchon +sentence=An efficient and elegant JSON library for Arduino. +paragraph=Like this project? Please star it on GitHub! +category=Data Processing +url=https://github.com/bblanchon/ArduinoJson +architectures=* diff --git a/src/third-party/arduino-json-5.1.1/src/ArduinoJson.h b/src/third-party/arduino-json-5.1.1/src/ArduinoJson.h new file mode 100644 index 00000000..d884cadc --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/ArduinoJson.h @@ -0,0 +1,14 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +// About this file +// --------------- +// This file is here to please the Arduino IDE. It must be present in the src/ +// for the IDE to find it. Feel free to ignore this file if your working in +// another environment + +#include "../include/ArduinoJson.h" diff --git a/src/third-party/arduino-json-5.1.1/src/Internals/Comments.cpp b/src/third-party/arduino-json-5.1.1/src/Internals/Comments.cpp new file mode 100644 index 00000000..88e9ea80 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/Internals/Comments.cpp @@ -0,0 +1,52 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../../include/ArduinoJson/Internals/Comments.hpp" + +inline static const char *skipCStyleComment(const char *ptr) { + ptr += 2; + for (;;) { + if (ptr[0] == '\0') return ptr; + if (ptr[0] == '*' && ptr[1] == '/') return ptr + 2; + ptr++; + } +} + +inline static const char *skipCppStyleComment(const char *ptr) { + ptr += 2; + for (;;) { + if (ptr[0] == '\0' || ptr[0] == '\n') return ptr; + ptr++; + } +} + +const char *ArduinoJson::Internals::skipSpacesAndComments(const char *ptr) { + for (;;) { + switch (ptr[0]) { + case ' ': + case '\t': + case '\r': + case '\n': + ptr++; + continue; + case '/': + switch (ptr[1]) { + case '*': + ptr = skipCStyleComment(ptr); + break; + case '/': + ptr = skipCppStyleComment(ptr); + break; + default: + return ptr; + } + break; + default: + return ptr; + } + } +} diff --git a/src/third-party/arduino-json-5.1.1/src/Internals/Encoding.cpp b/src/third-party/arduino-json-5.1.1/src/Internals/Encoding.cpp new file mode 100644 index 00000000..d9d070d6 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/Internals/Encoding.cpp @@ -0,0 +1,14 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../../include/ArduinoJson/Internals/Encoding.hpp" + +// How to escape special chars: +// _escapeTable[2*i+1] => the special char +// _escapeTable[2*i] => the char to use instead +const char ArduinoJson::Internals::Encoding::_escapeTable[] = + "\"\"\\\\b\bf\fn\nr\rt\t"; diff --git a/src/third-party/arduino-json-5.1.1/src/Internals/IndentedPrint.cpp b/src/third-party/arduino-json-5.1.1/src/Internals/IndentedPrint.cpp new file mode 100644 index 00000000..f59fb5a2 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/Internals/IndentedPrint.cpp @@ -0,0 +1,30 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../../include/ArduinoJson/Internals/IndentedPrint.hpp" + +using namespace ArduinoJson::Internals; + +size_t IndentedPrint::write(uint8_t c) { + size_t n = 0; + + if (isNewLine) n += writeTabs(); + + n += sink->write(c); + + isNewLine = c == '\n'; + + return n; +} + +inline size_t IndentedPrint::writeTabs() { + size_t n = 0; + + for (int i = 0; i < level * tabSize; i++) n += sink->write(' '); + + return n; +} diff --git a/src/third-party/arduino-json-5.1.1/src/Internals/JsonParser.cpp b/src/third-party/arduino-json-5.1.1/src/Internals/JsonParser.cpp new file mode 100644 index 00000000..beb68092 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/Internals/JsonParser.cpp @@ -0,0 +1,201 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../../include/ArduinoJson/Internals/JsonParser.hpp" + +#include "../../include/ArduinoJson/Internals/Comments.hpp" +#include "../../include/ArduinoJson/Internals/Encoding.hpp" +#include "../../include/ArduinoJson/JsonArray.hpp" +#include "../../include/ArduinoJson/JsonBuffer.hpp" +#include "../../include/ArduinoJson/JsonObject.hpp" + +using namespace ArduinoJson; +using namespace ArduinoJson::Internals; + +bool JsonParser::skip(char charToSkip) { + const char *ptr = skipSpacesAndComments(_readPtr); + if (*ptr != charToSkip) return false; + ptr++; + _readPtr = skipSpacesAndComments(ptr); + return true; +} + +bool JsonParser::parseAnythingTo(JsonVariant *destination) { + if (_nestingLimit == 0) return false; + _nestingLimit--; + bool success = parseAnythingToUnsafe(destination); + _nestingLimit++; + return success; +} + +inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) { + _readPtr = skipSpacesAndComments(_readPtr); + + switch (*_readPtr) { + case '[': + return parseArrayTo(destination); + + case '{': + return parseObjectTo(destination); + + default: + return parseStringTo(destination); + } +} + +JsonArray &JsonParser::parseArray() { + // Create an empty array + JsonArray &array = _buffer->createArray(); + + // Check opening braket + if (!skip('[')) goto ERROR_MISSING_BRACKET; + if (skip(']')) goto SUCCESS_EMPTY_ARRAY; + + // Read each value + for (;;) { + // 1 - Parse value + JsonVariant value; + if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE; + if (!array.add(value)) goto ERROR_NO_MEMORY; + + // 2 - More values? + if (skip(']')) goto SUCCES_NON_EMPTY_ARRAY; + if (!skip(',')) goto ERROR_MISSING_COMMA; + } + +SUCCESS_EMPTY_ARRAY: +SUCCES_NON_EMPTY_ARRAY: + return array; + +ERROR_INVALID_VALUE: +ERROR_MISSING_BRACKET: +ERROR_MISSING_COMMA: +ERROR_NO_MEMORY: + return JsonArray::invalid(); +} + +bool JsonParser::parseArrayTo(JsonVariant *destination) { + JsonArray &array = parseArray(); + if (!array.success()) return false; + + *destination = array; + return true; +} + +JsonObject &JsonParser::parseObject() { + // Create an empty object + JsonObject &object = _buffer->createObject(); + + // Check opening brace + if (!skip('{')) goto ERROR_MISSING_BRACE; + if (skip('}')) goto SUCCESS_EMPTY_OBJECT; + + // Read each key value pair + for (;;) { + // 1 - Parse key + const char *key = parseString(); + if (!key) goto ERROR_INVALID_KEY; + if (!skip(':')) goto ERROR_MISSING_COLON; + + // 2 - Parse value + JsonVariant value; + if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE; + if (!object.set(key, value)) goto ERROR_NO_MEMORY; + + // 3 - More keys/values? + if (skip('}')) goto SUCCESS_NON_EMPTY_OBJECT; + if (!skip(',')) goto ERROR_MISSING_COMMA; + } + +SUCCESS_EMPTY_OBJECT: +SUCCESS_NON_EMPTY_OBJECT: + return object; + +ERROR_INVALID_KEY: +ERROR_INVALID_VALUE: +ERROR_MISSING_BRACE: +ERROR_MISSING_COLON: +ERROR_MISSING_COMMA: +ERROR_NO_MEMORY: + return JsonObject::invalid(); +} + +bool JsonParser::parseObjectTo(JsonVariant *destination) { + JsonObject &object = parseObject(); + if (!object.success()) return false; + + *destination = object; + return true; +} + +static inline bool isInRange(char c, char min, char max) { + return min <= c && c <= max; +} + +static inline bool isLetterOrNumber(char c) { + return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') || + isInRange(c, 'A', 'Z') || c == '-' || c == '.'; +} + +static inline bool isQuote(char c) { return c == '\'' || c == '\"'; } + +const char *JsonParser::parseString() { + const char *readPtr = _readPtr; + char *writePtr = _writePtr; + + char c = *readPtr; + + if (isQuote(c)) { // quotes + char stopChar = c; + for (;;) { + c = *++readPtr; + if (c == '\0') break; + + if (c == stopChar) { + readPtr++; + break; + } + + if (c == '\\') { + // replace char + c = Encoding::unescapeChar(*++readPtr); + if (c == '\0') break; + } + + *writePtr++ = c; + } + } else { // no quotes + for (;;) { + if (!isLetterOrNumber(c)) break; + *writePtr++ = c; + c = *++readPtr; + } + } + // end the string here + *writePtr++ = '\0'; + + const char *startPtr = _writePtr; + + // update end ptr + _readPtr = readPtr; + _writePtr = writePtr; + + // return pointer to unquoted string + return startPtr; +} + +bool JsonParser::parseStringTo(JsonVariant *destination) { + bool hasQuotes = isQuote(_readPtr[0]); + const char *value = parseString(); + if (value == NULL) return false; + if (hasQuotes) { + *destination = value; + } else { + *destination = Unparsed(value); + } + return true; +} diff --git a/src/third-party/arduino-json-5.1.1/src/Internals/List.cpp b/src/third-party/arduino-json-5.1.1/src/Internals/List.cpp new file mode 100644 index 00000000..c31a859f --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/Internals/List.cpp @@ -0,0 +1,50 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../../include/ArduinoJson/Internals/List.hpp" + +#include "../../include/ArduinoJson/JsonPair.hpp" +#include "../../include/ArduinoJson/JsonVariant.hpp" + +using namespace ArduinoJson; +using namespace ArduinoJson::Internals; + +template +size_t List::size() const { + size_t nodeCount = 0; + for (node_type *node = _firstNode; node; node = node->next) nodeCount++; + return nodeCount; +} + +template +typename List::node_type *List::addNewNode() { + node_type *newNode = new (_buffer) node_type(); + + if (_firstNode) { + node_type *lastNode = _firstNode; + while (lastNode->next) lastNode = lastNode->next; + lastNode->next = newNode; + } else { + _firstNode = newNode; + } + + return newNode; +} + +template +void List::removeNode(node_type *nodeToRemove) { + if (!nodeToRemove) return; + if (nodeToRemove == _firstNode) { + _firstNode = nodeToRemove->next; + } else { + for (node_type *node = _firstNode; node; node = node->next) + if (node->next == nodeToRemove) node->next = nodeToRemove->next; + } +} + +template class ArduinoJson::Internals::List; +template class ArduinoJson::Internals::List; diff --git a/src/third-party/arduino-json-5.1.1/src/Internals/Prettyfier.cpp b/src/third-party/arduino-json-5.1.1/src/Internals/Prettyfier.cpp new file mode 100644 index 00000000..79bfe763 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/Internals/Prettyfier.cpp @@ -0,0 +1,87 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../../include/ArduinoJson/Internals/Prettyfier.hpp" + +using namespace ArduinoJson::Internals; + +size_t Prettyfier::write(uint8_t c) { + size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c); + _previousChar = c; + return n; +} + +inline size_t Prettyfier::handleStringChar(uint8_t c) { + bool isQuote = c == '"' && _previousChar != '\\'; + + if (isQuote) _inString = false; + + return _sink.write(c); +} + +inline size_t Prettyfier::handleMarkupChar(uint8_t c) { + switch (c) { + case '{': + case '[': + return handleBlockOpen(c); + + case '}': + case ']': + return handleBlockClose(c); + + case ':': + return handleColon(); + + case ',': + return handleComma(); + + case '"': + return handleQuoteOpen(); + + default: + return handleNormalChar(c); + } +} + +inline size_t Prettyfier::handleBlockOpen(uint8_t c) { + return indentIfNeeded() + _sink.write(c); +} + +inline size_t Prettyfier::handleBlockClose(uint8_t c) { + return unindentIfNeeded() + _sink.write(c); +} + +inline size_t Prettyfier::handleColon() { + return _sink.write(':') + _sink.write(' '); +} + +inline size_t Prettyfier::handleComma() { + return _sink.write(',') + _sink.println(); +} + +inline size_t Prettyfier::handleQuoteOpen() { + _inString = true; + return indentIfNeeded() + _sink.write('"'); +} + +inline size_t Prettyfier::handleNormalChar(uint8_t c) { + return indentIfNeeded() + _sink.write(c); +} + +size_t Prettyfier::indentIfNeeded() { + if (!inEmptyBlock()) return 0; + + _sink.indent(); + return _sink.println(); +} + +size_t Prettyfier::unindentIfNeeded() { + if (inEmptyBlock()) return 0; + + _sink.unindent(); + return _sink.println(); +} diff --git a/src/third-party/arduino-json-5.1.1/src/Internals/StaticStringBuilder.cpp b/src/third-party/arduino-json-5.1.1/src/Internals/StaticStringBuilder.cpp new file mode 100644 index 00000000..4ac5d3f3 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/Internals/StaticStringBuilder.cpp @@ -0,0 +1,18 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../../include/ArduinoJson/Internals/StaticStringBuilder.hpp" + +using namespace ArduinoJson::Internals; + +size_t StaticStringBuilder::write(uint8_t c) { + if (length >= capacity) return 0; + + buffer[length++] = c; + buffer[length] = '\0'; + return 1; +} diff --git a/src/third-party/arduino-json-5.1.1/src/JsonArray.cpp b/src/third-party/arduino-json-5.1.1/src/JsonArray.cpp new file mode 100644 index 00000000..7d39ced0 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/JsonArray.cpp @@ -0,0 +1,40 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../include/ArduinoJson/JsonArray.hpp" + +#include "../include/ArduinoJson/JsonBuffer.hpp" +#include "../include/ArduinoJson/JsonObject.hpp" + +using namespace ArduinoJson; +using namespace ArduinoJson::Internals; + +JsonArray JsonArray::_invalid(NULL); + +JsonArray::node_type *JsonArray::getNodeAt(size_t index) const { + node_type *node = _firstNode; + while (node && index--) node = node->next; + return node; +} + +void JsonArray::removeAt(size_t index) { removeNode(getNodeAt(index)); } + +void JsonArray::writeTo(JsonWriter &writer) const { + writer.beginArray(); + + const node_type *child = _firstNode; + while (child) { + child->content.writeTo(writer); + + child = child->next; + if (!child) break; + + writer.writeComma(); + } + + writer.endArray(); +} diff --git a/src/third-party/arduino-json-5.1.1/src/JsonBuffer.cpp b/src/third-party/arduino-json-5.1.1/src/JsonBuffer.cpp new file mode 100644 index 00000000..f67ed2a4 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/JsonBuffer.cpp @@ -0,0 +1,42 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../include/ArduinoJson/JsonBuffer.hpp" + +#include "../include/ArduinoJson/Internals/JsonParser.hpp" +#include "../include/ArduinoJson/JsonArray.hpp" +#include "../include/ArduinoJson/JsonObject.hpp" + +using namespace ArduinoJson; +using namespace ArduinoJson::Internals; + +JsonArray &JsonBuffer::createArray() { + JsonArray *ptr = new (this) JsonArray(this); + return ptr ? *ptr : JsonArray::invalid(); +} + +JsonObject &JsonBuffer::createObject() { + JsonObject *ptr = new (this) JsonObject(this); + return ptr ? *ptr : JsonObject::invalid(); +} + +JsonArray &JsonBuffer::parseArray(char *json, uint8_t nestingLimit) { + JsonParser parser(this, json, nestingLimit); + return parser.parseArray(); +} + +JsonObject &JsonBuffer::parseObject(char *json, uint8_t nestingLimit) { + JsonParser parser(this, json, nestingLimit); + return parser.parseObject(); +} + +char *JsonBuffer::strdup(const char *source, size_t length) { + size_t size = length + 1; + char *dest = static_cast(alloc(size)); + if (dest != NULL) memcpy(dest, source, size); + return dest; +} diff --git a/src/third-party/arduino-json-5.1.1/src/JsonObject.cpp b/src/third-party/arduino-json-5.1.1/src/JsonObject.cpp new file mode 100644 index 00000000..a81772ca --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/JsonObject.cpp @@ -0,0 +1,44 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../include/ArduinoJson/JsonObject.hpp" + +#include // for strcmp + +#include "../include/ArduinoJson/Internals/StaticStringBuilder.hpp" +#include "../include/ArduinoJson/JsonArray.hpp" +#include "../include/ArduinoJson/JsonBuffer.hpp" + +using namespace ArduinoJson; +using namespace ArduinoJson::Internals; + +JsonObject JsonObject::_invalid(NULL); + +JsonObject::node_type *JsonObject::getNodeAt(const char *key) const { + for (node_type *node = _firstNode; node; node = node->next) { + if (!strcmp(node->content.key, key)) return node; + } + return NULL; +} + +void JsonObject::writeTo(JsonWriter &writer) const { + writer.beginObject(); + + const node_type *node = _firstNode; + while (node) { + writer.writeString(node->content.key); + writer.writeColon(); + node->content.value.writeTo(writer); + + node = node->next; + if (!node) break; + + writer.writeComma(); + } + + writer.endObject(); +} diff --git a/src/third-party/arduino-json-5.1.1/src/JsonVariant.cpp b/src/third-party/arduino-json-5.1.1/src/JsonVariant.cpp new file mode 100644 index 00000000..d2bee252 --- /dev/null +++ b/src/third-party/arduino-json-5.1.1/src/JsonVariant.cpp @@ -0,0 +1,110 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include "../include/ArduinoJson/JsonVariant.hpp" + +#include "../include/ArduinoJson/JsonArray.hpp" +#include "../include/ArduinoJson/JsonObject.hpp" + +#include // for errno +#include // for strtol, strtod + +using namespace ArduinoJson::Internals; + +namespace ArduinoJson { + +const char *JsonVariant::asString() const { + if (_type == JSON_UNPARSED && _content.asString && + !strcmp("null", _content.asString)) + return NULL; + if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString; + return NULL; +} + +JsonFloat JsonVariant::asFloat() const { + if (_type >= JSON_FLOAT_0_DECIMALS) return _content.asFloat; + + if (_type == JSON_INTEGER || _type == JSON_BOOLEAN) + return static_cast(_content.asInteger); + + if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) + return parse(_content.asString); + + return 0.0; +} + +String JsonVariant::toString() const { + String s; + if ((_type == JSON_STRING || _type == JSON_UNPARSED) && + _content.asString != NULL) + s = _content.asString; + else + printTo(s); + return s; +} + +template <> +bool JsonVariant::is() const { + if (_type == JSON_BOOLEAN) return true; + + if (_type != JSON_UNPARSED || _content.asString == NULL) return false; + + return !strcmp(_content.asString, "true") || + !strcmp(_content.asString, "false"); +} + +template <> +bool JsonVariant::is() const { + if (_type == JSON_INTEGER) return true; + + if (_type != JSON_UNPARSED || _content.asString == NULL) return false; + + char *end; + errno = 0; + strtol(_content.asString, &end, 10); + + return *end == '\0' && errno == 0; +} + +template <> +bool JsonVariant::is() const { + if (_type >= JSON_FLOAT_0_DECIMALS) return true; + + if (_type != JSON_UNPARSED || _content.asString == NULL) return false; + + char *end; + errno = 0; + strtod(_content.asString, &end); + + return *end == '\0' && errno == 0 && !is(); +} + +void JsonVariant::writeTo(JsonWriter &writer) const { + if (_type == JSON_ARRAY) + _content.asArray->writeTo(writer); + + else if (_type == JSON_OBJECT) + _content.asObject->writeTo(writer); + + else if (_type == JSON_STRING) + writer.writeString(_content.asString); + + else if (_type == JSON_UNPARSED) + writer.writeRaw(_content.asString); + + else if (_type == JSON_INTEGER) + writer.writeInteger(_content.asInteger); + + else if (_type == JSON_BOOLEAN) + writer.writeBoolean(_content.asInteger != 0); + + else if (_type >= JSON_FLOAT_0_DECIMALS) { + uint8_t decimals = static_cast(_type - JSON_FLOAT_0_DECIMALS); + writer.writeFloat(_content.asFloat, decimals); + } +} +} diff --git a/test/arduino-mock b/test/arduino-mock new file mode 160000 index 00000000..ff0f896a --- /dev/null +++ b/test/arduino-mock @@ -0,0 +1 @@ +Subproject commit ff0f896a815df02c08bcd7d99168cd3bcbf05b1a diff --git a/test/dummies/ESP8266HTTPClient.h b/test/dummies/ESP8266HTTPClient.h new file mode 100644 index 00000000..8533d9a6 --- /dev/null +++ b/test/dummies/ESP8266HTTPClient.h @@ -0,0 +1,2 @@ +// Need a placeholder for complilation for now. +class HTTPClient {}; diff --git a/test/dummies/FirebaseHttpClient_dummy.cpp b/test/dummies/FirebaseHttpClient_dummy.cpp new file mode 100644 index 00000000..e8a746e9 --- /dev/null +++ b/test/dummies/FirebaseHttpClient_dummy.cpp @@ -0,0 +1,53 @@ +#ifdef __GNUC__ +# define UNUSED_ARG(x) UNUSED_ ## x __attribute__((__unused__)) +#else +# define UNUSED_ARG(x) UNUSED_ ## x +#endif + +#include "FirebaseHttpClient.h" + +class FirebaseHttpClientDummy : public FirebaseHttpClient { + public: + void setReuseConnection(bool UNUSED_ARG(reuse)) override { + } + + void begin(const String& UNUSED_ARG(url)) override { + } + + void begin(const String& UNUSED_ARG(host), const String& UNUSED_ARG(path)) override { + } + + void end() override { + } + + void addHeader(const String& UNUSED_ARG(name), const String& UNUSED_ARG(value)) override { + } + + void collectHeaders(const char* UNUSED_ARG(header_keys[]), const int UNUSED_ARG(count)) override { + } + + String header(const String& UNUSED_ARG(name)) override { + return ""; + } + + int sendRequest(const String& UNUSED_ARG(method), const String& UNUSED_ARG(data)) override { + return 0; + } + + String getString() override { + return ""; + } + + Stream* getStreamPtr() override { + return nullptr; + } + + String errorToString(int UNUSED_ARG(error_code)) override { + return String(); + } +}; + +FirebaseHttpClient* FirebaseHttpClient::create() { + return new FirebaseHttpClientDummy(); +} + diff --git a/test/dummies/Stream.h b/test/dummies/Stream.h new file mode 100644 index 00000000..8c5f427e --- /dev/null +++ b/test/dummies/Stream.h @@ -0,0 +1,34 @@ +#ifndef TEST_DUMMIES_STREAM_H +#define TEST_DUMMIES_STREAM_H + +#include "Arduino.h" + +class Stream { + public: + int available() { + return 0; + } + String readStringUntil(const char term __attribute__((unused))) { + return String(); + } + int println(const String&) { + return 0; + } + int println(const char*) { + return 0; + } + int println(int) { + return 0; + } + int print(const char*) { + return 0; + } + char peek() { + return '\0'; + } + char read() { + return '\0'; + } +}; + +#endif // TEST_DUMMIES_STREAM_H diff --git a/test/googletest b/test/googletest new file mode 160000 index 00000000..ff07a5de --- /dev/null +++ b/test/googletest @@ -0,0 +1 @@ +Subproject commit ff07a5de0e81580547f1685e101194ed1a4fcd56 diff --git a/test/mock-firebase.h b/test/mock-firebase.h new file mode 100644 index 00000000..97274b4c --- /dev/null +++ b/test/mock-firebase.h @@ -0,0 +1,52 @@ +#ifndef TEST_MOCK_FIREBASE_H +#define TEST_MOCK_FIREBASE_H + +#include +#include "gtest/gtest.h" +#include "Firebase.h" + +namespace firebase { +namespace modem { + +class MockFirebase : public Firebase { + public: + MOCK_METHOD1(getPtr, std::unique_ptr(const String&)); + MOCK_METHOD2(setPtr, std::unique_ptr(const String&, const String&)); + MOCK_METHOD2(pushPtr, std::unique_ptr(const String&, const String&)); + MOCK_METHOD1(removePtr, std::unique_ptr(const String&)); + MOCK_METHOD1(streamPtr, std::unique_ptr(const String&)); +}; + +class MockFirebaseGet : public FirebaseGet { + public: + MOCK_CONST_METHOD0(json, const String&()); + MOCK_CONST_METHOD0(error, const FirebaseError&()); +}; + +class MockFirebaseSet : public FirebaseSet { + public: + MOCK_CONST_METHOD0(json, const String&()); + MOCK_CONST_METHOD0(error, const FirebaseError&()); +}; + +class MockFirebasePush : public FirebasePush { + public: + MOCK_CONST_METHOD0(name, const String&()); + MOCK_CONST_METHOD0(error, const FirebaseError&()); +}; + +class MockFirebaseRemove : public FirebaseRemove { + public: + MOCK_CONST_METHOD0(error, const FirebaseError&()); +}; + +class MockFirebaseStream : public FirebaseStream { + public: + MOCK_METHOD0(available, bool()); + MOCK_METHOD1(read, Event(String& event)); + MOCK_CONST_METHOD0(error, const FirebaseError&()); +}; + +} // modem +} // firebase +#endif // TEST_MOCK_FIREBASE_H diff --git a/test/modem/Makefile b/test/modem/Makefile new file mode 100644 index 00000000..260dd0b6 --- /dev/null +++ b/test/modem/Makefile @@ -0,0 +1,197 @@ +# A sample Makefile for building both Google Mock and Google Test and +# using them in user tests. This file is self-contained, so you don't +# need to use the Makefile in Google Test's source tree. Please tweak +# it to suit your environment and project. You may want to move it to +# your project's root directory. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make clean - removes all files generated by make. + +# Please tweak the following variable definitions as needed by your +# project, except GMOCK_HEADERS and GTEST_HEADERS, which you can use +# in your own targets but shouldn't modify. + +# Points to the root of Google Test, relative to where this file is. +# Remember to tweak this if you move this file, or if you want to use +# a copy of Google Test at a different location. +GTEST_DIR = ../googletest/googletest/ + +# Points to the root of Google Mock, relative to where this file is. +# Remember to tweak this if you move this file. +GMOCK_DIR = ../googletest/googlemock/ + +# Points to the root of Arduino mock, relative to where this file is. +# Remember to tweak this if you move this file. +ARDUINO_MOCK_DIR = ../arduino-mock/ + +# Where to find user code. +TEST_DIR = . + +PROJECT_ROOT = ../../ +SRC_ROOT = $(PROJECT_ROOT)/src + +# Flags passed to the preprocessor. +# Set Google Test and Google Mock's header directories as system +# directories, such that the compiler doesn't generate warnings in +# these headers. +CPPFLAGS += -isystem $(GTEST_DIR)/include -isystem $(GMOCK_DIR)/include \ + -I$(ARDUINO_MOCK_DIR)/include/arduino-mock/ \ + -I$(ARDUINO_MOCK_DIR)/include/ \ + -I$(PROJECT_ROOT)/test/dummies \ + -I$(PROJECT_ROOT)/src \ + -I$(PROJECT_ROOT) + +# Flags passed to the C++ compiler. +CXXFLAGS += -g -Wall -Wextra -pthread -std=c++11 + +# All tests produced by this Makefile. Remember to add new tests you +# created to the list. +TESTS = get-command_test set-command_test remove-command_test \ + push-command_test begin-command_test stream-command_test + +# All Google Test headers. Usually you shouldn't change this +# definition. +GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ + $(GTEST_DIR)/include/gtest/internal/*.h + +# All Google Mock headers. Note that all Google Test headers are +# included here too, as they are #included by Google Mock headers. +# Usually you shouldn't change this definition. +GMOCK_HEADERS = $(GMOCK_DIR)/include/gmock/*.h \ + $(GMOCK_DIR)/include/gmock/internal/*.h \ + $(GTEST_HEADERS) + +# Arduino Mock headers. +# Usually you shouldn't change this definition. +ARDUINO_MOCK_HEADERS = $(ARDUINO_MOCK_DIR)/include/arduino-mock/*.h + +# House-keeping build targets. + +all : $(TESTS) + +test : $(TESTS) + for t in $(TESTS); do ./$$t; done; + +clean : + rm -f $(TESTS) gmock.a gmock_main.a arduino_mock_all.a *.o + +# Builds gmock.a and gmock_main.a. These libraries contain both +# Google Mock and Google Test. A test should link with either gmock.a +# or gmock_main.a, depending on whether it defines its own main() +# function. It's fine if your test only uses features from Google +# Test (and not Google Mock). + +# Usually you shouldn't tweak such internal variables, indicated by a +# trailing _. +GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) +GMOCK_SRCS_ = $(GMOCK_DIR)/src/*.cc $(GMOCK_HEADERS) +ARDUINO_MOCK_SRCS_ = $(ARDUINO_MOCK_DIR)/src/*.cc $(ARDUINO_MOCK_HEADERS) + +# For simplicity and to avoid depending on implementation details of +# Google Mock and Google Test, the dependencies specified below are +# conservative and not optimized. This is fine as Google Mock and +# Google Test compile fast and for ordinary users their source rarely +# changes. +gtest-all.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \ + -c $(GTEST_DIR)/src/gtest-all.cc + +gmock-all.o : $(GMOCK_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \ + -c $(GMOCK_DIR)/src/gmock-all.cc + +gmock_main.o : $(GMOCK_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \ + -c $(GMOCK_DIR)/src/gmock_main.cc + +gmock.a : gmock-all.o gtest-all.o + $(AR) $(ARFLAGS) $@ $^ + +gmock_main.a : gmock-all.o gtest-all.o gmock_main.o + $(AR) $(ARFLAGS) $@ $^ + + +# Builds Arduino mocks. +ArduinoMockAll.o : $(ARDUINO_MOCK_SRCS_) + $(CXX) $(CPPFLAGS) -I$(ARDUINO_MOCK_DIR) $(CXXFLAGS) -c \ + $(ARDUINO_MOCK_DIR)/src/ArduinoMockAll.cc + +arduino_mock_all.a : ArduinoMockAll.o + $(AR) $(ARFLAGS) $@ $^ + +# Builds shared objects. + +Firebase.o : $(SRC_ROOT)/Firebase.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_ROOT)/Firebase.cpp + +FirebaseHttpClient_dummy.o : $(PROJECT_ROOT)/test/dummies/FirebaseHttpClient_dummy.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(PROJECT_ROOT)/test/dummies/FirebaseHttpClient_dummy.cpp + +# Builds tests. + +get-command.o : $(SRC_ROOT)/modem/get-command.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_ROOT)/modem/get-command.cpp + +get-command_test.o : $(TEST_DIR)/get-command_test.cpp $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(TEST_DIR)/get-command_test.cpp + +get-command_test : get-command_test.o Firebase.o FirebaseHttpClient_dummy.o get-command.o gmock_main.a \ + arduino_mock_all.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + + +set-command.o : $(SRC_ROOT)/modem/set-command.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_ROOT)/modem/set-command.cpp + +set-command_test.o : $(TEST_DIR)/set-command_test.cpp $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(TEST_DIR)/set-command_test.cpp + +set-command_test : set-command.o set-command_test.o Firebase.o FirebaseHttpClient_dummy.o gmock_main.a \ + arduino_mock_all.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + + +remove-command.o : $(SRC_ROOT)/modem/remove-command.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_ROOT)/modem/remove-command.cpp + +remove-command_test.o : $(TEST_DIR)/remove-command_test.cpp $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(TEST_DIR)/remove-command_test.cpp + +remove-command_test : remove-command.o remove-command_test.o Firebase.o FirebaseHttpClient_dummy.o gmock_main.a \ + arduino_mock_all.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + + +push-command.o : $(SRC_ROOT)/modem/push-command.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_ROOT)/modem/push-command.cpp + +push-command_test.o : $(TEST_DIR)/push-command_test.cpp $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(TEST_DIR)/push-command_test.cpp + +push-command_test : push-command.o push-command_test.o Firebase.o FirebaseHttpClient_dummy.o gmock_main.a \ + arduino_mock_all.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +begin-command.o : $(SRC_ROOT)/modem/begin-command.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_ROOT)/modem/begin-command.cpp + +begin-command_test.o : $(TEST_DIR)/begin-command_test.cpp $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(TEST_DIR)/begin-command_test.cpp + +begin-command_test : begin-command.o begin-command_test.o Firebase.o FirebaseHttpClient_dummy.o gmock_main.a \ + arduino_mock_all.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +stream-command.o : $(SRC_ROOT)/modem/stream-command.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_ROOT)/modem/stream-command.cpp + +stream-command_test.o : $(TEST_DIR)/stream-command_test.cpp $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(TEST_DIR)/stream-command_test.cpp + +stream-command_test : stream-command.o stream-command_test.o Firebase.o FirebaseHttpClient_dummy.o gmock_main.a \ + arduino_mock_all.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + diff --git a/test/modem/begin-command_test.cpp b/test/modem/begin-command_test.cpp new file mode 100644 index 00000000..804b699f --- /dev/null +++ b/test/modem/begin-command_test.cpp @@ -0,0 +1,84 @@ +#include "Firebase.h" +#include "gtest/gtest.h" +#include "modem/commands.h" +#include "test/modem/mock-input-stream.h" +#include "test/modem/mock-output-stream.h" +#include "test/mock-firebase.h" + +namespace firebase { +namespace modem { + +using ::testing::Return; +using ::testing::ByMove; +using ::testing::ReturnRef; +using ::testing::StartsWith; +using ::testing::Matcher; +using ::testing::_; + +class BeginCommandTest : public ::testing::Test { + protected: + void FeedCommand(const String& host, const String& auth = "") { + String command_fragment(host); + if (!auth.empty()) { + command_fragment += String(" ") + auth; + } + + EXPECT_CALL(in_, readLine()) + .WillOnce(Return(command_fragment)); + } + + void ExpectOutput(const String& output) { + EXPECT_CALL(out_, println(output)) + .WillOnce(Return(3)); + } + + void ExpectOutputStartsWith(const String& output) { + // We have to be explicit here due to the polymorphic nature of println(). + const Matcher matcher = StartsWith(output); + EXPECT_CALL(out_, println(matcher)) + .WillOnce(Return(3)); + } + + MockInputStream in_; + MockOutputStream out_; +}; + +TEST_F(BeginCommandTest, hostOnly) { + const String host("http://test.firebase.com"); + + FeedCommand(host); + ExpectOutput("+OK"); + + BeginCommand command; + ASSERT_TRUE(command.execute("BEGIN", &in_, &out_)); + + std::unique_ptr firebase(command.firebase()); + EXPECT_EQ("", firebase->auth()); +} + +TEST_F(BeginCommandTest, hostAndAuth) { + const String host("http://test.firebase.com"); + const String auth("afasdfsadfasdssfadsfsd"); + + FeedCommand(host, auth); + ExpectOutput("+OK"); + + BeginCommand command; + ASSERT_TRUE(command.execute("BEGIN", &in_, &out_)); + + std::unique_ptr firebase(command.firebase()); + EXPECT_EQ(auth, firebase->auth()); +} + +TEST_F(BeginCommandTest, neitherHostNorAuth) { + FeedCommand(""); + ExpectOutputStartsWith("-FAIL"); + + BeginCommand command; + ASSERT_FALSE(command.execute("BEGIN", &in_, &out_)); + + std::unique_ptr firebase(command.firebase()); + EXPECT_FALSE(firebase); +} +} // modem +} // firebase diff --git a/test/modem/get-command_test.cpp b/test/modem/get-command_test.cpp new file mode 100644 index 00000000..d3494935 --- /dev/null +++ b/test/modem/get-command_test.cpp @@ -0,0 +1,77 @@ +#include "Firebase.h" +#include "gtest/gtest.h" +#include "modem/commands.h" +#include "test/modem/mock-input-stream.h" +#include "test/modem/mock-output-stream.h" +#include "test/mock-firebase.h" + +namespace firebase { +namespace modem { + +using ::testing::Return; +using ::testing::ByMove; +using ::testing::ReturnRef; +using ::testing::_; + +class GetCommandTest : public ::testing::Test { + protected: + void SetUp() override { + get_.reset(new MockFirebaseGet()); + } + + void FeedCommand(const String& path) { + const String command_fragment(String(" ") + path); + EXPECT_CALL(in_, readLine()) + .WillOnce(Return(command_fragment)); + } + + bool RunCommand(const FirebaseError& error) { + EXPECT_CALL(*get_, error()) + .WillRepeatedly(ReturnRef(error)); + + EXPECT_CALL(fbase_, getPtr(_)) + .WillOnce(Return(ByMove(std::move(get_)))); + + GetCommand getCmd(&fbase_); + return getCmd.execute("GET", &in_, &out_); + } + + MockInputStream in_; + MockOutputStream out_; + MockFirebase fbase_; + std::unique_ptr get_; +}; + +TEST_F(GetCommandTest, gets) { + const String path("/test/path"); + FeedCommand(path); + + const String value("Test value"); + EXPECT_CALL(*get_, json()) + .WillOnce(ReturnRef(value)); + + EXPECT_CALL(out_, print(String("+"))) + .WillOnce(Return(1)); + + EXPECT_CALL(out_, println(value)) + .WillOnce(Return(1)); + + ASSERT_TRUE(RunCommand(FirebaseError())); +} + +TEST_F(GetCommandTest, handlesError) { + FirebaseError error(-200, "Test Error."); + const String path("/test/path"); + FeedCommand(path); + + EXPECT_CALL(out_, print(String("-FAIL "))) + .WillOnce(Return(1)); + + EXPECT_CALL(out_, println(error.message())) + .WillOnce(Return(1)); + ASSERT_FALSE(RunCommand(error)); + +} + +} // modem +} // firebase diff --git a/test/modem/mock-input-stream.h b/test/modem/mock-input-stream.h new file mode 100644 index 00000000..d0f7e9ae --- /dev/null +++ b/test/modem/mock-input-stream.h @@ -0,0 +1,21 @@ +#ifndef MODEM_TEST_MOCK_INPUT_STREAM_H +#define MODEM_TEST_MOCK_INPUT_STREAM_H + +#include "gtest/gtest.h" +#include "modem/input-stream.h" + +namespace firebase { +namespace modem { + +class MockInputStream : public InputStream { + public: + MOCK_METHOD0(readLine, String ()); + MOCK_METHOD1(readStringUntil, String (const char)); + MOCK_METHOD0(drain, void ()); + MOCK_METHOD0(available, bool ()); +}; + +} // modem +} // firebase + +#endif //MODEM_TEST_MOCK_INPUT_STREAM_H diff --git a/test/modem/mock-output-stream.h b/test/modem/mock-output-stream.h new file mode 100644 index 00000000..ef15fadf --- /dev/null +++ b/test/modem/mock-output-stream.h @@ -0,0 +1,21 @@ +#ifndef MODEM_TEST_MOCK_OUTPUT_STREAM_H +#define MODEM_TEST_MOCK_OUTPUT_STREAM_H + +#include "gtest/gtest.h" +#include "modem/output-stream.h" + +namespace firebase { +namespace modem { + +class MockOutputStream : public OutputStream { + public: + MOCK_METHOD1(println, int (const String&)); + MOCK_METHOD1(println, int (const int)); + MOCK_METHOD1(print, int (const String&)); +}; + +} // modem +} // firebase + +#endif //MODEM_TEST_MOCK_OUTPUT_STREAM_H + diff --git a/test/modem/push-command_test.cpp b/test/modem/push-command_test.cpp new file mode 100644 index 00000000..7e4d17bc --- /dev/null +++ b/test/modem/push-command_test.cpp @@ -0,0 +1,83 @@ +#include "Firebase.h" +#include "gtest/gtest.h" +#include "modem/commands.h" +#include "modem/json_util.h" +#include "test/modem/mock-input-stream.h" +#include "test/modem/mock-output-stream.h" +#include "test/mock-firebase.h" + +namespace firebase { +namespace modem { + +using ::testing::Return; +using ::testing::ByMove; +using ::testing::ReturnRef; +using ::testing::_; + +class PushCommandTest : public ::testing::Test { + protected: + void SetUp() override { + push_.reset(new MockFirebasePush()); + } + + void FeedCommand(const String& path, const String& data) { + const String data_fragment(data); + EXPECT_CALL(in_, readStringUntil(' ')) + .WillOnce(Return(path)); + EXPECT_CALL(in_, readLine()) + .WillOnce(Return(data_fragment)); + } + + void ExpectOutput(const String& output) { + EXPECT_CALL(out_, println(output)) + .WillOnce(Return(output.length())); + } + + void ExpectErrorOutput(const String& error_message) { + EXPECT_CALL(out_, print(String("-FAIL "))) + .WillOnce(Return(5)); + EXPECT_CALL(out_, println(error_message)) + .WillOnce(Return(error_message.length())); + } + + bool RunExpectingData(const String& data, const FirebaseError& error) { + EXPECT_CALL(*push_, error()) + .WillRepeatedly(ReturnRef(error)); + + EXPECT_CALL(fbase_, pushPtr(_, EncodeForJson(data))) + .WillOnce(Return(ByMove(std::move(push_)))); + + PushCommand pushCmd(&fbase_); + return pushCmd.execute("PUSH", &in_, &out_); + } + + MockInputStream in_; + MockOutputStream out_; + MockFirebase fbase_; + std::unique_ptr push_; +}; + +TEST_F(PushCommandTest, sendsData) { + const String path("/test/path"); + const String data("This is a test payload."); + + FeedCommand(path, data); + ExpectOutput("+OK"); + + ASSERT_TRUE(RunExpectingData(data, FirebaseError())); +} + +TEST_F(PushCommandTest, HandlesError) { + const String path("/test/path"); + const String data("This is a test payload."); + FirebaseError error(-200, "Test error."); + + FeedCommand(path, data); + ExpectErrorOutput(error.message()); + + ASSERT_FALSE(RunExpectingData(data, error)); +} + +} // modem +} // firebase + diff --git a/test/modem/remove-command_test.cpp b/test/modem/remove-command_test.cpp new file mode 100644 index 00000000..5c361e7e --- /dev/null +++ b/test/modem/remove-command_test.cpp @@ -0,0 +1,69 @@ +#include "gtest/gtest.h" +#include "test/modem/mock-output-stream.h" +#include "test/modem/mock-input-stream.h" +#include "test/mock-firebase.h" +#include "Firebase.h" +#include "modem/commands.h" + +namespace firebase { +namespace modem { + +using ::testing::Return; +using ::testing::ByMove; +using ::testing::ReturnRef; +using ::testing::_; + +class RemoveCommandTest : public ::testing::Test { + protected: + void SetUp() override { + remove_.reset(new MockFirebaseRemove()); + } + + void FeedCommand(const String& path) { + const String command_fragment(String(" ") + path); + EXPECT_CALL(in_, readLine()) + .WillOnce(Return(command_fragment)); + } + + bool RunCommand(const FirebaseError& error) { + EXPECT_CALL(*remove_, error()) + .WillRepeatedly(ReturnRef(error)); + + EXPECT_CALL(fbase_, removePtr(_)) + .WillOnce(Return(ByMove(std::move(remove_)))); + + RemoveCommand command(&fbase_); + return command.execute("REMOVE", &in_, &out_); + } + + MockInputStream in_; + MockOutputStream out_; + MockFirebase fbase_; + std::unique_ptr remove_; +}; + +TEST_F(RemoveCommandTest, success) { + const String path("/test/path"); + FeedCommand(path); + + EXPECT_CALL(out_, println(String("+OK"))) + .WillOnce(Return(3)); + + ASSERT_TRUE(RunCommand(FirebaseError())); +} + +TEST_F(RemoveCommandTest, handlesError) { + FirebaseError error(-200, "Test Error."); + const String path("/test/path"); + FeedCommand(path); + + EXPECT_CALL(out_, print(String("-FAIL "))) + .WillOnce(Return(1)); + + EXPECT_CALL(out_, println(error.message())) + .WillOnce(Return(1)); + ASSERT_FALSE(RunCommand(error)); +} + +} // modem +} // firebase diff --git a/test/modem/set-command_test.cpp b/test/modem/set-command_test.cpp new file mode 100644 index 00000000..729a85d7 --- /dev/null +++ b/test/modem/set-command_test.cpp @@ -0,0 +1,81 @@ +#include "Firebase.h" +#include "gtest/gtest.h" +#include "modem/commands.h" +#include "modem/json_util.h" +#include "test/modem/mock-input-stream.h" +#include "test/modem/mock-output-stream.h" +#include "test/mock-firebase.h" + +namespace firebase { +namespace modem { + +using ::testing::Return; +using ::testing::ByMove; +using ::testing::ReturnRef; +using ::testing::_; + +class SetCommandTest : public ::testing::Test { + protected: + void SetUp() override { + set_.reset(new MockFirebaseSet()); + } + + void FeedCommand(const String& path, const String& data) { + const String data_fragment(data); + EXPECT_CALL(in_, readStringUntil(' ')) + .WillOnce(Return(path)); + EXPECT_CALL(in_, readLine()) + .WillOnce(Return(data_fragment)); + } + + void ExpectOutput(const String& output) { + EXPECT_CALL(out_, println(output)) + .WillOnce(Return(3)); + } + + void ExpectErrorOutput(const String& error_message) { + EXPECT_CALL(out_, print(String("-FAIL "))) + .WillOnce(Return(5)); + EXPECT_CALL(out_, println(error_message)) + .WillOnce(Return(error_message.length())); + } + + bool RunExpectingData(const String& data, const FirebaseError& error) { + EXPECT_CALL(*set_, error()) + .WillRepeatedly(ReturnRef(error)); + + EXPECT_CALL(fbase_, setPtr(_, EncodeForJson(data))) + .WillOnce(Return(ByMove(std::move(set_)))); + + SetCommand setCmd(&fbase_); + return setCmd.execute("SET", &in_, &out_); + } + + MockInputStream in_; + MockOutputStream out_; + MockFirebase fbase_; + std::unique_ptr set_; +}; + +TEST_F(SetCommandTest, sendsData) { + const String path("/test/path"); + const String data("This is a test payload."); + + FeedCommand(path, data); + ExpectOutput("+OK"); + + ASSERT_TRUE(RunExpectingData(data, FirebaseError())); +} + +TEST_F(SetCommandTest, HandlesError) { + const String path("/test/path"); + const String data("This is a test payload."); + FirebaseError error(-200, "Test error."); + + FeedCommand(path, data); + ExpectErrorOutput(error.message()); + + ASSERT_FALSE(RunExpectingData(data, error)); +} +} // modem +} // firebase diff --git a/test/modem/stream-command_test.cpp b/test/modem/stream-command_test.cpp new file mode 100644 index 00000000..4cfc17be --- /dev/null +++ b/test/modem/stream-command_test.cpp @@ -0,0 +1,93 @@ +#include "Firebase.h" +#include "gtest/gtest.h" +#include "modem/commands.h" +#include "test/modem/mock-input-stream.h" +#include "test/modem/mock-output-stream.h" +#include "test/mock-firebase.h" + +namespace firebase { +namespace modem { + +using ::testing::Return; +using ::testing::Invoke; +using ::testing::ByMove; +using ::testing::ReturnRef; +using ::testing::_; + +class StreamCommandTest : public ::testing::Test { + protected: + void SetUp() override { + stream_.reset(new MockFirebaseStream()); + } + + bool RunCommand(const FirebaseError& error) { + EXPECT_CALL(*stream_, error()) + .WillRepeatedly(ReturnRef(error)); + + EXPECT_CALL(fbase_, streamPtr(_)) + .WillOnce(Return(ByMove(std::move(stream_)))); + + StreamCommand cmd(&fbase_); + return cmd.execute("BEGIN_STREAM", &in_, &out_); + } + + MockInputStream in_; + MockOutputStream out_; + MockFirebase fbase_; + std::unique_ptr stream_; +}; + +TEST_F(StreamCommandTest, streams) { + const String path("/test/path"); + EXPECT_CALL(in_, available()) + .WillRepeatedly(Return(true)); + + EXPECT_CALL(in_, readLine()) + .WillOnce(Return(path)) + .WillOnce(Return("END_STREAM")); + + const String value("Test value"); + EXPECT_CALL(*stream_, available()) + .WillOnce(Return(true)) + .WillRepeatedly(Return(false)); + + EXPECT_CALL(*stream_, read(_)) + .WillOnce(Invoke([&value](String& json) { + json = value; + return FirebaseStream::PUT; + })); + + EXPECT_CALL(out_, print(String("+"))) + .WillOnce(Return(1)); + EXPECT_CALL(out_, print(String("PUT "))) + .WillOnce(Return(1)); + EXPECT_CALL(out_, println(String("/dummy/path"))) + .WillOnce(Return(1)); + + EXPECT_CALL(out_, println(value.length())) + .WillOnce(Return(1)); + EXPECT_CALL(out_, println(value)) + .WillOnce(Return(1)); + + EXPECT_CALL(out_, println(String("+OK"))) + .WillOnce(Return(1)); + + ASSERT_TRUE(RunCommand(FirebaseError())); +} + +TEST_F(StreamCommandTest, handlesError) { + FirebaseError error(-200, "Test Error."); + const String path("/test/path"); + EXPECT_CALL(in_, readLine()) + .WillOnce(Return(path)); + + EXPECT_CALL(out_, print(String("-FAIL "))) + .WillOnce(Return(1)); + + EXPECT_CALL(out_, println(error.message())) + .WillOnce(Return(1)); + ASSERT_FALSE(RunCommand(error)); +} + +} // modem +} // firebase