1414#include <string.h>
1515#include <zephyr/drivers/gpio.h>
1616#include <zephyr/devicetree.h>
17+ #include <string.h>
1718
1819#include <zephyr/logging/log.h>
1920LOG_MODULE_REGISTER (sd_card , CONFIG_MODULE_SD_CARD_LOG_LEVEL );
2021
21- #define SD_ROOT_PATH "/SD:/"
22- /* Maximum length for path support by Windows file system */
23- #define PATH_MAX_LEN 260
22+ #define SD_ROOT_PATH "/SD:/"
23+ /* Round down to closest 4-byte boundary */
24+ #define PATH_MAX_LEN ROUND_DOWN(CONFIG_FS_FATFS_MAX_LFN, 4)
25+ #define SD_CARD_LEVELS_MAX 8
26+ #define SD_CARD_BUF_SIZE 700
27+
28+ static uint32_t num_files_added ;
29+ static struct k_mem_slab slab_A ;
30+ static struct k_mem_slab slab_B ;
2431
2532static const char * sd_root_path = "/SD:" ;
2633static FATFS fat_fs ;
@@ -31,7 +38,165 @@ static struct fs_mount_t mnt_pt = {
3138 .fs_data = & fat_fs ,
3239};
3340
34- int sd_card_list_files (char const * const path , char * buf , size_t * buf_size )
41+ /**
42+ * @brief Replaces first carriage return or line feed with null terminator.
43+ */
44+ static void cr_lf_remove (char * str )
45+ {
46+ char * p = str ;
47+
48+ while (* p != '\0' ) {
49+ if (* p == '\r' || * p == '\n' ) {
50+ * p = '\0' ;
51+ break ;
52+ }
53+ p ++ ;
54+ }
55+ }
56+
57+ /**
58+ * @brief Recursively traverse the SD card tree.
59+ */
60+ static int traverse_down (char const * const path , uint8_t curr_depth , uint16_t result_file_num_max ,
61+ uint16_t result_path_len_max , char result [][result_path_len_max ],
62+ char const * const search_pattern )
63+ {
64+ int ret = 0 ;
65+
66+ if (curr_depth > SD_CARD_LEVELS_MAX ) {
67+ LOG_WRN ("At tree curr_depth %u, greater than %u" , curr_depth , SD_CARD_LEVELS_MAX );
68+ return 0 ;
69+ }
70+
71+ char * slab_A_ptr ;
72+
73+ ret = k_mem_slab_alloc (& slab_A , (void * * )& slab_A_ptr , K_NO_WAIT );
74+ if (ret ) {
75+ LOG_ERR ("Failed to alloc slab A: %d" , ret );
76+ return ret ;
77+ }
78+
79+ char * slab_A_ptr_origin = slab_A_ptr ;
80+ char * slab_B_ptr ;
81+
82+ ret = k_mem_slab_alloc (& slab_B , (void * * )& slab_B_ptr , K_NO_WAIT );
83+ if (ret ) {
84+ k_mem_slab_free (& slab_A , (void * )slab_A_ptr_origin );
85+ LOG_ERR ("Failed to alloc slab B: %d" , ret );
86+ return ret ;
87+ }
88+
89+ char * slab_B_ptr_origin = slab_B_ptr ;
90+ size_t slab_A_ptr_size = SD_CARD_BUF_SIZE ;
91+
92+ /* Search for folders */
93+ ret = sd_card_list_files (path , slab_A_ptr , & slab_A_ptr_size , false);
94+ if (ret == - ENOENT ) {
95+ /* Not able to open, hence likely not a folder */
96+ ret = 0 ;
97+ goto cleanup ;
98+ } else if (ret ) {
99+ goto cleanup ;
100+ }
101+
102+ LOG_DBG ("At curr_depth %d tmp_buf is: %s" , curr_depth , slab_A_ptr );
103+
104+ char * token = strtok_r (slab_A_ptr , "\r\n" , & slab_A_ptr );
105+
106+ while (token != NULL ) {
107+ if (strstr (token , "System Volume Information" ) != NULL ) {
108+ /* Skipping System Volume Information */
109+ token = strtok_r (NULL , "\n" , & slab_A_ptr );
110+ continue ;
111+ }
112+
113+ cr_lf_remove (token );
114+ memset (slab_B_ptr , '\0' , PATH_MAX_LEN );
115+
116+ if (path != NULL ) {
117+ strcat (slab_B_ptr , path );
118+ cr_lf_remove (slab_B_ptr );
119+ strcat (slab_B_ptr , "/" );
120+ }
121+
122+ strcat (slab_B_ptr , token );
123+
124+ if (strstr (token , search_pattern ) != NULL ) {
125+ if (num_files_added >= result_file_num_max ) {
126+ LOG_WRN ("Max file count reached %u" , result_file_num_max );
127+ ret = - ENOMEM ;
128+ goto cleanup ;
129+ }
130+ strcpy (result [num_files_added ], slab_B_ptr );
131+ num_files_added ++ ;
132+ LOG_DBG ("Added file num: %d at: %s" , num_files_added , slab_B_ptr );
133+
134+ } else {
135+ ret = traverse_down (slab_B_ptr , curr_depth + 1 , result_file_num_max ,
136+ result_path_len_max , result , search_pattern );
137+ if (ret ) {
138+ LOG_ERR ("Failed to traverse down: %d" , ret );
139+ }
140+ }
141+
142+ token = strtok_r (NULL , "\n" , & slab_A_ptr );
143+ }
144+
145+ cleanup :
146+ k_mem_slab_free (& slab_A , (void * )slab_A_ptr_origin );
147+ k_mem_slab_free (& slab_B , (void * )slab_B_ptr_origin );
148+ return ret ;
149+ }
150+
151+ int sd_card_list_files_match (uint16_t result_file_num_max , uint16_t result_path_len_max ,
152+ char result [][result_path_len_max ], char * path ,
153+ char const * const search_pattern )
154+ {
155+ int ret ;
156+
157+ num_files_added = 0 ;
158+
159+ if (result == NULL ) {
160+ return - EINVAL ;
161+ }
162+
163+ if (result_file_num_max == 0 ) {
164+ return - EINVAL ;
165+ }
166+
167+ if (result_path_len_max == 0 || (result_path_len_max > PATH_MAX_LEN )) {
168+ return - EINVAL ;
169+ }
170+
171+ if (search_pattern == NULL ) {
172+ return - EINVAL ;
173+ }
174+
175+ char __aligned (4 ) buf_A [SD_CARD_BUF_SIZE * SD_CARD_LEVELS_MAX ] = {'\0' };
176+ char __aligned (4 ) buf_B [PATH_MAX_LEN * SD_CARD_LEVELS_MAX ] = {'\0' };
177+
178+ ret = k_mem_slab_init (& slab_A , buf_A , SD_CARD_BUF_SIZE , SD_CARD_LEVELS_MAX );
179+ if (ret ) {
180+ LOG_ERR ("Failed to init slab: %d" , ret );
181+ return ret ;
182+ }
183+
184+ ret = k_mem_slab_init (& slab_B , buf_B , PATH_MAX_LEN , SD_CARD_LEVELS_MAX );
185+ if (ret ) {
186+ LOG_ERR ("Failed to init slab: %d" , ret );
187+ return ret ;
188+ }
189+
190+ ret = traverse_down (path , 0 , result_file_num_max , result_path_len_max , result ,
191+ search_pattern );
192+ if (ret ) {
193+ return ret ;
194+ }
195+
196+ return num_files_added ;
197+ }
198+
199+ int sd_card_list_files (char const * const path , char * buf , size_t * buf_size , bool extra_info )
35200{
36201 int ret ;
37202 struct fs_dir_t dirp ;
@@ -44,7 +209,6 @@ int sd_card_list_files(char const *const path, char *buf, size_t *buf_size)
44209 }
45210
46211 fs_dir_t_init (& dirp );
47-
48212 if (path == NULL ) {
49213 ret = fs_opendir (& dirp , sd_root_path );
50214 if (ret ) {
@@ -59,9 +223,14 @@ int sd_card_list_files(char const *const path, char *buf, size_t *buf_size)
59223
60224 strcat (abs_path_name , path );
61225
226+ if (strchr (abs_path_name , '.' )) {
227+ /* Path contains a dot. Regarded as not a folder*/
228+ return - ENOENT ;
229+ }
230+
62231 ret = fs_opendir (& dirp , abs_path_name );
63232 if (ret ) {
64- LOG_ERR ("Open assigned path failed" );
233+ LOG_ERR ("Open assigned path failed %d. %s" , ret , abs_path_name );
65234 return ret ;
66235 }
67236 }
@@ -78,9 +247,17 @@ int sd_card_list_files(char const *const path, char *buf, size_t *buf_size)
78247
79248 if (buf != NULL ) {
80249 size_t remaining_buf_size = * buf_size - used_buf_size ;
81- ssize_t len = snprintk (
82- & buf [used_buf_size ], remaining_buf_size , "[%s]\t%s\n" ,
83- entry .type == FS_DIR_ENTRY_DIR ? "DIR " : "FILE" , entry .name );
250+ ssize_t len ;
251+
252+ if (extra_info ) {
253+ len = snprintk (& buf [used_buf_size ], remaining_buf_size ,
254+ "[%s]\t%s\r\n" ,
255+ entry .type == FS_DIR_ENTRY_DIR ? "DIR " : "FILE" ,
256+ entry .name );
257+ } else {
258+ len = snprintk (& buf [used_buf_size ], remaining_buf_size , "%s\r\n" ,
259+ entry .name );
260+ }
84261
85262 if (len >= remaining_buf_size ) {
86263 LOG_ERR ("Failed to append to buffer, error: %d" , len );
@@ -290,7 +467,7 @@ int sd_card_init(void)
290467
291468 sd_card_size_bytes = (uint64_t )sector_count * sector_size ;
292469
293- LOG_INF ("SD card volume size: %d MB " , ( uint32_t )( sd_card_size_bytes >> 20 ) );
470+ LOG_INF ("SD card volume size: %lld B " , sd_card_size_bytes );
294471
295472 mnt_pt .mnt_point = sd_root_path ;
296473
0 commit comments