Update documentation

Remove SDFat2 warning
Add several sanity check
Fix some edge cases in authentication process
Remove debug messages
Clarify some status in http handler responses
This commit is contained in:
Luc 2022-09-04 15:40:03 +08:00
parent 3331c47927
commit a885afced8
12 changed files with 639 additions and 429 deletions

View File

@ -300,9 +300,9 @@ label can be: light/framesize/quality/contrast/brightness/saturation/gainceiling
* Get state / Set Enable / Disable Serial Bridge Communication
`[ESP930]<ENABLE/DISABLE> json=<no> pwd=<admin/user password>`
* Get / Set Serial Bridge Baud Rate
`[ESP931]<BAUD RATE> json=<no> pwd=<admin/user password>`
* Set quiet boot if strapping pin is High
`[ESP999]QUIETBOOT pwd=<admin/user password>`

View File

@ -1,43 +1,161 @@
# Web Handlers in ESP3D
# Web Handlers
#### /
### /
root is the default handler where all files will be served, if no file is defined, it looks for index.html or index.html.gz (compressed)
if you call specific file, it will look for the filename and filename.gz (compressed)
if no file is defined and there is not index.html(.gz) it will display embedded page
another way to show the embedded page is /?forcefallback=yes
#### /sd/
it will serve any file from SD card if there is one
### /sd/
it will serve any file from SD card if there is one, it is only a wrapper to read SD card, no upload
#### /files
this handler handle all commands for FS, including upload on FS
### /files
this handler handle all commands for FS, including upload on FS.
possible options/arguments are:
- `quiet=yes` can be used when you don't want list files but just upload them
- `path=...` define the path to the file
- `action=...` define the action to execute which can be:
- delete
delete the file defined by `filename=...` it will also use `path=...` to do full path
- deletedir
delete the directory defined by `filename=...` it will also use `path=...` to do full path
- createdir
create the directory defined by `filename=...` it will also use `path=...` to do full path
- `createPath=yes` when doing upload and the path do not exists, it will create it, POST only
- `<filename>S=...` give the size of uploaded file with <filename> name, need to be set before file is set in upload, POST only
#### /sdfiles
the output is a json file:
```
{
"files":[ //the files list
{
"name":"index.html.gz", //the name of the file
"size":"83.46 KB", //the formated size of the file
"time":"2022-09-04 11:56:05" //the time when the file was modified last time, this one is optional and depend on (FILESYSTEM_TIMESTAMP_FEATURE)
},
{
"name":"subdir", //the name of the file / directory
"size":"-1", //the size is -1 because it is a directory
"time":"" //no time for directories optional as depend on (FILESYSTEM_TIMESTAMP_FEATURE)
}
],
"path":"/", //current path
"occupation":"52", //% of occupation
"status":"subdir created", //status
"total":"192.00 KB", //Formated total space of Filesystem
"used":"100.00 KB" //Formated used space of Filesystem
}
```
### /sdfiles
this handler handle all commands for SD, including upload on SD (only shared and direct SD)
this handler handle all commands for FS, including upload on FS.
possible options/arguments are:
- `quiet=yes` can be used when you don't want list files but just upload them
- `path=...` define the path to the file
- `action=...` define the action to execute which can be:
- list
Will refresh the stats of the files
- delete
delete the file defined by `filename=...` it will also use `path=...` to do full path
- deletedir
delete the directory defined by `filename=...` it will also use `path=...` to do full path
- createdir
create the directory defined by `filename=...` it will also use `path=...` to do full path
- `createPath=yes` when doing upload and the path do not exists, it will create it, POST only
- `<filename>S=...` give the size of uploaded file with <filename> name, need to be set before file is set in upload, POST only
#### /upload
this handler is for MKS boards using MKS communication protocol if enabled, it handle all commands for SD, including upload on SD
the output is a json file:
#### /command
this handler is for all commands
```
{
"files":[ //the files list
{
"name":"3Oc-pika2.gco",//the name of the file
"shortname":"3Oc-pika2.gco", //the 8.3 shortname if available, if not the name of the file
"size":"83.46 KB", //the formated size of the file
"time":"2022-09-04 11:56:05" //the time when the file was modified last time, this one is optional and depend on (SD_TIMESTAMP_FEATURE)
},
{
"name":"subdir", //the name of the file / directory
"size":"-1", //the size is -1 because it is a directory
"time":"" //no time for directories optional as depend on (SD_TIMESTAMP_FEATURE)
}
],
"path":"/", //current path
"occupation":"52", //% of occupation
"status":"subdir created", //status
"total":"192.00 KB", //Formated total space of Filesystem
"used":"100.00 KB" //Formated used space of Filesystem
}
```
### /upload
this handler is for MKS boards using MKS communication protocol if enabled, it handle only upload on SD
#### /login
### /command
this handler is for all commands the parameter is `cmd=...`
if it is an `[ESPXXX]` command the answer is the `[ESPXXX]` response
if it is not an `[ESPXXX]` command the answer is `ESP3D says: command forwarded` and can be ignored
### /login
this handler is for authentication function if enabled
possible options/arguments are:
- `DISCONNECT=YES`
it will clear current session, remove authentication cookie, set status to `disconnected` and response code to 401
- `SUBMIT=YES`
to login it will need also `PASSWORD=...` and `USER=...`, the answer will be 200 if success and 401 if failed
if user is already authenticated it can use `NEWPASSWORD=...` instead of `PASSWORD=...` to change his password, if successful answer will be returned with code 200, otherwise code will be 500 if change failed or if password format is invalid
#### /config
this handler is a shortcut to [ESP420] command
Output:
#### /updatefw
- if authentified and no submission:
`{"status":"Identified","authentication_lvl":"admin"}` and code 200
- if not authenticated and no submission:
`{"status":"Wrong authentication!","authentication_lvl":"guest"}` and code 401
### /config
this handler is a shortcut to [ESP420] command in text mode, to get output in json add `json=yes`
### /updatefw
this handler is for FW upload and update
Answer output is :
`{"status":"..."}` if upload is successful the ESP will restart
#### /snap
### /snap
this handler is on esp32cam with camera enabled to capture a Frame
it answer by sending a jpg image
#### /description.xml
this handler is for SSDP if enabled to present device informations
### /description.xml
this handler is for SSDP if enabled to present device informations
#### Captive portal bypass handlers
```
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://192.168.2.178:80/</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:upnp:rootdevice:1</deviceType>
<friendlyName>esp3d</friendlyName>
<presentationURL>/</presentationURL>
<serialNumber>52332</serialNumber>
<modelName>ESP Board</modelName>
<modelDescription/>
<modelNumber>ESP3D 3.0</modelNumber>
<modelURL>https://www.espressif.com/en/products/devkits</modelURL>
<manufacturer>Espressif Systems</manufacturer>
<manufacturerURL>https://www.espressif.com</manufacturerURL>
<UDN>uuid:38323636-4558-4dda-9188-cda0e600cc6c</UDN>
<serviceList/>
<iconList/>
</device>
</root>
```
### Captive portal bypass handlers
to avoid a redirect to index.html and so a refresh of the page, some classic handler have been added so they all go to / handler actually
- /generate_204
- /gconnectivitycheck.gstatic.com
- /fwlink/

View File

@ -22,7 +22,7 @@
#define _VERSION_ESP3D_H
//version and sources location
#define FW_VERSION "3.0.0.a210"
#define FW_VERSION "3.0.0.a211"
#define REPOSITORY "https://github.com/luc-github/ESP3D/tree/3.0"
#endif //_VERSION_ESP3D_H

View File

@ -48,8 +48,8 @@ void HTTP_Server::handleSDFileList ()
if (_webserver->hasArg ("quiet")) {
if(_webserver->arg ("quiet") == "yes") {
Serial.println("quiet");
_webserver->send (200, "text/plain", "{\"status\":\"ok\"}");
status = "{\"status\":\"" + status + "\"}";
_webserver->send (200, "text/plain", status.c_str());
return;
}
}
@ -184,11 +184,13 @@ void HTTP_Server::handleSDFileList ()
}
#ifdef FILESYSTEM_TIMESTAMP_FEATURE
buffer2send+="\",\"time\":\"";
time_t t = sub.getLastWrite();
struct tm * tmstruct = localtime(&t);
char str[20]; //buffer should be 20
sprintf(str,"%d-%02d-%02d %02d:%02d:%02d",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
buffer2send+=str;
if (!sub.isDirectory()) {
time_t t = sub.getLastWrite();
struct tm * tmstruct = localtime(&t);
char str[20]; //buffer should be 20
sprintf(str,"%d-%02d-%02d %02d:%02d:%02d",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
buffer2send+=str;
}
#endif //FILESYSTEM_TIMESTAMP_FEATURE
buffer2send+="\"}";
if (buffer2send.length() > 1100) {

View File

@ -35,6 +35,9 @@ void HTTP_Server::handle_config ()
{
level_authenticate_type auth_level = AuthenticationService::authenticated_level();
String cmd = "[ESP420]";
if (_webserver->hasArg("json")) {
cmd = "[ESP420]json="+_webserver->arg("json");
}
ESP3DOutput output(_webserver);
output.printMSGLine("<pre>");
esp3d_commands.process((uint8_t*)cmd.c_str(), cmd.length(), &output, auth_level);

View File

@ -50,8 +50,8 @@ void HTTP_Server::handleFSFileList ()
}
if (_webserver->hasArg ("quiet")) {
if(_webserver->arg ("quiet") == "yes") {
Serial.println("quiet");
_webserver->send (200, "text/plain", "{\"status\":\"ok\"}");
status = "{\"status\":\"" + status + "\"}";
_webserver->send (200, "text/plain", status.c_str());
return;
}
}
@ -165,7 +165,9 @@ void HTTP_Server::handleFSFileList ()
}
#ifdef FILESYSTEM_TIMESTAMP_FEATURE
buffer2send+="\",\"time\":\"";
buffer2send+=timeserver.current_time(sub.getLastWrite());
if (!sub.isDirectory()) {
buffer2send+=timeserver.current_time(sub.getLastWrite());
}
#endif //FILESYSTEM_TIMESTAMP_FEATURE
buffer2send+="\"}";
if (buffer2send.length() > 1100) {

View File

@ -37,7 +37,7 @@ void HTTP_Server::handle_login()
int code = 401;
String status = "Wrong authentication!";
//Disconnect can be done anytime no need to check credential
if (_webserver->hasArg("DISCONNECT")) {
if (_webserver->hasArg("DISCONNECT") && _webserver->arg("DISCONNECT")=="YES") {
AuthenticationService::ClearCurrentSession();
_webserver->sendHeader("Set-Cookie","ESPSESSIONID=0");
_webserver->sendHeader("Cache-Control","no-cache");
@ -96,7 +96,12 @@ void HTTP_Server::handle_login()
}
}
}
}//SUBMIT
} else {
if (auth_level == LEVEL_USER || auth_level == LEVEL_ADMIN) {
status = "Identified";
code = 200;
}
}
_webserver->sendHeader("Cache-Control","no-cache");
String smsg = "{\"status\":\"";
smsg+=status;
@ -110,6 +115,7 @@ void HTTP_Server::handle_login()
}
smsg += "\"}";
_webserver->send(code, "application/json", smsg);
return;
#else // No AUTHENTICATION_FEATURE
_webserver->sendHeader("Cache-Control","no-cache");
_webserver->send(200, "application/json", "{\"status\":\"ok\",\"authentication_lvl\":\"admin\"}");

View File

@ -38,7 +38,20 @@ void HTTP_Server::handleUpdate ()
return;
}
String jsonfile = "{\"status\":\"" ;
jsonfile += String(_upload_status);
switch(_upload_status) {
case UPLOAD_STATUS_NONE :
jsonfile += "no file";
break;
case UPLOAD_STATUS_CANCELLED :
jsonfile += "canceled";
break;
case UPLOAD_STATUS_SUCCESSFUL :
jsonfile += "ok";
break;
default :
jsonfile += "error";
break;
}
jsonfile += "\"}";
_webserver->sendHeader("Cache-Control", "no-cache");
_webserver->send(200, "application/json", jsonfile);

View File

@ -261,6 +261,10 @@ bool NetServices::begin()
SSDP.setSerialNumber (stmp.c_str());
//Any customization could be here
SSDP.setModelName (ESP_MODEL_NAME);
#if defined(ESP_MODEL_DESCRIPTION)
//this one is optional because windows doesn't care about this field
SSDP.setModelDescription(ESP_MODEL_DESCRIPTION);
#endif //ESP_MODEL_DESCRIPTION
SSDP.setModelURL (ESP_MODEL_URL);
SSDP.setModelNumber (ESP_MODEL_NUMBER);
SSDP.setManufacturer (ESP_MANUFACTURER_NAME);

View File

@ -34,11 +34,6 @@ public:
{
return _started;
}
static void start()
{
_restart=true;
Serial.println("Restarting netservices");
}
private:
static bool _started;
static bool _restart;

View File

@ -139,7 +139,6 @@ uint8_t ESP3DSensor::getIDFromString(const char * s)
if (_device) {
return _device->getIDFromString(s);
}
Serial.println("no device");
return 0;
}

View File

@ -47,386 +47,450 @@
* \brief base SD file system template class.
*/
template <class Vol, class Fmt>
class SdBase : public Vol {
public:
//----------------------------------------------------------------------------
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \return true for success or false for failure.
*/
bool begin(SdCsPin_t csPin = SS) {
class SdBase : public Vol
{
public:
//----------------------------------------------------------------------------
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \return true for success or false for failure.
*/
bool begin(SdCsPin_t csPin = SS)
{
#ifdef BUILTIN_SDCARD
if (csPin == BUILTIN_SDCARD) {
return begin(SdioConfig(FIFO_SDIO));
}
if (csPin == BUILTIN_SDCARD) {
return begin(SdioConfig(FIFO_SDIO));
}
#endif // BUILTIN_SDCARD
return begin(SdSpiConfig(csPin, SHARED_SPI));
}
//----------------------------------------------------------------------------
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] maxSck Maximum SCK frequency.
* \return true for success or false for failure.
*/
bool begin(SdCsPin_t csPin, uint32_t maxSck) {
return begin(SdSpiConfig(csPin, SHARED_SPI, maxSck));
}
//----------------------------------------------------------------------------
/** Initialize SD card and file system for SPI mode.
*
* \param[in] spiConfig SPI configuration.
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig) {
return cardBegin(spiConfig) && Vol::begin(m_card);
}
//---------------------------------------------------------------------------
/** Initialize SD card and file system for SDIO mode.
*
* \param[in] sdioConfig SDIO configuration.
* \return true for success or false for failure.
*/
bool begin(SdioConfig sdioConfig) {
return cardBegin(sdioConfig) && Vol::begin(m_card);
}
//----------------------------------------------------------------------------
/** \return Pointer to SD card object. */
SdCard* card() {return m_card;}
//----------------------------------------------------------------------------
/** Initialize SD card in SPI mode.
*
* \param[in] spiConfig SPI configuration.
* \return true for success or false for failure.
*/
bool cardBegin(SdSpiConfig spiConfig) {
m_card = m_cardFactory.newCard(spiConfig);
return m_card && !m_card->errorCode();
}
//----------------------------------------------------------------------------
/** Initialize SD card in SDIO mode.
*
* \param[in] sdioConfig SDIO configuration.
* \return true for success or false for failure.
*/
bool cardBegin(SdioConfig sdioConfig) {
m_card = m_cardFactory.newCard(sdioConfig);
return m_card && !m_card->errorCode();
}
//----------------------------------------------------------------------------
/** End use of card. */
void end() {
Vol::end();
if (m_card) {
m_card->end();
return begin(SdSpiConfig(csPin, SHARED_SPI));
}
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
*/
void errorHalt(print_t* pr) {
if (sdErrorCode()) {
pr->print(F("SdError: 0X"));
pr->print(sdErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(sdErrorData(), HEX);
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
//----------------------------------------------------------------------------
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] maxSck Maximum SCK frequency.
* \return true for success or false for failure.
*/
bool begin(SdCsPin_t csPin, uint32_t maxSck)
{
return begin(SdSpiConfig(csPin, SHARED_SPI, maxSck));
}
while (true) {}
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(print_t* pr, const char* msg) {
pr->print(F("error: "));
pr->println(msg);
errorHalt(pr);
}
//----------------------------------------------------------------------------
/** %Print msg and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(print_t* pr, const __FlashStringHelper* msg) {
pr->print(F("error: "));
pr->println(msg);
errorHalt(pr);
}
//----------------------------------------------------------------------------
/** Format SD card
*
* \param[in] pr Print destination.
* \return true for success else false.
*/
bool format(print_t* pr = nullptr) {
Fmt fmt;
uint8_t* mem = Vol::end();
if (!mem) {
return false;
//----------------------------------------------------------------------------
/** Initialize SD card and file system for SPI mode.
*
* \param[in] spiConfig SPI configuration.
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig)
{
return cardBegin(spiConfig) && Vol::begin(m_card);
}
bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi();
if (switchSpi && !setDedicatedSpi(true)) {
return 0;
//---------------------------------------------------------------------------
/** Initialize SD card and file system for SDIO mode.
*
* \param[in] sdioConfig SDIO configuration.
* \return true for success or false for failure.
*/
bool begin(SdioConfig sdioConfig)
{
return cardBegin(sdioConfig) && Vol::begin(m_card);
}
bool rtn = fmt.format(card(), mem, pr);
if (switchSpi && !setDedicatedSpi(false)) {
return 0;
//----------------------------------------------------------------------------
/** \return Pointer to SD card object. */
SdCard* card()
{
return m_card;
}
return rtn;
}
//----------------------------------------------------------------------------
/** \return the free cluster count. */
uint32_t freeClusterCount() {
bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi();
if (switchSpi && !setDedicatedSpi(true)) {
return 0;
//----------------------------------------------------------------------------
/** Initialize SD card in SPI mode.
*
* \param[in] spiConfig SPI configuration.
* \return true for success or false for failure.
*/
bool cardBegin(SdSpiConfig spiConfig)
{
m_card = m_cardFactory.newCard(spiConfig);
return m_card && !m_card->errorCode();
}
uint32_t rtn = Vol::freeClusterCount();
if (switchSpi && !setDedicatedSpi(false)) {
return 0;
//----------------------------------------------------------------------------
/** Initialize SD card in SDIO mode.
*
* \param[in] sdioConfig SDIO configuration.
* \return true for success or false for failure.
*/
bool cardBegin(SdioConfig sdioConfig)
{
m_card = m_cardFactory.newCard(sdioConfig);
return m_card && !m_card->errorCode();
}
return rtn;
}
//----------------------------------------------------------------------------
/** \return true if can be in dedicated SPI state */
bool hasDedicatedSpi() {return m_card ? m_card->hasDedicatedSpi() : false;}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
*/
void initErrorHalt(print_t* pr) {
initErrorPrint(pr);
while (true) {}
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorHalt(print_t* pr, const char* msg) {
pr->println(msg);
initErrorHalt(pr);
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorHalt(print_t* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorHalt(pr);
}
//----------------------------------------------------------------------------
/** Print error details after begin() fails.
*
* \param[in] pr Print destination.
*/
void initErrorPrint(print_t* pr) {
pr->println(F("begin() failed"));
if (sdErrorCode()) {
pr->println(F("Do not reformat the SD."));
if (sdErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or wiring error?"));
}
//----------------------------------------------------------------------------
/** End use of card. */
void end()
{
Vol::end();
if (m_card) {
m_card->end();
}
}
errorPrint(pr);
}
//----------------------------------------------------------------------------
/** \return true if in dedicated SPI state. */
bool isDedicatedSpi() {return m_card ? m_card->isDedicatedSpi() : false;}
//----------------------------------------------------------------------------
/** %Print volume FAT/exFAT type.
*
* \param[in] pr Print destination.
*/
void printFatType(print_t* pr) {
if (Vol::fatType() == FAT_TYPE_EXFAT) {
pr->print(F("exFAT"));
} else {
pr->print(F("FAT"));
pr->print(Vol::fatType());
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
*/
void errorHalt(print_t* pr)
{
if (sdErrorCode()) {
pr->print(F("SdError: 0X"));
pr->print(sdErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(sdErrorData(), HEX);
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
}
while (true) {}
}
}
//----------------------------------------------------------------------------
/** %Print SD errorCode and errorData.
*
* \param[in] pr Print destination.
*/
void errorPrint(print_t* pr) {
if (sdErrorCode()) {
pr->print(F("SdError: 0X"));
pr->print(sdErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(sdErrorData(), HEX);
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(print_t* pr, const char* msg)
{
pr->print(F("error: "));
pr->println(msg);
errorHalt(pr);
}
//----------------------------------------------------------------------------
/** %Print msg and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(print_t* pr, const __FlashStringHelper* msg)
{
pr->print(F("error: "));
pr->println(msg);
errorHalt(pr);
}
//----------------------------------------------------------------------------
/** Format SD card
*
* \param[in] pr Print destination.
* \return true for success else false.
*/
bool format(print_t* pr = nullptr)
{
Fmt fmt;
uint8_t* mem = Vol::end();
if (!mem) {
return false;
}
bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi();
if (switchSpi && !setDedicatedSpi(true)) {
return 0;
}
bool rtn = fmt.format(card(), mem, pr);
if (switchSpi && !setDedicatedSpi(false)) {
return 0;
}
return rtn;
}
//----------------------------------------------------------------------------
/** \return the free cluster count. */
uint32_t freeClusterCount()
{
bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi();
if (switchSpi && !setDedicatedSpi(true)) {
return 0;
}
uint32_t rtn = Vol::freeClusterCount();
if (switchSpi && !setDedicatedSpi(false)) {
return 0;
}
return rtn;
}
//----------------------------------------------------------------------------
/** \return true if can be in dedicated SPI state */
bool hasDedicatedSpi()
{
return m_card ? m_card->hasDedicatedSpi() : false;
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
*/
void initErrorHalt(print_t* pr)
{
initErrorPrint(pr);
while (true) {}
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorHalt(print_t* pr, const char* msg)
{
pr->println(msg);
initErrorHalt(pr);
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorHalt(print_t* pr, const __FlashStringHelper* msg)
{
pr->println(msg);
initErrorHalt(pr);
}
//----------------------------------------------------------------------------
/** Print error details after begin() fails.
*
* \param[in] pr Print destination.
*/
void initErrorPrint(print_t* pr)
{
pr->println(F("begin() failed"));
if (sdErrorCode()) {
pr->println(F("Do not reformat the SD."));
if (sdErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or wiring error?"));
}
}
errorPrint(pr);
}
//----------------------------------------------------------------------------
/** \return true if in dedicated SPI state. */
bool isDedicatedSpi()
{
return m_card ? m_card->isDedicatedSpi() : false;
}
//----------------------------------------------------------------------------
/** %Print volume FAT/exFAT type.
*
* \param[in] pr Print destination.
*/
void printFatType(print_t* pr)
{
if (Vol::fatType() == FAT_TYPE_EXFAT) {
pr->print(F("exFAT"));
} else {
pr->print(F("FAT"));
pr->print(Vol::fatType());
}
}
//----------------------------------------------------------------------------
/** %Print SD errorCode and errorData.
*
* \param[in] pr Print destination.
*/
void errorPrint(print_t* pr)
{
if (sdErrorCode()) {
pr->print(F("SdError: 0X"));
pr->print(sdErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(sdErrorData(), HEX);
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
}
}
//----------------------------------------------------------------------------
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(print_t* pr, char const* msg)
{
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
}
//----------------------------------------------------------------------------
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(print_t* pr, char const* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(print_t* pr, const __FlashStringHelper* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
//----------------------------------------------------------------------------
/** %Print error info and return.
*
* \param[in] pr Print destination.
*/
void printSdError(print_t* pr) {
if (sdErrorCode()) {
if (sdErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or wiring error?"));
}
pr->print(F("SD error: "));
printSdErrorSymbol(pr, sdErrorCode());
pr->print(F(" = 0x"));
pr->print(sdErrorCode(), HEX);
pr->print(F(",0x"));
pr->println(sdErrorData(), HEX);
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(print_t* pr, const __FlashStringHelper* msg)
{
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
}
//----------------------------------------------------------------------------
/** \return SD card error code. */
uint8_t sdErrorCode() {
if (m_card) {
return m_card->errorCode();
//----------------------------------------------------------------------------
/** %Print error info and return.
*
* \param[in] pr Print destination.
*/
void printSdError(print_t* pr)
{
if (sdErrorCode()) {
if (sdErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or wiring error?"));
}
pr->print(F("SD error: "));
printSdErrorSymbol(pr, sdErrorCode());
pr->print(F(" = 0x"));
pr->print(sdErrorCode(), HEX);
pr->print(F(",0x"));
pr->println(sdErrorData(), HEX);
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
}
}
return SD_CARD_ERROR_INVALID_CARD_CONFIG;
}
//----------------------------------------------------------------------------
/** \return SD card error data. */
uint8_t sdErrorData() {return m_card ? m_card->errorData() : 0;}
//----------------------------------------------------------------------------
/** Set SPI sharing state
* \param[in] value desired state.
* \return true for success else false;
*/
bool setDedicatedSpi(bool value) {
if (m_card) {
return m_card->setDedicatedSpi(value);
//----------------------------------------------------------------------------
/** \return SD card error code. */
uint8_t sdErrorCode()
{
if (m_card) {
return m_card->errorCode();
}
return SD_CARD_ERROR_INVALID_CARD_CONFIG;
}
//----------------------------------------------------------------------------
/** \return SD card error data. */
uint8_t sdErrorData()
{
return m_card ? m_card->errorData() : 0;
}
//----------------------------------------------------------------------------
/** Set SPI sharing state
* \param[in] value desired state.
* \return true for success else false;
*/
bool setDedicatedSpi(bool value)
{
if (m_card) {
return m_card->setDedicatedSpi(value);
}
return false;
}
//----------------------------------------------------------------------------
/** \return pointer to base volume */
Vol* vol()
{
return reinterpret_cast<Vol*>(this);
}
//----------------------------------------------------------------------------
/** Initialize file system after call to cardBegin.
*
* \return true for success or false for failure.
*/
bool volumeBegin()
{
return Vol::begin(m_card);
}
return false;
}
//----------------------------------------------------------------------------
/** \return pointer to base volume */
Vol* vol() {return reinterpret_cast<Vol*>(this);}
//----------------------------------------------------------------------------
/** Initialize file system after call to cardBegin.
*
* \return true for success or false for failure.
*/
bool volumeBegin() {
return Vol::begin(m_card);
}
#if ENABLE_ARDUINO_SERIAL
/** Print error details after begin() fails. */
void initErrorPrint() {
initErrorPrint(&Serial);
}
//----------------------------------------------------------------------------
/** %Print msg to Serial and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(const __FlashStringHelper* msg) {
errorHalt(&Serial, msg);
}
//----------------------------------------------------------------------------
/** %Print error info to Serial and halt. */
void errorHalt() {errorHalt(&Serial);}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(const char* msg) {errorHalt(&Serial, msg);}
//----------------------------------------------------------------------------
/** %Print error info and halt. */
void initErrorHalt() {initErrorHalt(&Serial);}
//----------------------------------------------------------------------------
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void errorPrint(const char* msg) {errorPrint(&Serial, msg);}
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void errorPrint(const __FlashStringHelper* msg) {errorPrint(&Serial, msg);}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(const char* msg) {initErrorHalt(&Serial, msg);}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(const __FlashStringHelper* msg) {
initErrorHalt(&Serial, msg);
}
/** Print error details after begin() fails. */
void initErrorPrint()
{
initErrorPrint(&Serial);
}
//----------------------------------------------------------------------------
/** %Print msg to Serial and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(const __FlashStringHelper* msg)
{
errorHalt(&Serial, msg);
}
//----------------------------------------------------------------------------
/** %Print error info to Serial and halt. */
void errorHalt()
{
errorHalt(&Serial);
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(const char* msg)
{
errorHalt(&Serial, msg);
}
//----------------------------------------------------------------------------
/** %Print error info and halt. */
void initErrorHalt()
{
initErrorHalt(&Serial);
}
//----------------------------------------------------------------------------
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void errorPrint(const char* msg)
{
errorPrint(&Serial, msg);
}
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void errorPrint(const __FlashStringHelper* msg)
{
errorPrint(&Serial, msg);
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(const char* msg)
{
initErrorHalt(&Serial, msg);
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(const __FlashStringHelper* msg)
{
initErrorHalt(&Serial, msg);
}
#endif // ENABLE_ARDUINO_SERIAL
//----------------------------------------------------------------------------
private:
SdCard* m_card = nullptr;
SdCardFactory m_cardFactory;
//----------------------------------------------------------------------------
private:
SdCard* m_card = nullptr;
SdCardFactory m_cardFactory;
};
//------------------------------------------------------------------------------
/**
* \class SdFat32
* \brief SD file system class for FAT volumes.
*/
class SdFat32 : public SdBase<FatVolume, FatFormatter> {
public:
class SdFat32 : public SdBase<FatVolume, FatFormatter>
{
public:
};
//------------------------------------------------------------------------------
/**
* \class SdExFat
* \brief SD file system class for exFAT volumes.
*/
class SdExFat : public SdBase<ExFatVolume, ExFatFormatter> {
public:
class SdExFat : public SdBase<ExFatVolume, ExFatFormatter>
{
public:
};
//------------------------------------------------------------------------------
/**
* \class SdFs
* \brief SD file system class for FAT16, FAT32, and exFAT volumes.
*/
class SdFs : public SdBase<FsVolume, FsFormatter> {
public:
class SdFs : public SdBase<FsVolume, FsFormatter>
{
public:
};
//------------------------------------------------------------------------------
#if SDFAT_FILE_TYPE == 1 || defined(DOXYGEN)
@ -449,7 +513,7 @@ typedef FsBaseFile SdBaseFile;
#if defined __has_include
#if __has_include(<FS.h>)
#define HAS_INCLUDE_FS_H
#warning File not defined because __has_include(FS.h)
//#warning File not defined because __has_include(FS.h)
#endif // __has_include(<FS.h>)
#endif // defined __has_include
#ifndef HAS_INCLUDE_FS_H
@ -466,49 +530,53 @@ typedef FsFile File;
* \class SdFile
* \brief FAT16/FAT32 file with Print.
*/
class SdFile : public PrintFile<SdBaseFile> {
public:
SdFile() {}
/** Create an open SdFile.
* \param[in] path path for file.
* \param[in] oflag open flags.
*/
SdFile(const char* path, oflag_t oflag) {
open(path, oflag);
}
/** Set the date/time callback function
*
* \param[in] dateTime The user's call back function. The callback
* function is of the form:
*
* \code
* void dateTime(uint16_t* date, uint16_t* time) {
* uint16_t year;
* uint8_t month, day, hour, minute, second;
*
* // User gets date and time from GPS or real-time clock here
*
* // return date using FS_DATE macro to format fields
* *date = FS_DATE(year, month, day);
*
* // return time using FS_TIME macro to format fields
* *time = FS_TIME(hour, minute, second);
* }
* \endcode
*
* Sets the function that is called when a file is created or when
* a file's directory entry is modified by sync(). All timestamps,
* access, creation, and modify, are set when a file is created.
* sync() maintains the last access date and last modify date/time.
*
*/
static void dateTimeCallback(
void (*dateTime)(uint16_t* date, uint16_t* time)) {
FsDateTime::setCallback(dateTime);
}
/** Cancel the date/time callback function. */
static void dateTimeCallbackCancel() {
FsDateTime::clearCallback();
}
class SdFile : public PrintFile<SdBaseFile>
{
public:
SdFile() {}
/** Create an open SdFile.
* \param[in] path path for file.
* \param[in] oflag open flags.
*/
SdFile(const char* path, oflag_t oflag)
{
open(path, oflag);
}
/** Set the date/time callback function
*
* \param[in] dateTime The user's call back function. The callback
* function is of the form:
*
* \code
* void dateTime(uint16_t* date, uint16_t* time) {
* uint16_t year;
* uint8_t month, day, hour, minute, second;
*
* // User gets date and time from GPS or real-time clock here
*
* // return date using FS_DATE macro to format fields
* *date = FS_DATE(year, month, day);
*
* // return time using FS_TIME macro to format fields
* *time = FS_TIME(hour, minute, second);
* }
* \endcode
*
* Sets the function that is called when a file is created or when
* a file's directory entry is modified by sync(). All timestamps,
* access, creation, and modify, are set when a file is created.
* sync() maintains the last access date and last modify date/time.
*
*/
static void dateTimeCallback(
void (*dateTime)(uint16_t* date, uint16_t* time))
{
FsDateTime::setCallback(dateTime);
}
/** Cancel the date/time callback function. */
static void dateTimeCallbackCancel()
{
FsDateTime::clearCallback();
}
};
#endif // SdFat_h