0

Here is what I'm trying to do: I have a django app with a REST api on it. One of the routers returns a json array that looks like this : [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0] and will always be the same size and containing integers.

Now, I have an Arduino Uno with an Adafruit cc3000 wifi shield on it. I manage to connect to the wifi, do my get request and print the result, even save it in a char *.

My first problem is:

I'm pretty sure I'm not constructing my char array the right way (at least, not the proper way, I don't have a lot of experience with C, C++ etc.) if that's an excuse). And I think this prevents me to parse the json array.

#include <ArduinoJson.h>
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include <Adafruit_NeoPixel.h>

int PIN = 6;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);
StaticJsonBuffer<600> jsonBuffer;

#define ADAFRUIT_CC3000_IRQ   3  
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10

Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIVIDER);
#define WLAN_SSID       "mywifi"
#define WLAN_PASS       "mypwd"
#define WLAN_SECURITY   WLAN_SEC_WPA2
uint32_t ip = cc3000.IP2U32(00,00,00,00);


void setup(void)
{
  Serial.begin(9600);
  if (!cc3000.begin())
  {
    while(1);
  }
  strip.begin();
  strip.show();
  char *ssid = WLAN_SSID;
  Serial.print(F("\nAttempting to connect to "));
  Serial.println(ssid);
  cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
  Serial.println("Connected to WiFi network!");

  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP())
  {
    delay(3000);
  }
}


void loop(void){
  int lap = 0;
  if(!cc3000.checkConnected()){
    while(1){
    }
  }
  char *result;
  result  = send_request();
  result[71] = ']';
  JsonArray& root = jsonBuffer.parseArray(result);
  if (!root.success())
  {
    Serial.println("parseObject() failed");
  }
  while(lap<61){
    for (int i=0; i<24; i++){
      long is_free = root[i];
      if (is_free == 0){
        strip.setPixelColor(i, 255, 0, 0);
      }
      if(is_free == 1){
        strip.setPixelColor(i, 0, 255, 0);
      }
      if(lap % 2 ==0){
        if(is_free == 2){
          strip.setPixelColor(i, 0, 255, 0);
        }
        if(is_free == 3){
          strip.setPixelColor(i, 0, 255, 0);
        }
      }
      else{
        if(is_free == 2){
          strip.setPixelColor(i, 0, 0, 0);
        }
        if(is_free == 3){
          strip.setPixelColor(i, 0, 0, 0);
        }
      }
    }
    strip.setBrightness(15);
    strip.show();
    lap += 1;
    delay(1000);
  }  
}


char* send_request (void)
{
  char result[100];
  Serial.print(F("Initializing SendGET request\n"));
  Adafruit_CC3000_Client client = cc3000.connectTCP(ip, 8000);

  if (client.connected()) {
    //starts client connection, checks for connection
    Serial.println(F("Adding state to DB\n"));
    client.println("GET /myurl/?format=json"); //download text
    client.println(F("Host: xx.xx.xx.xx"));
    client.println("Connection: close");  //close 1.1 persistent connection  
    client.println(); //end of get request
    Serial.println(F("Ending connection to DB\n"));
  } 
  else {
    Serial.println("Connection to server failed"); //error message if no client connect
    Serial.println();
  }
  int i = 0;
  while (client.connected()){
    while (client.available()) {
      if (i<71){
        //Read answer
        char c = client.read();
        result[i] = c ;
        i++;
      }
      else{
        client.close();
        return result;
      }
    }
  }
}

To me send_request() is really dirty since I decided that i needed to be smaller than 71 because the result of this that I'd print looked like what I want. But I think the array is the wrong size and that this is why I can't parse it in the loop() function.

What is the good, nice, clear, precise way to do this, please? I have tried so many wrong things I'm running out of ideas.

Second problem is:

If I replace

char *result;
result[71] = ']';

by result = "[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0]"; And then print is_free, I get random values like:

91
49
44
32
48
44
32
48
44
32
48
44
32
48

etc.

So my guess is either I'm just not using ArduinoJson properly, either I'm not looking at the value at the right place. I'm looking for insights about that

Thanks for reading and the future eventual help!

Community
  • 1
  • 1
nnaelle
  • 892
  • 1
  • 8
  • 22
  • I wouldn't bother with JSON. If you know that you're always going to get values that fit in an unsigned int then just send a count of values and then the values themselves, all as bytes. – Ignacio Vazquez-Abrams Dec 09 '14 at 19:36
  • I tried that and think it is a good idea, though I'm pretty sure I messed something up because I got some weird numbers. Anyways, if ever I try again without JSON, I'll update my question! thanks for the suggestion – nnaelle Dec 10 '14 at 16:30

1 Answers1

1

Your code has multiple issues, but the main problem is the fact that function send_request returns a pointer to a local variable. Variable result is located in a stack frame that probably gets overwritten by the stack frame of whatever comes next (I guess function loop); hence the garbage you witnessed.

A quick and dirty solution is to replace:

char result[100];

by:

static char result[100];

This moves result to a dedicated piece of memory that is not reclaimed until your program finishes.

Parsing might fail because you never terminate your string; however this may no longer be a problem after the fix above (static variables are initialized with nulls). But just to be sure, add this command just before calling parseArray:

result[72] = '\0';

Other issues:

  • Part of your code is missing; where is the main function calling setup, send_request and loop? Thanks for the explanation.
  • while(1); is an infinite loop that will do nothing but turn your Arduino into a toaster; is that intentional?
  • long is_free = result[i]; should probably be long is_free = root[i];? Thanks for changing your code accordingly; I am pretty sure this will resolve problem #2.
Ruud Helderman
  • 10,563
  • 1
  • 26
  • 45
  • `main()` is provided by the Arduino libraries; it calls `setup()` once and `loop()` repeatedly. – Ignacio Vazquez-Abrams Dec 09 '14 at 21:22
  • I tried to change `char result[100]` to `static char result[100]`, it didn't change anything. Also arduino runs itself the setup and loop function and I edited my code because I cut some code that was supposed to be here – nnaelle Dec 09 '14 at 21:22
  • @nnaelle: I fixed problem #2 for you, didn't I? If problem #1 persists, then there's another bug. Debugging is going to be a lot harder if you don't get rid of your [undefined behavior](http://stackoverflow.com/questions/4570366/pointer-to-local-variable) first; _please_ make the string buffer static. See also my edit. – Ruud Helderman Dec 10 '14 at 08:32
  • Thanks for the link and explanations! I was missing the \0 and declared the array result at the very beginning of my code so it's always accessible. I also have deleted the while(1) and nothing changed so that's good! Thanks again. I'll update my post with the final code! – nnaelle Dec 10 '14 at 16:29