Writing a String or a char array to: PROGMEM const static char

Dear All,

I cannot find a solution for the following problem:

In my setup there are two Arduinos communicating with each others.

The first one will provide a website link to the second one which will access this website then.

So, in the code for the second one I need to use a String or a char array which contains the link.

We are only talking about the sketch for the second Arduino from now on.

First I define a variable, for me it doesn't matter if it is a String or a char type.
This variable contains the received link from the first Arduino.

String Link = "ptbtime1.ptb.de";

respectively:

char Link[] = "ptbtime1.ptb.de";

Now I want to assign this String or char the following way:

PROGMEM const static char website[] = Link;

I only get error messages and even after two full days of research I couldn't find a working solution.

If I directly assign the link value like below it is working.

PROGMEM const static char website[] = "ptbtime1.ptb.de";

However, I need to receive it in a String/char first as it comes from the other Arduino.

Can anyone help me?

Thank you very much in advance!

Alex

Additional information:

Hardware:
Arduino Nano with ENC82J60 Ethernet Shield V1.0

Sketch:
It is for a NTP client with EtherCard.h library which unfortunately requires the website stored in
PROGMEM const static char website[] = ...

It's tricky to write to PROGMEM, for very good reasons.

Have you thought of using EEPROM?

AWOL:
It's tricky to write to PROGMEM ....

It is at run-time anyway.

Dear AWOL,

First of all, thank you very much for your fast reply!!!

I wish I could write it to the EEPROM.
My problem is that I have to use the EtherCard.h library (for the ENC28J60) which seems to require that I write to PROGMEM.

I have tried to get basically all available Arduino NTP codes to run which I found online (which use the ENC28J60 Ethernet Shield as NTP client). And believe it or not, only the one I try to use now worked.
Not even the sample one that comes with the EtherCard.h library is working.

It might not help much but I add the code here anyways now:

NTP Client.txt (5.63 KB)

/*
This is a simple program that demonstrates how to use an ENC28J60 Ethernet controller module to syncronize
the Arduino's clock and the clock in an RTC module to time retreived from an NTP time server.
*/

#include <EtherCard.h> //GitHub - njh/EtherCard: EtherCard is an IPv4 driver for the ENC28J60 chip, compatible with Arduino IDE
#include <Time.h> //Time Library, Timekeeping and Time/Date Manipulation on Teensy
#include <TimeLib.h>

byte Ethernet::buffer[350]; // Ethernet storage buffer size
static byte mymac[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; // MAC address of ENC28J60
uint8_t ipDestinationAddress[4]; // Array to hold NTP time server IP

boolean request_sent = false; // Program control boolean
boolean got_response = false; // Program control boolean
uint32_t NTP_time; // Variable to store NTP time returned
time_t networkTime; // Variable to hold NTP time to be set in Arduino/RTC

// string conversion variables
char time_string[20];
char m[3], d[3], y[5], h[3], mn[3], s[3];

// Error control variable and screen title variables
byte moduleStatus;

void setup () {

//this doesn't work:
//char ws[] = "ptbtime1.ptb.de";
//PROGMEM const static char website[] = char ws[];

//this works:
PROGMEM const static char website[] = "ptbtime1.ptb.de"; // String to hold NTP time server address

Serial.begin(115200);

if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) moduleStatus = 0; // Create an instance of the ethernet class and start it up, else error out
else if (!ether.dhcpSetup()) moduleStatus = 1; // Obtain an IP from DHCP, else error out
else if (!ether.dnsLookup(website)) moduleStatus = 2; // Verify ability to use DNS, else error out
else moduleStatus = 3; // If all the above processes complete successfully, everything is a "Go"
}

// function to convert and display various IPs
char * formatIP(char *IP, uint8_t *f_ip) {
String outputString = IP;
for (byte q = 0; q < 4; q++) {
outputString.concat(f_ip[q]);
if (q < 3) {
outputString.concat(".");
}
//Serial.println(outputString);
}
static char IPout[25];
outputString.toCharArray(IPout, 25);
return IPout;
}

void draw(void) {
switch (moduleStatus) {
case 0:
Serial.println("Failed to access ethernet controller");
break;
case 1:
Serial.println("DHCP failed");
break;
case 2:
Serial.println("DNS failed");
break;
case 3:
Serial.println("ENC28J60 Ethernet Module");
break;
case 4:
Serial.println("Gets network time from an NTP server");
break;
case 5:
Serial.print("NTP Server Time: "); Serial.println(now());
break;
}
}

// function that makes the NTP time request, waits for a response, then returns the time as a <Time.h> library time_t variable
time_t getNTPTime(char NTPServer[15]) {
uint16_t dat_p;
int plen = 0;
while (!got_response) { // Wait until a time is successfully received from the NTP time server
plen = ether.packetReceive(); // Clear the buffer
dat_p = ether.packetLoop(plen); // wait for some data to fill the buffer
if (plen > 0) {
NTP_time = 0L; // Clear the variable the time will be stored in
if (ether.ntpProcessAnswer(&NTP_time, 123)) { // If a time was successfully received,
got_response = true; // set the "got response" flag, and
return time_t(NTP_time); // return the time as a <Time.h> library time_t variable
}
}
if (!request_sent) { // If the request hasn't been sent yet, send it
request_sent = true; // Set the "request sent" flag,
ether.parseIp(ipDestinationAddress, NTPServer); // convert the NTP server IP for use by the Ethernet library, and
ether.ntpRequest(ipDestinationAddress, 123); // send the NTP time request
}
}
}

void loop () {
if (moduleStatus == 3) {
delay(5000);
moduleStatus++;
}
else if (moduleStatus == 4) {
delay(7000);
moduleStatus++;
}
if (moduleStatus > 4) {
if (!got_response) { // If the time hasn't already been set, make an NTP request for the time
networkTime = getNTPTime("199.102.46.75"); // Make the request

setTime(networkTime-2208988800ul); // Set the Arduino's clock to UTC Unix time
Serial.println("Network Time: "); Serial.println(now());
//setSyncProvider(RTC.get); // Define the function to be used by <Time.h> to preiodically sync the Arduino's clock from the RTC
//adjustTime(-2208988800ul); // Correction for UTC Time in seconds
Serial.print("IP-Address: "); for (int ii=0; ii<=3; ii++) {Serial.print(ether.myip[ii]); if (ii<=2) {Serial.print(".");};} Serial.println();
Serial.print("Gateway-Address: "); for (int ii=0; ii<=3; ii++) {Serial.print(ether.gwip[ii]); if (ii<=2) {Serial.print(".");};} Serial.println();
Serial.print("Mask: "); for (int ii=0; ii<=3; ii++) {Serial.print(ether.netmask[ii]); if (ii<=2) {Serial.print(".");};} Serial.println();
Serial.print("DNS: "); for (int ii=0; ii<=3; ii++) {Serial.print(ether.dnsip[ii]); if (ii<=2) {Serial.print(".");};} Serial.println();
}

}
}

[code][/code] - you can have those, they're spares I had lying on my desk.

You have the library source - it's not like you have only a binary library

Dear AWOL,

I guess you tried to give me a link or a source for Sketches.

Let me copy for you what I received from you:

`` - you can have those, they're spares I had lying on my desk.

You have the library source - it's not like you have only a binary library

I am not sure what to do with the ``...

Anyways, thank you so much so far :slight_smile:

aklein9999:
I am not sure what to do with the ``...

They're for putting your code in.

The source code (ethercard.h) says:

   // dns.cpp
    /**   @brief  Perform DNS lookup
    *     @param  name Host name to lookup
    *     @param  fromRam Set true to indicate whether name is in RAM or in program space. Default = false
    *     @return <i>bool</i> True on success.
    *     @note   Result is stored in <i>hisip</i> member
    */
    static bool dnsLookup (const char* name, bool fromRam =false);

So all you need to do is change the example code:

//Old code, "website" variable in PROGMEM:
    else if (!ether.dnsLookup(website)) moduleStatus = 2;   // Verify ability to use DNS, else error out

// Replacement code: "ws" variable in RAM:
    else if (!ether.dnsLookup(ws, true)) moduleStatus = 2;  // Verify ability to use DNS, else error out

Dear All,

The tip from westfw absolutely did it!

I looked at the problem from the wrong end haha....

Thank you very much for spending your precious time for my problem, you really made my day.

Alex