3#include "AudioLogger.h"
4#include "AudioTools/Disk/AudioSource.h"
5#include "AudioTools/CoreAudio/AudioBasic/Str.h"
16#define SPI_CLOCK SD_SCK_MHZ(50)
18#define MAX_FILE_LEN 256
20#if defined(ARDUINO_ARCH_RP2040) && !defined(PICO)
22 typedef sdfat::SdSpiConfig SdSpiConfig;
23 typedef sdfat::SdFs AudioFs;
26 typedef SdFat AudioFs;
27 typedef File AudioFile;
29 typedef SdFat32 AudioFs;
30 typedef File32 AudioFile;
32 typedef SdExFat AudioFs;
33 typedef ExFile AudioFile;
36 typedef FsFile AudioFile;
48class AudioSourceSDFAT :
public AudioSource {
51 AudioSourceSDFAT(
const char* startFilePath =
"/",
const char* ext =
".mp3",
int chipSelect = PIN_CS,
int speedMHz = 10) {
53 LOGI(
"SD chipSelect: %d", chipSelect);
54 LOGI(
"SD speedMHz: %d", speedMHz);
56 p_cfg =
new SdSpiConfig(chipSelect, DEDICATED_SPI, SD_SCK_MHZ(speedMHz));
58 start_path = startFilePath;
67 start_path = startFilePath;
74 if (p_cfg!=
nullptr && owns_cfg){
81 static bool is_sd_setup =
false;
83 while (!sd.begin(*p_cfg)) {
84 LOGE(
"SD.begin failed with cs=%d!", p_cfg->csPin);
85 sd.initErrorHalt(&Serial);
95 LOGW(
"-> nextStream: %d", offset);
103 file.getName(file_name, MAX_FILE_LEN);
104 LOGW(
"-> selectStream: %d '%s'", idx_pos, file_name);
105 return file ? &file :
nullptr;
110 file = getFileByPath(path);
111 LOGW(
"-> selectStream: %s", path);
112 return file ? &file :
nullptr;
117 file_name_pattern = (
char*)filter;
146 SdSpiConfig *p_cfg =
nullptr;
150 char file_name[MAX_FILE_LEN];
151 const char* exension =
nullptr;
152 const char* start_path =
nullptr;
153 char* file_name_pattern = (
char*)
"*";
159 LOGD(
"-> isValidAudioFile: '%s': %d", file_name,
false);
162 char file_name[MAX_FILE_LEN];
163 file.getName(file_name, MAX_FILE_LEN);
164 StrView strFileName(file_name);
166 LOGD(
"-> isValidAudioFile: '%s': %d", file_name, result);
170 AudioFile getFileByPath(
const char* path) {
177 strfileName.
substring(path, pos, inPath.length());
178 if (!dir.open(strPath.
c_str())) {
179 LOGE(
"directory: %s not open", path);
182 LOGE(
"directory: %s is not dictory", path);
184 if (!file.open(&dir, strfileName.
c_str(), O_RDWR)) {
185 LOGE(
"file: %s not open", path);
187 LOGD(
"-> getFileByPath: %s , %s", strPath.
c_str(), strfileName.
c_str());
199 if (sd.exists(dirStr)){
200 LOGI(
"directory: '%s'", dirStr);
201 if (dir.open(dirStr)){
204 getFileAtIndex(dir, pos, count, result);
205 result.getName(file_name, MAX_FILE_LEN);
206 result.setTimeout(timeout);
207 LOGI(
"-> getFile: '%s': %d - %s", file_name, pos, result.isOpen() ?
"open":
"closed");
209 LOGE(
"'%s' is not a directory!", dirStr);
212 LOGE(
"Could not open direcotry: '%s'", dirStr);
215 LOGE(
"directory: '%s' does not exist", dirStr);
222 void getFileAtIndex(AudioFile dir,
size_t pos,
size_t& idx, AudioFile& result) {
223 LOGD(
"%s: %d", LOG_METHOD, idx);
224 char file_name_act[MAX_FILE_LEN];
225 dir.getName(file_name_act, MAX_FILE_LEN);
226 LOGD(
"-> processing directory: %s ", file_name_act);
229 while (!result && file.openNext(&dir, O_RDONLY)) {
231 if (!file.isHidden()) {
232 file.getName(file_name_act, MAX_FILE_LEN);
233 LOGD(
"-> processing: %s with index %d", file_name_act, idx);
238 result.getName(file_name, MAX_FILE_LEN);
239 LOGD(
"==> found: '%s' at index %d", file_name, idx);
245 getFileAtIndex(file, pos, idx, result);
249 if (file.dirIndex()!=result.dirIndex()){
250 LOGD(
"Close: %s", file_name_act);