Răsfoiți Sursa

Writing documentation...

Benoit Blanchon 11 ani în urmă
părinte
comite
6eef52cc9c
4 a modificat fișierele cu 194 adăugiri și 44 ștergeri
  1. 1 44
      doc/Generating JSON.md
  2. 0 0
      doc/Installing for Arduino.md
  3. 51 0
      doc/Memory model.md
  4. 142 0
      doc/Parsing JSON.md

+ 1 - 44
doc/Generating JSON.md

@@ -28,52 +28,9 @@ Here is an example to generate `{"sensor":"gps","time":1351824120,"data":[48.756
 
 ## Step 1: Reserve memory space
 
-#### Introducing `StaticJsonBuffer`
-
 Arduino JSON uses a preallocated memory pool to store the object tree, this is done by the `StaticJsonBuffer`.
 
-Before using any function of the library you need to create a `StaticJsonBuffer`. Then you can use this instance to create arrays and objects, or parse a JSON string.
-
-`StaticJsonBuffer` has a template parameter that determines the number of bytes that it contains. For example, the following line create a `StaticJsonBuffer` containing 200 bytes on the stack:
-
-    StaticJsonBuffer<200> jsonBuffer;
-
-The bigger the buffer is, the more complex the object tree can be, but also the more memory you need.
-
-#### How to determine the buffer size?
-
-So the big question you should have in mind right now is *How can I determine the size?*. 
-
-There are basically two approaches here:
-
-1. either you can predict the content of the object tree,
-2. or, you know how much memory is available.
-
-In the first case, you know some constraints on the object tree. For instance, let's say that your know in advance (and by that I mean "at compilation time") that you want to generate an object with 3 values, one of them being an array with 2 values, like the following:
-
-    {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
-
-To determine the memory usage of this object tree, you use the two macros `JSON_ARRAY_SIZE(n)` `JSON_OBJECT_SIZE(n)`, both take the number of elements as a parameter.
-For the example above, it would be:
-
-    const int BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2);
-    StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
-
-In the second case, let's say you dynamically generate a JSON object tree of a random complexity so you can't put a limit base on that. But on the other hand, you don't want your program to crash because the object tree doesn't fit in memory.
-The solution here is to determine how much memory is available, or in other words how much memory you can afford for the JSON generation.
-
-#### Why choosing fixed allocation?
-
-This fixed allocation approach may seem a bit strange, especially if your a desktop app developer used to dynamic allocation, but it make a lot of sense in an embedded context:
-
-1. the code is smaller
-2. it uses less memory
-3. it doesn't create memory fragmentation
-4. it predictable
-
-Don't forget that, the memory is "freed" as soon as the `StaticJsonBuffer` is out of scope, like any other variable. It only hold the memory for a short amount of time.
-
-For that reason, you should never use a `StaticJsonBuffer` as a **global variable** because it would hold a lot of memory for the whole life of the program.
+Before continuing please read the page [Arduino JSON memory model](Memory model.md) that explains everything you need to know about `StaticJsonBuffer`.
 
 ## Step 2: Build object tree in memory
 

+ 0 - 0
doc/Installing for Arduino.md


+ 51 - 0
doc/Memory model.md

@@ -0,0 +1,51 @@
+Arduino JSON memory model
+=========================
+
+## Fixed memory allocation
+
+### Introducing `StaticJsonBuffer`
+
+Arduino JSON uses a preallocated memory pool to store the object tree, this is done by the `StaticJsonBuffer`.
+
+Before using any function of the library you need to create a `StaticJsonBuffer`. Then you can use this instance to create arrays and objects, or parse a JSON string.
+
+`StaticJsonBuffer` has a template parameter that determines the number of bytes that it contains. For example, the following line create a `StaticJsonBuffer` containing 200 bytes on the stack:
+
+    StaticJsonBuffer<200> jsonBuffer;
+
+The bigger the buffer is, the more complex the object tree can be, but also the more memory you need.
+
+### How to determine the buffer size?
+
+So the big question you should have in mind right now is *How can I determine the size?*. 
+
+There are basically two approaches here:
+
+1. either you can predict the content of the object tree,
+2. or, you know how much memory is available.
+
+In the first case, you know some constraints on the object tree. For instance, let's say that your know in advance (and by that I mean "at compilation time") that you want to generate an object with 3 values, one of them being an array with 2 values, like the following:
+
+    {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
+
+To determine the memory usage of this object tree, you use the two macros `JSON_ARRAY_SIZE(n)` `JSON_OBJECT_SIZE(n)`, both take the number of elements as a parameter.
+For the example above, it would be:
+
+    const int BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2);
+    StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
+
+In the second case, let's say you dynamically generate a JSON object tree of a random complexity so you can't put a limit base on that. But on the other hand, you don't want your program to crash because the object tree doesn't fit in memory.
+The solution here is to determine how much memory is available, or in other words how much memory you can afford for the JSON generation.
+
+### Why choosing fixed allocation?
+
+This fixed allocation approach may seem a bit strange, especially if your a desktop app developer used to dynamic allocation, but it make a lot of sense in an embedded context:
+
+1. the code is smaller
+2. it uses less memory
+3. it doesn't create memory fragmentation
+4. it predictable
+
+Don't forget that, the memory is "freed" as soon as the `StaticJsonBuffer` is out of scope, like any other variable. It only hold the memory for a short amount of time.
+
+For that reason, you should never use a `StaticJsonBuffer` as a **global variable** because it would hold a lot of memory for the whole life of the program.

+ 142 - 0
doc/Parsing JSON.md

@@ -0,0 +1,142 @@
+Parsing JSON with Arduino JSON
+==============================
+
+## Example
+
+Here an example that parse the string `{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}`:
+
+    char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
+    
+    //
+    // Step 1: Reserve memory space
+    //
+    StaticJsonBuffer<200> jsonBuffer;
+    
+    //
+    // Step 2: Deserialize the JSON string
+    //
+    JsonObject& root = jsonBuffer.parseObject(json);
+
+    if (!root.success()) 
+    {
+      Serial.println("parseObject() failed");
+      return;
+    }
+
+    //
+    // Step 3: Retrieve the values
+    //
+    const char* sensor    = root["sensor"];
+    long        time      = root["time"];
+    double      latitude  = root["data"][0];
+    double      longitude = root["data"][1];
+
+## Step 1: Reserve memory space
+
+Arduino JSON uses a preallocated memory pool to store the object tree, this is done by the `StaticJsonBuffer`.
+
+Before continuing please read the page [Arduino JSON memory model](Memory model.md) that explains everything you need to know about `StaticJsonBuffer`.
+
+## Step 2: Parse the JSON string
+
+You call the JSON parser through the instance of `StaticJsonBuffer`.
+It exposes two function for parsing JSON:
+
+1. parseArray() that returns a reference to a `JsonArray`
+2. parseObject() that returns a reference to a `JsonObject`
+
+Let's see an example.
+Say we want to parse `{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}`, it's an object so we call `parseObject` as follows:
+
+    char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
+
+    JsonObject& root = jsonBuffer.parseObject(json);
+
+As you can see `parseObject()` takes a `char*` as a parameter.
+Be careful, it's not a `const char*`, the memory must be writable.
+Indeed, the parser will modify the string in two cases:
+
+1. to insert string endings (character `\0`),
+2. to translate escaped characters (like `\n` or `\t`).
+
+Another thing that you must keep in mind is that the string (`char json[]` in the example above) must stay in memory during the whole parsing process.
+That is because the in memory object tree will store pointer to chunks of the string, so as to avoid any memory duplication. 
+
+Now, to check if the parsing was successful, you can call `JsonObject::success()`:
+
+    if (!root.success())
+    {
+        // Parsing fail
+    }
+
+The result can be `false` for tree reasons:
+
+1. the JSON string is invalid,
+2. the JSON string doesn't represent an object,
+3. the `StaticJsonBuffer` is too small.
+
+We just saw how to parse an object, there is nothing more to say for arrays, the procedure is exactly the same.
+
+## Step 3: Retrieve the values
+
+Now that the object or array is in memory, you can extract the data very easily.
+
+In this section, we'll see how to do it with a `JsonObject`.
+Once again, there is nothing more to say about arrays, `JsonArray` works exactly the same as `JsonObject`.
+
+#### Subscript operator
+
+The simplest way is to use the subscript operator of `JsonObject`:
+    
+    const char* sensor = root["sensor"];
+    long time = root["time"];
+ 
+You can chain the subscript operator if you have nested arrays or objects:
+
+    double latitude  = root["data"][0];
+    double longitude = root["data"][1];
+
+But alternatively, you can get a reference to the nested array:
+
+    JsonArray& nestedArray = root["data"];
+
+#### Casting values
+
+In the previous examples, the values were implicitly casted to the target type.
+You can also do this explicitly
+
+    const char* sensor = root["sensor"].asString();
+    long time = root["time"].as<long>();
+    JsonArray& nestedArray = root["data"].asArray();
+
+If the actual value doesn't match the target type, a default value will be return:
+
+1. `false` for boolean values
+2. `0` for integer values
+3. `NULL` for string values
+4. `JsonArray::invalid()` for nested arrays
+5. `JsonObject::invalid()` for nested object
+
+#### Check values
+
+If you want to know if some value is present, call `containsKey()`:
+
+    if (root.contains("extra")) 
+    {
+        // root["extra"] is valid
+    }
+
+If you want to check the type value has a certain type, call `is<T>()`:
+
+    if (root["extra"].is<JsonArray&>()) 
+    {
+        // root["extra"] is an array
+    }
+
+You can also iterate through the key-value pairs of the object:
+
+    for (JsonObject::itertor it=root.begin(); it!=root.end(); ++it)
+    {
+      Serial.println(it->key);
+      Serial.println(i->value.asString());
+    }