So I am currently using the VS1053 board and photon to upload/download voice recordings from FTP server, and I have no problem receiving date information from server when creating new download files (with callback function) but I am having issues with accessing the creation (or modification date/time) for the files on my SD card for the purpose of a weekly cleanup function (If downloaded file is older than week…delete). Do I need to create another function within SD class that has access to some of the internal root items? Any help would be great.
@ScruffR
@peekay123
**I have used peekay123’s code for handling FTP communication and will post my full code at bottom.
Topic is similar to issue in: Sd card percent full function
#include "Adafruit_VS1053_Photon.h"
#include "sd-card-library-photon-compat.h"
#include <sd-fat.h>
#define BREAKOUT_SCK A3
#define BREAKOUT_MISO A4
#define BREAKOUT_MOSI A5
// These are the pins used for the breakout example
#define BREAKOUT_RESET D6//9 // VS1053 reset pin (output)
#define BREAKOUT_CS A2//10 // VS1053 chip select pin (output)
#define BREAKOUT_DCS D5//8 // VS1053 Data/command select pin (output)
// These are the pins used for the music maker shield
// These are common pins between breakout and shield
#define CARDCS D3//4 // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ WKP//3 // VS1053 Data request, ideally an Interrupt pin
Adafruit_VS1053_FilePlayer musicPlayer =
// create breakout-example object!
Adafruit_VS1053_FilePlayer(BREAKOUT_MOSI, BREAKOUT_MISO, BREAKOUT_SCK, BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
// comment out next line to write to SD from FTP server
// #define FTPWRITE
// Need to replace with host name instead of ip for drivehq
IPAddress server( 66, 220, 9, 50 );
TCPClient client;
TCPClient dclient;
char outBuf[128];
char outCount;
//SYSTEM_THREAD(ENABLED);
byte doFTP();
byte eRcv();
void efail();
void readSD();
// change fileName to your file (8.3 format!)
// Receiving device, date (day, month, year), time(hour, minute, 24hr format), A-Z 1-26, a-z 27-53,
char fileName[13];
// Declare constants for directory time
time_t tval;
File root;
String fileList[50];
String sdList[50];
String sdCreationTime[50];
String sdCreationDate[50];
SdVolume volume;
SdFile roots;
void setup()
{
Time.zone(-7);
delay(2000);
Serial.begin(9600);
// while(!Serial.available()) Particle.process();
Serial.println("Initialization");
if(!SD.begin(BREAKOUT_MOSI,BREAKOUT_MISO,BREAKOUT_SCK,CARDCS))
{
Serial.println("SD init fail");
}
Serial.println("Ready. Press f/r/d/l/q - ver 1");
delay(2000);
}
void loop()
{
byte inChar;
inChar = Serial.read();
if(inChar == 'f')
{
if(doFTP(fileName)) Serial.println("FTP OK");
else Serial.println("FTP FAIL");
}
if(inChar == 'r')
{
readSD();
}
if(inChar == 'd')
{
if(directoryDate(fileList[0])) Serial.println("FTP OK");
else Serial.println("FTP FAIL");
}
if(inChar == 'l')
{
root = SD.open("/");
printDirectory(root, 0);
}
if(inChar == 'q')
{
if(directoryList()) Serial.println("List");
else Serial.println("FTP FAIL");
delay(5000);
if(directoryDate(fileList[0])) Serial.println("Date");
else Serial.println("FTP FAIL");
delay(5000);
(fileList[0]).toCharArray(fileName, 13);
if(doFTP(fileName)) Serial.println("Retrieve");
else Serial.println("FTP FAIL");
}
}
File fh;
byte doFTP(char fileFTP[13])
{
#ifdef FTPWRITE
fh = SD.open(fileFTP,FILE_READ);
#else
SD.remove(fileFTP);
SdFile::dateTimeCallback(DateTime);
fh = SD.open(fileFTP,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)) { // port number is 21 for driveHQ
if (client.connect(server, 21)){
Serial.println("Command connected");
}
else {
fh.close();
Serial.println("Command connection failed");
return 0;
}
// For remote FTP server replace particle with username and photon with password, ftp.drivehq.com/drivehqshare/clabadmin/dev1-2
// unsure about the format for the rest but PASV is likely passive TCP
if(!eRcv()) return 0;
client.println("USER clab-dev1");
if(!eRcv()) return 0;
client.println("PASS connectionslab");
if(!eRcv()) return 0;
client.println("CWD /drivehqshare/clabadmin/dev1-2");
if(!eRcv()) return 0;
client.println("SYST");
if(!eRcv()) return 0;
client.println("Type I");
if(!eRcv()) return 0;
client.println("PASV");
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;
}
#ifdef FTPWRITE
client.print("STOR ");
client.println(fileFTP);
#else
client.print("RETR ");
client.println(fileFTP);
#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)
{
dclient.write(clientBuf,64);
clientCount = 0;
delay(2);
}
}
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");
client.stop();
Serial.println("Command disconnected");
fh.close();
Serial.println("SD closed");
return 1;
}
byte eRcv()
{
byte respCode;
byte thisByte;
while(!client.available()) Spark.process();
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.println("QUIT");
while(!client.available()) Spark.process();
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();
}
byte directoryDate(String fileInput)
{
// if (client.connect(server,21)) { // port number is 21 for driveHQ
if (client.connect(server, 21)){
Serial.println("Command connected");
}
else {
Serial.println("Command connection failed");
return 0;
}
if(!eRcv()) return 0;
client.println("USER clab-dev1");
if(!eRcv()) return 0;
client.println("PASS connectionslab");
if(!eRcv()) return 0;
client.println("CWD /drivehqshare/clabadmin/dev1-2");
if(!eRcv()) return 0;
client.println("SYST");
if(!eRcv()) return 0;
client.println("Type ascii");
if(!eRcv()) return 0;
client.println("PASV");
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();
return 0;
}
// Sending list command to server for date of file
byte testBuffer[65];
byte newBuffer[13];
client.println("LIST " + fileInput);
// Reading buffer values
if(!eRcv()) return 0;
dclient.read(testBuffer, 65);
// String val = String((char*)testBuffer);
// Serial.println("List Command Has been Issued");
// Serial.println(val);
// Formatting date
int i = 0;
for (i=39; i<51; i++) {
newBuffer[i-39] = testBuffer[i];
}
String val = String((char*)newBuffer);
val = val.remove(12);
//char date[12];
//val.toCharArray(date, 12);
String monthInput = val.substring(0, 3);
int Day = (val.substring(4, 6)).toInt();
int Hour = (val.substring(7, 9)).toInt();
int Minute = (val.substring(10, 12)).toInt();
int Month;
// Switch statement for month values
if (monthInput == "Jan") {
Month = 1; }
else if (monthInput == "Feb") {
Month = 2; }
else if (monthInput == "Mar") {
Month = 3; }
else if (monthInput == "Apr") {
Month = 4; }
else if (monthInput == "May") {
Month = 5; }
else if (monthInput == "Jun") {
Month = 6; }
else if (monthInput == "Jul") {
Month = 7; }
else if (monthInput == "Aug") {
Month = 8; }
else if (monthInput == "Sep") {
Month = 9; }
else if (monthInput == "Oct") {
Month = 10; }
else if (monthInput == "Nov") {
Month = 11; }
else if (monthInput == "Dec") {
Month = 12; }
tval = tmConvert_t(2019, Month, Day, Hour, Minute, 00);
Serial.println("UNIX OFFSET");
Serial.println(Time.month(tval));
Serial.println(Time.day(tval));
Serial.println(Time.hour(tval));
Serial.println(Time.minute(tval));
if(!eRcv())
{
dclient.stop();
return 0;
}
dclient.stop();
Serial.println("Data disconnected");
client.stop();
Serial.println("Command disconnected");
return 1;
}
byte directoryList()
{
// if (client.connect(server,21)) { // port number is 21 for driveHQ
if (client.connect(server, 21)){
Serial.println("Command connected");
}
else {
Serial.println("Command connection failed");
return 0;
}
// For remote FTP server replace particle with username and photon with password, ftp.drivehq.com/drivehqshare/clabadmin/dev1-2
// unsure about the format for the rest but PASV is likely passive TCP
if(!eRcv()) return 0;
client.println("USER clab-dev1");
if(!eRcv()) return 0;
client.println("PASS connectionslab");
if(!eRcv()) return 0;
client.println("CWD /drivehqshare/clabadmin/dev1-2");
if(!eRcv()) return 0;
client.println("SYST");
if(!eRcv()) return 0;
client.println("Type ascii");
if(!eRcv()) return 0;
client.println("PASV");
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();
return 0;
}
Serial.println("Testing NLST Command");
byte testBuffer2[500];
client.println("NLST");
if(!eRcv()) return 0;
dclient.read(testBuffer2, 500);
String val = String((char*)testBuffer2);
val = val.trim();
int i = 0;
for (i=0; i < (val.length()/13); i++) {
// file array limit
if (i == 50) {
break;
}
if (i == (val.length()/13 -1)) {
fileList[i] = (val.substring(i*13, (i*13) + 14)).trim();
}
else {
fileList[i] = (val.substring(i*13, (i*13) + 13)).trim();
}
}
// String test = (val.substring(0, 13)).trim();
Serial.println("List Command Has been Issued");
Serial.println(fileList[0]);
if(!eRcv())
{
dclient.stop();
return 0;
}
dclient.stop();
Serial.println("Data disconnected");
client.stop();
Serial.println("Command disconnected");
return 1;
}
time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss) // inlined for speed
{
struct tm t;
t.tm_year = YYYY-1900;
t.tm_mon = MM - 1;
t.tm_mday = DD;
t.tm_hour = hh;
t.tm_min = mm;
t.tm_sec = ss;
t.tm_isdst = 0; // not used
time_t t_of_day = mktime(&t);
return t_of_day;
}
void DateTime(uint16_t* date, uint16_t* timeVal) {
// return date using FAT_DATE macro to format fields
*date = FAT_DATE(2019, Time.month(tval), Time.day(tval));
// return time using FAT_TIME macro to format fields
*timeVal = FAT_TIME(Time.hour(tval), Time.minute(tval), 00);
}
void printDirectory(File dir, int numTabs) {
int i = 0;
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
// for (uint8_t i = 0; i < numTabs; i++) {
// Serial.print('\t');
// }
if (entry.isDirectory()) {
}
else if (String(entry.name()).startsWith("RE")) {
sdList[i] = String(entry.name());
i++;
}
// if (entry.isDirectory()) {
// Serial.println("/");
// printDirectory(entry, numTabs + 1);
// } else {
// // files have sizes, directories do not
// Serial.print("\t\t");
// Serial.println(entry.size(), DEC);
// }
entry.close();
}
Serial.println(sdList[0]); // Testing
}
// Testing sample code
void printTimestamps(SdFile& f) {
dir_t d;
if (!f.dirEntry(&d)) Serial.println("Error");
f.printFatDate(d.creationDate);
f.printFatTime(d.creationTime);
}