v0.2.3 Firmware RAM Optimizations Shipped!

@BDub than i need to change buffer limit 512 byte to 128 byte ? Isnt it ?

Flip that, reverse it. 128 to 512. You could do that if you are building locally.

The better way would be to handle it in your code. Letā€™s see if we can do that here:

#define DEBUG_SERIAL false

String http_get(char const* hostname, String path) {

  int i = 0;
  int k = 0;
  bool printOnce = false;

  if (client.connect(hostname, 80)) {
    client.print("GET ");
    client.print(path);
    client.println(" HTTP/1.1");
    client.print("HOST: ");
    client.println(hostname);
    client.println("Connection: close");
    client.println();
    client.flush();
  } else {
    if(DEBUG_SERIAL) Serial.println("\r\n\r\nConnection Failed!");
    client.flush();
    client.stop();
    return NULL;
  }

  // wait 5 seconds or less for the host to respond
  uint32_t startTime = millis();
  while(!client.available() && (millis() - startTime) < 5000);

  if(DEBUG_SERIAL) Serial.println("\r\n\r\nREADING HOST DATA......");
  uint32_t lastRead = millis();
  // If the host doesn't close it's connection, we'll timeout in 10 seconds.
  while (client.connected() && (millis() - lastRead) < 10000) {
    while (client.available()) {
      char c = client.read();
      /*
      if(DEBUG_SERIAL) {
        Serial.print(c);
        if(i++ > 100) {
          delay(5);
          i = 0;
        }
      }
      */
      if(c == -1) {
        Serial.print("\r\n\r\nERROR......\r\n\r\n");
        client.flush();
        client.stop();
      }
      if(DEBUG_SERIAL && !printOnce) {
        Serial.print("\r\n\r\nSAVING......\r\n\r\n");
        printOnce = true;
      }
      buffer[k++] = c; // save character to buffer
      //Serial.print(c);
      //delayMicroseconds(100);
      if(k >= BUFFER_SIZE_MAX) { // if we reach the end of our buffer, just bail.
        Serial.print("\r\n\r\nOUT OF BUFFER SPACE......\r\n\r\n");
        client.flush();
        client.stop();
      }
      // as long as we're reading data, reset the lastRead time.
      lastRead = millis();
    } // END while(client.available())
  } // END while(client.connected())
  
  client.flush();
  client.stop();

  // At this point the entire response with header is in 'buffer'
  // Let's strip off just the response, we don't care about the header.
  String response(buffer);
  int bodyPos = response.indexOf("\r\n\r\n");
  if (bodyPos == -1) {
    if(DEBUG_SERIAL)Serial.println("\r\n\r\nCannot find http reponse body!\r\n\r\n");
    return NULL;
  }
  return response.substring(bodyPos + 4);
}

You should be able to drop this right into your codeā€¦ replacing that function. Be warned, I have not compiled this exact version which I modified from my Facebook Likes Alert code.

1 Like

I changed my code with your code but making little changes (BUFFER_SIZE_MAX to TCPCLIENT_BUF_MAX_SIZE) and have been successfully compiled.

And my result is below.. I think the problem still continues.

millis(): 300001

OUT OF BUFFER SPACE......

Any update ? Someone can help me?

Hi @Yasin,

Sure, I can help, Iā€™ll try it out and let you know what I find.

Thanks,
David

1 Like

Hey Yasin,

I think you might want to try the HttpClient library thatā€™s currently under development, I put your URL in the example app, and Iā€™m getting responses back from your server, I copied all the code into a GIST here:

I hope that helps!

Thanks,
David

Looks good Dave! Thanks for stepping in :smile:

I would only suggest changing the millis() math to use subtraction to prevent weirdness when millis() overflows (probably doesnā€™t matter much for this app, but good practice anyway). Also renamed nextTime to lastTime.

void loop() {
  if ( (millis() - lastTime) > 10000UL ) {
    lastTime = millis();
 
    Serial.println();
    Serial.println("Application>\tStart of Loop.");
    // Request path and body can be set at runtime or at setup.
    request.port = 80;
    request.hostname = "roman-mueller.ch";
    request.path = "/api/weather";
 
    // The library also supports sending a body with your request:
    //request.body = "{\"key\":\"value\"}";
  
    // Get request
    http.get(request, response, headers);
    Serial.print("Application>\tResponse status: ");
    Serial.println(response.status);
 
    Serial.print("Application>\tHTTP Response Body: ");
    Serial.println(response.body);
  }
}

@Dave yes , now your app is working. I am getting responses from server. By the way this is not my own code . This project @kwyjib0 weather lamp project. I wanted to create my own weather lamp. So i tried replace with @kwyjib0 code with HttpClient library but failed.

Could you help me a little more? Can you edit this with your codes?

Iā€™ll try to take a try at this later today if I can, but it might take me a while before Iā€™ll have some time to work on it. :slight_smile:

Thanks,
David

@Dave i did that :)) but i want to know how can i remove server headers.?

I want see only that.

W-[255,255,000][000,128,000]-Temp:20,9Ā°C;Yellow-Condition:SkyIsClear;Green

Hello all,

Maybe a solution, itā€™s work for me.
Before v0.2.3 my program worked perfectly and since 0.2.3 lot of BDubā€™s similar error :

../inc/spark_wiring_ipaddress.h:54:105: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };

The error was in my pin definition :

int STARTPIN = D7;
int BUTTONPIN = D0;
int RELAY1 = D5;
int RELAY2 = D6;
int LIGHTPIN = A0;Ā  //LIGHT PIN, photoresistanceĀ Ā  Ā 
int TEMPPIN = A1;Ā  //MCP9700A temperature sensor
int REDLED = A6;
int MOISTURE_VCC = D4;//MOISTURE VSS POWER SUPPLY
int MOISTURE1_ANA = A2; //MOISTUREĀ  analog in 1
int MOISTURE2_ANA = A3; //MOISTUREĀ  analog in 2
int WATER_ANA = A4; //waterĀ  analog in 1
int 12VTEST_ANA = A5; //measure 12V

==> Ā Ā Ā  int 12VTEST_ANA = A5; remplaced by int TEST12V_ANA = A5;
Start variable with number is forbidden with new firmware for me.

1 Like

Hi @Yasin,

If you just want the response body and not the headers, I think thatā€™s parsed out and exposed with the response.body variable I think:

 Serial.print("Application>\tHTTP Response Body: ");
 Serial.println(response.body);

Thanks,
David

@Dave My code uses a TCP Client along with UDP Server & Client. Iā€™ve been able to make a decently sized application and Iā€™ve managed to not overflow on RAM usage most of the time. I overflow on the RAM majorly when I have to send a message both using the TCP Client and UDP Client.

TCPClient seems to accept ā€œuint8_tā€ buffer and UDPClient seems to accept a ā€œcharā€ buffer. So I find myself allocating double the memory for a single message because of the datatype difference.

Example:

TCPClient tcpClient;
UDP udpClient;

void sendMessage(){
        char udpMessage[12] =  "Hello World";  // UDP Message Buffer 
        udpClient.beginPacket(IP, PORT);
        udpClient.write(udpMessage);
        udpClient.endPacket();

        uint8_t tcpMessage[13];                // TCP Message Buffer
        memcpy(tcpMessage, udpMessage, 12);
        tcpClient.write(tcpMessage);
       
}

Any changes made for this or could you give me some notes as to how to optimize or do this better?

Edit: I mixed up the datatypes in the code. Corrected and re-arranged it.

1 Like

Hi @nitred,

Oh interesting! Iā€™m noticing that the write functions both support uint8_t:

https://github.com/spark/core-firmware/blob/master/inc/spark_wiring_udp.h#L56
https://github.com/spark/core-firmware/blob/master/inc/spark_wiring_tcpclient.h#L45

But the read operations are different, so I added an issue for you here:

Thanks,
David

1 Like

@Dave Thank you for the additional comment as well to add ā€˜charā€™ into the write array. I prefer using ā€˜charā€™ arrays since they offer me additional functions such as ā€˜strcatā€™ and ā€˜strcpyā€™ when I have some string manipulation to do.

I was having issues before with using uint8_t with udpClient. I just figured out that I have to mention the size of the uint8_t array as one of the parameters.

uint8_t udpMessage[] = "Hello World";
udpClient.write(udpMessage, 12); <---- Have to add array length as parameter

So thatā€™s solved as well
Thanks! :slight_smile:

1 Like

That seems like something that the function should take care of itself. When are you going to call udpClient.write() without using the whole array youā€™ve passed in?

Hi @NanoAkron,

Good question! I think the limitation there is that itā€™s hard for C/C++ programs to know the length of native arrays without providing the length or using a terminating character which doesnā€™t necessarily apply to raw buffers.

Thanks!
David

But isnā€™t this array defined at compile time and not dynamically changing? Surely you could use something like strlen() or sizeof() in the function, or scan to the next unoccupied space in the array.

@NanoAkron I donā€™t think having to add the array size is such a bad thing. If I were using a global buffer and only wanted to use the first three bytes of the buffer, then mentioning the buffer size would come in handy.

but,

@Dave tcpClient.write() doesnā€™t seem to need array length passed to it, but udpClient.write() needs it. It would be nice if both of them have a standard way of doing things. :smile:

Hi Guys,

C++ array length can be a bit contentious, I might be wrong on this, but hereā€™s a stack overflow article to back me up - http://stackoverflow.com/questions/874169/how-to-get-the-size-of-an-array

@nitred - I think you are looking at the single-byte write function versus the array write functions:

from TCPClient:

virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size);

from UDP:
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size);

Thanks!
David

1 Like