Go Down

Topic: Is the F() print macro meant to generate an eth packet per character? (Read 299 times) previous topic - next topic

cossoft

If I do the following when using the standard Arduino Ethernet2 shield and associated library:-

Code: [Select]
       
     if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: application/octet-stream"));
          client.println(F("Content-Length: 512"));
          client.println(F("Connection: close")); 
          client.println();


every character of the header text seems to be send within it's own tcp packet.  Which then need all the associated syn/ack stuff.  The F() macro seems to pop out each char individually. It doesn't seem very efficient and produces floods of packets back and forth. So it saves RAM at the expense of packets/transmission time and wears out my wires. Is this correct?

pert

Yes, that's correct. It's because of the way the Print class converts the __FlashStringHelper type:
https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Print.cpp#L44-L55
Code: [Select]
size_t Print::print(const __FlashStringHelper *ifsh)
{
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    if (write(c)) n++;
    else break;
  }
  return n;
}

You can see that write() is called for each character. write is defined in whichever Ethernet library you're using.

Juraj

You can't write an Arduino sketch if you didn't learn programming. Not the language, but the concepts of programming - algorithms and data types.

noiasca

it's not the F Makro but the Println!

use something like this as a first step and use as less print/println as possible:

Code: [Select]

  client.println(F("HTTP/1.1 200 OK\r\n"
          "Content-Type: application/octet-stream\r\n"
          "Content-Length: 512\r\n"
          "Connection: close\r\n"));  // including the additional empty line!


DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

Whandall

use something like this as a first step and use as less print/println as possible:

The \n of all but the last line were missing in the above code.  ;)

Added:

An example including R" syntax

Code: [Select]

void setup() {
  Serial.begin(250000);
  Serial.println(F(" * concat strings"));
  Serial.println(F("HTTP/1.1 200 OK\n"
                   "Content-Type: application/octet-stream\n"
                   "Content-Length: 512\n"
                   "Connection: close\n"));
  Serial.println(F(" * R\""));
  Serial.println(F(R"delimiter(HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 512
Connection: close
)delimiter"));
  Serial.println(F(" * done"));
}
void loop() {}

Code: [Select]
* concat strings
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 512
Connection: close

 * R"
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 512
Connection: close

 * done
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

noiasca

The \n of all but the last line are missing in the above code.  ;)

you are very right - and it would be nice if you could leave out the quote of the wrong example because quoting of wrong information is ... somehow ... ugly.

edited in post #3
DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

Whandall

and it would be nice if you could leave out the quote of the wrong example because quoting of wrong information is ... somehow ... ugly.
I thought that posting the wrong information is a problem, not quoting or correcting it.  ;)

To post untested code is rarely a good idea, so I try to present a working example if possible.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Juraj

it's not the F Makro but the Println!

use something like this as a first step and use as less print/println as possible:

Code: [Select]

  client.println(F("HTTP/1.1 200 OK\n"
          "Content-Type: application/octet-stream\n"
          "Content-Length: 512\n"
          "Connection: close\n\n"));  // including the additional empty line!



so println is wrog, use println?
You can't write an Arduino sketch if you didn't learn programming. Not the language, but the concepts of programming - algorithms and data types.

noiasca

DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

cossoft

That's brilliant.  Thanks guys.

Can I just ask, how do all the quoted strings work?  There's no concatenation between them like a "+".  Just returns.  Is concatenation inferred by the compiler? Or is it just programmer's magic?

pert

In C++, adjacent string literals are automatically concatenated. In fact, there is no concatenation operator such as +.

cossoft

Sorry, is
Code: [Select]

"Connection: close\n\n"));  // including the additional empty line!

correct?  I think that's two additional lines as it's messing up my transfers.  Isn't a return automatically appended by println? It works for me with just one slash en.

Juraj

Sorry, is
Code: [Select]

"Connection: close\n\n"));  // including the additional empty line!

correct?  I think that's two additional lines as it's messing up my transfers.  Isn't a return automatically appended by println? It works for me with just one slash en.
HTTP request headers should be terminated by an empty line. standard requires them for GET request too. and HTTP requires \r\n not only \n.

use your original code only put BuffredPrint over client. Install StreamLib from Library Manager

Code: [Select]
if (c == '\n' && currentLineIsBlank) {
     char buff[64];
     BufferedPrint bp(client, buff, sizeof(buff));
     bp.println(F("HTTP/1.1 200 OK"));
     bp.println(F("Content-Type: application/octet-stream"));
     bp.println(F("Content-Length: 512"));
     bp.println(F("Connection: close"));
     bp.println();
     bp.write(data);
     bp.flush();


you can even use printf with BufferedPrint

Code: [Select]
    bp.printf(F("Content-Length: %d\r\n"), dataLength);
read about StreamLib purpose
.
You can't write an Arduino sketch if you didn't learn programming. Not the language, but the concepts of programming - algorithms and data types.

Go Up