Send file to arduino sd card with ethernet shield

Hi all..
I have a task related to Arduino and Embarcadero Delphi 10...
I want to send a .txt file to the Arduino SD card via a local network with an Ethernet shield.

Has anyone ever done the same thing?
If so, can I get an example sketch?

Thank You

you could run either an FTP or Web Server on the Arduino, get the data and store it to the SD card.

What kind of Arduino do you have?

I use Arduino Uno and ethernet shield... bro

That’s quite a memory constraint board…

You could explore a very simple web server and see how to handle file upload but it’s going to be a challenge within 2KB of RAM when you need to handle the SD and Ethernet libraries…

Can’t you move to a more capable board?

I just want to send a small .txt file containing some RFID card code to the SD card, is there any reference for that..

in the future maybe I will replace the board with a more compatible one...

The problem is not the size of the file you want to upload,

The challenge is to fit both the Ethernet Library plus an FTP Server or Web Server library as well as the SD card library on the arduino with only 2KB of RAM... I don't know if that will work out, I suspect it won't.

You could give it a try and start with the web server and the Ethernet library, see

https://docs.arduino.cc/tutorials/ethernet-shield-rev2/web-server/

Modify the code to add the sdFat library and open a file when you get a request and see the impact on available memory when you compile.

I would not be surprised to see the IDE issuing a warning that memory is low and board stability not guaranteed.

oh yeah, i see... the size of the sketch might be too big when compiled into the board...
so what board should be used for this case?
thanks for the suggestion

an Arduino Mega would offer more memory but is still quite an old board. Modern boards like an ESP32 with on board WiFi and advanced libraries for FTP or HTTP would make it easier to code this.

Do you need Ethernet absolutely or would WiFi be an option (you could also attach an Ethernet board to an ESP32 if necessary)

yes, i really need ethernet because at the location the board will communicate with the PC using a cable in a local network

I have FTP code for a client, but not as a server. I presume it would also work the other way. Mine will read or write to the FTP server. I don't think I can post it here. It's a rather large file.

what programming language is the code written in?

is it okay if I leave my email address here?

and if you don't mind sending me an email?

It is not a problem to connect the ethernet module to the an ESP32/8266. I would prefer the ESP32 since you can use 2 SPI busses, 1 for each, but you can get it to work on a single SPI bus as well. Using a 3.3v device simplifies the SD card connection.

Agreed

Also if the file does not really need to be on an SD card, it could go in littkeFS on board.


What’s the purpose of that file ? Some config options ? Do they change often ? Could you write them by uploading the files to the SD card and then plugging that SD card into the Arduino ?

I'm just saying it is possible. The file date on my code is January 2017.
It may not fit on an Uno. I used a Mega2560
My web server code will certainly not fit on an Uno. File date January 2017
I can no longer test it. The FTP server is no longer available. The server required auth to access it.

The EthernetServer library is versatile and can handle TCP connections for any protocol, including FTP, as long as you manually manage the specifics of the FTP protocol.

So you can technically use EthernetServer on an Arduino UNO with an Ethernet shield to implement an FTP server, though it’s more complex than for HTTP as the protocol implementation requires managing both a control connection (port 21) and a separate data connection (typically port 20 or an arbitrary port for passive mode).

You’d need to handle both connections in your code, parsing commands like USER, PASS, LIST, RETR, STOR, etc., and establishing additional sockets for data transfers.

Add to this the SD library and its need for a 512 bytes buffer in RAM and that's why I'm unclear if that will fit in 2KB.

That's why I was suggesting exploring an HTTP server with file transfer capabilities instead. HTTP is lighter on resources, and there are existing libraries and examples for simple HTTP-based file transfer on Arduino that could be looked at and see if they fit on the UNO.

Yes, friend, it looks like I still have to search and read a lot of code libraries regarding HTTP file transfer... thanks for the advice...

I set up my RPi with an FTP server and got my code partially working. It does upload a file from the FTP server to the SD.

I need to do more testing. Give me a while. I'm old as dirt.

Nice

Being an FTP client is indeed "lighter"

as @ranggajulizar said

it seems this is driven from outside the arduino, so you'll need a way to tell the arduino it's time to fetch the file.

If FTP isn't acceptable, let me know. I won't waste time on it.
Seems to be working ok. I can download and read the file.

It is FTP with user and password auth.

Edit: Here is the code. Enter 'f' to download. 'r' to read the file from the SD.
Change the user, password, and fileName. I cleaned up the code a bit. Left the response troubleshooting stuff for you.

#include <SD.h>
#include <Ethernet.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 };  
IPAddress ip( 192, 168, 1, 2 );    
IPAddress gateway( 192, 168, 1, 1 );
IPAddress subnet( 255, 255, 255, 0 );
IPAddress server(192,168,1,29);

EthernetClient client;
EthernetClient dclient;

char outBuf[128];
char outCount;
char user[] = "myUser";
char password[] = "myPassword";
char fileName[] = "test.txt";

void setup()
{
  Serial.begin(115200);

  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  if(SD.begin(4) == 0)
  {
    Serial.println("SD init fail");          
  }

  Ethernet.begin(mac, ip, gateway, gateway, subnet); 
  delay(2000);

  Serial.println("Ready. Press f or r");
}

void loop()
{
  byte inChar;

  inChar = Serial.read();

  if(inChar == 'f')
  {
    if(doFTP()) Serial.println("FTP OK");
    else Serial.println("FTP FAIL");
  }

  if(inChar == 'r')
  {
    readSD();    
  }

}

File fh;

byte doFTP()
{
  SD.remove(fileName);
  fh = SD.open(fileName,FILE_WRITE);

  if(!fh)
  {
    Serial.println("SD open fail");
    return 0;    
  }

  Serial.println("SD open");
  
  if (client.connect(server,21)) {
    Serial.println("Command connected");
  } 
  else {
    fh.close();
    Serial.println("Command connection failed");
    return 0;
  }

  if(!eRcv()) return 0;

  client.write("USER ");
  client.write(user);
  client.write("\r\n");
  if(!eRcv()) return 0;

  client.write("PASS ");
  client.write(password);
  client.write("\r\n");
  if(!eRcv()) return 0;

  client.write("SYST\r\n");
  if(!eRcv()) return 0;

  client.write("TYPE I\r\n");
  if(!eRcv()) return 0;

  client.write("PWD\r\n");
  if(!eRcv()) return 0;

//  client.write("CWD ./htdocs\r\n");
//  client.write("PWD\r\n");
//  if(!eRcv()) return 0;

  client.write("PASV\r\n");
  if(!eRcv()) return 0;

  char *tStr = strtok(outBuf,"(,");
  int array_pasv[6];
  for ( int i = 0; i < 6; i++) {
    tStr = strtok(NULL,"(,");
    array_pasv[i] = atoi(tStr);
    if(tStr == NULL)
    {
      Serial.println("Bad PASV Answer");    

    }
  }

  unsigned int hiPort,loPort;

  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;
  
  Serial.print("Data port: ");
  hiPort = hiPort | loPort;
  Serial.println(hiPort);
  
  if (dclient.connect(server,hiPort)) {
    Serial.println("Data connected");
  } 
  else {
    Serial.println("Data connection failed");
    client.stop();
    fh.close();
    return 0;
  }

  client.write("RETR ");
  client.println(fileName);

  if(!eRcv())
  {
    dclient.stop();
    return 0;
  }

  while(dclient.connected())
  {
    while(dclient.available())
    {
      byte c = dclient.read();
      fh.write(c);      
      Serial.write(c); 
    }
  }

  fh.close();
  Serial.println("SD closed");

  dclient.stop();
  Serial.println("Data disconnected");
  
  client.write("QUIT\r\n");

  client.stop();
  Serial.println("Command disconnected");

  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;

  while(!client.available()) delay(1);

  respCode = client.peek();

  outCount = 0;
  
  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);

    if(outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;      
      outBuf[outCount] = 0;
    }
  }

  if(respCode >= '4')
  {
    efail();
    return 0;  
  }

  return 1;
}


void efail()
{
  byte thisByte = 0;

  client.write("QUIT\r\n");

  while(!client.available()) delay(1);

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }

  client.stop();
  Serial.println("Command disconnected");
  fh.close();
  Serial.println("SD closed");
}

void readSD()
{
  Serial.println("SD read");
  
  fh = SD.open(fileName,FILE_READ);

  if(!fh)
  {
    Serial.println("SD open fail");
    return;    
  }

  while(fh.available())
  {
    Serial.write(fh.read());
  }
  
  fh.close();
  Serial.println("Done");
}

I have a prototype http (not https) script that downloads files from a web server to the SD.
Does text and graphics files like text, html, bmp and jpeg.
It uses the SdFat library to avoid the 8.3 filename format limit.
I'm still testing it. Having a challenge with virtual servers. Apache server on a RPi no problem.
Mega2560 and ethernet shield is what I'm using. Should fit on an Uno.
Interested in trying it?