Je t’embrasse Salutations from Silicon Valley, California

15Aug/150

Teensy 3.1 SdFat File Browser

I was working on making a test application for the SDFat library, but I eventually ended up creating was more of a Linux-style file browser.
All that I currently have implemented is "cd", "ls", and a SdFat-style "ls -l"...

/*
 * Print size, modify date/time, and name for all files in root.
 */
#include <SPI.h>
#include <SdFat.h>

#define LINUX_PROMPT_STYLE

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

// file system objects
SdFat sd;
SdFile file;
SdBaseFile *cwd;
String path;

// =============================================================================

void printPrompt()
{
  
#ifdef LINUX_PROMPT_STYLE
  Serial.print("[root@localhost \"");
  Serial.print(path);
  Serial.println("\"]$ ");
#else
  Serial.println("#");
#endif

}

void cmd_ll(SdBaseFile *d)
{ 
  // cache the current d position
  FatPos_t p;
  d->getpos(&p);
  
  // open next file in root.  The volume working directory, vwd, is root
  while (file.openNext(d, O_READ)) {
    file.printFileSize(&Serial);
    Serial.write(' ');
    file.printModifyDateTime(&Serial);
    Serial.write(' ');
    file.printName(&Serial);
    if (file.isDir()) {
      // Indicate a directory.
      Serial.write('/');
    }
    Serial.println();
    file.close();
  }

  d->setpos(&p);
  printPrompt();
}

void cmd_ls(SdBaseFile *d)
{
  // cache the current d position
  FatPos_t p;
  d->getpos(&p);
  
  // open next file in root.  The volume working directory, vwd, is root
  while (file.openNext(d, O_READ)) {
    if (file.isHidden()) {
      file.close();
      continue;
    }
    file.printName(&Serial);
    if (file.isDir()) {
      // Indicate a directory.
      Serial.write('/');
    }
    Serial.println();
    file.close();
  }
  
  d->setpos(&p);
  printPrompt();
}

void cmd_cd(SdBaseFile *d, String *args)
{
  if (*args == "") {
    if (sd.chdir()) path = "/";
  }
  else if (*args == ".") {
  }
  else if (*args == "..") {
    int slash = path.lastIndexOf("/", path.length() - 1);
    String temp;
    if (slash == 0) temp = "/";
    else temp = path.substring(0, slash);
    
    char pbuf[512];
    memset(&pbuf, 0, sizeof(pbuf));
    temp.toCharArray(pbuf, sizeof(pbuf));
    if (sd.chdir(pbuf))
      path = temp;
  }
  else if ((*args)[0] == '/') {
    int slash = path.lastIndexOf("/", path.length() - 1);
    String temp = path.substring(0, slash);

    char buf[64];
    memset(&buf, 0, sizeof(buf));
    args->toCharArray(buf, sizeof(buf));
    if (sd.chdir(buf))
      path = *args;
  }
  else {
    int slash = path.lastIndexOf("/", path.length() - 1);
    String temp = path.substring(0, slash);

    char buf[64];
    memset(&buf, 0, sizeof(buf));
    args->toCharArray(buf, sizeof(buf));
    if (sd.chdir(buf)) {
      if (path == "/") {
        path.concat(buf);
      } 
      else {
        path.concat("/");
        path.concat(buf);
      }
    }
  }

  printPrompt();
  return;
}

// =============================================================================

#define CMD_IS(x,y) (x.substring(0, strlen(y)) == y)
//#define SAVE_ARGS(x,y) { Serial.println(x); Serial.println(y); };
#define SAVE_ARGS(x, y) { args = x.substring(strlen(y) + 1); }
int getInputCommand()
{
  String args;
  
  if (!Serial.available()) return -1;  
  String i = Serial.readString();

  // Flush
  while (Serial.available()) { Serial.read(); Serial.print("."); };
  
  if CMD_IS(i, "ls -l") {
    cmd_ll(cwd);
    return 0;
  }
  else if CMD_IS(i, "ll") {
    cmd_ll(cwd);
    return 0;
  }
  else if CMD_IS(i, "ls") {
    cmd_ls(cwd);
    return 0;
  }
  else if CMD_IS(i, "cd") {
    SAVE_ARGS(i, "cd");
    cmd_cd(cwd, &args);
    return 0;
  }

  return -1;
}

//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  while (!Serial) {} // wait for Leonardo
  delay(400);

  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
    sd.initErrorHalt();
  }

  cwd = (SdBaseFile *)sd.vwd();
  path = "/";
}

//------------------------------------------------------------------------------
void loop()
{
  getInputCommand();
}