Pages: 1 2 3 [4]   Go Down
Author Topic: List only *.csv files  (Read 3010 times)
0 Members and 1 Guest are viewing this topic.
East Anglia (UK)
Offline Offline
Faraday Member
**
Karma: 118
Posts: 4398
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What are the symptoms of the failure to load the sketch ?
Error messages ?
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Offline Offline
Full Member
***
Karma: 0
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have worked out the upload issues it was me bricking the Mega as it does not like uploading a sketch with the timeout library in it, lesson learned.

What I have got the sketch doing is checking for a network connection every time it sends a packet and if it fails it call the following command
Code:
byte FTPDroped()
{
  byte thisByte = 0;
  Serial.println("-----------------FTP Dropped !!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  dclient.stop();
  Serial.println("Data disconnected");
  client.write("QUIT\r\n");
  client.stop();
  Serial.println("Command disconnected");
  ufile.close();
  Serial.println("SD closed");
  return 0;
  void loop ();
}

The only issue is that keeps on cycling through ever packet and I need it stop and go back to the normal loop

pingfail
----------------- FTP Dropped !!!!!!!!!!!!!!!!!!!!!!!!!!!!
Data disconnected
Command disconnected
SD closed
Packet

Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

here is the full code

Code:
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SdFile.h>
#include <SPI.h>
#include <Ethernet.h>
#include <ICMPPing.h>

// comment out next line to write to SD from FTP server
#define FTPWRITE
#define error(s) error_P(PSTR(s))
SOCKET pingSocket = 0;

// this must be unique
byte mac[] = {
  0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 }; 

// change to your network settings
IPAddress ip( 192, 168, 3, 177 );   
IPAddress gateway( 192, 168, 3, 254 );
IPAddress subnet( 255, 255, 255, 0 );
byte pingAddr[] = {
  192,168,3,254}; // ip address to ping

// SD chip select pin
const uint8_t chipSelect = SS;

// file system object
SdFat sd;
SdFile uploadfile;
uint16_t count; // count of files
int const file_size =13;
char fname[file_size];
char dname[file_size];
//char file_list[13] = "10000219.CSV";
char fileName[13] = "10000221.CSV";
char *CSV_EXT = "CSV";
char pingbuffer [256];
#define SD_SELECT 4


/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile dfile;
SdBaseFile ufile;

// change to your server
//IPAddress server(serverName);
char serverName[] = "update.FTP.com";

EthernetClient client;
EthernetClient dclient;

char outBuf[128];
char outCount;
int CYCCount = 0;
byte pingcount=0;
byte pingfail=0;

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


ArduinoOutStream cout(Serial);
//...............errors..................
void error_P(const char* str) {
  PgmPrint("error: ");
  SerialPrintln_P(str);
  if (card.errorCode()) {
    PgmPrint("SD error: ");
    Serial.print(card.errorCode(), HEX);
    Serial.print(',');
    Serial.println(card.errorData(), HEX);
  }
  while(1);
}

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

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

  if(sd.begin(4) == 0)
  {
    Serial.println("SD init fail");         
  }
  PgmPrint("Free RAM: ");
  Serial.println(FreeRam());

  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  // if (!card.init(SPI_HALF_SPEED))

  pinMode(10, OUTPUT); // set the SS pin as an output (necessary!)
  digitalWrite(10, HIGH); // but turn off the W5100 chip!
  if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed!");

  // initialize a FAT volume
  if (!volume.init(&card)) error("vol.init failed!");

  PgmPrint("Volume is FAT");
  Serial.println(volume.fatType(),DEC);
  Serial.println();

  if (!root.openRoot(&volume)) error("openRoot failed");

  // list file in root with date and size
  PgmPrintln("Files found in root:");
  root.ls(LS_DATE | LS_SIZE);
  Serial.println();

  // Recursive list of all directories
  PgmPrintln("Files found in all dirs:");
  root.ls(LS_R);

  Serial.println();
  PgmPrintln("Done");


  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);
  delay(2000);
}

void loop()
{

  if ( CYCCount >= 1000)
  {
    bool pingRet;
    ICMPPing ping(pingSocket);
    pingRet = ping(3, pingAddr, pingbuffer);
    Serial.println(pingbuffer);
    if(pingRet) // Failure
    {
      Serial.println("pingSuccess");
      pingcount = pingcount +1;
    }
    else
    {
      Serial.println("pingfail");
      pingfail = pingfail +1; 
    }

    if (pingcount >=10)
    {
      Serial.println("FTP upload Started ");
      sd.vwd()->rewind();
      callfile();
      CYCCount = CYCCount =0;
      pingcount =pingcount =0;
    }

    if (pingfail >=1)
    {
      pingcount =pingcount =0;
      pingfail = pingfail =0; 
      CYCCount = CYCCount =0;
    }
  }

  Serial.println(CYCCount);
  CYCCount =CYCCount +1 ;
}






//***************************************** voids******************************************//
void callfile()
{
  Serial.println("Call File");
  count = 0;
  while (uploadfile.openNext(sd.vwd(), O_READ))
  { 
    if (uploadfile.isFile())
    {
      uploadfile.getFilename(fname);
      if (strcmp(CSV_EXT, &fname[strlen(fname)-strlen(CSV_EXT)]) == 0){
        Serial.print("Call File -----------------");     
        Serial.println(fname);
        doFTP();
        count++;
      }
    }
    delay (1000);
    uploadfile.close();
  }


}


void todelete()

  if (strcmp(fname,fileName) == 0){
    Serial.println("Working File");
    uploadfile.close();
  }
  else
  {
    uploadfile.close();
    if (dfile.open(&root, fname, O_RDWR))
      dfile.remove() ;
    Serial.println("----------------------------------------------------------->File To Be Deleted");
  }
}

byte doFTP()
{


  Serial.println("SD opened");

  if (client.connect(serverName,21)) {
    Serial.println("Command connected");
  }
  else {
    ufile.close();
    Serial.println("Command connection failed");
    return 0;
  }

  if(!eRcv()) return 0;

  client.write("USER username\r\n");  // change your username here

    if(!eRcv()) return 0;

  client.write("PASS password\r\n"); // change your password here

    if(!eRcv()) return 0;

  client.write("SYST\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(serverName,hiPort)) {
    Serial.println("Data connected");
  }
  else {
    Serial.println("Data connection failed");
    client.stop();
    ufile.close();
    return 0;
  }

  Serial.println("open file");
  ufile.open(fname,O_READ);

  client.write("STOR ");
  client.println(fname);

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

  Serial.println("Writing");
  byte clientBuf[64];
  int clientCount = 0;

  while(ufile.available())
  {

    clientBuf[clientCount] = ufile.read();
    clientCount++;

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

    }
  }

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


  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");

  ufile.close();
  Serial.println("SD closed");
  return 1;
  // todelete();
}




byte eRcv()
{
  Serial.println("Running Err Check");
  byte respCode;
  byte thisByte;
  Serial.print ("Response Code1 -");
  Serial.println (respCode);
  Serial.print ("byte Code1 - ");
  Serial.println (thisByte);
  while(!client.available()) delay(1);
  Serial.println("Past Delay");
  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;
    }
  }
  Serial.print ("Response Code");
  Serial.println (respCode);
  if(respCode >= '4')
  {
    efail();
    return 0; 
  }

  Serial.println("-----------------buffe ");
  return 1;
}

//*********************************** Standard Fail*************************************//
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");
  ufile.close();
  Serial.println("SD closed");

}


//*********************************** Ping Network*************************************//

void connectionConnect()
{

  ICMPPing ping(pingSocket);
  bool pingRet = ping(1, pingAddr, pingbuffer);
  //Serial.println(pingbuffer);
  if(pingRet) // Check if ping is alive
  {
    Serial.println("pingSuccess");
  }
  else
  {
    Serial.println("pingfail");
    FTPDroped();
  }

}


//*********************************** Interrupt Fail*************************************//

byte FTPDroped()
{
  byte thisByte = 0;
  Serial.println("----------------- FTP Dropped !!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  dclient.stop();
  Serial.println("Data disconnected");
  client.write("QUIT\r\n");
  client.stop();
  Serial.println("Command disconnected");
  ufile.close();
  Serial.println("SD closed");
  return 0;
  void loop ();
}




any ideas 
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

if I add a ICMP ping server command in the byte eRcv() part it just hangs it never continue the loop. any ideas why?
 

Code:
byte eRcv()
{
 ICMPPing ping(pingSocket);
  bool pingRet = ping(1, pingAddr, pingbuffer);
  //Serial.println(pingbuffer);
  if(pingRet) // Check if ping is alive
  { Serial.println("pingSuccess"); }
  else
  {
    Serial.println("pingfail");
    ftpfail= ftpfail=1;
    FTPDroped();
      }


Serial.println("Running Err Check");
  byte respCode;
  byte thisByte;
 Serial.print ("Response Code1 -");
  Serial.println (respCode);
   Serial.print ("byte Code1 - ");
  Serial.println (thisByte);
  while(!client.available()) delay(1);
Serial.println("Past Delay");
  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;
    }
  }
    Serial.print ("Response Code");
  Serial.println (respCode);
  if(respCode >= '4')
  {
    efail();
    return 0; 
  }

  Serial.println("-----------------buffe ");
  return 1;
}
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

okay I worked it out it was the erfail() hanging so I changed it to just bailout and it works a treat  smiley
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 652
Posts: 50861
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have worked out the upload issues it was me bricking the Mega as it does not like uploading a sketch with the timeout library in it, lesson learned.
That's not it. It doesn't like you (trying to) upload(ing) a sketch with this in it:
Code:
  Serial.println("-----------------FTP Dropped !!!!!!!!!!!!!!!!!!!!!!!!!!!!");
Three exclamation marks in a row trigger debug mode. The rest of the sketch is not then debug instructions.

Is that really necessary? Do all those dashes and exclamation marks add any value? The text "FTP Dropped" tells you all that you need to know. Hyperventilating over the dropped connection isn't going to help.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have worked out the upload issues it was me bricking the Mega as it does not like uploading a sketch with the timeout library in it, lesson learned.
I was trying to use the following watch dog timer.
http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html

Quote
  Serial.println("-----------------FTP Dropped !!!!!!!!!!!!!!!!!!!!!!!!!!!!");

This was really only  for debugging so I could see the FTP drop.

now I have it all working I just need to bring all the modules together.

Paul, thankyou for all your assistance.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If any one wants the full working code ( based on the original code from surfertim, only works in passive mode).

That does the follow
1. Work with sdfat library
2. Work with w5100
3. Check sd card for *.csv files but can be changed easily to .txt or what ever you want
4. Pings the FTP server and starts to upload the file and if connection drops it bailsout and restarts the cycle.
5. Pings the server with every packet it send then send the packet.
6. If completed successfully it will delete the file from the SD card unless it is the current working file.
7. Goes in to a loop currently counting to 1000 then check for the network connection.

Well it all seems to work a treat for me.. Thanks to everyone assistance. smiley

Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:

#include <SdFat.h>
#include <SdFatUtil.h>
#include <SdFile.h>
#include <SPI.h>
#include <Ethernet.h>
#include <ICMPPing.h>

// comment out next line to write to SD from FTP server
#define FTPWRITE
#define error(s) error_P(PSTR(s))
SOCKET pingSocket = 0;

// this must be unique
byte mac[] = {
  0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 }; 

// change to your network settings
IPAddress ip( 192, 168, 3, 177 );   
IPAddress gateway( 192, 168, 3, 254 );
IPAddress subnet( 255, 255, 255, 0 );
byte pingAddr[] = {192,168,3,254}; // ip address to ping

// SD chip select pinM
const uint8_t chipSelect = SS;

// file system object
SdFat sd;
SdFile uploadfile;
uint16_t count; // count of files
int const file_size =13;
char fname[file_size];
char dname[file_size];
//char file_list[13] = "10000219.CSV";
char fileName[13] = "10000221.CSV";
char *CSV_EXT = "CSV";
char pingbuffer [256];
#define SD_SELECT 4


/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile dfile;
SdBaseFile ufile;

// change to your server
//IPAddress server(serverName);
char serverName[] = "update.ftpserver.com"; // Change Server name

EthernetClient client;
EthernetClient dclient;

char outBuf[128];
char outCount;
int CYCCount = 0;
byte pingcount=0;
byte pingfail=0;
byte ftpfail=0;



ArduinoOutStream cout(Serial);
//...............errors..................
void error_P(const char* str) {
  PgmPrint("error: ");
  SerialPrintln_P(str);
  if (card.errorCode()) {
    PgmPrint("SD error: ");
    Serial.print(card.errorCode(), HEX);
    Serial.print(',');
    Serial.println(card.errorData(), HEX);
  }
  while(1);
}



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

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

  if(sd.begin(4) == 0)
  {
    Serial.println("SD init fail");         
  }
  PgmPrint("Free RAM: ");
  Serial.println(FreeRam());

  pinMode(10, OUTPUT); // set the SS pin as an output (necessary!)
  digitalWrite(10, HIGH); // but turn off the W5100 chip!
  if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed!");

  // initialize a FAT volume
  if (!volume.init(&card)) error("vol.init failed!");

  PgmPrint("Volume is FAT");
  Serial.println(volume.fatType(),DEC);
  Serial.println();

  if (!root.openRoot(&volume)) error("openRoot failed");

  // list file in root with date and size
  PgmPrintln("Files found in root:");
  root.ls(LS_DATE | LS_SIZE);
  Serial.println();

  // Recursive list of all directories
  PgmPrintln("Files found in all dirs:");
  root.ls(LS_R);

  Serial.println();
  PgmPrintln("Done");


  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);
  delay(2000);
}

void loop()
{

  if ( CYCCount >= 1000)
  {
    bool pingRet;
    ICMPPing ping(pingSocket);
    pingRet = ping(3, pingAddr, pingbuffer);
    Serial.println(pingbuffer);
    if(pingRet) // Failure
    {
      Serial.println("pingSuccess");
      pingcount = pingcount +1;
    }
    else
    {
      Serial.println("pingfail");
      pingfail = pingfail +1; 
    }

    if (pingcount >=10)
    {
      Serial.println("FTP upload Started ");
      sd.vwd()->rewind();
      callfile();
      CYCCount = CYCCount =0;
      pingcount =pingcount =0;
    }

    if (pingfail >=1)
    {
      pingcount =pingcount =0;
      pingfail = pingfail =0; 
      CYCCount = CYCCount =0;
    }
  }

  Serial.println(CYCCount);
  CYCCount =CYCCount +1 ;
}






//********************************************* Voids*****************************************************//
void callfile()
{
  Serial.println("Call File");
  count = 0;
  while (uploadfile.openNext(sd.vwd(), O_READ))
  { 
    if (uploadfile.isFile())
    {
      uploadfile.getFilename(fname);
      if (strcmp(CSV_EXT, &fname[strlen(fname)-strlen(CSV_EXT)]) == 0){
        Serial.print("Call File -----------------");     
        Serial.println(fname);
        doFTP();
        count++;
      }
    }
    delay (1000);
    uploadfile.close();
  }

  ftpfail = 0;

}

//----------------------------------------------------- Delete Not Current File---------------------------------------//
void todelete()

  if (strcmp(fname,fileName) == 0){
    Serial.println("Working File");
    uploadfile.close();
  }
  else
  {
    uploadfile.close();
    if (dfile.open(&root, fname, O_RDWR))
      dfile.remove() ;
    Serial.println("----------------->File To Be Deleted");
  }
}


//----------------------------------------------------- FTP Server Connection---------------------------------------//
byte doFTP()
{
  ICMPPing ping(pingSocket);
  bool pingRet = ping(1, pingAddr, pingbuffer);
  //Serial.println(pingbuffer);
  if(pingRet) // Check if ping is alive
  {
    Serial.println("pingSuccess");
  }
  else
  {
    Serial.println("pingfail");
    ftpfail= ftpfail=1;
  }
  Serial.println("SD opened");
  if (ftpfail==0){
    if (client.connect(serverName,21)) {
      Serial.println("Command connected");


    }
  }
  else {
    ufile.close();
    Serial.println("Command connection failed");
    return 0;
  }

  if(!eRcv()) return 0;

  client.write("USER username\r\n");  // change your username here

    if(!eRcv()) return 0;

  client.write("PASS password\r\n"); // change your password here

    if(!eRcv()) return 0;

  client.write("SYST\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(serverName,hiPort)) {
    Serial.println("Data connected");
  }
  else {
    Serial.println("Data connection failed");
    client.stop();
    ufile.close();
    return 0;
  }

  Serial.println("open file");
  ufile.open(fname,O_READ);

  client.write("STOR ");
  client.println(fname);

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

  Serial.println("Writing");
  byte clientBuf[64];
  int clientCount = 0;

  while(ufile.available())
  {

    clientBuf[clientCount] = ufile.read();
    clientCount++;

    if(clientCount > 63)
    {
      ICMPPing ping(pingSocket);
      bool pingRet = ping(1, pingAddr, pingbuffer);
      //Serial.println(pingbuffer);
      if(pingRet) // Check if ping is alive
      {
        Serial.println("pingSuccess");
      }
      else
      {
        Serial.println("pingfail");
        ftpfail= ftpfail=1;
        goto bailout;
        //FTPDroped();
      }
      Serial.println("Packet");
      dclient.write(clientBuf,64);
      clientCount = 0;

    }
  }

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

bailout:

  dclient.stop();
  Serial.println("Data disconnected");
  client.write("QUIT\r\n");
  client.stop();
  Serial.println("Command disconnected");
  ufile.close();
  Serial.println("SD closed");
  Serial.print("Ftp Status - ");
  Serial.println(ftpfail);
  if (ftpfail==0)
  {
    todelete();
  }
  return 1;

}


//----------------------------------------------------- FTP Errors---------------------------------------//

byte eRcv()
{
  Serial.println("Running Error Check");
  byte respCode;
  byte thisByte;
 // Serial.println (respCode);
 // Serial.println (thisByte);
  while(client.connected() && !client.available()) delay(1);
  respCode = client.peek();
    Serial.print ("Response Return -");
  Serial.println(respCode );
  outCount = 0;

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

    if(outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;     
      outBuf[outCount] = 0;
    }
  }
  Serial.print ("Response Code");
  Serial.println (respCode);
  if(respCode >= '4')
  { 
    Serial.println("-----------------Fail Response");
    FTPDroped();
    return 0; 
  }
  return 1;
}

//----------------------------------------------------- Ping Server---------------------------------------//

byte pingserver()
{
  ICMPPing ping(pingSocket);
  bool pingRet = ping(1, pingAddr, pingbuffer);
  if(pingRet) // Check if ping is alive
  {
    Serial.println("pingSuccess");
  }
  else
  {
    Serial.println("pingfail");
    ftpfail= ftpfail=1;
  }
}

//----------------------------------------------------- FTP Fail & Quit---------------------------------------//
byte FTPDroped()
{
  Serial.println("-----------------FTP Dropped");
  dclient.stop();
  Serial.println("Data disconnected");
  client.write("QUIT\r\n");
  client.stop();
  Serial.println("Command disconnected");
  ufile.close();
  Serial.println("SD closed");
  return 0;
}




Logged

Pages: 1 2 3 [4]   Go Up
Jump to: