All Articles

JSON with Quectel OpenCPU

My friend wrote this post in Russian and I couldn’t find any information about it, so I want to translate it for you.

When anybody talks about JSON, we remind about it’s usage in Web programming, client – server and server – server data transmission. However, we can use this form of data in embedded devices. I want to show my experience in usage JSON in programming of Quectel modules with OpenCPU.

First of all, a small quote from Wikipedia about JSON:

In computing, JavaScript Object Notation (JSON) (/ˈdʒeɪsən/ “jay-son”, /dʒeɪˈsɒn/) is an open-standard file format that uses human-readable text to transmit data objects consisting of attribute–value pairs and array data types (or any other serializable value). It is a very common data format used for asynchronous browser–server communication, including as a replacement for XML in some AJAX-style systems.

OpenCPU is written in C so we cannot use different C++ libraries with JSON dependencies. Moreover, the resources are limited, because it is not a personal computer :). For instance, in Quectel M66 we have 360 kB Flash and 100kB RAM.

Speaking of which, OpenCPU is not so user-friendly, and while using it, you can often face with questions, which were never discussed. The library is replete with binaries and it’s sometimes hard to understand how function works. However, we have no other choice, so we need to use what we have.

Based on the above, I was trying to find a code to use JSON according to this criteria:

  1. It should have no dependencies;
  2. It must be written in C;
  3. It must be useful for my needs;
  4. It should have ability to form JSON objects and serialize them.

I found JFES – JSON For Embedded Systems. Documentation of the project is written it README of the repo. I hope you read it, so let’s move to the usage of it with OpenCPU.

In order to start working with JFES you need to copy files jfes.c and jfes.h to the /custom folder of OpenCPU project and include header file in main.c :

    #include "jfes.h"

Then you need to initialize jfes_config_t object:

    jfes_config_t config;

JFES doesn’t support automatic memory allocation, so you need to use memory allocating functions by OpenCPU:

    config.jfes_malloc = Ql_MEM_Alloc;
    config.jfes_free = Ql_MEM_Free;

After the end of initializing we can parse JSON. Let’s try a sample to form the JSON to send it by GPRS:

    {
        "id": 12345,
        "imei": "759304218643261",
        "status": true
    }

The piece of code will look like this:

    jfes_value_t data;
    jfes_value_t * value = jfes_create_object_value ( &config );
    jfes_set_object_property ( &config, value, jfes_create_integer_value ( &config, 12345 ), "id", 0 );
    jfes_set_object_property ( &config, value, jfes_create_string_value ( &config, "759304218643261", 0 ), "imei", 0 );
    jfes_set_object_property ( &config, value, jfes_create_boolean_value ( &config, true ), "status", 0 );
    jfes_set_object_property ( &config, &data, jfes_create_null_value ( &config ), "null_property", 0 );

When you create string-type object you need to send the length of the string (or 0 if string is ended by null symbol) as the last parameter.

Then we are serializing the object to the string before sending. The length of the string will be stored in dump_size variable:

    char beauty_dump[1024];
    jfes_size_t dump_size = 1024;
    jfes_value_to_string ( &data, &beauty_dump[0], &dump_size, 1 );

If you send 1 instead of 0 as the last parameter, then created string will be without spaces, tabs, carries etc. (ugly JSON).

The produced string won’t be null-terminated, so null must be added to the end:

    beauty_dump[dump_size] = '\0';

The produced JSON can be outputted to the debugging interface:

    APP_DEBUG ( "[ JSON ] %s \r\n",  &beauty_dump[0] );

That is what I wanted to tell you about. I hope this information was useful for you…