Hello!!
Project Info : I am uploading a .csv file to a remote FTP server using ESP8266 nodemcu as a FTP client.I am using LittleFS file system to make a file, append it and then send it to the remote FTP server.I am able to upload the file to the server but sometimes ESP8266 restarts and write garbage data to it (Note : before it restarts, it throws an exception (28) )
This is my code :
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <Arduino.h>
/*------------------------------------------------------
LIBRARIES
--------------------------------------------------------*/
#include<LittleFS.h>
#include <ESP8266WiFi.h>
//FTP server details
/*
char* xhost = ; //synology diskstation
char* xusername = ;
char* xpassword = ;
char* xfolder = ;
*/
/*destination folder on FTP server
this is an optional parameter with the function prototype
defined below. To leave the default folder on the server
unchanged, either enter "" for xfolder or omit this param in
the function call in doFTP() */
//file to upload
char* xfilename = "file.csv";
short FTPresult; //outcome of FTP upload
/*------------------------------------------------------
* OBJECTS
--------------------------------------------------------*/
/*------------------------------------------------------
SETUP
--------------------------------------------------------*/
//Function prototype - required if folder is an optional argument
short doFTP(char* , char* , char* , char* , char* = "");
void setup()
{
//a one-time test to check it works
Serial.begin(9600);
delay(100);
//Wifi Setup
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println("Prima");
WiFi.begin("Prima","Prima1234");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("----------------------------------------");
//----------------------------------------------------
// LittleFS setup
LittleFS.begin();
// assumes that LittleFS exists and is formatted
//Open test file, write sample data to it
File f = LittleFS.open(xfilename, "a");
if (!f)
{
Serial.println("file open failed");
Serial.println("Sketch terminating...");
}
else
{
Serial.println("file data.txt exists in LittleFS");
//write sample data
f.println("Hello");
f.close();
//LittleFS.available()
//get and print contents of root folder
String str = "";
Dir dir = LittleFS.openDir("");
while (dir.next()) {
str += dir.fileName();
str += " / ";
str += dir.fileSize();
str += "\r\n";}
Serial.print(str);
Serial.println("--------------------------------");
//Attempt FTP upload
FTPresult = doFTP("65.2.20.165","primaftpuser","Primaftp@123",xfilename,"/FTPTest");
//What is the outcome?
Serial.println("A return code of 226 is success");
Serial.print("Return code = ");
Serial.println(FTPresult);
}
} //end setup
/*
------------------------------------------------------
* MAIN LOOP
-------------------------------------------------------- */
void loop()
{
LittleFS.begin();
delay(200);
File f = LittleFS.open(xfilename, "a");
if (!f)
{
Serial.println("file open failed");
Serial.println("Sketch terminating...");
}
else
{
Serial.println("file exists in LittleFS");
f.println("123");
delay(50);
f.close();
delay(200);
FTPresult = doFTP("<FTP server IP>","<user name>","<password>",xfilename,"/FTPTest");
}
delay(5000);
/* char* x1filename = "1_10.csv"; */
/*
LittleFS.remove(x1filename);
delay(100);
*/
}
/*------------------------------------------------------
* FUNCTION - doFTP
* Connects to a FTP server and transfers a file. Connection
* is established using the FTP commands/responses defined at
* https://en.wikipedia.org/wiki/List_of_FTP_commands or in
* more detail at http://www.nsftools.com/tips/RawFTP.htm
*
* Parameters passed:
* host - the IP address of the FTP server
* uname - username for the account on the server
* pwd - user password
* filename - the file to be transferred
* folder (optional) - folder on the server where
* the file will be copied. This is may be omitted if
* the file is to be copied into the default folder on
* the server.
*
* Return codes:
* 226 - a successful transfer
* 400+ - any return code greater than 400 indicates
* an error. These codes are defined at
* https://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
* Exceptions to this are:
* 900 - failed to open file on LittleFS
* 910 - failed to connect to server
*
* Dependencies:
* Libraries - <ESP8266WiFi.h> wifi library
* <FS.h> LittleFS library
* Functions - eRcv
--------------------------------------------------------*/
/*-------------------------------- -------------------*/
short eRcv(WiFiClient aclient, char outBuf[], int size)
{
byte thisByte;
char index;
String respStr = "";
while(!aclient.available()) delay(1);
index = 0;
while(aclient.available())
{
thisByte = aclient.read();
Serial.write(thisByte);
if(index < (size - 2)) { //less 2 to leave room for null at end
outBuf[index] = thisByte;
index++;}
} //note if return from server is > size it is truncated.
outBuf[index] = 0; //putting a null because later strtok requires a null-delimited string
//The first three bytes of outBuf contain the FTP server return code - convert to int.
for(index = 0; index < 3; index++) {respStr += (char)outBuf[index];}
return respStr.toInt();
} // end function eRcv
short doFTP(char* host, char* uname, char* pwd, char* fileName, char* folder)
{
WiFiClient ftpclient;
WiFiClient ftpdclient;
const short FTPerrcode = 400; //error codes are > 400
const byte Bufsize = 128;
char outBuf[Bufsize];
short FTPretcode = 0;
const byte port = 21; //21 is the standard connection port
File ftx = LittleFS.open(fileName, "r"); //file to be transmitted
if (!ftx)
{
Serial.println(F("file open failed"));
return 900;
}
if (ftpclient.connect(host,port))
{
Serial.println(F("Connected to FTP server"));
}
else
{
ftx.close();
Serial.println(F("Failed to connect to FTP server"));
return 910;
}
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
/* User - Authentication username
* Send this command to begin the login process. username should be a
* valid username on the system, or "anonymous" to initiate an anonymous login.
*/
//------------------------ ------------------------------------------
ftpclient.print("USER ");
ftpclient.println(uname);
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
/* PASS - Authentication password
* After sending the USER command, send this command to complete
* the login process. (Note, however, that an ACCT command may have to be
* used on some systems, not needed with synology diskstation)
*/
//------------------------ ------------------------------------------
ftpclient.print("PASS ");
ftpclient.println(pwd);
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
//CWD - Change the working folder on the FTP server
if(!(folder == "")) {
ftpclient.print("CWD ");
ftpclient.println(folder);
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) {return FTPretcode;} }
/* SYST - Returns a word identifying the system, the word "Type:",
* and the default transfer type (as would be set by the
* TYPE command). For example: UNIX Type: L8 - this is what
* the diskstation returns
*/
//------------------------ ------------------------------------------
ftpclient.println("SYST");
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
/* TYPE - sets the transfer mode
* A - ASCII text
* E - EBCDIC text
* I - image (binary data)
* L - local format
* for A & E, second char is:
* N - Non-print (not destined for printing). This is the default if
* second-type-character is omitted
* Telnet format control (<CR>, <FF>, etc.)
* C - ASA Carriage Control
*/
//------------------------ ------------------------------------------
ftpclient.println("Type I");
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
/* PASV - Enter passive mode
* Tells the server to enter "passive mode". In passive mode, the server
* will wait for the client to establish a connection with it rather than
* attempting to connect to a client-specified port. The server will
* respond with the address of the port it is listening on, with a message like:
* 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2), e.g. from diskstation
* Entering Passive Mode (192,168,0,5,217,101)
*/
//------------------------ ------------------------------------------
ftpclient.println("PASV");
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
/* This is parsing the return from the server
* where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
*/
char *tStr = strtok(outBuf,"(,"); //chop the output buffer into tokens based on the delimiters
int array_pasv[6];
for ( int i = 0; i < 6; i++) { //there are 6 elements in the address to decode
tStr = strtok(NULL,"(,"); //1st time in loop 1st token, 2nd time 2nd token, etc.
array_pasv[i] = atoi(tStr); //convert to int, why atoi - because it ignores any non-numeric chars
//after the number
if(tStr == NULL) {Serial.println(F("Bad PASV Answer"));}
}
//extract data port number
unsigned int hiPort,loPort;
hiPort=array_pasv[4]<<8; //bit shift left by 8
loPort=array_pasv[5]&255;//bitwise AND
Serial.print(F("Data port: "));
hiPort = hiPort|loPort; //bitwise OR
Serial.println(hiPort);
//first instance of dftp
if(ftpdclient.connect(host, hiPort))
{
Serial.println(F("Data port connected"));
}
else
{
Serial.println(F("Data connection failed"));
ftpclient.stop();
ftx.close();
}
/* STOR - Begin transmission of a file to the remote site. Must be preceded
* by either a PORT command or a PASV command so the server knows where
* to accept data from
*/
ftpclient.print("STOR ");
ftpclient.println(fileName);
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) {
ftpdclient.stop();
return FTPretcode; }
Serial.println(F("Writing..."));
byte clientBuf[64];
int clientCount = 0;
while(ftx.available())
{
clientBuf[clientCount] = ftx.read();
clientCount++;
if(clientCount > 63)
{
ftpdclient.write((const uint8_t *)clientBuf, 64);
clientCount = 0;
}
}
if(clientCount > 0) ftpdclient.write((const uint8_t *)clientBuf, clientCount);
ftpdclient.stop();
Serial.println(F("Data disconnected"));
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) {return FTPretcode; }
//End the connection
ftpclient.println("QUIT");
ftpclient.stop();
Serial.println(F("Disconnected from FTP server"));
ftx.close();
Serial.println(F("File closed"));
return FTPretcode;
} // end function doFTP
/*------------------------------------------------------
* FUNCTION - eRcv
* Reads the response from an FTP server and stores the
* output in a buffer.Extracts the server return code from
* the buffer.
*
* Parameters passed:
* aclient - a wifi client connected to FTP server and
* delivering the server response
* outBuf - a buffer to store the server response on
* size - size of the buffer in bytes
*
* Return codes:
* These are the first three chars in the buffer and are
* defined in
* https://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
*
* Dependencies:
* Libraries - <ESP8266WiFi.h> wifi library
* Functions - none
--------------------------------------------------------*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
This is the error i am receiving :
15:02:34.793 ->
15:02:34.793 -> Exception (28):
15:02:34.793 -> epc1=0x402107ae epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
15:02:34.888 ->
15:02:34.888 -> >>>stack>>>
15:02:34.935 ->
15:02:34.935 -> ctx: cont
15:02:34.935 -> sp: 3ffffbc0 end: 3fffffc0 offset: 0190
15:02:34.982 -> 3ffffd50: 0000007e 00000003 3ffffdc0 4020e138
15:02:35.028 -> 3ffffd60: 00000030 3ffe8368 3ffef67c 402091c0
15:02:35.075 -> 3ffffd70: 40207b8c 3ffffe40 000000c8 40205482
15:02:35.122 -> 3ffffd80: 00000000 3ffe8905 00000000 3fffff0c
15:02:35.169 -> 3ffffd90: 0000018f 3fffff24 3ffee854 40210910
15:02:35.216 -> 3ffffda0: 3fffdad0 3ffe85c8 3ffee854 4020e110
15:02:35.311 -> 3ffffdb0: 0000018f 3fffff24 3ffee854 40205740
15:02:35.357 -> 3ffffdc0: 20303032 65707954 74657320 206f7420
15:02:35.404 -> 3ffffdd0: 000a0d49 6c694620 6c695a65 0a0d616c
15:02:35.451 -> 3ffffde0: 75632000 6e657272 69642074 74636572
15:02:35.498 -> 3ffffdf0: 2e79726f 67000a0d 46207265 40005054
15:02:35.545 -> 3ffffe00: 00000000 00000000 00000000 00000000
15:02:35.592 -> 3ffffe10: 00000000 40204518 3ffffe6c 00000000
15:02:35.639 -> 3ffffe20: 00000001 00001fc0 500ffc30 ffffffff
15:02:35.685 -> 3ffffe30: 00001f80 00001ff8 500ffc30 ffffffff
15:02:35.779 -> 3ffffe40: 4020cdc4 00000000 00001388 00001f80
15:02:35.863 -> 3ffffe50: 00000000 00000000 3ffefeec 00000000
15:02:35.873 -> 3ffffe60: 00000000 00000000 00000000 3ffef57c
15:02:35.920 -> 3ffffe70: 3ffffe20 3fff03c4 00000008 3ffef57c
15:02:35.966 -> 3ffffe80: 4020ce40 00000000 000003e8 3ffef5f4
15:02:36.013 -> 3ffffe90: 00000000 3ffefddc 3ffefdcc 40206470
15:02:36.060 -> 3ffffea0: 00000000 00000000 3ffee80c 401006bf
15:02:36.107 -> 3ffffeb0: 37400008 3fffff30 37400000 3ffee8e0
15:02:36.153 -> 3ffffec0: 3fffdad0 00000020 3fff0314 4020cdc4
15:02:36.246 -> 3ffffed0: 00000000 00001388 3ffe85e0 00000000
15:02:36.293 -> 3ffffee0: 3ffffeec 00000000 00000000 4020cdc4
15:02:36.340 -> 3ffffef0: 00000000 00001388 3ffefdcc 00000000
15:02:36.387 -> 3fffff00: 00000000 3ffefeec 00000000 40213ce8
15:02:36.433 -> 3fffff10: 007a1200 dbcac153 3ffefd00 40213c74
15:02:36.480 -> 3fffff20: 401059fd 08d74734 3ffee944 00000000
15:02:36.526 -> 3fffff30: 3ffe886a 3ffe8937 3ffe8847 3ffe885d
15:02:36.573 -> 3fffff40: 3ffe8850 00000000 000000c8 40209368
15:02:36.620 -> 3fffff50: 40209a25 000000c8 3ffee8e0 3ffee8e0
15:02:36.714 -> 3fffff60: 3fffdad0 3ffe85c8 3ffee854 40205983
15:02:36.761 -> 3fffff70: 4020ce40 00000000 000003e8 00000000
15:02:36.808 -> 3fffff80: 00000000 00000000 00000000 40206470
15:02:36.883 -> 3fffff90: 00000000 00000000 3ffee80c 40100185
15:02:36.883 -> 3fffffa0: 3fffdad0 00000000 3ffee8cc 40209488
15:02:36.948 -> 3fffffb0: feefeffe feefeffe 3ffe85dc 40100b5d
15:02:36.994 -> <<<stack<<<
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
** This is the decoded version of exception i am receiving (for which i have used ESP Exception Decoder tool ) :**
Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
PC: 0x402107ae
EXCVADDR: 0x00000000
Decoding stack results
0x4020e138: atol at /workdir/repo/newlib/newlib/libc/stdlib/atol.c line 12
0x402091c0: String::toInt() const at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/WString.h line 277
0x40207b8c: WiFiClient::write(unsigned char const, unsigned int)* at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi\src*WiFiClient.cpp* line 213
0x40205482: eRcv(WiFiClient, char, int)* at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/WString.h line 79
0x40210910: strtol at /workdir/repo/newlib/newlib/libc/stdlib/../locale/setlocale.h line 237
0x4020e110: atoi at /workdir/repo/newlib/newlib/libc/stdlib/atoi.c line 52
0x40205740: doFTP(char, char, char*, char*, char*)** at C:\Users\PE-COM-14\Desktop\Hi_tech_backup\FTP1/FTP1.ino line 343
0x40204518: lfs_dir_commit_commit at c:\users\pe-com-14\appdata\local\arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\littlefs\lib\littlefs/lfs.c line 1560
0x40206470: fs::FS::_defaultTimeCB() at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/FS.h line 249
0x401006bf: umm_free_core(umm_heap_context_t, void)** at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266\umm_malloc*umm_malloc.cpp* line 549
0x40213ce8: operator delete(void)* at /workdir/repo/gcc-gnu/libstdc++-v3/libsupc++/del_op.cc line 49
0x40213c74: operator delete(void, unsigned int)* at /workdir/repo/gcc-gnu/libstdc++-v3/libsupc++/del_ops.cc line 33
0x40209368: __esp_yield() at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266*core_esp8266_main.cpp* line 116
0x40209a25: __delay(unsigned long) at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266*core_esp8266_wiring.cpp* line 55
0x40205983: loop() at C:\Users\PE-COM-14\Desktop\Hi_tech_backup\FTP1/FTP1.ino line 147
0x40206470: fs::FS::_defaultTimeCB() at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/FS.h line 249
0x40100185: esp_schedule() at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266*core_esp8266_main.cpp* line 128
0x40209488: loop_wrapper() at C:\Users\PE-COM-14\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266*core_esp8266_main.cpp* line 201
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
What could be the issue triggering exception??