//*************************************************************************** //Function: get cluster entry value from FAT to find out the next cluster in the chain //or set new cluster entry in FAT //Arguments: 1. current cluster number, 2. get_set (=GET, if next cluster is to be found or = SET, //if next cluster is to be set 3. next cluster number, if argument#2 = SET, else 0 //return: next cluster number, if if argument#2 = GET, else 0 //**************************************************************************** unsigned long getSetNextCluster (unsigned long clusterNumber, unsigned char get_set, unsigned long clusterEntry) { unsigned int FATEntryOffset; unsigned long *FATEntryValue; unsigned long FATEntrySector; unsigned char retry = 0; //get sector number of the cluster entry in the FAT FATEntrySector = unusedSectors + reservedSectorCount + ((clusterNumber * 4) / bytesPerSector) ; //get the offset address in that sector number FATEntryOffset = (unsigned int) ((clusterNumber * 4) % bytesPerSector); //read the sector into a buffer while(retry <10) { if(!SD_readSingleBlock(FATEntrySector)) break; retry++; } //get the cluster address from the buffer FATEntryValue = (unsigned long *) &buffer[FATEntryOffset]; if(get_set == GET) return ((*FATEntryValue) & 0x0fffffff); *FATEntryValue = clusterEntry; //for setting new value in cluster entry in FAT SD_writeSingleBlock(FATEntrySector); return 0; }
//******************************************************************************************** //Function: to get or set next free cluster or total free clusters in FSinfo sector of SD card //Arguments: 1.flag:TOTAL_FREE or NEXT_FREE, // 2.flag: GET or SET // 3.new FS entry, when argument2 is SET; or 0, when argument2 is GET //return: -next free cluster, if arg1 is NEXT_FREE & arg2 is GET // -total number of free clusters, if arg1 is TOTAL_FREE & arg2 is GET // -0xffffffff, if any error or if arg2 is SET //******************************************************************************************** unsigned long getSetFreeCluster(unsigned char totOrNext, unsigned char get_set, unsigned long FSEntry) { struct FSInfo_Structure *FS = (struct FSInfo_Structure *) &buffer; unsigned char error; SD_readSingleBlock(unusedSectors + 1); if((FS->leadSignature != 0x41615252) || (FS->structureSignature != 0x61417272) || (FS->trailSignature !=0xaa550000)) return 0xffffffff; if(get_set == GET) { if(totOrNext == TOTAL_FREE) return(FS->freeClusterCount); else // when totOrNext = NEXT_FREE return(FS->nextFreeCluster); } else { if(totOrNext == TOTAL_FREE) FS->freeClusterCount = FSEntry; else // when totOrNext = NEXT_FREE FS->nextFreeCluster = FSEntry; error = SD_writeSingleBlock(unusedSectors + 1); return error; //update FSinfo } return 0xffffffff; }
unsigned char readBootSector(void) { unsigned int signature; unsigned long firstSector; unsigned long bootfilestart; unsigned long hiddenSectors; unsigned char numberofFATs; unsigned long FATsize_F32; unsigned char found; unusedSectors = 0; // read first block on card SD_readSingleBlock(0); // check if it is boot sector if (buffer[JUMPBOOT] != 0xE9 && buffer[JUMPBOOT] != 0xEB) { firstSector = *(unsigned long *)&buffer[FIRSTSECTOR]; unusedSectors = firstSector; SD_readSingleBlock(firstSector); if (buffer[JUMPBOOT] != 0xE9 && buffer[JUMPBOOT] != 0xEB) { return 1; } } // read data from bpb bytesPerSector = *(unsigned int*)&buffer[BYTESPERSECTOR]; hiddenSectors = *(unsigned long*)&buffer[28]; reservedSectorCount = *(unsigned int*)&buffer[RESERVEDSECTORCOUNT]; numberofFATs = *(unsigned char*)&buffer[16]; FATsize_F32 = *(unsigned long*)&buffer[FATSIZEF32]; sectorPerCluster = *(unsigned char*)&buffer[SECTORPERCLUSTER]; rootCluster = *(unsigned char*)&buffer[ROOTCLUSTER]; firstDataSector = hiddenSectors + reservedSectorCount + (numberofFATs * FATsize_F32); return 0; }
//*************************************************************************** //Function: to get DIR/FILE list or a single file address (cluster number) or to delete a specified file //Arguments: #1 - flag: GET_LIST, GET_FILE or DELETE #2 - pointer to file name (0 if arg#1 is GET_LIST) //return: first cluster of the file, if flag = GET_FILE // print file/dir list of the root directory, if flag = GET_LIST // Delete the file mentioned in arg#2, if flag = DELETE //**************************************************************************** struct dir_Structure* findFiles (unsigned char flag, unsigned char *fileName) { unsigned long cluster, sector, firstSector; struct dir_Structure *dir; unsigned int i; unsigned char j; cluster = rootCluster; //root cluster while(1) { firstSector = getFirstSector (cluster); for(sector = 0; sector < sectorPerCluster; sector++) { SD_readSingleBlock (firstSector + sector); for(i=0; i<bytesPerSector; i+=32) { dir = (struct dir_Structure *) &buffer[i]; if(dir->name[0] == EMPTY) //indicates end of the file list of the directory { if((flag == GET_FILE) || (flag == DELETE)) //transmitString("File does not exist!"); return 0; } else if((dir->name[0] != DELETED) && (dir->attrib != ATTR_LONG_NAME)) { if((flag == GET_FILE) || (flag == DELETE)) { for(j=0; j<11; j++) if(dir->name[j] != fileName[j]) break; if(j == 11) { if(flag == GET_FILE) return (dir); } } } } } cluster = (getSetNextCluster (cluster, GET, 0)); if(cluster > 0x0ffffff6) return 0; if(cluster == 0) { //transmitString("Error in getting cluster"); return 0; } } return 0; }
//*************************************************************************** //Function: to read data from boot sector of SD card, to determine important //parameters like bytesPerSector, sectorsPerCluster etc. //Arguments: none //return: none //*************************************************************************** unsigned char getBootSectorData (void) { struct BS_Structure *bpb; //mapping the buffer onto the structure struct MBRinfo_Structure *mbr; struct partitionInfo_Structure *partition; unsigned long dataSectors; unusedSectors = 0; SD_readSingleBlock(0); bpb = (struct BS_Structure *)buffer; if(bpb->jumpBoot[0]!=0xE9 && bpb->jumpBoot[0]!=0xEB) //check if it is boot sector { mbr = (struct MBRinfo_Structure *) buffer; //if it is not boot sector, it must be MBR if(mbr->signature != 0xaa55) return 1; //if it is not even MBR then it's not FAT32 partition = (struct partitionInfo_Structure *)(mbr->partitionData);//first partition unusedSectors = partition->firstSector; //the unused sectors, hidden to the FAT SD_readSingleBlock(partition->firstSector);//read the bpb sector bpb = (struct BS_Structure *)buffer; if(bpb->jumpBoot[0]!=0xE9 && bpb->jumpBoot[0]!=0xEB) return 1; } bytesPerSector = bpb->bytesPerSector; sectorPerCluster = bpb->sectorPerCluster; reservedSectorCount = bpb->reservedSectorCount; rootCluster = bpb->rootCluster;// + (sector / sectorPerCluster) +1; firstDataSector = bpb->hiddenSectors + reservedSectorCount + (bpb->numberofFATs * bpb->FATsize_F32); dataSectors = bpb->totalSectors_F32 - bpb->reservedSectorCount - ( bpb->numberofFATs * bpb->FATsize_F32); totalClusters = dataSectors / sectorPerCluster; if((getSetFreeCluster (TOTAL_FREE, GET, 0)) > totalClusters) //check if FSinfo free clusters count is valid freeClusterCountUpdated = 0; else freeClusterCountUpdated = 1; return 0; }
unsigned long findFirmware() { unsigned long cluster, firstSector; unsigned char attrib; unsigned int firstClusterHI; // high word of first cluster unsigned int firstClusterLO; // low word of first cluster unsigned long firstCluster; unsigned long theCluster; unsigned long sector; int i,j; cluster = rootCluster; firstSector = getFirstSector(cluster); SD_readSingleBlock(firstSector); for (i = 0; i < bytesPerSector; i += 32) { if (buffer[i] == EMPTY) { return 0; } attrib = buffer[ATTRIB+i]; if ((buffer[i] != DELETED) && attrib != ATTR_LONG_NAME) { // check for firmware file if ((buffer[i] == 'F') && (buffer[i+1] == 'I') && (buffer[i+2] == 'R') && (buffer[i+3] == 'M') && (buffer[i+8] == 'B') && (buffer[i+9] == 'I') && (buffer[i+10] == 'N')) { firstClusterLO = *(unsigned int*)&buffer[i+FIRSTCLUSTERLO]; // assume firstClusterHI is 0 firstCluster = firstClusterLO; return firstCluster; } } } return 0; }
//uint8_t readCfgFile(DATE *adate,TIME *atime, uint8_t *filename_dat, uint8_t atomic) uint8_t readCfgFile(char *filename_dat) //, uint8_t atomic) { DIR *dir; uint32_t cluster, fileSize, firstSector; uint16_t k; uint8_t i,j,ld,lt; uint8_t filename[]= "CONFIG CFG"; uint8_t filename2[]="_CONFIG CFG"; dir = findFiles (GET_FILE, filename, filename); //, atomic); //get the file location if(dir == 0) return(0); cluster = (((uint32_t) dir->firstClusterHI) << 16) | dir->firstClusterLO; fileSize = dir->fileSize; ld = 0; lt = 0; while(1) { ClusterNumber = cluster; firstSector = getFirstSector (); for(j=0; j<SectorPerCluster; j++) { SD_readSingleBlock(firstSector + j); //, atomic); for(k=0; k<512; k++) { switch(buffer[k]) { case 'S': k++; if(buffer[k]=='T') { k++; Time.h = getDec((uint8_t*)buffer+k); //k +=2; Time.m = getDec((uint8_t*)buffer+k+2); //k +=2; Time.s = getDec((uint8_t*)buffer+k+4); } else if(buffer[k]=='D') { k++; Date.d = getDec(&buffer[k]); //k +=2; Date.m = getDec(&buffer[k+2]); //k +=2; Date.y = 20 + getDec(&buffer[k+4]); } else if(buffer[k]=='F') { k = k+2; for(i=0;i<8;i++) { if(buffer[k+i] < 0x21) //if any control code and space { filename_dat[i] = 0x00; break; } filename_dat[i] = buffer[k+i]; } filename_dat[i+1] = 0x00; // i = strlcpy(filename_dat,&(buffer[k]),9); k = k+i; } else if(buffer[k]=='I') { k +=2; for(i=0;i<13;i++) { if(buffer[k+i] < 0x20) //if any control code break; inset[i] = buffer[k+i]; } } break; case 'A': k++; if(buffer[k]=='D') { k++; ADate[ld].d = getDec((uint8_t*)buffer+k); //k +=2; ADate[ld].m = getDec((uint8_t*)buffer+k+2); //k +=2; ADate[ld].y = 20 + getDec((uint8_t*)buffer+k+4); ld++; } else if(buffer[k]=='T') { k++; ATime[lt].h = getDec((uint8_t*)buffer+k); //k +=2; ATime[lt].m = getDec((uint8_t*)buffer+k+2); //k +=2; ATime[lt].s = getDec((uint8_t*)buffer+k+4); lt++; } break; } if (k >= fileSize ) { findFiles(RENAME, filename, filename2); //, atomic); return(lt); } } } ClusterNumber = cluster; cluster = getSetNextCluster (GET); //, 0, atomic); if(cluster == 0) { //#if BIGAVR == 1 // printf_P(PSTR("ERR GETTING CLUSTERb\n")); //#endif //BIGAVR return(0); } } return(0); }
int main(void) { unsigned char option, error, data, FAT32_active; unsigned int i; unsigned char fileName[13]; _delay_ms(100); //delay for VCC stabilization init_devices(); PORTD |= 0x04; //switching ON the LED (for testing purpose only) TX_NEWLINE; TX_NEWLINE; transmitString_F (PSTR("***********************************")); TX_NEWLINE; transmitString_F (PSTR(" Dharmani's microSD Card Testing..")); TX_NEWLINE; transmitString_F (PSTR("***********************************")); TX_NEWLINE; SD_init(); SPI_HIGH_SPEED; //SCK - 4 MHz _delay_ms(1); FAT32_active = 1; error = getBootSectorData (); //read boot sector and keep necessary data in global variables if(error) { transmitString_F (PSTR("FAT32 not found!")); //FAT32 incompatible drive FAT32_active = 0; } while(1) { TX_NEWLINE; transmitString_F(PSTR("Press any key...")); TX_NEWLINE; option = receiveByte(); TX_NEWLINE; transmitString_F(PSTR("> 0 : Erase Blocks")); TX_NEWLINE; transmitString_F(PSTR("> 1 : Write single Block")); TX_NEWLINE; transmitString_F(PSTR("> 2 : Read single Block")); #ifndef FAT_TESTING_ONLY TX_NEWLINE; transmitString_F(PSTR("> 3 : Write multiple Blocks")); TX_NEWLINE; transmitString_F(PSTR("> 4 : Read multiple Blocks")); #endif TX_NEWLINE; transmitString_F(PSTR("> 5 : Get file list")); TX_NEWLINE; transmitString_F(PSTR("> 6 : Read File")); TX_NEWLINE; transmitString_F(PSTR("> 7 : Create File")); TX_NEWLINE; transmitString_F(PSTR("> 8 : Delete File")); TX_NEWLINE; transmitString_F(PSTR("> 9 : Read SD Memory Capacity (Total/Free)")); TX_NEWLINE; TX_NEWLINE; transmitString_F(PSTR("> Select Option (0-9): ")); /*WARNING: If option 0, 1 or 3 is selected, the card may not be detected by PC/Laptop again, as it disturbs the FAT format, and you may have to format it again with FAT32. This options are given for learning the raw data transfer to & from the SD Card*/ option = receiveByte(); transmitByte(option); if(option >= 0x35 && option <= 0x39) //options 5 to 9 disabled if FAT32 not found { if(!FAT32_active) { TX_NEWLINE; TX_NEWLINE; transmitString_F(PSTR("FAT32 options disabled!")); continue; } } if((option >= 0x30) && (option <=0x34)) //get starting block address for options 0 to 4 { TX_NEWLINE; TX_NEWLINE; transmitString_F(PSTR("Enter the Block number (0000-9999):")); data = receiveByte(); transmitByte(data); startBlock = (data & 0x0f) * 1000; data = receiveByte(); transmitByte(data); startBlock += (data & 0x0f) * 100; data = receiveByte(); transmitByte(data); startBlock += (data & 0x0f) * 10; data = receiveByte(); transmitByte(data); startBlock += (data & 0x0f); TX_NEWLINE; } totalBlocks = 1; #ifndef FAT_TESTING_ONLY if((option == 0x30) || (option == 0x33) || (option == 0x34)) //get total number of blocks for options 0, 3 or 4 { TX_NEWLINE; TX_NEWLINE; transmitString_F(PSTR("How many blocks? (000-999):")); data = receiveByte(); transmitByte(data); totalBlocks = (data & 0x0f) * 100; data = receiveByte(); transmitByte(data); totalBlocks += (data & 0x0f) * 10; data = receiveByte(); transmitByte(data); totalBlocks += (data & 0x0f); TX_NEWLINE; } #endif switch (option) { case '0': //error = SD_erase (block, totalBlocks); error = SD_erase (startBlock, totalBlocks); TX_NEWLINE; if(error) transmitString_F(PSTR("Erase failed..")); else transmitString_F(PSTR("Erased!")); break; case '1': TX_NEWLINE; transmitString_F(PSTR(" Enter text (End with ~):")); i=0; do { data = receiveByte(); transmitByte(data); buffer[i++] = data; if(data == '\r') //append 'newline' character whenevr 'carriage return' is received { transmitByte('\n'); buffer[i++] = '\n'; } if(i == 512) break; }while (data != '~'); error = SD_writeSingleBlock (startBlock); TX_NEWLINE; TX_NEWLINE; if(error) transmitString_F(PSTR("Write failed..")); else transmitString_F(PSTR("Write successful!")); break; case '2': error = SD_readSingleBlock (startBlock); TX_NEWLINE; if(error) transmitString_F(PSTR("Read failed..")); else { for(i=0;i<512;i++) { if(buffer[i] == '~') break; transmitByte(buffer[i]); } TX_NEWLINE; TX_NEWLINE; transmitString_F(PSTR("Read successful!")); } break; //next two options will work only if following macro is cleared from SD_routines.h #ifndef FAT_TESTING_ONLY case '3': error = SD_writeMultipleBlock (startBlock, totalBlocks); TX_NEWLINE; if(error) transmitString_F(PSTR("Write failed..")); else transmitString_F(PSTR("Write successful!")); break; case '4': error = SD_readMultipleBlock (startBlock, totalBlocks); TX_NEWLINE; if(error) transmitString_F(PSTR("Read failed..")); else transmitString_F(PSTR("Read successful!")); break; #endif case '5': TX_NEWLINE; findFiles(GET_LIST,0); break; case '6': case '7': case '8': TX_NEWLINE; TX_NEWLINE; transmitString_F(PSTR("Enter file name: ")); for(i=0; i<13; i++) fileName[i] = 0x00; //clearing any previously stored file name i=0; while(1) { data = receiveByte(); if(data == '\r') break; //'ENTER' key pressed if(data == 0x08) //'Back Space' key pressed { if(i != 0) { transmitByte(data); transmitByte(' '); transmitByte(data); i--; } continue; } if(data <0x20 || data > 0x7e) continue; //check for valid English text character transmitByte(data); fileName[i++] = data; if(i==13){transmitString_F(PSTR(" file name too long..")); break;} } if(i>12) break; TX_NEWLINE; if(option == '6') readFile( READ, fileName); if(option == '7') createFile(fileName); if(option == '8') deleteFile(fileName); break; case '9': memoryStatistics(); break; default: TX_NEWLINE; TX_NEWLINE; transmitString_F(PSTR(" Invalid option!")); TX_NEWLINE; } TX_NEWLINE; } return 0; }
//uint8_t readCfgFile(DATE *adate,TIME *atime, uint8_t *filename_dat, uint8_t atomic) uint8_t readCfgFile(uint8_t *filename_dat, uint8_t atomic) { DIR *dir; uint32_t cluster, fileSize, firstSector; uint16_t k; uint8_t i,j,ld,lt; uint8_t filename[]="CONFIG CFG"; uint8_t filename2[]="_CONFIG CFG"; TIME_t time; DATE_t date; dir = findFiles (GET_FILE, filename, filename, atomic); //get the file location if(dir == 0) return(0); cluster = (((uint32_t) dir->firstClusterHI) << 16) | dir->firstClusterLO; fileSize = dir->fileSize; ld = 0; lt = 0; while(1) { firstSector = getFirstSector (cluster); for(j=0; j<SectorPerCluster; j++) { SD_readSingleBlock(firstSector + j, atomic); for(k=0; k<512; k++) { switch(buffer[k]) { case 'S': k++; switch(buffer[k]) { case 'T': k++; time.h = getDec((uint8_t*)buffer+k); time.m = getDec((uint8_t*)buffer+k+2); time.s = getDec((uint8_t*)buffer+k+4); break; case 'D': k++; date.d = getDec(&buffer[k]); date.m = getDec(&buffer[k+2]); date.y = 20 + getDec(&buffer[k+4]); break; case 'F': k = k+2; for(i=0;i<13;i++) { if(buffer[k+i] < 0x20) //if any control code break; filename_dat[i] = buffer[k+i]; } k = k+i; break; case 'M': //mask definitions: M - mic only, S - SHT sensor only, T - DS1820 1-wire sensor, X - Mic+SHT, '-' - nothing k++; for(i=0;i<12;i++) { Mask.SHT = Mask.SHT<<1; Mask.MIC = Mask.MIC<<1; switch(buffer[k+i]) { // case 'X': //SHT mask generated from mic mask! // Mask.SHT |= 0x0001; case 'M': Mask.MIC |= 0x0001; break; // case 'S': // Mask.SHT |= 0x0001; // break; case 'T': Mask.DS |= 0x01; // any T will cause DS mask to be one... break; default: break; } } k = k+i; } break; case 'A': k++; if(buffer[k]=='D') { k++; ADate[ld].d = getDec((uint8_t*)buffer+k); //k +=2; ADate[ld].m = getDec((uint8_t*)buffer+k+2); //k +=2; ADate[ld].y = 20 + getDec((uint8_t*)buffer+k+4); ld++; } else if(buffer[k]=='T') { k++; ATime[lt].h = getDec((uint8_t*)buffer+k); //k +=2; ATime[lt].m = getDec((uint8_t*)buffer+k+2); //k +=2; ATime[lt].s = getDec((uint8_t*)buffer+k+4); lt++; } break; } if (k >= fileSize ) { findFiles(RENAME,filename, filename2, atomic); RTC_SetDateTime(&date, &time); //?? if(Mask.SHT) // { generate_mask_bm(); // } return(lt); } } } cluster = getSetNextCluster (cluster, GET, 0, atomic); if(cluster == 0) { #if RSCOM == 1 printf_P(PSTR("ERR GETTING CLUSTERb\n")); #endif //BIGAVR return(0); } } return(0); }