1 #ifndef LIBPROPELLER_SD_H_
2 #define LIBPROPELLER_SD_H_
6 #include "libpropeller/sd/sdsafespi.h"
8 #include "libpropeller/printstream/printstream.h"
10 #define RET_IF_ERROR_NULL if(HasError()){return NULL;}
11 #define RET_IF_ERROR if(HasError()){return;}
12 #define THROW_NULL(value) {SetErrorCode((value)); return NULL;}
14 #define THROW(value) {SetErrorCode((value)); return;}
67 static const int kNoError = libpropeller::SDSafeSPI::kNoError;
70 static const int kErrorNotFatVolume = -20;
71 static const int kErrorBadBytesPerSector = -21;
72 static const int kErrorBadSectorsPerCluster = -22;
73 static const int kErrorNotTwoFats = -23;
74 static const int kErrorBadFatSignature = -24;
75 static const int kErrorBufNotLongwordAligned = -512;
78 static const int kErrorFileNotFound = -1;
79 static const int kErrorNoEmptyDirectoryEntry = -2;
80 static const int kErrorBadArgument = -3;
81 static const int kErrorNoWritePermission = -6;
82 static const int kErrorEofWhileFollowingChain = -7;
83 static const int kErrorBadClusterValue = -9;
84 static const int kErrorBadClusterNumber = -26;
85 static const int kErrorFileNotOpenForWriting = -27;
88 static const int kErrorCardNotReset = libpropeller::SDSafeSPI::kErrorCardNotReset;
89 static const int kError3v3NotSupported = libpropeller::SDSafeSPI::kError3v3NotSupported;
90 static const int kErrorOcrFailed = libpropeller::SDSafeSPI::kErrorOcrFailed;
91 static const int kErrorBlockNotLongAligned = libpropeller::SDSafeSPI::kErrorBlockNotLongAligned;
93 static const int kErrorAsmNoReadToken = -libpropeller::SDSafeSPI::kErrorAsmNoReadToken;
94 static const int kErrorAsmBlockNotWritten = -libpropeller::SDSafeSPI::kErrorAsmBlockNotWritten;
96 static const int kErrorSpiEngineNotRunning = libpropeller::SDSafeSPI::kErrorSpiEngineNotRunning;
97 static const int kErrorCardBusyTimeout = libpropeller::SDSafeSPI::kErrorCardBusyTimeout;
115 Mount(basepin, (basepin + 1), (basepin + 2), (basepin + 3));
125 void Mount(
const int pin_do,
const int pin_clk,
const int pin_di,
const int pin_cs) {
126 if (file_date_time_ == 0) {
134 if ((((
int) buffer_1_) & 0b11) != 0)
135 THROW(kErrorBufNotLongwordAligned);
136 if ((((
int) buffer_2_) & 0b11) != 0)
137 THROW(kErrorBufNotLongwordAligned);
142 sd_spi_.
Start(pin_do, pin_clk, pin_di, pin_cs);
147 sd_spi_.ReadBlock(0, (
char *) (&buffer_1_));
151 if (GetFilesystemType() != kFileSystemUnknown) {
154 start = ReverseBytesInLong(((
char *) (&buffer_1_) + 0x1C6));
155 sd_spi_.ReadBlock(start, buffer_1_);
158 filesystem_ = GetFilesystemType();
159 if (filesystem_ == kFileSystemUnknown) {
160 THROW(kErrorNotFatVolume);
162 if (ReverseBytesInWord(((
char *) (&buffer_1_) + 11)) != kSectorSize) {
163 THROW(kErrorBadBytesPerSector);
165 int sectors_per_cluster = buffer_1_[13];
166 if (sectors_per_cluster & (sectors_per_cluster - 1)) {
167 THROW(kErrorBadSectorsPerCluster);
170 while (sectors_per_cluster > 1) {
172 sectors_per_cluster = (Shr__(sectors_per_cluster, 1));
174 sectors_per_cluster = (1 << cluster_shift_);
175 cluster_size_ = (kSectorSize << cluster_shift_);
176 int reserved = ReverseBytesInWord(((
char *) (&buffer_1_) + 14));
177 if (buffer_1_[16] != 2) {
178 THROW(kErrorNotTwoFats);
180 int sectors = ReverseBytesInWord(((
char *) (&buffer_1_) + 19));
182 sectors = ReverseBytesInLong(((
char *) (&buffer_1_) + 32));
184 fat1_ = (start + reserved);
185 if (filesystem_ == kFileSystemFAT32) {
186 int root_entries = (16 << cluster_shift_);
187 sectors_per_fat_ = ReverseBytesInLong(((
char *) (&buffer_1_) + 36));
188 data_region_ = ((fat1_ + (2 * sectors_per_fat_)) - (2 * sectors_per_cluster));
189 root_directory_ = ((data_region_ + (ReverseBytesInWord(((
char *) (&buffer_1_) + 44)) << cluster_shift_)) << kSectorShift);
190 root_directory_end_ = (root_directory_ + (root_entries << kDirectoryShift));
191 end_of_chain_ = 268435440;
193 int root_entries = ReverseBytesInWord(((
char *) (&buffer_1_) + 17));
194 sectors_per_fat_ = ReverseBytesInWord(((
char *) (&buffer_1_) + 22));
195 root_directory_ = ((fat1_ + (2 * sectors_per_fat_)) << kSectorShift);
196 root_directory_end_ = (root_directory_ + (root_entries << kDirectoryShift));
197 data_region_ = ((1 + (Shr__((root_directory_end_ - 1), kSectorShift))) - (2 * sectors_per_cluster));
198 end_of_chain_ = 65520;
200 if (ReverseBytesInWord(((
char *) (&buffer_1_) + 510)) != 43605) {
201 THROW(kErrorBadFatSignature);
203 total_clusters_ = (Shr__(((sectors - data_region_) + start), cluster_shift_));
232 void Open(
const char * filename,
const char file_mode) {
237 char cleaned_filename[11];
240 while (I < 8 && filename[0] !=
'\0' && filename[0] !=
'.') {
241 cleaned_filename[(I++)] = ConvertToUppercase((filename++)[0]);
244 cleaned_filename[(I++)] =
' ';
246 while (filename[0] !=
'\0' && filename[0] !=
'.') {
249 if ((filename)[0] ==
'.') {
252 while ((I < 11) && ((filename)[0])) {
253 cleaned_filename[(I++)] = ConvertToUppercase((filename++)[0]);
256 cleaned_filename[(I++)] =
' ';
270 for (
int directory_pointer = root_directory_;
271 directory_pointer <= root_directory_end_ - kDirectorySize;
272 directory_pointer += kDirectorySize) {
273 char * disk_filename = ReadByte(directory_pointer);
277 if ((free_entry == 0) && (((disk_filename)[0] == 0) || ((disk_filename)[0] == 0xe5))) {
278 free_entry = directory_pointer;
280 if ((disk_filename)[0] == 0) {
281 sentinel = directory_pointer;
287 for (; i <= 10; i++) {
288 if (cleaned_filename[i] != (disk_filename)[i]) {
294 if ((i == 11) && (0 == ((disk_filename)[0x0b] & 0x18))) {
295 current_cluster_ = ReverseBytesInWord((disk_filename + 0x1a));
296 if (filesystem_ == kFileSystemFAT32) {
297 current_cluster_ = (current_cluster_ + (ReverseBytesInWord((disk_filename + 0x14)) << 16));
299 first_cluster_of_file_ = current_cluster_;
300 total_filesize_ = ReverseBytesInLong((disk_filename + 0x1c));
303 if (file_mode ==
'r') {
307 if ((disk_filename)[11] & 0xd9) {
308 THROW(kErrorNoWritePermission);
312 if (file_mode ==
'd') {
313 OpenForDelete(disk_filename);
315 }
else if (file_mode ==
'w') {
316 OpenForWrite(disk_filename, directory_pointer);
318 }
else if (file_mode ==
'a') {
319 OpenForAppend(directory_pointer);
322 THROW(kErrorBadArgument);
328 if (file_mode ==
'd') {
332 if ((file_mode !=
'w') && (file_mode !=
'a')) {
333 THROW(kErrorFileNotFound);
335 directory_entry_position_ = free_entry;
336 if (directory_entry_position_ == 0) {
337 THROW(kErrorNoEmptyDirectoryEntry);
341 char * S = ReadByte(directory_entry_position_);
343 memset((
void *) S, 0, kDirectorySize);
344 memcpy((
void *) S, (
void *) &cleaned_filename, 11);
345 WriteReversedWord((S + 0x1a), 0);
346 WriteReversedWord((S + 0x14), 0);
347 WriteReversedLong((S + 0x0e), file_date_time_);
348 WriteReversedLong((S + 0x16), file_date_time_);
349 if ((directory_entry_position_ == sentinel) && ((directory_entry_position_ + kDirectorySize) < root_directory_end_)) {
350 WriteReversedWord(ReadByte((directory_entry_position_ + kDirectorySize)), 0);
355 cluster_write_offset_ = 0;
356 current_cluster_ = 0;
357 buffer_end_ = kSectorSize;
369 if (directory_entry_position_) {
373 current_buffer_location_ = 0;
377 remaining_cluster_bytes_ = 0;
378 cluster_write_offset_ = 0;
379 directory_entry_position_ = 0;
380 current_cluster_ = 0;
381 first_cluster_of_file_ = 0;
392 if (current_buffer_location_ >= buffer_end_) {
399 return buffer_1_[(current_buffer_location_++)];
412 int Get(
char * read_buffer,
int bytes_to_read_count) {
415 while (bytes_to_read_count > 0) {
416 if (current_buffer_location_ >= buffer_end_) {
425 T = (Min__((buffer_end_ - current_buffer_location_), bytes_to_read_count));
426 if (((T | (
int) read_buffer) | current_buffer_location_) & 0x3) {
427 memcpy((
void *) read_buffer, (
void *) (
void *) (((
int) (&buffer_1_) + current_buffer_location_)), 1 * (T));
429 memmove((
void *) read_buffer, (
void *) (
void *) (((
int) (&buffer_1_) + current_buffer_location_)), 4 * ((Shr__(T, 2))));
431 current_buffer_location_ = (current_buffer_location_ + T);
433 read_buffer = (read_buffer + T);
434 bytes_to_read_count = (bytes_to_read_count - T);
445 if (current_buffer_location_ == kSectorSize) {
446 if (FlushBuffer(kSectorSize, 0) < 0) {
450 buffer_1_[(current_buffer_location_++)] = C;
462 return Put(B, strlen(B));
473 int Put(
const char * buffer,
int byte_count) {
474 int total_bytes_written = 0;
475 while (byte_count > 0) {
476 if (current_buffer_location_ >= buffer_end_) {
477 FlushBuffer(current_buffer_location_, 0);
481 int bytes_to_write = (Min__((buffer_end_ - current_buffer_location_), byte_count));
482 memcpy((
void *) (
void *) (((
int) (&buffer_1_) + current_buffer_location_)), (
void *) buffer, bytes_to_write);
484 total_bytes_written = (total_bytes_written + bytes_to_write);
485 current_buffer_location_ = (current_buffer_location_ + bytes_to_write);
486 buffer = (buffer + bytes_to_write);
487 byte_count = (byte_count - bytes_to_write);
489 return total_bytes_written;
492 int PutFormatted(
const char * formatString, ...) {
496 va_start(list, formatString);
497 int result = ps.Format(formatString, list);
511 int off = (root_directory_ - (data_region_ << kSectorShift));
512 current_cluster_ = (Shr__(off, (cluster_shift_ + kSectorShift)));
513 seek_position_ = (off - (current_cluster_ << (cluster_shift_ + kSectorShift)));
514 remaining_cluster_bytes_ = (root_directory_end_ - root_directory_);
515 total_filesize_ = (seek_position_ + remaining_cluster_bytes_);
527 int filesize, year, month, day, hour, minute, second;
528 return NextFile(filename, filesize, year, month, day, hour, minute, second);
531 bool NextFile(
char * filename,
int & filesize) {
532 int year, month, day, hour, minute, second;
533 return NextFile(filename, filesize, year, month, day, hour, minute, second);
538 int & year,
int & month,
int & day,
int & hour,
int & minute,
int & second) {
541 if (current_buffer_location_ >= buffer_end_) {
542 if (FillBuffer() < 0) {
545 if (((Shr__(seek_position_, kSectorShift)) & ((1 << cluster_shift_) - 1)) == 0) {
546 (current_cluster_++);
550 char * at = (
char *) ((
int) &buffer_1_ + current_buffer_location_);
555 current_buffer_location_ = (current_buffer_location_ + kDirectorySize);
556 if (((at)[0] != 0xe5) && ((at)[0] != 0xeb)
557 && (((at)[0x0b] & 0x18) == 0)) {
558 char * lns = filename;
560 for (
int i = 0; i <= 10; i++) {
561 filename[0] = (at)[i];
566 if (i == 7 || i == 10) {
576 filesize = ReverseBytesInLong(at + 28);
577 ExtractDateTime(ReverseBytesInLong(at + 22), year, month, day, hour, minute, second);
594 if (((directory_entry_position_) || (position < 0)) || (position > total_filesize_)) {
597 int delta = ((seek_position_ - buffer_end_) & (-cluster_size_));
598 if (position < delta) {
599 current_cluster_ = first_cluster_of_file_;
600 remaining_cluster_bytes_ = (Min__(cluster_size_, total_filesize_));
602 current_buffer_location_ = 0;
606 while (position >= (delta + cluster_size_)) {
607 current_cluster_ = NextCluster();
610 seek_position_ = (seek_position_ + cluster_size_);
611 delta = (delta + cluster_size_);
612 remaining_cluster_bytes_ = (Min__(cluster_size_, (total_filesize_ - seek_position_)));
613 current_buffer_location_ = 0;
617 || position < (seek_position_ - buffer_end_)
618 || position >= (seek_position_ - buffer_end_) + kSectorSize
621 int delta_2 = (seek_position_ + remaining_cluster_bytes_);
622 seek_position_ = (position & -kSectorSize);
623 remaining_cluster_bytes_ = (delta_2 - seek_position_);
627 current_buffer_location_ = position & (kSectorSize - 1);
648 int SetDate(
const int year,
const int month,
const int day,
649 const int hour,
const int minute,
const int second) {
650 file_date_time_ = ((year - 1980) << 25) + (month << 21) + (day << 16);
651 file_date_time_ += (hour << 11) + (minute << 5) + (second >> 1);
652 return file_date_time_;
661 return (error_ != kNoError) || sd_spi_.
HasError();
676 if (error_ != kNoError) {
679 return sd_spi_.GetError();
687 return cluster_size_;
697 return total_clusters_;
705 return total_filesize_;
711 static const int kFileSystemUnknown = 0;
712 static const int kFileSystemFAT16 = 1;
713 static const int kFileSystemFAT32 = 2;
716 static const int kSectorSize = 512;
717 static const int kSectorShift = 9;
718 static const int kDirectorySize = 32;
719 static const int kDirectoryShift = 5;
723 int current_cluster_;
726 int remaining_cluster_bytes_;
727 int current_buffer_location_;
729 int directory_entry_position_;
730 int cluster_write_offset_;
732 int first_cluster_of_file_;
736 int root_directory_end_;
742 int sectors_per_fat_;
767 void SetErrorCode(
const int abort_code) {
774 void WriteBlock(
const int block_index,
char * buffer_address) {
775 sd_spi_.WriteBlock(block_index, buffer_address);
777 if (block_index >= fat1_) {
778 if (block_index < (fat1_ + sectors_per_fat_)) {
779 sd_spi_.WriteBlock(block_index + sectors_per_fat_, buffer_address);
787 void FlushIfDirty(
void) {
789 WriteBlock(last_read_, buffer_2_);
797 void ReadBlock(
const int block_index) {
798 if (block_index != last_read_) {
801 sd_spi_.ReadBlock(block_index, buffer_2_);
803 last_read_ = block_index;
809 int ReverseBytesInWord(
const char * data)
const {
810 return ((data)[0] + ((data)[1] << 8));
815 int ReverseBytesInLong(
const char * data)
const {
816 return (ReverseBytesInWord(data) + (ReverseBytesInWord((data + 2)) << 16));
821 int ReverseBytesInCluster(
const char * cluster)
const {
822 if (filesystem_ == kFileSystemFAT16) {
823 return ReverseBytesInWord(cluster);
825 return ReverseBytesInLong(cluster);
831 void WriteReversedWord(
char * result,
const int data) {
833 result[0] = data >> 8;
839 void WriteReversedLong(
char * result,
const int data) {
840 WriteReversedWord(result, data);
841 WriteReversedWord(result + 2, data >> 16);
846 void WriteReversedCluster(
char * result,
const int data) {
848 if (filesystem_ == kFileSystemFAT16) {
849 WriteReversedWord(result, data);
851 WriteReversedLong(result, data);
855 int GetFilesystemType(
void) {
856 const int kFAT1 =
'F' + (
'A' << 8) + (
'T' << 16) + (
'1' << 24);
857 const int kFAT3 =
'F' + (
'A' << 8) + (
'T' << 16) + (
'3' << 24);
859 if ((ReverseBytesInLong(&buffer_1_[0x36]) == kFAT1) && (buffer_1_[58] ==
'6')) {
860 return kFileSystemFAT16;
862 if ((ReverseBytesInLong(&buffer_1_[0x52]) == kFAT3) && (buffer_1_[86] ==
'2')) {
863 return kFileSystemFAT32;
865 return kFileSystemUnknown;
870 char * ReadByte(
const int Byteloc) {
871 ReadBlock((Shr__(Byteloc, kSectorShift)));
874 return ((
char *) (&buffer_2_) + (Byteloc & 0x1ff));
879 char * ReadFAT(
const int Clust) {
880 last_fat_entry_ = ((fat1_ << kSectorShift) + (Clust << filesystem_));
881 return ReadByte(last_fat_entry_);
886 int FollowFATChain(
void) {
887 char * temp = ReadFAT(current_cluster_);
889 cluster_write_offset_ = last_fat_entry_;
890 return ReverseBytesInCluster(temp);
895 int NextCluster(
void) {
896 int result = FollowFATChain();
898 if ((result < 2) || (result >= total_clusters_)) {
899 THROW_NULL(kErrorBadClusterValue);
906 void FreeClusters(
int cluster) {
907 while (cluster < end_of_chain_) {
909 THROW(kErrorBadClusterNumber);
911 char * byte_pointer = ReadFAT(cluster);
914 cluster = ReverseBytesInCluster(byte_pointer);
915 WriteReversedCluster(byte_pointer, 0);
931 int CalculateCurrentBlockAddress(
void)
const {
932 return (current_cluster_ << cluster_shift_) +data_region_
933 + (Shr__(seek_position_, kSectorShift) & ((1 << cluster_shift_) - 1));
939 char ConvertToUppercase(
const char character)
const {
940 if ((
'a' <= character) && (character <=
'z')) {
941 return (character - 32);
948 int FlushBuffer(
int r_cnt,
const int flush_metadata) {
949 if (directory_entry_position_ == 0) {
950 THROW_NULL(kErrorFileNotOpenForWriting);
953 if (remaining_cluster_bytes_ < kSectorSize) {
956 int Newcluster = (-1);
957 int Cluststart = (current_cluster_ & (~((Shr__(kSectorSize, filesystem_)) - 1)));
965 int _limit__0025 = (kSectorSize - (1 << filesystem_));
966 int _step__0026 = (1 << filesystem_);
968 if (I >= _limit__0025) _step__0026 = -_step__0026;
970 if (buffer_2_[I] == 0) {
971 if (ReverseBytesInCluster(((
char *) (&buffer_2_) + I)) == 0) {
972 Newcluster = (Cluststart + (Shr__(I, filesystem_)));
973 if (Newcluster >= total_clusters_) {
979 I = (I + _step__0026);
980 }
while (((_step__0026 > 0) && (I <= _limit__0025)) || ((_step__0026 < 0) && (I >= _limit__0025)));
982 if (Newcluster > 1) {
983 WriteReversedCluster(((
char *) (&buffer_2_) + I), (end_of_chain_ + 15));
984 if (cluster_write_offset_ == 0) {
985 WriteReversedWord((ReadByte(directory_entry_position_) + 26), Newcluster);
986 cluster_write_offset_ = (directory_entry_position_ & (kSectorSize - filesystem_));
987 WriteReversedLong((((
char *) (&buffer_2_) + cluster_write_offset_) + 28), (seek_position_ + current_buffer_location_));
988 if (filesystem_ == kFileSystemFAT32) {
989 WriteReversedWord((((
char *) (&buffer_2_) + cluster_write_offset_) + 20), (Shr__(Newcluster, 16)));
992 WriteReversedCluster(ReadByte(cluster_write_offset_), Newcluster);
994 cluster_write_offset_ = (last_fat_entry_ + I);
995 current_cluster_ = Newcluster;
996 remaining_cluster_bytes_ = cluster_size_;
999 Cluststart = (Cluststart + (Shr__(kSectorSize, filesystem_)));
1000 if (Cluststart >= total_clusters_) {
1011 if (remaining_cluster_bytes_ >= kSectorSize) {
1012 sd_spi_.WriteBlock(CalculateCurrentBlockAddress(), (
char *) (&buffer_1_));
1015 if (r_cnt == kSectorSize) {
1016 seek_position_ = (seek_position_ + r_cnt);
1017 remaining_cluster_bytes_ = (remaining_cluster_bytes_ - r_cnt);
1018 current_buffer_location_ = 0;
1019 buffer_end_ = r_cnt;
1023 if ((r_cnt < 0) || (flush_metadata)) {
1024 ReadBlock((Shr__(directory_entry_position_, kSectorShift)));
1027 WriteReversedLong((((
char *) (&buffer_2_) + (directory_entry_position_ & (kSectorSize - filesystem_))) + 28), (seek_position_ + current_buffer_location_));
1040 return FlushBuffer(current_buffer_location_, 1);
1045 int FillBuffer(
void) {
1046 if (seek_position_ >= total_filesize_) {
1049 if (remaining_cluster_bytes_ == 0) {
1050 current_cluster_ = NextCluster();
1051 if (current_cluster_ < 0) {
1052 return current_cluster_;
1054 remaining_cluster_bytes_ = (Min__(cluster_size_, (total_filesize_ - seek_position_)));
1056 sd_spi_.ReadBlock(CalculateCurrentBlockAddress(), buffer_1_);
1059 int bytes_read = kSectorSize;
1060 if ((seek_position_ + bytes_read) >= total_filesize_) {
1061 bytes_read = (total_filesize_ - seek_position_);
1063 seek_position_ = (seek_position_ + bytes_read);
1064 remaining_cluster_bytes_ = (remaining_cluster_bytes_ - bytes_read);
1065 current_buffer_location_ = 0;
1066 buffer_end_ = bytes_read;
1073 void OpenForRead(
void) {
1074 remaining_cluster_bytes_ = (Min__(cluster_size_, total_filesize_));
1081 void OpenForDelete(
char *
string) {
1082 WriteReversedWord(
string, 0xe5);
1083 if (current_cluster_) {
1084 FreeClusters(current_cluster_);
1093 void OpenForWrite(
char *
string,
const int dir_pointer) {
1094 WriteReversedWord((
string + 0x1a), 0);
1095 WriteReversedWord((
string + 0x14), 0);
1096 WriteReversedLong((
string + 0x1c), 0);
1097 cluster_write_offset_ = 0;
1098 directory_entry_position_ = dir_pointer;
1099 if (current_cluster_) {
1100 FreeClusters(current_cluster_);
1104 buffer_end_ = kSectorSize;
1105 current_cluster_ = 0;
1106 total_filesize_ = 0;
1107 remaining_cluster_bytes_ = 0;
1116 void OpenForAppend(
const int dir_pointer) {
1118 remaining_cluster_bytes_ = total_filesize_;
1119 int free_entry = cluster_size_;
1120 if (current_cluster_ >= end_of_chain_) {
1121 current_cluster_ = 0;
1123 while (remaining_cluster_bytes_ > free_entry) {
1124 if (current_cluster_ < 2) {
1125 THROW(kErrorEofWhileFollowingChain);
1127 current_cluster_ = NextCluster();
1130 remaining_cluster_bytes_ = (remaining_cluster_bytes_ - free_entry);
1132 seek_position_ = (total_filesize_ & !(kSectorSize - 1));
1133 buffer_end_ = kSectorSize;
1134 current_buffer_location_ = (remaining_cluster_bytes_ & 0x1ff);
1135 cluster_write_offset_ = 0;
1136 directory_entry_position_ = dir_pointer;
1137 if (current_buffer_location_) {
1138 sd_spi_.ReadBlock(CalculateCurrentBlockAddress(), (
char *) (&buffer_1_));
1141 remaining_cluster_bytes_ = (free_entry - (seek_position_ & (free_entry - 1)));
1143 if ((current_cluster_ < 2) || (remaining_cluster_bytes_ == free_entry)) {
1144 remaining_cluster_bytes_ = 0;
1146 remaining_cluster_bytes_ = (free_entry - (seek_position_ & (free_entry - 1)));
1149 if (current_cluster_ >= 2) {
1160 void ExtractDateTime(
int FATDate,
1161 int & year,
int & month,
int & day,
1162 int & hour,
int & minute,
int & second){
1163 year = ((FATDate >> 25) & 0b1111111) + 1980;
1164 month = (FATDate >> 21) & 0b1111;
1165 day = (FATDate >> 16) & 0b11111;
1166 hour = (FATDate >> 11) & 0b11111;
1167 minute = (FATDate >> 5) & 0b111111;
1168 second = (FATDate & 0b11111) << 1;
1177 static int Min__(
const int a,
const int b) {
1178 return a < b ? a : b;
1187 static int Shr__(
const unsigned int a,
const unsigned int b) {
1195 #ifdef SINGLE_TRANSLATION_UNIT
1199 #endif // LIBPROPELLER_SD_H_