0

I am trying to Parse the below JSON String in my Microcontroller code using CJSON.

    {
    "A":
        {
            "A1":
                [
                    {"S":0,"V":-5},
                    {"S":60,"V":5}
                ],
            "A2":
                [
                    {"S":0,"V":-5},
                    {"S":60,"V":5}
                ]
        },
    "B":
        {
            "B1":
                [
                    {"S":0,"V":-5},
                    {"S":60,"V":5}
                ],
            "B2":
                [
                    {"S":0,"V":-5},
                    {"S":60,"V":5}
                ]
        },
    "C":60
}

I tried this so far to filter the string of A. Then I can run the parse again to filter A1 from A. The code did not worked. Its printing the ' error_ptr".

int cJSON_Test()
{
    char text[1024];

    char JSON_STRING[] =
    "{\n"
    "\"A\":{\"A1\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}],\"A2\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}]},\n"
    "\"B\":{\"B1\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}],\"B2\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}]},\n"
    "\"C\":60\n"
    "}";

    const cJSON *A_Data = NULL;
    const cJSON *B_Data = NULL;
    const cJSON *C_Data = NULL;

    const cJSON *A1_Data = NULL;
    const cJSON *A2_Data = NULL;

  int status = 0;
  cJSON *root = cJSON_Parse(JSON_STRING);
  if (root == NULL)
  {
    const char *error_ptr = cJSON_GetErrorPtr();
    if (error_ptr != NULL)
    {
            sprintf(text,"Error before: %s\r\n", error_ptr);
            SendDataToUart(&huart1, (uint8_t*)text, strlen(text));

    }
    status = 0;
    goto end;
  }

    A_Data = cJSON_GetObjectItemCaseSensitive(root, "A");
    if (cJSON_IsString(A_Data) && (A_Data->valuestring != NULL))
    {
        sprintf(text,"A String: %s\r\n", A_Data->valuestring);
        SendDataToUart(&huart1, (uint8_t*)text, strlen(text));
    }

    end:
    cJSON_Delete(root);
    return status;
}

My need is to parse all the string and its value separately then print it. Can anyone please advice?

Regards.

user3125451
  • 49
  • 2
  • 6
  • Since the JSON is valid, you probably don't have enough heap space and an allocation fails. Also note that `A_DATA` is not a string but an object. – FSMaxB Feb 06 '18 at 10:49
  • If I counted correctly, the parser will create 32 cJSON items, each of which takes roundabout 50 bytes + additonal space for the object keys. With additional overhead from you allocator this would probably take about 2 kilobytes of heap space. – FSMaxB Feb 06 '18 at 10:54
  • Also please provide what the `error_ptr` was, when it was printed. – FSMaxB Feb 06 '18 at 11:01
  • Hello. Thanks for reply. I am getting the below print output. Error before: ,"A2":[{"S":0,"V":-5},{"S":60,"V":5}]}, "B":{"B1":[{"S":0,"V":-5},{"S":60,"V":5}],"B2":[{"S":0,"V":-5},{"S":60,"V":5}]}, "C":60 } Can you advice how I cam parse the full object of A and print? Thanks. – user3125451 Feb 06 '18 at 11:28
  • Is there any option in cJSON to print object as a string? Thanks. – user3125451 Feb 06 '18 at 15:35
  • I added printing to my answer. – FSMaxB Feb 06 '18 at 15:42
  • Also please read the documentation! It's not like I wrote the documentation so that nobody reads it. – FSMaxB Feb 06 '18 at 15:42
  • About the documentation, if something is unclear, you can always make an issue on GitHub and it can be improved! – FSMaxB Feb 06 '18 at 16:12

1 Answers1

1

You can debug problems with your allocator by making wrappers that you then install using cJSON_InitHooks.

I wrote an example of how your input could be parsed as well as some debugging allocators, that should help you find the problem. Just replace all the printfs with your function to send strings via UART.

#include <cjson/cJSON.h>
#include <stdio.h>
#include <stdlib.h>

size_t total_allocated = 0;

void *debugging_malloc(size_t size) {
    void *pointer = malloc(size);
    if (pointer == NULL) {
        printf("Failed to allocate %zu bytes\n", size);
    } else {
        total_allocated += size;
        printf("Allocated %zu bytes: %p\n", size, pointer);
    }

    return pointer;
}

void debugging_free(void *pointer) {
    free(pointer);
    printf("Freed %p\n", pointer);
}

cJSON_Hooks debugging_allocators = {debugging_malloc, debugging_free};

int print_s_v_array(const cJSON *array, const char *name) {
    const cJSON *element = NULL;
    size_t index = 0;
    printf("\t%s: [", name);
    cJSON_ArrayForEach(element, array) {
        cJSON *S = NULL;
        cJSON *V = NULL;

        if (!cJSON_IsObject(element)) {
            return 0;
        }

        S = cJSON_GetObjectItemCaseSensitive(element, "S");
        if (!cJSON_IsNumber(S)) {
            return 0;
        }

        V = cJSON_GetObjectItemCaseSensitive(element, "V");
        if (!cJSON_IsNumber(V)) {
            return 0;
        }

        printf("\t%zu: S is %f and V is %f\n", index, S->valuedouble, V->valuedouble);

        index++;
    }
    printf("\t]\n");

    return 1;
}

cJSON_bool print_sub_object(const cJSON *object, const char *name) {
    cJSON *element = NULL;
    printf("%s: {\n", name);
    cJSON_ArrayForEach(element, object) {
        if (!cJSON_IsArray(element) || (element->string == NULL)) {
            return 0;
        }

        print_s_v_array(element, element->string);
    }
    printf("}\n");

    return 1;
}

int main() {
    char JSON_STRING[] =
    "{\n"
    "\"A\":{\"A1\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}],\"A2\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}]},\n"
    "\"B\":{\"B1\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}],\"B2\":[{\"S\":0,\"V\":-5},{\"S\":60,\"V\":5}]},\n"
    "\"C\":60\n"
    "}";

    const cJSON *A = NULL;
    const cJSON *B = NULL;
    const cJSON *C = NULL;
    const cJSON *A1 = NULL;
    const cJSON *A2 = NULL;
    const cJSON *B1 = NULL;
    const cJSON *B2 = NULL;
    const cJSON *element = NULL;
    size_t index = 0;

    int status = EXIT_SUCCESS;

    cJSON_InitHooks(&debugging_allocators);

    cJSON *root = cJSON_Parse(JSON_STRING);
    if (root == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            printf("Error before: %s\r\n", error_ptr);
        }
        goto fail;
    }

    A = cJSON_GetObjectItemCaseSensitive(root, "A");
    if (!cJSON_IsObject(A)) {
        goto fail;
    }
    print_sub_object(A, "A");
    /* you could of course just get A1 and A2 via cJSON_GetObjectItemCaseSensitive manually
     * instead of making such a function, not sure what you actually want to do with your data */


    B = cJSON_GetObjectItemCaseSensitive(root, "B");
    if (!cJSON_IsObject(B)) {
        goto fail;
    }
    print_sub_object(B, "B");

    C = cJSON_GetObjectItemCaseSensitive(root, "C");
    if (!cJSON_IsNumber(C)) {
        goto fail;
    }
    printf("C: %f\n", C->valuedouble);

    goto end;

fail:
    status = EXIT_FAILURE;
end:
        cJSON_Delete(root);
        printf("Allocated in total: %zu bytes\n", total_allocated);
        return status;
}

When running this on my x86_64 machine it outputs the following:

Allocated 64 bytes: 0xf14a51915d0
Allocated 64 bytes: 0xf14a5192630
Allocated 3 bytes: 0xf14a5192680
Allocated 64 bytes: 0xf14a51926a0
Allocated 4 bytes: 0xf14a51926f0
Allocated 64 bytes: 0xf14a5192710
Allocated 64 bytes: 0xf14a5192760
Allocated 3 bytes: 0xf14a51927b0
Allocated 64 bytes: 0xf14a51927d0
Allocated 3 bytes: 0xf14a5192820
Allocated 64 bytes: 0xf14a5192840
Allocated 64 bytes: 0xf14a5192890
Allocated 3 bytes: 0xf14a51928e0
Allocated 64 bytes: 0xf14a5192900
Allocated 3 bytes: 0xf14a5192950
Allocated 64 bytes: 0xf14a5192970
Allocated 4 bytes: 0xf14a51929c0
Allocated 64 bytes: 0xf14a51929e0
Allocated 64 bytes: 0xf14a5192a30
Allocated 3 bytes: 0xf14a5192a80
Allocated 64 bytes: 0xf14a5192aa0
Allocated 3 bytes: 0xf14a5192af0
Allocated 64 bytes: 0xf14a5192b10
Allocated 64 bytes: 0xf14a5192b60
Allocated 3 bytes: 0xf14a5192bb0
Allocated 64 bytes: 0xf14a5192bd0
Allocated 3 bytes: 0xf14a5192c20
Allocated 64 bytes: 0xf14a5192c40
Allocated 3 bytes: 0xf14a5192c90
Allocated 64 bytes: 0xf14a5192cb0
Allocated 4 bytes: 0xf14a5192d00
Allocated 64 bytes: 0xf14a5192d20
Allocated 64 bytes: 0xf14a5192d70
Allocated 3 bytes: 0xf14a5192dc0
Allocated 64 bytes: 0xf14a5192de0
Allocated 3 bytes: 0xf14a5192e30
Allocated 64 bytes: 0xf14a5192e50
Allocated 64 bytes: 0xf14a5192ea0
Allocated 3 bytes: 0xf14a5192ef0
Allocated 64 bytes: 0xf14a5192f10
Allocated 3 bytes: 0xf14a5192f60
Allocated 64 bytes: 0xf14a5192f80
Allocated 4 bytes: 0xf14a5192fd0
Allocated 64 bytes: 0xf14a5192ff0
Allocated 64 bytes: 0xf14a5193040
Allocated 3 bytes: 0xf14a5193090
Allocated 64 bytes: 0xf14a51930b0
Allocated 3 bytes: 0xf14a5193100
Allocated 64 bytes: 0xf14a5193120
Allocated 64 bytes: 0xf14a5193170
Allocated 3 bytes: 0xf14a51931c0
Allocated 64 bytes: 0xf14a51931e0
Allocated 3 bytes: 0xf14a5193230
Allocated 64 bytes: 0xf14a5193250
Allocated 3 bytes: 0xf14a51932a0
A: {
    A1: [   0: S is 0.000000 and V is -5.000000
    1: S is 60.000000 and V is 5.000000
    ]
    A2: [   0: S is 0.000000 and V is -5.000000
    1: S is 60.000000 and V is 5.000000
    ]
}
B: {
    B1: [   0: S is 0.000000 and V is -5.000000
    1: S is 60.000000 and V is 5.000000
    ]
    B2: [   0: S is 0.000000 and V is -5.000000
    1: S is 60.000000 and V is 5.000000
    ]
}
C: 60.000000
Freed 0xf14a51927b0
Freed 0xf14a5192760
Freed 0xf14a5192820
Freed 0xf14a51927d0
Freed 0xf14a5192710
Freed 0xf14a51928e0
Freed 0xf14a5192890
Freed 0xf14a5192950
Freed 0xf14a5192900
Freed 0xf14a5192840
Freed 0xf14a51926f0
Freed 0xf14a51926a0
Freed 0xf14a5192a80
Freed 0xf14a5192a30
Freed 0xf14a5192af0
Freed 0xf14a5192aa0
Freed 0xf14a51929e0
Freed 0xf14a5192bb0
Freed 0xf14a5192b60
Freed 0xf14a5192c20
Freed 0xf14a5192bd0
Freed 0xf14a5192b10
Freed 0xf14a51929c0
Freed 0xf14a5192970
Freed 0xf14a5192680
Freed 0xf14a5192630
Freed 0xf14a5192dc0
Freed 0xf14a5192d70
Freed 0xf14a5192e30
Freed 0xf14a5192de0
Freed 0xf14a5192d20
Freed 0xf14a5192ef0
Freed 0xf14a5192ea0
Freed 0xf14a5192f60
Freed 0xf14a5192f10
Freed 0xf14a5192e50
Freed 0xf14a5192d00
Freed 0xf14a5192cb0
Freed 0xf14a5193090
Freed 0xf14a5193040
Freed 0xf14a5193100
Freed 0xf14a51930b0
Freed 0xf14a5192ff0
Freed 0xf14a51931c0
Freed 0xf14a5193170
Freed 0xf14a5193230
Freed 0xf14a51931e0
Freed 0xf14a5193120
Freed 0xf14a5192fd0
Freed 0xf14a5192f80
Freed 0xf14a5192c90
Freed 0xf14a5192c40
Freed 0xf14a51932a0
Freed 0xf14a5193250
Freed 0xf14a51915d0
Allocated in total: 2121 bytes

If you want to print e.g. A, you can use cJSON_Print. Please read the documentation here.

char *printed_a = cJSON_Print(A);
if (printed_a == NULL) {
    goto fail;
}
printf("%s\n", printed_a);
free(printed_a);

Or in this case, because you need to print into a buffer anyways for sending it over UART, you can use cJSON_PrintPreallocated:

char buffer[1024];
if (!cJSON_PrintPreallocated(A, buffer, sizeof(buffer), true)) {
    goto fail;
}
FSMaxB
  • 2,280
  • 3
  • 22
  • 41
  • Hello FSMaxB. Thanks much for giving time to run the example in our machine. I tried your code into my Microcntroller Keil MDK Simulator and gets the below print log. I am not getting the same output as yours.I am unable to share the total print log here in comment. Thanks. – user3125451 Feb 06 '18 at 16:15
  • Well you should see if the allocation fails at some point (which it most certainly does). Also you could upload your print log to pastebin or some other website and post a link here. – FSMaxB Feb 06 '18 at 16:54
  • How much RAM does your particular microcontroller even have? – FSMaxB Feb 06 '18 at 16:54
  • My MCU Ram is 20KB. Here is my print log with allocate failed. https://pastebin.com/fFSFAqnk – user3125451 Feb 06 '18 at 17:08
  • Well there you have your problem, not enough space. 20KB is not that much, maybe cJSON isn't the right library for that purpose. Or maybe you have to change some kind of setting to increase the heap size on your platform. – FSMaxB Feb 06 '18 at 17:29
  • All cJSON can do here is to recover gracefully from the out of memory situation, which is exactly what it does. – FSMaxB Feb 06 '18 at 17:29
  • Googling a bit I found that there is some kind of startup file that can be used to configure the heap size. – FSMaxB Feb 06 '18 at 17:44
  • See also this issue on GitHub: https://github.com/DaveGamble/cJSON/issues/223#issuecomment-351594756 – FSMaxB Feb 06 '18 at 18:05
  • Thank you. Then it will be a bit complex for me. Its Ok, let me look for its solution. Thanks again. – user3125451 Feb 06 '18 at 18:06