mqttstm32stm32cubeidelwipcjson

Converting u8_t to JSON and manipulate data, in C


I am using LwIP library in order to create an MQTT connection with a broker. The client, which I am programming is connected to the broker successfully and I can read messages also. Nonetheless, when I am trying to send a JSON message with the MQTT-Explorer I can't read it. Let me explain a little bit more. I have a callback function which is named as static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags). The data from MQTT-Explorer is stored into the variable *const u8_t data and I converting it into a proper char *json_data value in order to manipulate it in another function, which takes the json_data and parsing it with the cJSON library. The issue here is that the json = cJSON_Parse(json_string); returns NULL. I think that the problem is the way I am converting it to char. I am writing the program to the STM32CubeIDE 1.13.2. Let me know if you can figure out what is the problem with the NULL return in cJSON_Parse(json_string).

In the code below I have used a dummy method for debug, with queue and MVP model, because I am working with graphics in STM32H7 microcontroller and Riverdi screen.

Here is the code from the callback function where lets say I am converting u8_t to char and calling the extract_data function where the issue is.

static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
    //char *json_data = (char *) data; First try of conversion.
        char json_data[len+1];
        memcpy(json_data, data, len);
    if (flag0.fl.f0)
    {
        extract_data(json_data); // Send the valid data of topology topic for data extraction.
        while (flag0.fl.f0) {} // Wait until the data extraction successfully finished.
        if (osMessageQueueGetSpace(TaskQueueHandle)>0)
        {
            osMessageQueuePut(TaskQueueHandle, &topics_data_s, 0, 0); // Send data to the screen via the queue.
        }
    }else if (flag0.fl.f1)
    {
        if (osMessageQueueGetSpace(DataQueueHandle)>0)
        {
            osMessageQueuePut(DataQueueHandle, json_data, 0, 0); // Send data to the screen via the queue.
        }
    }
}

Here is the function that shows the issue:

void extract_data(const char *json_string) {


    cJSON *json;

    json = cJSON_Parse(json_string); // Parsing string contents, in order to convert it as JSON format.

    if (json == NULL) // Error in parsing data.
    {
                **THE CODE IS GETTING HERE WHEN I AM CALLING THE FUNCTION.**
                // Just a dummy message.
        if (osMessageQueueGetSpace(DataQueueHandle)>0)
        {
            osMessageQueuePut(DataQueueHandle, "m", 0, 0); // Send data to the screen via the queue.
        }
        printf("Error in parsing JSON data!\n\r");
    }else if (json != NULL) // Parsing data was successfully done.
    {

        cJSON *controllers = cJSON_GetObjectItemCaseSensitive(json, "controllers"); // From JSON format get the contents of array "controllers".
        if (cJSON_IsArray(controllers)){
            cJSON *controller1 = cJSON_GetArrayItem(controllers, 0); // Store to controller1 the first item of the array, which are those two contents " device_uid:...., position:......", left side.
            cJSON *controller2 = cJSON_GetArrayItem(controllers, 1); // Store to controller2 the second item of the array, which are those two contents " device_uid:...., position:.....", right side

            cJSON *device_uid_1 = cJSON_GetObjectItemCaseSensitive(controller1, "device_uid"); // Extract the data of device_uid, which its position value is equal to one("1").
            cJSON *device_uid_2 = cJSON_GetObjectItemCaseSensitive(controller2, "device_uid"); // Extract the data of device_uid, which its position value is equal to two("2").

            /* Check if device_uid data is valid and up to date */
            if (cJSON_IsString(device_uid_1)) // For left device.
            {
                strcpy(topics_data_s.left_uid, device_uid_1->valuestring); // Store the content of device_uid to left parameter, in order to specify the left socket UID.
            }

            if (cJSON_IsString(device_uid_2)) // For right device
            {
                strcpy(topics_data_s.right_uid, device_uid_2->valuestring); // Store the content of device_uid to right parameter, in order to specify the right socket UID.
            }

        }
        cJSON_Delete(json); // Finish with the JSON parser and close it.

        flag0.fl.f0=0; // This flag when it is equal to 0, means that the UID identification was successfully done and the back end can send the data to the queue.

    }
}

I had tried the above code example in order to manipulate the MQTT incoming message as a JSON because it has a lot of useful information that I need to extract, but it return NULL. Nonetheless, the other messages are appearing properly to the screen when I use publish method via MQTT-Explorer. The data that I am publishing thought MQTT-Explorer is that with this form:

[
  {
    "parent_uid": "d0a13a",
    "position": 1,
    "controllers": [
      {
        "parent_device_uid": "d0a13a",
        "device_uid": "018660",
        "position": 1
      },
      {
        "parent_device_uid": "d0a13a",
        "device_uid": "013523",
        "position": 2
      }
    ]
  }
]


Solution

  • As per the comments; cJSON_Parse is expecting a null terminated string. However

    char json_data[len+1];
    memcpy(json_data, data, len);
    

    Does not deliver this; the value of json_data[len] is indeterminate; C does not initialise arrays to 0 (well it does in some cases) and the memcpy copies data into json_data[0] to json_data[len-1] so nothing is written to json_data[len] (the source is an array for which you are provided a length, meaning it's most likely not null terminated).

    The easy fix is to add the null with json_data[len] = '\0';.