1 #ifndef LIBPROPELLER_SD_H_
2 #define LIBPROPELLER_SD_H_
8 #define RET_IF_ERROR_NULL if(HasError()){return NULL;}
9 #define RET_IF_ERROR if(HasError()){return;}
10 #define THROW_NULL(value) {SetErrorCode((value)); return NULL;}
12 #define THROW(value) {SetErrorCode((value)); return;}
112 Mount(basepin, (basepin + 1), (basepin + 2), (basepin + 3));
122 void Mount(
const int pin_do,
const int pin_clk,
const int pin_di,
const int pin_cs) {
123 if (file_date_time_ == 0) {
131 if ((((
int) buffer_1_) & 0b11) != 0)
133 if ((((
int) buffer_2_) & 0b11) != 0)
139 sd_spi_.
Start(pin_do, pin_clk, pin_di, pin_cs);
144 sd_spi_.
ReadBlock(0, (
char *) (&buffer_1_));
148 if (GetFilesystemType() != kFileSystemUnknown) {
151 start = ReverseBytesInLong(((
char *) (&buffer_1_) + 0x1C6));
155 filesystem_ = GetFilesystemType();
156 if (filesystem_ == kFileSystemUnknown) {
159 if (ReverseBytesInWord(((
char *) (&buffer_1_) + 11)) != kSectorSize) {
162 int sectors_per_cluster = buffer_1_[13];
163 if (sectors_per_cluster & (sectors_per_cluster - 1)) {
167 while (sectors_per_cluster > 1) {
169 sectors_per_cluster = (Shr__(sectors_per_cluster, 1));
171 sectors_per_cluster = (1 << cluster_shift_);
172 cluster_size_ = (kSectorSize << cluster_shift_);
173 int reserved = ReverseBytesInWord(((
char *) (&buffer_1_) + 14));
174 if (buffer_1_[16] != 2) {
177 int sectors = ReverseBytesInWord(((
char *) (&buffer_1_) + 19));
179 sectors = ReverseBytesInLong(((
char *) (&buffer_1_) + 32));
181 fat1_ = (start + reserved);
182 if (filesystem_ == kFileSystemFAT32) {
183 int root_entries = (16 << cluster_shift_);
184 sectors_per_fat_ = ReverseBytesInLong(((
char *) (&buffer_1_) + 36));
185 data_region_ = ((fat1_ + (2 * sectors_per_fat_)) - (2 * sectors_per_cluster));
186 root_directory_ = ((data_region_ + (ReverseBytesInWord(((
char *) (&buffer_1_) + 44)) << cluster_shift_)) << kSectorShift);
187 root_directory_end_ = (root_directory_ + (root_entries << kDirectoryShift));
188 end_of_chain_ = 268435440;
190 int root_entries = ReverseBytesInWord(((
char *) (&buffer_1_) + 17));
191 sectors_per_fat_ = ReverseBytesInWord(((
char *) (&buffer_1_) + 22));
192 root_directory_ = ((fat1_ + (2 * sectors_per_fat_)) << kSectorShift);
193 root_directory_end_ = (root_directory_ + (root_entries << kDirectoryShift));
194 data_region_ = ((1 + (Shr__((root_directory_end_ - 1), kSectorShift))) - (2 * sectors_per_cluster));
195 end_of_chain_ = 65520;
197 if (ReverseBytesInWord(((
char *) (&buffer_1_) + 510)) != 43605) {
200 total_clusters_ = (Shr__(((sectors - data_region_) + start), cluster_shift_));
229 void Open(
const char * filename,
const char file_mode) {
234 char cleaned_filename[11];
237 while (I < 8 && filename[0] !=
'\0' && filename[0] !=
'.') {
238 cleaned_filename[(I++)] = ConvertToUppercase((filename++)[0]);
241 cleaned_filename[(I++)] =
' ';
243 while (filename[0] !=
'\0' && filename[0] !=
'.') {
246 if ((filename)[0] ==
'.') {
249 while ((I < 11) && ((filename)[0])) {
250 cleaned_filename[(I++)] = ConvertToUppercase((filename++)[0]);
253 cleaned_filename[(I++)] =
' ';
267 for (
int directory_pointer = root_directory_;
268 directory_pointer <= root_directory_end_ - kDirectorySize;
269 directory_pointer += kDirectorySize) {
270 char * disk_filename = ReadByte(directory_pointer);
273 if ((free_entry == 0) && (((disk_filename)[0] == 0) || ((disk_filename)[0] == 0xe5))) {
274 free_entry = directory_pointer;
276 if ((disk_filename)[0] == 0) {
277 sentinel = directory_pointer;
283 for (; i <= 10; i++) {
284 if (cleaned_filename[i] != (disk_filename)[i]) {
290 if ((i == 11) && (0 == ((disk_filename)[0x0b] & 0x18))) {
291 current_cluster_ = ReverseBytesInWord((disk_filename + 0x1a));
292 if (filesystem_ == kFileSystemFAT32) {
293 current_cluster_ = (current_cluster_ + (ReverseBytesInWord((disk_filename + 0x14)) << 16));
295 first_cluster_of_file_ = current_cluster_;
296 total_filesize_ = ReverseBytesInLong((disk_filename + 0x1c));
299 if (file_mode ==
'r') {
303 if ((disk_filename)[11] & 0xd9) {
308 if (file_mode ==
'd') {
309 OpenForDelete(disk_filename);
311 }
else if (file_mode ==
'w') {
312 OpenForWrite(disk_filename, directory_pointer);
314 }
else if (file_mode ==
'a') {
315 OpenForAppend(directory_pointer);
324 if (file_mode ==
'd') {
328 if ((file_mode !=
'w') && (file_mode !=
'a')) {
331 directory_entry_position_ = free_entry;
332 if (directory_entry_position_ == 0) {
337 char * S = ReadByte(directory_entry_position_);
339 memset((
void *) S, 0, kDirectorySize);
340 memcpy((
void *) S, (
void *) &cleaned_filename, 11);
341 WriteReversedWord((S + 0x1a), 0);
342 WriteReversedWord((S + 0x14), 0);
343 WriteReversedLong((S + 0x0e), file_date_time_);
344 WriteReversedLong((S + 0x16), file_date_time_);
345 if ((directory_entry_position_ == sentinel) && ((directory_entry_position_ + kDirectorySize) < root_directory_end_)) {
346 WriteReversedWord(ReadByte((directory_entry_position_ + kDirectorySize)), 0);
351 cluster_write_offset_ = 0;
352 current_cluster_ = 0;
353 buffer_end_ = kSectorSize;
365 if (directory_entry_position_) {
369 current_buffer_location_ = 0;
373 remaining_cluster_bytes_ = 0;
374 cluster_write_offset_ = 0;
375 directory_entry_position_ = 0;
376 current_cluster_ = 0;
377 first_cluster_of_file_ = 0;
388 if (current_buffer_location_ >= buffer_end_) {
395 return buffer_1_[(current_buffer_location_++)];
408 int Get(
char * read_buffer,
int bytes_to_read_count) {
411 while (bytes_to_read_count > 0) {
412 if (current_buffer_location_ >= buffer_end_) {
421 T = (Min__((buffer_end_ - current_buffer_location_), bytes_to_read_count));
422 if (((T | (
int) read_buffer) | current_buffer_location_) & 0x3) {
423 memcpy((
void *) read_buffer, (
void *) (
void *) (((
int) (&buffer_1_) + current_buffer_location_)), 1 * (T));
425 memmove((
void *) read_buffer, (
void *) (
void *) (((
int) (&buffer_1_) + current_buffer_location_)), 4 * ((Shr__(T, 2))));
427 current_buffer_location_ = (current_buffer_location_ + T);
429 read_buffer = (read_buffer + T);
430 bytes_to_read_count = (bytes_to_read_count - T);
441 if (current_buffer_location_ == kSectorSize) {
442 if (FlushBuffer(kSectorSize, 0) < 0) {
446 buffer_1_[(current_buffer_location_++)] = C;
458 return Put(B, strlen(B));
469 int Put(
const char * buffer,
int byte_count) {
470 int total_bytes_written = 0;
471 while (byte_count > 0) {
472 if (current_buffer_location_ >= buffer_end_) {
473 FlushBuffer(current_buffer_location_, 0);
477 int bytes_to_write = (Min__((buffer_end_ - current_buffer_location_), byte_count));
478 memcpy((
void *) (
void *) (((
int) (&buffer_1_) + current_buffer_location_)), (
void *) buffer, bytes_to_write);
480 total_bytes_written = (total_bytes_written + bytes_to_write);
481 current_buffer_location_ = (current_buffer_location_ + bytes_to_write);
482 buffer = (buffer + bytes_to_write);
483 byte_count = (byte_count - bytes_to_write);
485 return total_bytes_written;
497 int off = (root_directory_ - (data_region_ << kSectorShift));
498 current_cluster_ = (Shr__(off, (cluster_shift_ + kSectorShift)));
499 seek_position_ = (off - (current_cluster_ << (cluster_shift_ + kSectorShift)));
500 remaining_cluster_bytes_ = (root_directory_end_ - root_directory_);
501 total_filesize_ = (seek_position_ + remaining_cluster_bytes_);
513 if (current_buffer_location_ >= buffer_end_) {
514 if (FillBuffer() < 0) {
517 if (((Shr__(seek_position_, kSectorShift)) & ((1 << cluster_shift_) - 1)) == 0) {
518 (current_cluster_++);
522 unsigned char * at = (
unsigned char *) ((
int) &buffer_1_ + current_buffer_location_);
527 current_buffer_location_ = (current_buffer_location_ + kDirectorySize);
528 if (((at)[0] != 0xe5)
529 && (((at)[0x0b] & 0x18) == 0)) {
530 char * lns = filename;
532 for (
int i = 0; i <= 10; i++) {
533 filename[0] = (at)[i];
538 if (i == 7 || i == 10) {
562 if (((directory_entry_position_) || (position < 0)) || (position > total_filesize_)) {
565 int delta = ((seek_position_ - buffer_end_) & (-cluster_size_));
566 if (position < delta) {
567 current_cluster_ = first_cluster_of_file_;
568 remaining_cluster_bytes_ = (Min__(cluster_size_, total_filesize_));
570 current_buffer_location_ = 0;
574 while (position >= (delta + cluster_size_)) {
575 current_cluster_ = NextCluster();
578 seek_position_ = (seek_position_ + cluster_size_);
579 delta = (delta + cluster_size_);
580 remaining_cluster_bytes_ = (Min__(cluster_size_, (total_filesize_ - seek_position_)));
581 current_buffer_location_ = 0;
585 || position < (seek_position_ - buffer_end_)
586 || position >= (seek_position_ - buffer_end_) + kSectorSize
589 int delta_2 = (seek_position_ + remaining_cluster_bytes_);
590 seek_position_ = (position & -kSectorSize);
591 remaining_cluster_bytes_ = (delta_2 - seek_position_);
595 current_buffer_location_ = position & (kSectorSize - 1);
616 int SetDate(
const int year,
const int month,
const int day,
617 const int hour,
const int minute,
const int second) {
618 file_date_time_ = ((year - 1980) << 25) + (month << 21) + (day << 16);
619 file_date_time_ += (hour << 11) + (minute << 5) + (second >> 1);
620 return file_date_time_;
655 return cluster_size_;
665 return total_clusters_;
673 return total_filesize_;
679 static const int kFileSystemUnknown = 0;
680 static const int kFileSystemFAT16 = 1;
681 static const int kFileSystemFAT32 = 2;
684 static const int kSectorSize = 512;
685 static const int kSectorShift = 9;
686 static const int kDirectorySize = 32;
687 static const int kDirectoryShift = 5;
691 int current_cluster_;
694 int remaining_cluster_bytes_;
695 int current_buffer_location_;
697 int directory_entry_position_;
698 int cluster_write_offset_;
700 int first_cluster_of_file_;
704 int root_directory_end_;
710 int sectors_per_fat_;
735 void SetErrorCode(
const int abort_code) {
742 void WriteBlock(
const int block_index,
char * buffer_address) {
743 sd_spi_.
WriteBlock(block_index, buffer_address);
745 if (block_index >= fat1_) {
746 if (block_index < (fat1_ + sectors_per_fat_)) {
747 sd_spi_.
WriteBlock(block_index + sectors_per_fat_, buffer_address);
755 void FlushIfDirty(
void) {
757 WriteBlock(last_read_, buffer_2_);
765 void ReadBlock(
const int block_index) {
766 if (block_index != last_read_) {
769 sd_spi_.
ReadBlock(block_index, buffer_2_);
771 last_read_ = block_index;
777 int ReverseBytesInWord(
const char * data)
const {
778 return ((data)[0] + ((data)[1] << 8));
783 int ReverseBytesInLong(
const char * data)
const {
784 return (ReverseBytesInWord(data) + (ReverseBytesInWord((data + 2)) << 16));
789 int ReverseBytesInCluster(
const char * cluster)
const {
790 if (filesystem_ == kFileSystemFAT16) {
791 return ReverseBytesInWord(cluster);
793 return ReverseBytesInLong(cluster);
799 void WriteReversedWord(
char * result,
const int data) {
801 result[0] = data >> 8;
807 void WriteReversedLong(
char * result,
const int data) {
808 WriteReversedWord(result, data);
809 WriteReversedWord(result + 2, data >> 16);
814 void WriteReversedCluster(
char * result,
const int data) {
816 if (filesystem_ == kFileSystemFAT16) {
817 WriteReversedWord(result, data);
819 WriteReversedLong(result, data);
823 int GetFilesystemType(
void) {
824 const int kFAT1 =
'F' + (
'A' << 8) + (
'T' << 16) + (
'1' << 24);
825 const int kFAT3 =
'F' + (
'A' << 8) + (
'T' << 16) + (
'3' << 24);
827 if ((ReverseBytesInLong(&buffer_1_[0x36]) == kFAT1) && (buffer_1_[58] ==
'6')) {
828 return kFileSystemFAT16;
830 if ((ReverseBytesInLong(&buffer_1_[0x52]) == kFAT3) && (buffer_1_[86] ==
'2')) {
831 return kFileSystemFAT32;
833 return kFileSystemUnknown;
838 char * ReadByte(
const int Byteloc) {
839 ReadBlock((Shr__(Byteloc, kSectorShift)));
842 return ((
char *) (&buffer_2_) + (Byteloc & 0x1ff));
847 char * ReadFAT(
const int Clust) {
848 last_fat_entry_ = ((fat1_ << kSectorShift) + (Clust << filesystem_));
849 return ReadByte(last_fat_entry_);
854 int FollowFATChain(
void) {
855 char * temp = ReadFAT(current_cluster_);
857 cluster_write_offset_ = last_fat_entry_;
858 return ReverseBytesInCluster(temp);
863 int NextCluster(
void) {
864 int result = FollowFATChain();
866 if ((result < 2) || (result >= total_clusters_)) {
874 void FreeClusters(
int cluster) {
875 while (cluster < end_of_chain_) {
879 char * byte_pointer = ReadFAT(cluster);
882 cluster = ReverseBytesInCluster(byte_pointer);
883 WriteReversedCluster(byte_pointer, 0);
899 int CalculateCurrentBlockAddress(
void)
const {
900 return (current_cluster_ << cluster_shift_) +data_region_
901 + (Shr__(seek_position_, kSectorShift) & ((1 << cluster_shift_) - 1));
907 char ConvertToUppercase(
const char character)
const {
908 if ((
'a' <= character) && (character <=
'z')) {
909 return (character - 32);
916 int FlushBuffer(
int r_cnt,
const int flush_metadata) {
917 if (directory_entry_position_ == 0) {
921 if (remaining_cluster_bytes_ < kSectorSize) {
924 int Newcluster = (-1);
925 int Cluststart = (current_cluster_ & (~((Shr__(kSectorSize, filesystem_)) - 1)));
933 int _limit__0025 = (kSectorSize - (1 << filesystem_));
934 int _step__0026 = (1 << filesystem_);
936 if (I >= _limit__0025) _step__0026 = -_step__0026;
938 if (buffer_2_[I] == 0) {
939 if (ReverseBytesInCluster(((
char *) (&buffer_2_) + I)) == 0) {
940 Newcluster = (Cluststart + (Shr__(I, filesystem_)));
941 if (Newcluster >= total_clusters_) {
947 I = (I + _step__0026);
948 }
while (((_step__0026 > 0) && (I <= _limit__0025)) || ((_step__0026 < 0) && (I >= _limit__0025)));
950 if (Newcluster > 1) {
951 WriteReversedCluster(((
char *) (&buffer_2_) + I), (end_of_chain_ + 15));
952 if (cluster_write_offset_ == 0) {
953 WriteReversedWord((ReadByte(directory_entry_position_) + 26), Newcluster);
954 cluster_write_offset_ = (directory_entry_position_ & (kSectorSize - filesystem_));
955 WriteReversedLong((((
char *) (&buffer_2_) + cluster_write_offset_) + 28), (seek_position_ + current_buffer_location_));
956 if (filesystem_ == kFileSystemFAT32) {
957 WriteReversedWord((((
char *) (&buffer_2_) + cluster_write_offset_) + 20), (Shr__(Newcluster, 16)));
960 WriteReversedCluster(ReadByte(cluster_write_offset_), Newcluster);
962 cluster_write_offset_ = (last_fat_entry_ + I);
963 current_cluster_ = Newcluster;
964 remaining_cluster_bytes_ = cluster_size_;
967 Cluststart = (Cluststart + (Shr__(kSectorSize, filesystem_)));
968 if (Cluststart >= total_clusters_) {
979 if (remaining_cluster_bytes_ >= kSectorSize) {
980 sd_spi_.
WriteBlock(CalculateCurrentBlockAddress(), (
char *) (&buffer_1_));
983 if (r_cnt == kSectorSize) {
984 seek_position_ = (seek_position_ + r_cnt);
985 remaining_cluster_bytes_ = (remaining_cluster_bytes_ - r_cnt);
986 current_buffer_location_ = 0;
991 if ((r_cnt < 0) || (flush_metadata)) {
992 ReadBlock((Shr__(directory_entry_position_, kSectorShift)));
995 WriteReversedLong((((
char *) (&buffer_2_) + (directory_entry_position_ & (kSectorSize - filesystem_))) + 28), (seek_position_ + current_buffer_location_));
1008 return FlushBuffer(current_buffer_location_, 1);
1013 int FillBuffer(
void) {
1014 if (seek_position_ >= total_filesize_) {
1017 if (remaining_cluster_bytes_ == 0) {
1018 current_cluster_ = NextCluster();
1019 if (current_cluster_ < 0) {
1020 return current_cluster_;
1022 remaining_cluster_bytes_ = (Min__(cluster_size_, (total_filesize_ - seek_position_)));
1024 sd_spi_.
ReadBlock(CalculateCurrentBlockAddress(), buffer_1_);
1027 int bytes_read = kSectorSize;
1028 if ((seek_position_ + bytes_read) >= total_filesize_) {
1029 bytes_read = (total_filesize_ - seek_position_);
1031 seek_position_ = (seek_position_ + bytes_read);
1032 remaining_cluster_bytes_ = (remaining_cluster_bytes_ - bytes_read);
1033 current_buffer_location_ = 0;
1034 buffer_end_ = bytes_read;
1041 void OpenForRead(
void) {
1042 remaining_cluster_bytes_ = (Min__(cluster_size_, total_filesize_));
1049 void OpenForDelete(
char *
string) {
1050 WriteReversedWord(
string, 0xe5);
1051 if (current_cluster_) {
1052 FreeClusters(current_cluster_);
1061 void OpenForWrite(
char *
string,
const int dir_pointer) {
1062 WriteReversedWord((
string + 0x1a), 0);
1063 WriteReversedWord((
string + 0x14), 0);
1064 WriteReversedLong((
string + 0x1c), 0);
1065 cluster_write_offset_ = 0;
1066 directory_entry_position_ = dir_pointer;
1067 if (current_cluster_) {
1068 FreeClusters(current_cluster_);
1072 buffer_end_ = kSectorSize;
1073 current_cluster_ = 0;
1074 total_filesize_ = 0;
1075 remaining_cluster_bytes_ = 0;
1084 void OpenForAppend(
const int dir_pointer) {
1086 remaining_cluster_bytes_ = total_filesize_;
1087 int free_entry = cluster_size_;
1088 if (current_cluster_ >= end_of_chain_) {
1089 current_cluster_ = 0;
1091 while (remaining_cluster_bytes_ > free_entry) {
1092 if (current_cluster_ < 2) {
1095 current_cluster_ = NextCluster();
1098 remaining_cluster_bytes_ = (remaining_cluster_bytes_ - free_entry);
1100 seek_position_ = (total_filesize_ & !(kSectorSize - 1));
1101 buffer_end_ = kSectorSize;
1102 current_buffer_location_ = (remaining_cluster_bytes_ & 0x1ff);
1103 cluster_write_offset_ = 0;
1104 directory_entry_position_ = dir_pointer;
1105 if (current_buffer_location_) {
1106 sd_spi_.
ReadBlock(CalculateCurrentBlockAddress(), (
char *) (&buffer_1_));
1109 remaining_cluster_bytes_ = (free_entry - (seek_position_ & (free_entry - 1)));
1111 if ((current_cluster_ < 2) || (remaining_cluster_bytes_ == free_entry)) {
1112 remaining_cluster_bytes_ = 0;
1114 remaining_cluster_bytes_ = (free_entry - (seek_position_ & (free_entry - 1)));
1117 if (current_cluster_ >= 2) {
1130 static int Min__(
const int a,
const int b) {
1131 return a < b ? a :
b;
1140 static int Shr__(
const unsigned int a,
const unsigned int b) {
1146 #endif // LIBPROPELLER_SD_H_