FTP - I can get it to work over LAN - I want it over Wifi - I'm close - help!

Hello. I am only a beginner at Arduino. I have searched the net and forums for FTP over wifi but there doesnt seem to be much out there. Based on this page http://playground.arduino.cc/Code/FTP I got an freetronics Etherten to upload a file off an SD card to my webspace. I will put this code first below. The only real modification i made to that code was to hardcode the inChar value to ‘f’ so i didnt have to put an f value and send in on the serial monitor (so nothing really). The other little mod was add a second server ip as my webserver returns a different ip for the data connection for ftp. The output from the serial monitor is the second lot of text i’ll put below.

The only modifications I made to the first code to get it to work over Wifi is just what you need to make the Wifi connnection. This code will be the third text I put below. The program runs a fair way through and only stops about when it comes time to write the data in packets up to the server. I’ll put the serial monitor code below. It is frustrating that I can get through all the parts i consider difficult but the part I thought would work easily (the file transfer) is what seems to be stuffing me up (it could be something else mind you). The Wifi setup is and Arduino Uno with an Arduino Wifi Shield attached.

/*
   FTP passive client for IDE v1.0.1 and w5100/w5200
   Posted October 2012 by SurferTim
*/

#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
// comment out next line to write to SD from FTP server
#define FTPWRITE
  byte inChar;
// this must be unique
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 };  

// change to your network settings
IPAddress ip( 192, 168, 1, 109 );    
IPAddress gateway( 192, 168, 1, 254 );
IPAddress subnet( 255, 255, 255, 0 );

// change to your server
IPAddress server( 216, 74, 70, 96 );
IPAddress server2(xxx,xx,xxx,xx);
EthernetClient client;
EthernetClient dclient;

char outBuf[128];
char outCount;

// change fileName to your file (8.3 format!)
char fileName[13] = "datalog2.txt";

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

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

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

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);
  delay(2000);
 // Serial.println("Ready. Press f or r");
}

void loop()
{
//  byte inChar;
inChar = 'f';
  //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()
{
#ifdef FTPWRITE
  fh = SD.open(fileName,FILE_READ);
#else
  SD.remove(fileName);
  fh = SD.open(fileName,FILE_WRITE);
#endif

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

#ifndef FTPWRITE  
  if(!fh.seek(0))
  {
    Serial.println("Rewind fail");
    fh.close();
    return 0;    
  }
#endif

  Serial.println("SD opened");
  //if (client.connect(server,21)) {
  if (client.connect("ftp.rickc.id.au",21)) {
    Serial.println("Command connected");
  }
  else {
    fh.close();
    Serial.println("Command connection failed");
    return 0;
  }

  if(!eRcv()) return 0;

  client.write("USER xxxx\r\n");

  if(!eRcv()) return 0;

  client.write("PASS xxxx\r\n");

  if(!eRcv()) return 0;

  client.write("SYST\r\n");
  Serial.println("syst command sent");
  if(!eRcv()) return 0;
  
  client.write("CWD /www/temp\r\n");

  if(!eRcv()) return 0;

  client.write("PASV\r\n");
  Serial.println("PASV command sent");
  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;
  
  Serial.println(array_pasv[4]);
  Serial.println(array_pasv[5]);

  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;

  Serial.print("Data port: ");
  hiPort = hiPort | loPort;
  Serial.println(hiPort);

  if (dclient.connect(server2,hiPort)) {
    Serial.println("Data connected");
  }
  else {
    Serial.println("Data connection failed");
    client.stop();
    fh.close();
    return 0;
  }

#ifdef FTPWRITE
  client.write("STOR ");
  client.println(fileName);
#else
  client.write("RETR ");
  client.println(fileName);
#endif

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

#ifdef FTPWRITE
  Serial.println("Writing");

  byte clientBuf[64];
  int clientCount = 0;

  while(fh.available())
  {
    clientBuf[clientCount] = fh.read();
    clientCount++;

    if(clientCount > 63)
    {
      Serial.println("Packet");
      dclient.write(clientBuf,64);
      clientCount = 0;
    }
  }

  if(clientCount > 0) dclient.write(clientBuf,clientCount);

#else
  while(dclient.connected())
  {
    while(dclient.available())
    {
      char c = dclient.read();
      fh.write(c);      
      Serial.write(c);
    }
  }
#endif

  dclient.stop();
  Serial.println("Data disconnected");

  if(!eRcv()) return 0;

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

  if(!eRcv()) return 0;

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

  fh.close();
  Serial.println("SD closed");
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;

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

  respCode = client.peek();
  Serial.println(respCode);
  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()
{
  fh = SD.open(fileName,FILE_READ);

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

  while(fh.available())
  {
    Serial.write(fh.read());
  }

  fh.close();
}

Serial monitor output:
SD opened
Command connected
50
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 2 of 50 allowed.
220-Local time is now 08:56. Server port: 21.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.
51
331 User xxxx OK. Password required
50
230 OK. Current restricted directory is /
syst command sent
50
215 UNIX Type: L8
50
250 OK. Current directory is /www/temp
PASV command sent
50
227 Entering Passive Mode (xxx,xx,xxx,xx,135,230)
135
230
Data port: 34790
Data connected
49
150 Accepted data connection
Writing
Packet
Packet
.
.
Lots of packets……
.
.
Packet
Packet
Data disconnected
50
226-File successfully transferred
226 2.760 seconds (measured here), 3.77 Kbytes per second
50
221-Goodbye. You uploaded 11 and downloaded 0 kbytes.
221 Logout.
Command disconnected
SD closed
FTP OK

#include <WiFi.h>
#include <SD.h>
#include <SPI.h>

//#define FTPWRITE
byte mac[6] ;
//IPAddress ip( 192, 168, 1, 101 );    
IPAddress gateway( 192, 168, 1, 254 );
IPAddress subnet( 255, 255, 255, 0 );

// change to your server
IPAddress server( 216, 74, 70, 96 );
IPAddress server2(xxx,xx,xxx,xx);
WiFiClient client;
WiFiClient dclient;

char outBuf[128];
char outCount;

// change fileName to your file (8.3 format!)
char fileName[13] = "datalog.txt";

char ssid[] = "carmos network";                     // your network SSID (name) 
char key[] = "a1b2c3d4e5";       // your network key
int keyIndex = 1;                                // your network key Index number
int status = WL_IDLE_STATUS;                     // the Wifi radio's status

int count = 0; 
byte inChar;

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

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

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

    if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present"); 
    // don't continue:
    while(true);
  } 
  
  // attempt to connect to Wifi network:
  if ( status != WL_CONNECTED) { 
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:    
    status=WiFi.begin(ssid, keyIndex, key);
  
    // wait 10 seconds for connection:
    delay(3000);
  } 
  Serial.println("Connected to wifi");
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

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

void loop()
{
//  byte inChar;
inChar = 'f';
  //inChar = Serial.read();

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

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

}

File fh;

byte doFTP()
{
  Serial.println("doing doFTP");
#ifdef FTPWRITE
  fh = SD.open(fileName,FILE_READ);
#else
  SD.remove(fileName);
  fh = SD.open(fileName,FILE_WRITE);
#endif

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

#ifndef FTPWRITE  
  if(!fh.seek(0))
  {
    Serial.println("Rewind fail");
    fh.close();
    return 0;    
  }
#endif

  Serial.println("SD opened");
  //if (client.connect(server,21)) {
  if (client.connect("ftp.xxxx.id.au",21)) {
    Serial.println("Command connected");
  }
  else {
    fh.close();
    Serial.println("Command connection failed");
    return 0;
  }

  if(!eRcv()) return 0;

  client.write("USER xxxx\r\n");

  if(!eRcv()) return 0;

  client.write("PASS xxxx\r\n");

  if(!eRcv()) return 0;

  client.write("SYST\r\n");
  Serial.println("syst command sent");
  if(!eRcv()) return 0;
  
  client.write("CWD /www/temp\r\n");

  if(!eRcv()) return 0;

  client.write("PASV\r\n");
  Serial.println("PASV command sent");
  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;
  
  Serial.println(array_pasv[4]);
  Serial.println(array_pasv[5]);

  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;

  Serial.print("Data port: ");
  hiPort = hiPort | loPort;
  Serial.println(hiPort);

  if (dclient.connect(server2,hiPort)) {
    Serial.println("Data connected");
  }
  else {
    Serial.println("Data connection failed");
    client.stop();
    fh.close();
    return 0;
  }

#ifdef FTPWRITE
  client.write("STOR ");
  client.println(fileName);
#else
  client.write("RETR ");
  client.println(fileName);
#endif

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

#ifdef FTPWRITE
  Serial.println("Writing");

  byte clientBuf[64];
  int clientCount = 0;

  while(fh.available())
  {
    clientBuf[clientCount] = fh.read();
    clientCount++;

    if(clientCount > 63)
    {
      Serial.println("Packet");
      dclient.write(clientBuf,64);
      clientCount = 0;
    }
  }

  if(clientCount > 0) dclient.write(clientBuf,clientCount);

#else
  while(dclient.connected())
  {
    while(dclient.available())
    {
      char c = dclient.read();
      fh.write(c);      
      Serial.write(c);
    }
  }
#endif

  dclient.stop();
  Serial.println("Data disconnected");

  if(!eRcv()) return 0;

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

  if(!eRcv()) return 0;

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

  fh.close();
  Serial.println("SD closed");
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;

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

  respCode = client.peek();
  Serial.println(respCode);
  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()
{
  fh = SD.open(fileName,FILE_READ);

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

  while(fh.available())
  {
    Serial.write(fh.read());
  }

  fh.close();
}

Serial monitor output
Attempting to connect to SSID: carmos network
Connected to wifi
SSID: carmos network
about to doFTP
doing doFTP
SD opened
Command connected
50
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 3 of 50 allowed.
220-Local time is now 09:04. Server port: 21.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.
51
331 User xxxx OK. Password required
50
230 OK. Current restricted directory is /
syst command sent
50
215 UNIX Type: L8
50
250 OK. Current directory is /www/temp
PASV command sent
50
227 Entering Passive Mode (xxx,xx,xxx,xx,130,187)
130
187
Data port: 33467
Data connected

Looks like it is doing ok until the sketch tries to read/write to the data port. If you are using an Uno, you will be right on the ragged edge of running out of memory, especially SRAM.

Try using the F() function to reduce the amount of SRAM your code uses. This function keeps the static strings in program memory. Use it like this.

    Serial.println(F("WiFi shield not present"));

Do the same to all the static strings in your code. Does that help?

Whoa! I never expected a reply this quick and it appears to be from the man who created the original FTP code no less!

I'll try that solution tommorrow morning surfer tim, I've been working on this stuff for a good 16hrs today and I'm stuffed!

I thought memory shortage might be an issue, in which case, would using a mega solve it?

Cheers for the help, Rick

I use a Mega for stuff like this. It has 4 times the SRAM, but I still use the F() function now. No sense wasting the SRAM. I might need it later.

If you are using an Uno or Uno-like processor, that FTP code is about all you can upload, so if you want to have it along with any other code, use a Mega. Just my opinion.

Gday again Tim, I looked at a Freetronics EtherMega which i can get locally but that wont work with the wifi shield. So I've ordered a normal Arduino Mega that should be here in about ten days. I'll upload the program when it gets here and report back on how it goes.

Thanks for your help.

Rick

Hey, I got the mega and tried that and used the static strings but the program hung at the same point ]:D

I was still wondering if it might be memory related (but far less likely now with the mega) so I pulled out all references to the SD library and instead of uploading a file I coded in so that it would send up one byte into the file after the stor command using dclient.write(64) This still didnt work. So I thought I'd test the same idea on the mega with ethernet rather than wifi. It works no problem, the file is there on the server with a little @ (ASCII number 64) symbol in it.

I looked through what happens in the text line section when I use FTPCommander to do basically the same action as I'm trying to do with the arduino. It mentions a time taken to do the file transfer, so I wondered if that might be a place to start looking.

So I put some code in to try and see what is happening with the connections. If i put the stor command in but then do nothing after it (or attempt to write a single byte as above) the data connection and more suprisingly the command connection both stop after about 6 seconds. If I do everything else up to but dont do the stor command, then the data and command connection will happily stay open for a while, I havent checked to see how long exactly, but at least 15 seconds, that's as far as I tested.

I'm wondering if the stor command needs to have the data written in a short time span after the command is issued and that the wifi might perhaps be too slow???

Anyone have any ideas?

I'm going to keep testing and trying stuff today. I'd really love to be able to get this off my list, I had 3 arduino projects I wanted to do and I've got the other two done and this one peeves me that I can get so close with everything working over ethernet fine, but I dont want to have ethernet cables running all over the place to my arduinos with sensors connected, would love to log sensor data and ftp it up to server via wifi.

rick_storm_opal: the wifi might perhaps be too slow???

This seems unlikely. I don't recall reading of any timeouts other than the overall session timeout (typically tens of minutes) and I've used FTP over excruciatingly slow links taking far longer than six seconds per command. I haven't looked at your symptoms in detail, but could you clarify what part of the behaviour is wrong? If I understood you right the trace output is completing the FTP sequence and reporting a successful upload.

Why did you comment out this in your code?

//#define FTPWRITE

Spatula, Originally I was trying to do it on an Uno and I suspected memory to be the issue. So I was looking for ways to use as little memory as possible. So I started commenting out anything relating to using the SD library and functions, as I wanted to debug purely the Wifi network communications rather than the SD side of things, the FTP_WRITE as far as I know was only a switch in the program that either writes a file up to the file server or else reads one down from the server.

Cheers, Rich.

rick_storm_opal: Spatula, Originally I was trying to do it on an Uno and I suspected memory to be the issue. So I was looking for ways to use as little memory as possible. So I started commenting out anything relating to using the SD library and functions, as I wanted to debug purely the Wifi network communications rather than the SD side of things, the FTP_WRITE as far as I know was only a switch in the program that either writes a file up to the file server or else reads one down from the server.

Cheers, Rich.

Hi Rich, it's probably time for me to take a nap, but aren't you trying to transmit a file up to the server? If you look in the code you will find statements such as

#ifdef FTPWRITE
// not to be confused with #ifndef FTPWRITE, which does the opposite

If FTPWRITE is not defined, the following actions until #endif are not executed (they aren't even compiled).

Well, I subtracted out everything to do with the SD card library and just made a mockup of a file write / upload in the code. The binary file size is typically 12KB. I tested it with a mega over ethernet and it works fine. But I still get the same probs when I try to do the same thing over Wifi, it works fine but hangs when i try to write. I tried also to use read (RETR) but that didnt work either. I think this problem is over my head, I reckon its buried down in the library files and how they work over wifi versus over ethernet and the 5100 chipset. I can’t find many (any!) references to someone having successfully done ftp over wifi so I don’t think i’m alone being stuck - it would be really great to get it resolved though as it would be a boon to many people’s projects.

Here’s my code and the serial monitor outputs, for the ethernet first and then for wifi:

/* code for ftp over ethernet minus anything to do with
SD library - instead we just upload a bogus file with one 
byte in it which is done  by the coding
*/

#include <SPI.h>
#include <Ethernet.h>
// comment out next line to write to SD from FTP server
  byte inChar;
// this must be unique
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 };  

// change to your network settings
IPAddress ip( 192, 168, 1, 109 );    
IPAddress gateway( 192, 168, 1, 254 );
IPAddress subnet( 255, 255, 255, 0 );

// change to your server
IPAddress server( xxx, xx, xxx, xx );
IPAddress server2(x,x,x,x);
EthernetClient client;
EthernetClient dclient;

char outBuf[128];
char outCount;
int count = 0;
// change fileName to your file (8.3 format!)
char fileName[13] = "bogus.txt";
byte respCode;
byte thisByte;

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

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

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);
  delay(2000);
}
//long hand code ie no calls
void loop()
{
  if (count<1)//put this in so code only runs once
  {
    if(client.connect("xxxxxx",21))
    {
      Serial.println("Command connected");
    }
    else
    {
      Serial.println("Command connection failed");
    }  
  //print out the command port response
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
  
  
  client.write("USER xxxx\r\n");

  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
  
  client.write("PASS xxx\r\n");  
  
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }  
  
  client.write("SYST\r\n");
  
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }  
    
  client.write("CWD /www/temp\r\n");

  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }    
  
  client.write("PASV\r\n");
  Serial.println("PASV command sent");
  
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;
  
  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  
   if(outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;    
      outBuf[outCount] = 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;
  
  Serial.println(array_pasv[4]);
  Serial.println(array_pasv[5]);

  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;

  Serial.print("Data port: ");
  hiPort = hiPort | loPort;
  Serial.println(hiPort);

  if (dclient.connect(server2,hiPort))
  {
    Serial.println("Data connected");
  }
  else 
    {
    Serial.println("Data connection failed");
    client.stop();
    }
  
  client.write("STOR ");
  client.println(fileName);
  Serial.println("Writing");
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  } 
  
  
    
  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"); 
  delay(2500);
  Serial.println("delay window before starting");  
  }    
delay(2500);  
count = count+1;
//Serial.println(count);
}

serial monitor output

Command connected
50
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 1 of 50 allowed.
220-Local time is now 05:01. Server port: 21.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.
51
331 User xxxx OK. Password required
50
230 OK. Current restricted directory is /
50
215 UNIX Type: L8
50
250 OK. Current directory is /www/temp
PASV command sent
50
227 Entering Passive Mode (x,x,x,x,x,x)
128
220
Data port: 32988
Data connected
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
Writing
49
150 Accepted data connection
426 Transfer aborted
226-Transfer aborted
226 0.364 seconds (measured here), 16.47 bytes per second
Command disconnected
delay window before starting

Note:even though it says transfer aborted there at the bottom it still works - I can go on to my website and see the file there that wasnt there before and that has the correct bytes in it.

Here’s the wifi code. Its pretty much identical except with the Wifi connection at the start. I will include two serial monitor outputs. The first will be for this exact code, however there is some commented out code in here just after STOR command, the second serial monitor output will be if that code is uncommented. It seems like either the data connection or the STOR command seem to upset the control connection, because you wont get command client available return true after the data connection is made, which is strange. You can see in the ethernet version its not available for a few thousands of a second, but then it becomes available and everything flows smoothly after that, but with wifi it never becomes available at all.

/* code for ftp over wifi minus anything to do with
SD library - instead we just upload a bogus file with a few
bytes in it which is done  by the coding
*/

#include <SPI.h>
#include <WiFi.h>
// comment out next line to write to SD from FTP server

  byte inChar;
// this must be unique
byte mac[6] ;

// change to your network settings
IPAddress ip( 192, 168, 1, 109 );    
IPAddress gateway( 192, 168, 1, 254 );
IPAddress subnet( 255, 255, 255, 0 );

// change to your server
IPAddress server( x,x,x,x );
IPAddress server2(x,x,x,x);
WiFiClient client;
WiFiClient dclient;

char outBuf[128];
char outCount;
int count = 0;
// change fileName to your file (8.3 format!)
char fileName[13] = "bogus2.txt";
byte respCode;
byte thisByte;
char ssid[] = "carmos network";                     // your network SSID (name) 
char key[] = "a1b2c3d4e5";       // your network key
int keyIndex = 1;                                // your network key Index number
int status = WL_IDLE_STATUS;  


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

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

  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present"); 
    // don't continue:
    while(true);
  } 
  
  // attempt to connect to Wifi network:
  if ( status != WL_CONNECTED) { 
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:    
    status=WiFi.begin(ssid, keyIndex, key);
  
    // wait 10 seconds for connection:
    delay(3000);
  } 
  Serial.println("Connected to wifi");
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
}
//long hand code ie no calls for ftp
void loop()
{
  if (count<1)//put this in so code only runs once
  {
    if(client.connect("xxxxxxx",21))
    {
      Serial.println("Command connected");
    }
    else
    {
      Serial.println("Command connection failed");
    }  
  //print out the command port response
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
  
  
  client.write("USER xxxx\r\n");

  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
  
  client.write("PASS xxxx\r\n");  
  
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }  
  
  client.write("SYST\r\n");
  
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }  
    
  client.write("CWD /www/temp\r\n");

  while(!client.available()) delay(1);
  
  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }    
  
  client.write("PASV\r\n");
  Serial.println("PASV command sent");
  
  while(!client.available()) delay(1);
  
  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;
  
  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  
   if(outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;    
      outBuf[outCount] = 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;
  
  Serial.println(array_pasv[4]);
  Serial.println(array_pasv[5]);

  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;

  Serial.print("Data port: ");
  hiPort = hiPort | loPort;
  Serial.println(hiPort);

  if (dclient.connect(server2,hiPort))
  {
    Serial.println("Data connected");
    
  }
  else 
    {
    Serial.println("Data connection failed");
    client.stop();
    }
  
 
  client.write("STOR ");
  client.println(fileName);
  
 /* 
  while(!dclient.available())
  {delay(1);//while client not available wait a little bit
  Serial.println("client issues");
  }
  */
  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  } 
  
  Serial.println("Writing");
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  dclient.write(64);
  Serial.println("end writing");
 
  while(!client.available()) delay(1);//while client not available wait a little bit

  respCode = client.peek();
  Serial.println(respCode);
  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  } 
  
 
    
  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"); 
      
  delay(2500);
  Serial.println("delay window before starting");  
  }    
delay(2500);  
count = count+1;
//Serial.println(count);
}

Serial monitor output 1:

Attempting to connect to SSID: carmos network
Connected to wifi
SSID: carmos network
Command connected
50
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 2 of 50 allowed.
220-Local time is now 04:54. Server port: 21.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.
51
331 User xxxx OK. Password required
50
230 OK. Current restricted directory is /
50
215 UNIX Type: L8
50
250 OK. Current directory is /www/temp
PASV command sent
50
227 Entering Passive Mode (x,x,x,x,x,x)
119
43
Data port: 30507
Data connected
255
Writing
end writing

Serial monitor output 2:

Attempting to connect to SSID: carmos network
Connected to wifi
SSID: carmos network
Command connected
50
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 2 of 50 allowed.
220-Local time is now 04:56. Server port: 21.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.
51
331 User xxxx OK. Password required
50
230 OK. Current restricted directory is /
50
215 UNIX Type: L8
50
250 OK. Current directory is /www/temp
PASV command sent
50
227 Entering Passive Mode (x,x,x,x,x,x)
136
162
Data port: 34978
Data connected
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues
client issues forever and ever…

One other question, but does anyone have some definite info on how you are supposed to connect the wifi shield to the mega? For example, do I just push it on and thats it, or do I have to have jumpers from 50,51,52 to 11,12,12 for spi? Do I have to put pin 53 to output in the code for the mega?

Thanks

Seeyas.

I can see a few ways you could tackle this.

Firstly, in the FTP library I suggest you find out what "client issues" means. Is that an error message? Also find out why the 'successful' attempt is ending with the transfer aborted. It suggests the client and server are not cooperating properly.

Secondly, look at the network traffic in the successful (Ethernet) and unsuccessful (WiFi) cases and see what's different. The FTP protocol is pretty clear and well documented and you should be able to follow it with Wireshark or similar.

Which way is the transfer? If you are using "STOR", then it should be transferring from the SD to the FTP server. After you send the "STOR filename", you should wait for a response on the command channel (client), not the data channel (dclient). That seems to be where the "client issues" is being printed if nothing on the data channel. But there won't be anything received (inbound) on the data channel. The FTP server is waiting for the Arduino to send on the data channel.

edit: Other than that, it sounds like you have it working now. If so, congrats! That was no easy feat. I am impressed. :)

You must evaluate the command channel response from the FTP server after sending either "STOR filename" or "RECV filename". The ability to log in to the server does not guarantee write or read permissions for every file in that directory.

PeterH: I can see a few ways you could tackle this.

Firstly, in the FTP library I suggest you find out what "client issues" means. Is that an error message? Also find out why the 'successful' attempt is ending with the transfer aborted. It suggests the client and server are not cooperating properly.

Secondly, look at the network traffic in the successful (Ethernet) and unsuccessful (WiFi) cases and see what's different. The FTP protocol is pretty clear and well documented and you should be able to follow it with Wireshark or similar.

Gday Peter, Thanks for your suggestions, I'll have a look at what Wireshark is and see if I can find anything out from that. If you have any further info you could add to expand on how to "look at network traffic" id be grateful.

The client issues is just an error message I put into the program to write to the serial monitor if the command connection [via client.available()] was not returning true. Part of my fault finding process.

The abort is because I didnt wind up the communication correctly out of laziness (but I have worked on this for many hours so hopefully you appreciate where I'm coming from :) ), but even with that message being sent the wifi version still works fine.

Cheers, Rich.

SurferTim: Which way is the transfer? If you are using "STOR", then it should be transferring from the SD to the FTP server. After you send the "STOR filename", you should wait for a response on the command channel (client), not the data channel (dclient). That seems to be where the "client issues" is being printed if nothing on the data channel. But there won't be anything received (inbound) on the data channel. The FTP server is waiting for the Arduino to send on the data channel.

edit: Other than that, it sounds like you have it working now. If so, congrats! That was no easy feat. I am impressed. :)

You must evaluate the command channel response from the FTP server after sending either "STOR filename" or "RECV filename". The ability to log in to the server does not guarantee write or read permissions for every file in that directory.

Hey Tim, I havent got it yet :(

I can do the ethernet with my eyes closed now.

Still cant do via WIFI.

Can you expand on the "command channel response" from FTP server bit, what would I be looking for?

Have you ever successfully done FTP over Wifi tim? Or does anyone know anyone who has?

Cheers, Rich.

Have you ever successfully done FTP over Wifi tim? Or does anyone know anyone who has?

No. I have an ethernet shield only. Normally, the transport is not a problem. I use fiber-optic, wireless, and CAT5 on some connections and they work fine. The transport layer is supposed to be transparent to the protocol, and on my systems, it is.

That does not mean the wifi shield does not have limitations. I have not looked at the actual hardware on the shield. The manufacturer wants me to register to get the datasheet, but I get enough spam mail now, and don't need any more advertising. I wanted to check if it had multiple sockets available like the w5100. The w5100 has 4, so this is not a problem for it, but may affect the wifi.

Network speed should not be a problem. I inserted Serial.println("Packet") and delay() statements into the loop to test that, and there was no problem if the delay was less than about 10 seconds.

edit: This appears to be where your code fails. This is the first send attempt on the command port after the data port is opened, so I guess the wifi shield may have a problem with multiple sockets open simultaneously.

#ifdef FTPWRITE 
  client.write("STOR ");
  client.println(fileName);
#else
  client.write("RETR ");
  client.println(fileName);
#endif

I do use wireless devices to connect my ethernet shield to the internet. This is my fav. http://routerboard.com/RB433UAH It not only provides wireless, but also usb power AND a way to connect to the serial monitor remotely through a ssh connection.

Wireshark is an application you can use to record and display network traffic on the local network segment. Ideally, you would display this on the FTP server. If you don't have access to that then you might want to do your testing against a local FTP server that you do have control over. With Wireshark running you should be able to see the control and data sockets connecting and then filter the display to show the packets sequences on those two connections. You should be able to recognise the control commands and responses easily enough, and also see your file content being carried over the data stream.

I suggest you try to get the 'working' case squeaky clean so that it follows the FTP protocol exactly and succeeds without provoking any errors.

Then do the same with the WiFi hardware and see how the network traffic differs.

I don't know how much or the protocol stack is implemented within your WiFi shield, but I suppose it's possible it imposes some artificial limitations on the use of concurrent sockets. The use of dual sockets by FTP is slightly unusual and it may be the shield/library designers didn't support that for some reason. But I'd keep investigating until you can see where the problem is - it could easily be something more mundane that you can fix.