This repository has been archived on 2025-02-01. You can view files and clone it, but cannot push or open issues or pull requests.
reprapfirmware-dc42/src/Storage/MassStorage.cpp
David Crocker ed40658c45 Version 1.15rc2
Fixed doubling of M301 I parameter and halving of M301 P parameter
Implemented M303 auto tune and M307 heater process model
Improved temperature monitoring to detect heater cartridges or
thermistor falling out
Implemented M38 (thanks chrishamm)
Retructured course code tree
2016-08-20 12:14:28 +01:00

365 lines
9.1 KiB
C++

#include "RepRapFirmware.h"
#include "sd_mmc.h"
MassStorage::MassStorage(Platform* p) : platform(p)
{
memset(&fileSystems, 0, sizeof(fileSystems));
}
void MassStorage::Init()
{
sd_mmc_init(SdCardDetectPins, SdWriteProtectPins, SdSpiCSPins); // Initialize SD MMC stack
// Try to mount the first SD card only
char replyBuffer[100];
StringRef reply(replyBuffer, ARRAY_SIZE(replyBuffer));
do { } while (!Mount(0, reply));
if (reply.strlen() != 0)
{
delay(3000); // Wait a few seconds so users have a chance to see this
platform->Message(HOST_MESSAGE, reply.Pointer());
}
}
const char* MassStorage::CombineName(const char* directory, const char* fileName)
{
size_t outIndex = 0;
size_t inIndex = 0;
// DC 2015-11-25 Only prepend the directory if the filename does not have an absolute path
if (directory != NULL && fileName[0] != '/' && (strlen(fileName) < 3 || !isdigit(fileName[0]) || fileName[1] != ':' || fileName[2] != '/'))
{
while (directory[inIndex] != 0 && directory[inIndex] != '\n')
{
combinedName[outIndex] = directory[inIndex];
inIndex++;
outIndex++;
if (outIndex >= ARRAY_SIZE(combinedName))
{
platform->MessageF(GENERIC_MESSAGE, "CombineName() buffer overflow.");
outIndex = 0;
}
}
if (inIndex > 0 && directory[inIndex - 1] != '/' && outIndex < ARRAY_UPB(combinedName))
{
combinedName[outIndex] = '/';
outIndex++;
}
inIndex = 0;
}
while (fileName[inIndex] != 0 && fileName[inIndex] != '\n')
{
combinedName[outIndex] = fileName[inIndex];
inIndex++;
outIndex++;
if (outIndex >= ARRAY_SIZE(combinedName))
{
platform->Message(GENERIC_MESSAGE, "CombineName() buffer overflow.");
outIndex = 0;
}
}
combinedName[outIndex] = 0;
return combinedName;
}
// Open a directory to read a file list. Returns true if it contains any files, false otherwise.
bool MassStorage::FindFirst(const char *directory, FileInfo &file_info)
{
TCHAR loc[FILENAME_LENGTH + 1];
// Remove the trailing '/' from the directory name
size_t len = strnlen(directory, ARRAY_UPB(loc));
if (len == 0)
{
loc[0] = 0;
}
else if (directory[len - 1] == '/')
{
strncpy(loc, directory, len - 1);
loc[len - 1] = 0;
}
else
{
strncpy(loc, directory, len);
loc[len] = 0;
}
findDir.lfn = nullptr;
FRESULT res = f_opendir(&findDir, loc);
if (res == FR_OK)
{
FILINFO entry;
entry.lfname = file_info.fileName;
entry.lfsize = ARRAY_SIZE(file_info.fileName);
for(;;)
{
res = f_readdir(&findDir, &entry);
if (res != FR_OK || entry.fname[0] == 0) break;
if (StringEquals(entry.fname, ".") || StringEquals(entry.fname, "..")) continue;
file_info.isDirectory = (entry.fattrib & AM_DIR);
file_info.size = entry.fsize;
uint16_t day = entry.fdate & 0x1F;
if (day == 0)
{
// This can happen if a transfer hasn't been processed completely.
day = 1;
}
file_info.day = day;
file_info.month = (entry.fdate & 0x01E0) >> 5;
file_info.year = (entry.fdate >> 9) + 1980;
if (file_info.fileName[0] == 0)
{
strncpy(file_info.fileName, entry.fname, ARRAY_SIZE(file_info.fileName));
}
return true;
}
}
return false;
}
// Find the next file in a directory. Returns true if another file has been read.
bool MassStorage::FindNext(FileInfo &file_info)
{
FILINFO entry;
entry.lfname = file_info.fileName;
entry.lfsize = ARRAY_SIZE(file_info.fileName);
findDir.lfn = nullptr;
if (f_readdir(&findDir, &entry) != FR_OK || entry.fname[0] == 0)
{
//f_closedir(findDir);
return false;
}
file_info.isDirectory = (entry.fattrib & AM_DIR);
file_info.size = entry.fsize;
uint16_t day = entry.fdate & 0x1F;
if (day == 0)
{
// This can happen if a transfer hasn't been processed completely.
day = 1;
}
file_info.day = day;
file_info.month = (entry.fdate & 0x01E0) >> 5;
file_info.year = (entry.fdate >> 9) + 1980;
if (file_info.fileName[0] == 0)
{
strncpy(file_info.fileName, entry.fname, ARRAY_SIZE(file_info.fileName));
}
return true;
}
// Month names. The first entry is used for invalid month numbers.
static const char *monthNames[13] = { "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
// Returns the name of the specified month or '???' if the specified value is invalid.
const char* MassStorage::GetMonthName(const uint8_t month)
{
return (month <= 12) ? monthNames[month] : monthNames[0];
}
// Delete a file or directory
bool MassStorage::Delete(const char* directory, const char* fileName)
{
const char* location = (directory != NULL)
? platform->GetMassStorage()->CombineName(directory, fileName)
: fileName;
if (f_unlink(location) != FR_OK)
{
platform->MessageF(GENERIC_MESSAGE, "Can't delete file %s\n", location);
return false;
}
return true;
}
// Create a new directory
bool MassStorage::MakeDirectory(const char *parentDir, const char *dirName)
{
const char* location = platform->GetMassStorage()->CombineName(parentDir, dirName);
if (f_mkdir(location) != FR_OK)
{
platform->MessageF(GENERIC_MESSAGE, "Can't create directory %s\n", location);
return false;
}
return true;
}
bool MassStorage::MakeDirectory(const char *directory)
{
if (f_mkdir(directory) != FR_OK)
{
platform->MessageF(GENERIC_MESSAGE, "Can't create directory %s\n", directory);
return false;
}
return true;
}
// Rename a file or directory
bool MassStorage::Rename(const char *oldFilename, const char *newFilename)
{
if (f_rename(oldFilename, newFilename) != FR_OK)
{
platform->MessageF(GENERIC_MESSAGE, "Can't rename file or directory %s to %s\n", oldFilename, newFilename);
return false;
}
return true;
}
// Check if the specified file exists
bool MassStorage::FileExists(const char *file) const
{
FILINFO fil;
fil.lfname = nullptr;
return (f_stat(file, &fil) == FR_OK);
}
bool MassStorage::FileExists(const char *directory, const char *fileName) const
{
const char *location = (directory != nullptr)
? platform->GetMassStorage()->CombineName(directory, fileName)
: fileName;
return FileExists(location);
}
// Check if the specified directory exists
bool MassStorage::DirectoryExists(const char *path) const
{
DIR dir;
dir.lfn = nullptr;
return (f_opendir(&dir, path) == FR_OK);
}
bool MassStorage::DirectoryExists(const char* directory, const char* subDirectory)
{
return DirectoryExists(CombineName(directory, subDirectory));
}
// Mount the specified SD card, returning true if done, false if needs to be called again.
// If an error occurs, return true with the error message in 'reply'.
// This may only be called to mount one card at a time.
bool MassStorage::Mount(size_t card, StringRef& reply)
{
if (card >= NumSdCards)
{
reply.copy("SD card number out of range");
return true;
}
static bool mounting = false;
static size_t startTime;
if (!mounting)
{
sd_mmc_unmount(card); // this forces it to re-initialise the card
startTime = millis();
mounting = true;
delay(2);
}
sd_mmc_err_t err = sd_mmc_check(card);
if (err != SD_MMC_OK && millis() - startTime < 5000)
{
delay(2);
return false;
}
mounting = false;
if (err != SD_MMC_OK)
{
f_mount(card, NULL);
reply.printf("Cannot initialise SD card %u: ", card);
switch (err)
{
case SD_MMC_ERR_NO_CARD:
reply.cat("Card not found");
break;
case SD_MMC_ERR_UNUSABLE:
reply.cat("Card is unusable, try another one");
break;
case SD_MMC_ERR_SLOT:
reply.cat("Slot unknown");
break;
case SD_MMC_ERR_COMM:
reply.cat("General communication error");
break;
case SD_MMC_ERR_PARAM:
reply.cat("Illegal input parameter");
break;
case SD_MMC_ERR_WP:
reply.cat("Card write protected");
break;
default:
reply.catf("Unknown (code %d)", err);
break;
}
}
else
{
if (reprap.Debug(moduleStorage))
{
// Print some card details
platform->MessageF(DEBUG_MESSAGE, "SD card %u detected, capacity: %u\n", card, sd_mmc_get_capacity(card));
platform->Message(DEBUG_MESSAGE, "Card type: ");
switch (sd_mmc_get_type(card))
{
case CARD_TYPE_SD | CARD_TYPE_HC:
platform->Message(DEBUG_MESSAGE, "SDHC\n");
break;
case CARD_TYPE_SD:
platform->Message(DEBUG_MESSAGE, "SD\n");
break;
case CARD_TYPE_MMC | CARD_TYPE_HC:
platform->Message(DEBUG_MESSAGE, "MMC High Density\n");
break;
case CARD_TYPE_MMC:
platform->Message(DEBUG_MESSAGE, "MMC\n");
break;
case CARD_TYPE_SDIO:
platform->Message(DEBUG_MESSAGE, "SDIO\n");
break;
case CARD_TYPE_SD_COMBO:
platform->Message(DEBUG_MESSAGE, "SD COMBO\n");
break;
case CARD_TYPE_UNKNOWN:
default:
platform->Message(DEBUG_MESSAGE, "Unknown\n");
break;
}
}
// Mount the file systems
FRESULT mounted = f_mount(card, &fileSystems[card]);
if (mounted != FR_OK)
{
reply.printf("Can't mount SD card %u: code %d\n", card, mounted);
}
}
return true;
}
// Unmount the specified SD card, returning true if done, false if needs to be called again.
// If an error occurs, return true with the error message in 'reply'.
bool MassStorage::Unmount(size_t card, StringRef& reply)
{
if (card >= NumSdCards)
{
reply.copy("SD card number out of range");
return true;
}
platform->InvalidateFiles(&fileSystems[card]);
f_mount(card, NULL);
sd_mmc_unmount(card);
return true;
}
// End