Académique Documents
Professionnel Documents
Culture Documents
1 of 54
FAQ
Forum Help
Register
Profile
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
Search
Log
in
Message
CCS FAT driver bugfix!
Posted: Sun Aug 29, 2010 10:46 am
and
Code:
signed int8 get_prev_addr(int32* my_addr)
{
int32 temp;
#ifdef FAT32
int32 c;
3/17/2015 3:49 PM
2 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
#else
int16 c;
#endif
temp = *my_addr;
// if we're trying to go backwards one entry from the beginning of the root,
// we won't be able to...
if(temp <= Root_Dir)
return GOODEC;
// check to make sure that the next iteration will give us a contiguous address
if((temp >= Data_Start ) && ((temp - Data_Start) % Bytes_Per_Cluster == 0))
{
c = addr_to_cluster(temp);
if(get_prev_cluster(&c) == EOF)
return EOF;
temp = cluster_to_addr(c) + Bytes_Per_Cluster;
}
*my_addr = temp - 1;
return GOODEC;
}
Edit, I've realized the above works because I've slightly altered the "fat_init" function too. The
following in "fat_init":
Code:
#ifdef FAT32
Data_Start = Bytes_Per_Cluster + Root_Dir;
#else // FAT16
andrewg
Code:
signed int8 get_short_file_name(int32 file_entry_addr, char sname[], int8 type)
{
int8
buf,
i,
j = 0;
// one short file name has, at the most, 11 characters
for(i = 0; i < 11; ++i)
{
// read in a character
if(mmcsd_read_data(i + file_entry_addr, 1, &buf) != GOODEC)
return EOF;
// convert the character
if(buf != ' ')
{
if (i == 8 && type != 0x10) sname[j++] = '.';
sname[j++] = tolower(buf);
}
}
if (sname[j - 1] == '.') --j;
sname[j] = '\0';
return GOODEC;
}
_________________
Andrew
BugVito
3/17/2015 3:49 PM
3 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
Good stuff andrewg. This got me going until I formatted the sd card. It has seen a fair amount of trial
and error and procedures before it finally worked, and this was all before applying your changes.
Could you explain exactly what is needed for the sd card to work on both a pc and on a board using ccs
mmcsd and fat drivers, or simply what format type, etc...?
I have tried formatting as FAT32 with default settings, no luck, FAT32 with 512 size blocks, still no luck,
completely wiped the card using a hex editor, then format with both options above, still no luck.
It is unfortunate that ccs would deploy a crippled/incomplete driver without maintaining it. I've had an
ethernet board from ccs for a while, with close to no luck at using the sd card.
andrewg
I've only ever used cards formatted on my PC or in a camera. All my standard SD (not SHDC) cards
work fine. After I made my changes (cluster fix and MBR enhancement) the cards have just worked.
I have to admit, though, that so far I've only ever had the PIC read a card (I've only used it for
firmware updating, so far). Writing is coming soon. Once I've done some writing and made sure it
actually works (I don't see why it won't, since reading works fine), then I'm going to write to CCS and
give them my new code.
When using the CCS code, make sure you've compiled it for the correct FAT16/32 variant for the cards
you're using (probably FAT32).
Also, so far I've implemented SD cards on pure 3.3V logic, so no 5V <--> 3.3V level translations
complicate things. I've also made sure I have pullup resistors on both the CS and MISO (data from card
to PIC) lines.
_________________
Andrew
BugVito
Ahh read only. This is good to know, and may be sufficient for now actually.
Joined: 12 Nov 2010
Posts: 3
My test starts by writting a file, appending text to it, and then reading from it. I'll chop those first bits
off for now, and test a few different formats.
Everything was working, read and write, using the ex_fat.c example and your fixed code. That is
before formatting the card. So a fix may not be that far off.
I seem to be using the same setup, FAT32, 3.3V, and pullup resistors.
Thanks for the info and initiative! Most appreciated!
KONAMI
FAT32
Posted: Sat Dec 17, 2011 6:58 am
quangtk87
3/17/2015 3:49 PM
4 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
When I repair fat.c and mmcsd.c on ccs follow Andrewg. Every command is good, but it just working on
my Hyperterminal. Plug SD card in my PC is nothing, empty. Anybody help me! plz
_________________
tinhquang
opas
I tried to use CCS lib to make a data logger. I found a lot of bugs in the lib and need much time to
modify it. At last I can make file with text in the card and can read it in Windows. Only one thing I can
not fix it : when I put data in cluster 2, Notepad show errors. If someone know the solution, please let
me know
Next is the lib code
mmcsd.c
Code:
/////////////////////////////////////////////////////////////////////////
////
MMCSD.c
////
////
////
////
This is a low-level driver for MMC and SD cards.
////
////
////
//// --User Functions-////
////
////
//// mmcsd_init(): Initializes the media.
////
////
////
//// mmcsd_read_byte(a, p)
////
//// Reads a byte from the MMC/SD card at location a, saves to
////
//// pointer p. Returns 0 if OK, non-zero if error.
////
////
////
//// mmcsd_read_data(a, n, p)
////
//// Reads n bytes of data from the MMC/SD card starting at address ////
//// a, saves result to pointer p. Returns 0 if OK, non-zero if
////
//// error.
////
////
////
//// mmcsd_flush_buffer()
////
//// The two user write functions (mmcsd_write_byte() and
////
//// mmcsd_write_data()) maintain a buffer to speed up the writing ////
//// process. Whenever a read or write is performed, the write
////
//// buffer is loaded with the specified page and only the
////
//// contents of this buffer is changed. If any future writes
////
//// cross a page boundary then the buffer in RAM is written
////
//// to the MMC/SD and then the next page is loaded into the
////
//// buffer. mmcsd_flush_buffer() forces the contents in RAM
////
//// to the MMC/SD card. Returns 0 if OK, non-zero if errror.
////
////
////
//// mmcsd_write_byte(a, d)
////
//// Writes data byte d to the MMC/SD address a. Intelligently
////
//// manages a write buffer, therefore you may need to call
////
//// mmcsd_flush_buffer() to flush the buffer.
////
////
////
//// mmcsd_write_data(a, n, p)
////
//// Writes n bytes of data from pointer p to the MMC/SD card
////
//// starting at address a. This function intelligently manages
////
//// a write buffer, therefore if you may need to call
////
//// mmcsd_flush_buffer() to flush any buffered characters.
////
//// returns 0 if OK, non-zero if error.
////
////
////
//// mmcsd_read_block(a, s, p)
////
//// Reads an entire page from the SD/MMC. Keep in mind that the
////
//// start of the read has to be aligned to a block
////
//// (Address % 512 = 0). Therefore s must be evenly divisible by ////
//// 512. At the application level it is much more effecient to
////
//// to use mmcsd_read_data() or mmcsd_read_byte(). Returns 0
////
//// if successful, non-zero if error.
////
////
////
//// mmcsd_write_block(a, s, p):
////
//// Writes an entire page to the SD/MMC. This will write an
////
//// entire page to the SD/MMC, so the address and size must be
////
//// evenly divisble by 512. At the application level it is much ////
//// more effecient to use mmcsd_write_data() or mmcsd_write_byte().////
//// Returns 0 if successful, non-zero if error.
////
////
////
3/17/2015 3:49 PM
5 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
PIN_C3
PIN_C4
PIN_C5
PIN_B4
//o
//i
//o
//o
3/17/2015 3:49 PM
6 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
enum MMCSD_err
{MMCSD_GOODEC = 0,
MMCSD_IDLE = 0x01,
MMCSD_ERASE_RESET = 0x02,
MMCSD_ILLEGAL_CMD = 0x04,
MMCSD_CRC_ERR = 0x08,
MMCSD_ERASE_SEQ_ERR = 0x10,
MMCSD_ADDR_ERR = 0x20,
MMCSD_PARAM_ERR = 0x40,
RESP_TIMEOUT = 0x80};
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
GO_IDLE_STATE 0
SEND_OP_COND 1
SEND_IF_COND 8
SEND_CSD 9
SEND_CID 10
SD_STATUS 13
SEND_STATUS 13
SET_BLOCKLEN 16
READ_SINGLE_BLOCK 17
WRITE_BLOCK 24
SD_SEND_OP_COND 41
APP_CMD 55
READ_OCR 58
CRC_ON_OFF 59
3/17/2015 3:49 PM
7 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
mmcsd_load_buffer(void);
mmcsd_flush_buffer(void);
mmcsd_move_buffer(uint32_t new_addr);
mmcsd_read_byte(uint32_t addr, char* data);
mmcsd_write_byte(uint32_t addr, char data);
output_drive(MMCSD_PIN_SCL);
output_drive(MMCSD_PIN_SDO);
output_drive(MMCSD_PIN_SELECT);
output_float(MMCSD_PIN_SDI);
mmcsd_deselect();
delay_ms(15);
/* begin initialization */
i = 0;
do
{
delay_ms(1);
mmcsd_select();
r1=mmcsd_go_idle_state();
mmcsd_deselect();
i++;
if(i == 0xFF)
{
mmcsd_deselect();
return r1;
}
} while(!bit_test(r1, 0));
i = 0;
do
{
3/17/2015 3:49 PM
8 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
delay_ms(1);
mmcsd_select();
r1=mmcsd_send_op_cond();
mmcsd_deselect();
i++;
if(i == 0xFF)
{
mmcsd_deselect();
return r1;
}
} while(r1 & MMCSD_IDLE);
/* figure out if we have an SD or MMC */
mmcsd_select();
r1=mmcsd_app_cmd();
r1=mmcsd_sd_send_op_cond();
mmcsd_deselect();
printf("The card is : 0x%x\r\n",r1);
/* an mmc will return an 0x04 here */
if(r1 == 0x04)
{ g_card_type = MMC; printf("MMC\r\n");}
else
{ g_card_type = SD; printf("SD\r\n");
// mmcsd_print_cid();
// mmcsd_print_csd();
}
delay_ms(1000);
/* set block length to 512 bytes */
mmcsd_select();
r1 = mmcsd_set_blocklen(MMCSD_MAX_BLOCK_SIZE);
//
if(r1 != MMCSD_GOODEC)
{
mmcsd_deselect();
return r1;
}
mmcsd_deselect();
//if (r1 == 0) printf("Set block length failed !!!!!!!\r\n");
if (g_mmcsd_buffer[0x1C6] < 80 )
g_mmcsdBufferAddress = g_mmcsd_buffer[0x1C6]*0x200;
// for card => 1GByte need to add more offset
else
g_mmcsdBufferAddress = g_mmcsd_buffer[0x1C6]*0x200+0x10000;
printf("offset Adr : %lX\r\n",g_mmcsdBufferAddress ) ;
g_mmcsdPartitionOffset=g_mmcsdBufferAddress; ;
3/17/2015 3:49 PM
9 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
r1 = mmcsd_load_buffer();
if (g_mmcsd_buffer[0] == 0xEB)
{ printf("Boot sector found " ) ;
}
return r1;
}
MMCSD_err mmcsd_read_data(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err r1;
uint16_t i; // counter for loops
for(i = 0; i < size; i++)
{
r1 = mmcsd_read_byte(address++, ptr++);
if(r1 != MMCSD_GOODEC)
return r1;
}
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_read_block(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t i; // counter for loops
// send command
mmcsd_select();
ec = mmcsd_read_single_block(address);
if(ec != MMCSD_GOODEC)
{
mmcsd_deselect();
return ec;
}
// wait for the data start token
ec = mmcsd_wait_for_token(DATA_START_TOKEN);
if(ec != MMCSD_GOODEC)
{
mmcsd_deselect();
return ec;
}
// read in the data
for(i = 0; i < size; i += 1)
ptr[i] = spi_xfer(mmcsd_spi, 0xFF);
if(g_CRC_enabled)
{
/* check the crc */
if(make16(spi_xfer(mmcsd_spi, 0xFF), spi_xfer(mmcsd_spi, 0xFF)) !=
mmcsd_crc16(g_mmcsd_buffer, MMCSD_MAX_BLOCK_SIZE))
{
mmcsd_deselect();
return MMCSD_CRC_ERR;
}
}
else
{
/* have the card transmit the CRC, but ignore it */
spi_xfer(mmcsd_spi, 0xFF);
spi_xfer(mmcsd_spi, 0xFF);
}
mmcsd_deselect();
//printf("print block \r\n") ;
//for(i = 0; i < 32; i += 1)
// printf("adr :%x -> %X \r\n", i, ptr[i] ) ;
// printf(" %c ", ptr[i] ) ;
return MMCSD_GOODEC;
}
3/17/2015 3:49 PM
10 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
if(ec != MMCSD_GOODEC)
return ec;
}
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_write_block(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t i;
// send command
mmcsd_select();
ec = mmcsd_write_single_block(address);
if(ec != MMCSD_GOODEC)
{
mmcsd_deselect();
return ec;
}
// send a data start token
spi_xfer(mmcsd_spi, DATA_START_TOKEN);
// send all the data
for(i = 0; i < size; i += 1)
spi_xfer(mmcsd_spi, ptr[i]);
// if the CRC is enabled we have to calculate it, otherwise just send an 0xFFFF
if(g_CRC_enabled)
spi_xfer(mmcsd_spi, mmcsd_crc16(ptr, size));
else
{
spi_xfer(mmcsd_spi, 0xFF);
spi_xfer(mmcsd_spi, 0xFF);
}
// get the error code back from the card; "data accepted" is 0bXXX00101
ec = mmcsd_get_r1();
if(ec & 0x0A)
{
mmcsd_deselect();
return ec;
}
// wait for the line to go back high, this indicates that the write is complete
while(spi_xfer(mmcsd_spi, 0xFF) == 0);
mmcsd_deselect();
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_go_idle_state(void)
{
mmcsd_send_cmd(GO_IDLE_STATE, 0);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_send_op_cond(void)
{
mmcsd_send_cmd(SEND_OP_COND, 0);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_send_if_cond(uint8_t r7[])
3/17/2015 3:49 PM
11 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
{
mmcsd_send_cmd(SEND_IF_COND, 0x45A);
return mmcsd_get_r7(r7);
}
MMCSD_err mmcsd_print_csd()
{
uint8_t
buf[16],
i,
r1;
// MMCs don't support this command
if(g_card_type == MMC)
return MMCSD_PARAM_ERR;
mmcsd_select();
mmcsd_send_cmd(SEND_CSD, 0);
r1 = mmcsd_get_r1();
if(r1 != MMCSD_GOODEC)
{
mmcsd_deselect();
return r1;
}
r1 = mmcsd_wait_for_token(DATA_START_TOKEN);
if(r1 != MMCSD_GOODEC)
{
mmcsd_deselect();
return r1;
}
for(i = 0; i < 16; i++)
buf[i] = spi_xfer(mmcsd_spi, 0xFF);
mmcsd_deselect();
printf("\r\nCSD_STRUCTURE: %X", (buf[0] & 0x0C) >> 2);
printf("\r\nTAAC: %X", buf[1]);
printf("\r\nNSAC: %X", buf[2]);
printf("\r\nTRAN_SPEED: %X", buf[3]);
printf("\r\nCCC: %lX", (make16(buf[4], buf[5]) & 0xFFF0) >> 4);
printf("\r\nREAD_BL_LEN: %X", buf[5] & 0x0F);
printf("\r\nREAD_BL_PARTIAL: %X", (buf[6] & 0x80) >> 7);
printf("\r\nWRITE_BLK_MISALIGN: %X", (buf[6] & 0x40) >> 6);
printf("\r\nREAD_BLK_MISALIGN: %X", (buf[6] & 0x20) >> 5);
printf("\r\nDSR_IMP: %X", (buf[6] & 0x10) >> 4);
printf("\r\nC_SIZE: %lX", (((buf[6] & 0x03) << 10) | (buf[7] << 2) | ((buf[8] &
0xC0) >> 6)));
printf("\r\nVDD_R_CURR_MIN: %X", (buf[8] & 0x38) >> 3);
printf("\r\nVDD_R_CURR_MAX: %X", buf[8] & 0x07);
printf("\r\nVDD_W_CURR_MIN: %X", (buf[9] & 0xE0) >> 5);
printf("\r\nVDD_W_CURR_MAX: %X", (buf[9] & 0x1C) >> 2);
printf("\r\nC_SIZE_MULT: %X", ((buf[9] & 0x03) << 1) | ((buf[10] & 0x80) >> 7));
printf("\r\nERASE_BLK_EN: %X", (buf[10] & 0x40) >> 6);
printf("\r\nSECTOR_SIZE: %X", ((buf[10] & 0x3F) << 1) | ((buf[11] & 0x80) >>
7));
printf("\r\nWP_GRP_SIZE: %X", buf[11] & 0x7F);
printf("\r\nWP_GRP_ENABLE: %X", (buf[12] & 0x80) >> 7);
printf("\r\nR2W_FACTOR: %X", (buf[12] & 0x1C) >> 2);
printf("\r\nWRITE_BL_LEN: %X", ((buf[12] & 0x03) << 2) | ((buf[13] & 0xC0) >>
6));
printf("\r\nWRITE_BL_PARTIAL: %X", (buf[13] & 0x20) >> 5);
printf("\r\nFILE_FORMAT_GRP: %X", (buf[14] & 0x80) >> 7);
printf("\r\nCOPY: %X", (buf[14] & 0x40) >> 6);
printf("\r\nPERM_WRITE_PROTECT: %X", (buf[14] & 0x20) >> 5);
printf("\r\nTMP_WRITE_PROTECT: %X", (buf[14] & 0x10) >> 4);
printf("\r\nFILE_FORMAT: %X", (buf[14] & 0x0C) >> 2);
printf("\r\nCRC: %X", buf[15]);
return r1;
}
MMCSD_err mmcsd_print_cid()
{
uint8_t
buf[16],
i,
r1;
3/17/2015 3:49 PM
12 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
3/17/2015 3:49 PM
13 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
mmcsd_send_cmd(WRITE_BLOCK, address);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_sd_send_op_cond(void)
{
mmcsd_send_cmd(SD_SEND_OP_COND, 0);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_app_cmd(void)
{
mmcsd_send_cmd(APP_CMD, 0);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_read_ocr(int r3[])
{
mmcsd_send_cmd(READ_OCR, 0);
return mmcsd_get_r3(r3);
}
MMCSD_err mmcsd_crc_on_off(int1 crc_enabled)
{
mmcsd_send_cmd(CRC_ON_OFF, crc_enabled);
g_CRC_enabled = crc_enabled;
return mmcsd_get_r1();
}
MMCSD_err mmcsd_send_cmd(uint8_t cmd, uint32_t arg)
{
uint8_t packet[6]; // the entire command, argument, and crc in one variable
// construct the packet
// every command on an SD card is or'ed with 0x40
packet[0] = cmd | 0x40;
packet[1] = make8(arg, 3);
packet[2] = make8(arg, 2);
packet[3] = make8(arg, 1);
packet[4] = make8(arg, 0);
// calculate the crc if needed
if(g_CRC_enabled)
packet[5] = mmcsd_crc7(packet, 5);
else
packet[5] = 0xFF;
// transfer the command and argument, with an extra 0xFF hacked in there
spi_xfer(mmcsd_spi, packet[0]);
spi_xfer(mmcsd_spi, packet[1]);
spi_xfer(mmcsd_spi, packet[2]);
spi_xfer(mmcsd_spi, packet[3]);
spi_xfer(mmcsd_spi, packet[4]);
spi_xfer(mmcsd_spi, packet[5]);
//!
spi_write2(packet[0]);
//!
spi_write2(packet[1]);
//!
spi_write2(packet[2]);
//!
spi_write2(packet[3]);
//!
spi_write2(packet[4]);
//!
spi_write2(packet[5]);
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_get_r1(void)
{
uint8_t
response = 0, // place to hold the response coming back from the SPI line
timeout = 0xFF; // maximum amount loops to wait for idle before getting
impatient and leaving the function with an error code
// loop until timeout == 0
3/17/2015 3:49 PM
14 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
while(timeout)
{
// read what's on the SPI line
// the SD/MMC requires that you leave the line high when you're waiting for
data from it
response = spi_xfer(mmcsd_spi, 0xFF);
//response = spi_xfer(mmcsd_spi, 0x00);//leave the line idle
// check to see if we got a response
if(response != 0xFF)
{
// fill in the response that we got and leave the function
return response;
}
// wait for a little bit longer
timeout--;
}
// for some reason, we didn't get a response back from the card
// return the proper error codes
return RESP_TIMEOUT;
}
MMCSD_err mmcsd_get_r2(uint8_t r2[])
{
r2[1] = mmcsd_get_r1();
r2[0] = spi_xfer(mmcsd_spi, 0xFF);
return 0;
}
MMCSD_err mmcsd_get_r3(uint8_t r3[])
{
return mmcsd_get_r7(r3);
}
MMCSD_err mmcsd_get_r7(uint8_t r7[])
{
uint8_t i;
// counter for loop
// the top byte of r7 is r1
r7[4]=mmcsd_get_r1();
// fill in the other 4 bytes
for(i = 0; i < 4; i++)
r7[3 - i] = spi_xfer(mmcsd_spi, 0xFF);
return r7[4];
}
MMCSD_err mmcsd_wait_for_token(uint8_t token)
{
MMCSD_err r1;
// get a token
r1 = mmcsd_get_r1();
// check to see if the token we recieved was the one that we were looking for
if(r1 == token)
return MMCSD_GOODEC;
// if that wasn't right, return the error
return r1;
}
unsigned int8 mmcsd_crc7(char *data,uint8_t length)
{
uint8_t i, ibit, c, crc;
crc = 0x00;
Set initial value
//
3/17/2015 3:49 PM
15 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
{
crc = crc << 1;
if ((c ^ crc) & 0x80) crc = crc ^ 0x09;
// ^
is XOR
c = c << 1;
}
crc = crc & 0x7F;
}
shift_left(&crc, 1, 1);
MMC card stores the result in the top 7 bits so shift them left 1
//
//
Should shift in a 1 not a 0 as one of the cards I have won't work otherwise
return crc;
}
uint16_t mmcsd_crc16(char *data, uint8_t length)
{
uint8_t i, ibit, c;
uint16_t crc;
crc = 0x0000;
Set initial value
//
//
//
Should shift in a 1 not a 0 as one of the cards I have won't work otherwise
return crc;
}
void mmcsd_select()
{
output_low(MMCSD_PIN_SELECT);
}
void mmcsd_deselect()
{
spi_xfer(mmcsd_spi, 0xFF);
output_high(MMCSD_PIN_SELECT);
}
MMCSD_err mmcsd_load_buffer(void)
{
g_MMCSDBufferChanged = FALSE;
return(mmcsd_read_block(g_mmcsdBufferAddress, MMCSD_MAX_BLOCK_SIZE,
g_mmcsd_buffer));
}
MMCSD_err mmcsd_flush_buffer(void)
{
if (g_MMCSDBufferChanged)
{ //printf(" flush buffer \r\n");
g_MMCSDBufferChanged = FALSE;
return(mmcsd_write_block(g_mmcsdBufferAddress, MMCSD_MAX_BLOCK_SIZE,
g_mmcsd_buffer));
}
return(0); //ok
}
MMCSD_err mmcsd_move_buffer(uint32_t new_addr)
{
3/17/2015 3:49 PM
16 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
MMCSD_err ec = MMCSD_GOODEC;
uint32_t
//cur_block,
new_block,address;
int value;
// make sure we're still on the same block
//cur_block = g_mmcsdBufferAddress - (g_mmcsdBufferAddress %
MMCSD_MAX_BLOCK_SIZE);
// new_block = (new_addr) % MMCSD_MAX_BLOCK_SIZE;
// printf(" move buffer: new ad = %lX, new_addr mod max_block --> %lX \n\r",
new_addr, new_block) ;
address = new_addr-g_mmcsdPartitionOffset;
// new_block = new_addr - (new_addr % MMCSD_MAX_BLOCK_SIZE);
new_block = address - (address % MMCSD_MAX_BLOCK_SIZE);
//
printf(" move buffer: new block befor offset = %lX \n\r",
new_block) ;
new_block += g_mmcsdPartitionOffset;
//
;
//
g_mmcsdBufferAddress)
new_block) ;
//if(cur_block != new_block)
if(g_mmcsdBufferAddress != new_block)
{
// printf(" move buffer: g_mmcsdBufferAddress = %lX :new block = %lX
\n\r", g_mmcsdBufferAddress, new_block ) ;
//
3/17/2015 3:49 PM
17 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
ec = mmcsd_move_buffer(addr);
if(ec != MMCSD_GOODEC)
return ec;
g_mmcsd_buffer[addr % MMCSD_MAX_BLOCK_SIZE] = data;
// value = addr % MMCSD_MAX_BLOCK_SIZE;
// printf("value=%lX:x%c ",value,g_mmcsd_buffer[value]) ;
g_MMCSDBufferChanged = TRUE;
return MMCSD_GOODEC;
}
#endif
3/17/2015 3:49 PM
18 of 54
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
"w" will erase all of the data in the file upon ////
the opening of the file. ////
"a" will tack on all of the data to the end of the ////
file. ////
"r" will keep on reading until the stream ////
hits an '\0' ////
"rb" will keep on reading until the amount of ////
bytes read equals the size of the file. ////
////
Unlike standard C fopen(), this does not malloc a FILE - ////
instead the caller will have to have allready allocated a ////
a FILE and pass a pointer to it. ////
////
fatreopen(char *name, char *mode, FILE *fstream) ////
Closes a FILE stream, then reopens the stream with a new file ////
and new permissions. ////
////
fatclose(FILE *fstream) ////
Closes a FILE stream. It is very important to call this ////
function when you're done reading or writing to a file. //// ////
////
fatgetc(FILE *fstream) ////
Gets a character from a stream. An EOF will be returned at ////
different times depending on whether or not the stream is ////
reading binarily. If not reading binarily: EOF when the ////
stream reads a '\0'. If reading binarily: EOF when the amount ////
of bytes read equals the size of the file (end of file). ////
////
fatputc(char c, FILE *fstream) ////
Puts a character into a stream (write to the file). ////
Writes are buffered, so the media may not be written to until ////
a fatclose(). ////
////
char* fatgets(char* str, int num, FILE *fstream) ////
Gets characters from a stream until either a '\r', EOF, or ////
num - 1 is hit. ////
////
fatputs(char* str, FILE *fstream) ////
Puts a string into a stream (write a string to the file). ////
////
fatprintf(FILE *stream): Printfs the entire stream. ////
printf()'s the entire stream (printf()'s the contents of the
file).
////
fatgetpos(FILE *fstream, fatpos_t *pos) ////
Gets the current position of the stream/file, saves to pos. ////
////
fatsetpos(FILE *fstream, fatpos_t *pos) ////
Sets the current position of the stream/file. ////
////
fatseek(FILE *fstream, int32 offset, int origin) ////
Sets the current position of the stream according to the ////
origin parameter: ////
SEEK_CUR: Set position relative to the ////
current stream position. ////
SEEK_END: Set position relative to the ////
end of the stream. ////
SEEK_SET: Set position relative to the ////
beginning of the stream. ////
3/17/2015 3:49 PM
19 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
//// ////
//// fateof(FILE *fstream) ////
//// Returns non-zero if the stream/file position is at EOF, ////
//// non-zero if there are still data left in the stream. ////
//// ////
//// faterror(FILE *fstream): ////
//// Returns non-zero if there have been errors with the stream, ////
//// zero if the stream has been operating correctly since it has ////
//// been opened. ////
//// ////
//// fatread(void* buffer, int size, int32 num, FILE* fstream) ////
//// Reads size*num chars from the stream, saves to buffer. ////
//// ////
//// fatwrite(void* buffer, int size, int32 num, FILE* fstream) ////
//// Writes size*num chars from buffer to the stream. ////
//// ////
//// fatflush(FILE *fstream) ////
//// Flushes the buffer in a stream. ////
//// ////
//// clearerr(FILE *fstream) ////
//// Clears any error flags in the stream. ////
//// ////
//// rewind(FILE *fstream) ////
//// Send the stream back to the beginning of the file. ////
//// ////
//// fatpos_t fattell(FILE *fstream) ////
//// Returns the current position of the stream. ////
//// ////
//// rm_file(char *fname) ////
//// Removes a file. ////
//// ////
//// rm_dir(char *dirname) ////
//// Removes a directory. ////
//// ////
//// mk_file(char *fname) ////
//// Makes a file, file will be blank. ////
//// ////
//// mk_dir(char *dirname) ////
//// Makes a directory. ////
//// ////
//// format(int32 mediaSize) ////
//// Formats the media into a FAT32 or FAT16 file system. ////
//// If you specify a mediaSize larger than the actual media bad ////
//// things will happen. If you specify a mediaSize smaller than ////
//// the actual media size will simply limit the filesystem from ////
//// using 0 to mediaSize-1. Anything after mediaSize can be used ////
//// by the application (perhaps as a general purpose EEPROM?) ////
//// NOTE: Windows thinks the filesystem is RAW. ////
//// NOTE: This may be a little buggy. ////
//// ////
/////////////////////////////////////////////////////////////////////////
//// ////
//// This library was written to use CCS's MMC/SD library as the ////
//// media source. If you want to use a different media source, ////
//// you must provide the following 4 functions: ////
//// ////
//// int8 mmcsd_init(void); ////
//// Initializes the media. This will be called by fat_init(). ////
//// ////
3/17/2015 3:49 PM
20 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
//
//
//
//
//
//
NOTE The current maximum file name length (full path) is 32 characters
long. If longer file names are desired, change the
MAX_FILE_NAME_LENGTH define below. Creating a file whose full path
is longer than MAX_FILE_NAME_LENGTH may lead to weird operation. Keep
in mind that making this define larger will make your RAM usage go
up.
#ifndef FAT_PIC_C
#define FAT_PIC_C
#include <ctype.h>
#include <string.h>
#case
//////////////////////
/// ///
/// Useful Defines ///
/// ///
//////////////////////
3/17/2015 3:49 PM
21 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
EOF -1
GOODEC 0
fatpos_t int32
SEEK_CUR 0
SEEK_END 1
SEEK_SET 2
////////////////////////
/// ///
/// Global Variables ///
/// ///
////////////////////////
unsigned int16
Bytes_Per_Cluster, // number of addressable bytes per cluster
FAT_Start; // when the first FAT begins
unsigned int32
Data_Start, // when data starts
FAT_Length, // the length of one FAT
Next_Free_Clust, // where the next free cluster is
Root_Dir; // when the root directory starts
enum filetype
{
Data_File, // the stream is pointing to a binary, data file
Directory, // the stream is pointing to a directory
None // the stream isn't currently pointing to anything
};
enum ioflags
{
Closed = 0x00,
Read = 0x01,
Write = 0x02,
Append = 0x04,
Binary = 0x08,
EOF_Reached = 0x10,
Read_Error = 0x20,
Write_Error = 0x40,
File_Not_Found = 0x80
};
struct iobuf
{
3/17/2015 3:49 PM
22 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
fatpos_t
Bytes_Until_EOF, // how many bytes until the stream's end of file
Cur_Char, // the current byte that the stream is pointing at
Entry_Addr, // the entry address of the file that is associated with the stream
Parent_Start_Addr, // the parent's start adddress of the file that is associated with the stream
Size, // the size of the file that is associated with the stream
Start_Addr; // the beginning of the data in the file that is associated with the stream
enum filetype File_Type; // the type of file that is associated with the stream
enum ioflags Flags; // any associated input/output flag
int Buf[STREAM_BUF_SIZE]; // this is a buffer so that during fatputc() or fatgetc()
// the media won't have to be read at every character
};
typedef struct iobuf FILE;
///////////////////////////
/// ///
/// Function Prototypes ///
/// ///
///////////////////////////
/// Standard C Functions ///
signed int fatopen(char fname[], char mode[], FILE* stream);
signed int fatreopen(char fname[], char mode[], FILE* stream);
signed int fatclose(FILE* stream);
signed int fatgetc(FILE* stream);
signed int fatputc(int ch, FILE* stream);
char* fatgets(char* str, int num, FILE* stream);
signed int fatputs(char* str, FILE* stream);
signed int fatprintf(FILE* stream);
signed int fatgetpos(FILE* stream, fatpos_t* position);
signed int fatsetpos(FILE* stream, fatpos_t* position);
signed int fatseek(FILE* stream, int32 offset, int origin);
signed int fateof(FILE* stream);
signed int faterror(FILE* stream);
signed int fatread(void* buffer, int size, int32 num, FILE* stream);
signed int fatwrite(void* buffer, int size, int32 count, FILE* stream );
signed int fatflush(FILE* stream);
signed int remove(char* fname);
void clearerr(FILE* stream);
void rewind(FILE* stream);
fatpos_t fattell(FILE* stream);
/// Non-Standard C Functions ///
signed int rm_file(char fname[]);
signed int rm_dir(char dname[]);
signed int mk_file(char fname[]);
signed int mk_dir(char dname[]);
/// Functions' Utility Functions ///
signed int set_file(char fname[], int attrib, FILE* stream);
signed int get_file_name(int32 file_entry_addr, char name[]);
signed int set_file_name(int32 parent_dir_addr, int32* entry_addr, char name[]);
signed int get_short_file_name(int32 file_entry_addr, char sname[], int type);
signed int make_short_file_name(int32 parent_dir_addr, char fname[], char sname[]);
int long_name_chksum (int* pFcbName);
signed int check_invalid_char(char fname[]);
3/17/2015 3:49 PM
23 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
#ifdef FAT32
signed int get_next_free_cluster(int32* my_cluster);
signed int dealloc_clusters(int32 start_cluster);
signed int alloc_clusters(int32 start_cluster, int32* new_cluster_addr);
signed int clear_cluster(int32 cluster);
signed int write_fat(int32 cluster, int32 data);
#else // FAT16
signed int get_next_free_cluster(int16* my_cluster);
signed int dealloc_clusters(int16 start_cluster);
signed int alloc_clusters(int16 start_cluster, int32* new_cluster_addr);
signed int clear_cluster(int16 cluster);
signed int write_fat(int16 cluster, int16 data);
#endif // #ifdef FAT32
signed int get_next_file(FILE* stream);
signed int get_prev_file(FILE* stream);
signed int get_next_free_addr(int32* my_addr);
signed int get_next_free_entry(int32* start_addr);
signed int get_next_entry(int32* start_addr);
signed int get_prev_entry(int32* start_addr);
signed int read_buffer(FILE* stream, int* val);
signed int write_buffer(FILE* stream, int val);
void fill_entry(char the_entry[], char val, int8 start_ind);
void disp_timestamp(int16 timestamp);
void disp_datestamp(int16 datestamp);
/// Data Utility Functions ///
signed int fat_init();
#ifdef FAT32
signed int get_next_cluster(int32* my_cluster);
signed int get_prev_cluster(int32* my_cluster);
int32 cluster_to_addr(int32 cluster);
int32 addr_to_cluster(int32 addr);
#else // FAT16
signed int get_next_cluster(int16* my_cluster);
signed int get_prev_cluster(int16* my_cluster);
int32 cluster_to_addr(int16 cluster);
int16 addr_to_cluster(int32 addr);
#endif // #ifdef FAT32
signed int get_next_addr(int32* my_addr);
signed int get_prev_addr(int32* my_addr);
signed int format(int32 DskSize);
/// Debugging Utility Functions ///
signed int disp_folder_contents(char foldername[]);
signed int dump_addr(int32 from, int32 to);
signed int dump_clusters(int32 from, int32 to);
void disp_fat_stats();
signed int fatprintfinfo(FILE* stream);
////////////////////////////////
/// ///
/// Function Implementations ///
/// ///
////////////////////////////////
/// Standard C Functions ///
/*
signed int fatopen(char fname[], char mode[], FILE* stream)
3/17/2015 3:49 PM
24 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
Summary: This will open up a file stream for reading, writing, or appending.
Param fname: The full path of the file to open.
Param mode: The mode to open up the stream into.
"r" = Read
"w" = Write
"a" = Append
"rb", "wb", "ab" = Read, Write, or Append in Binary mode
Param stream: The stream to open up.
Returns: EOF if there was a problem, GOODEC if everything went okay.
Note: fname must be in the form of /filename.fil for a file in the root directory
/Directory/filename.fil for a file in a subdirectory of root
/Directory/Subdirectory/filename.fil and so on...
Note: Standard C will make a file in case a file isn't found,
however due to recursion this is not possible in CCSC.
*/
signed int fatopen(char fname[], char mode[], FILE* stream)
{
int fname_parse_pos = 1; // the current index of the fname character
char target_file[MAX_FILE_NAME_LENGTH]; // temporary buffer to hold names of files
FILE cur_stream; // this will be the stream that will be returned if all goes well
#ifndef FAST_FAT
int
depth = 0, // how many subdirectories deep the file is
target_file_parse_pos; // the current index of the target_file character
#endif // #ifndef FAST_FAT
// set flags
#ifdef FAST_FAT
switch(mode[0])
{
case 'w':
cur_stream.Flags = Write;
break;
case 'a':
cur_stream.Flags = Append;
break;
default:
return EOF;
}
// start looking for the file, start at root
cur_stream.Start_Addr = cur_stream.Parent_Start_Addr = Root_Dir;
while(fname[fname_parse_pos] != '\0')
{
target_file[fname_parse_pos - 1] = fname[fname_parse_pos];
fname_parse_pos += 1;
}
target_file[fname_parse_pos] = '\0';
// find the file inside of its subdirectory
if(set_file(target_file, 0x20, &cur_stream) != GOODEC)
{
cur_stream.Flags |= File_Not_Found;
*stream = cur_stream;
3/17/2015 3:49 PM
25 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
return EOF;
}
// at this point, we've found the file
*stream = cur_stream;
return GOODEC;
#else // NO FAST_FAT
switch(mode[0])
{
case 'r':
cur_stream.Flags = Read;
break;
case 'w':
cur_stream.Flags = Write;
break;
case 'a':
cur_stream.Flags = Append;
break;
default:
return EOF;
}
if(mode[1] == 'b')
cur_stream.Flags |= Binary;
// start looking for the file, start at root
cur_stream.Start_Addr = cur_stream.Parent_Start_Addr = Root_Dir;
//printf("fatopen:cur_stream.Start_Addr--> %lX \n\r", cur_stream.Start_Addr);
// figure out how deep we have to go, count how many '/' we have in the string
while(fname[fname_parse_pos] != '\0')
{
if(fname[fname_parse_pos] == '/')
depth++;
fname_parse_pos += 1;
}
// start the fname index at 1 to skip over the '/'
fname_parse_pos = 1;
// open up to the subdirectory, if possible
while(depth > 0)
{
// find the name of our next target directory
target_file_parse_pos = 0;
while(fname[fname_parse_pos] != '/')
{
// check to make sure that we're not at the end of a poorly formatted string
if(fname[fname_parse_pos] == '\0')
return EOF;
// fill up the buffer and increment the indexes
target_file[target_file_parse_pos] = fname[fname_parse_pos];
fname_parse_pos += 1;
target_file_parse_pos += 1;
}
// increment the fname index one more because it's currently pointing at the '/'
fname_parse_pos += 1;
3/17/2015 3:49 PM
26 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
3/17/2015 3:49 PM
27 of 54
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
////
-- User Functions -- ////
////
fat_init() ////
Initializes the FAT library, also initializes the media. ////
////
fatopen(char *name, char *mode, FILE *fstream) ////
Opens up a FILE stream to a specified file with the specified ////
permission mode: ////
Permissions: "r" = read ////
"w" = write ////
"a" = append ////
"rb" = read binarily ////
"w" will erase all of the data in the file upon ////
the opening of the file. ////
"a" will tack on all of the data to the end of the ////
file. ////
"r" will keep on reading until the stream ////
hits an '\0' ////
"rb" will keep on reading until the amount of ////
bytes read equals the size of the file. ////
////
Unlike standard C fopen(), this does not malloc a FILE - ////
instead the caller will have to have allready allocated a ////
a FILE and pass a pointer to it. ////
////
fatreopen(char *name, char *mode, FILE *fstream) ////
Closes a FILE stream, then reopens the stream with a new file ////
and new permissions. ////
////
fatclose(FILE *fstream) ////
Closes a FILE stream. It is very important to call this ////
function when you're done reading or writing to a file. //// ////
////
fatgetc(FILE *fstream) ////
Gets a character from a stream. An EOF will be returned at ////
different times depending on whether or not the stream is ////
reading binarily. If not reading binarily: EOF when the ////
stream reads a '\0'. If reading binarily: EOF when the amount ////
of bytes read equals the size of the file (end of file). ////
////
fatputc(char c, FILE *fstream) ////
Puts a character into a stream (write to the file). ////
Writes are buffered, so the media may not be written to until ////
a fatclose(). ////
////
char* fatgets(char* str, int num, FILE *fstream) ////
Gets characters from a stream until either a '\r', EOF, or ////
num - 1 is hit. ////
////
fatputs(char* str, FILE *fstream) ////
Puts a string into a stream (write a string to the file). ////
////
fatprintf(FILE *stream): Printfs the entire stream. ////
printf()'s the entire stream (printf()'s the contents of the
file).
////
fatgetpos(FILE *fstream, fatpos_t *pos) ////
Gets the current position of the stream/file, saves to pos. ////
3/17/2015 3:49 PM
28 of 54
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
////
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
////
fatsetpos(FILE *fstream, fatpos_t *pos) ////
Sets the current position of the stream/file. ////
////
fatseek(FILE *fstream, int32 offset, int origin) ////
Sets the current position of the stream according to the ////
origin parameter: ////
SEEK_CUR: Set position relative to the ////
current stream position. ////
SEEK_END: Set position relative to the ////
end of the stream. ////
SEEK_SET: Set position relative to the ////
beginning of the stream. ////
////
fateof(FILE *fstream) ////
Returns non-zero if the stream/file position is at EOF, ////
non-zero if there are still data left in the stream. ////
////
faterror(FILE *fstream): ////
Returns non-zero if there have been errors with the stream, ////
zero if the stream has been operating correctly since it has ////
been opened. ////
////
fatread(void* buffer, int size, int32 num, FILE* fstream) ////
Reads size*num chars from the stream, saves to buffer. ////
////
fatwrite(void* buffer, int size, int32 num, FILE* fstream) ////
Writes size*num chars from buffer to the stream. ////
////
fatflush(FILE *fstream) ////
Flushes the buffer in a stream. ////
////
clearerr(FILE *fstream) ////
Clears any error flags in the stream. ////
////
rewind(FILE *fstream) ////
Send the stream back to the beginning of the file. ////
////
fatpos_t fattell(FILE *fstream) ////
Returns the current position of the stream. ////
////
rm_file(char *fname) ////
Removes a file. ////
////
rm_dir(char *dirname) ////
Removes a directory. ////
////
mk_file(char *fname) ////
Makes a file, file will be blank. ////
////
mk_dir(char *dirname) ////
Makes a directory. ////
////
format(int32 mediaSize) ////
Formats the media into a FAT32 or FAT16 file system. ////
If you specify a mediaSize larger than the actual media bad ////
things will happen. If you specify a mediaSize smaller than ////
the actual media size will simply limit the filesystem from ////
using 0 to mediaSize-1. Anything after mediaSize can be used ////
3/17/2015 3:49 PM
29 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
//
//
//
//
//
//
NOTE The current maximum file name length (full path) is 32 characters
long. If longer file names are desired, change the
MAX_FILE_NAME_LENGTH define below. Creating a file whose full path
is longer than MAX_FILE_NAME_LENGTH may lead to weird operation. Keep
in mind that making this define larger will make your RAM usage go
up.
3/17/2015 3:49 PM
30 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
#ifndef FAT_PIC_C
#define FAT_PIC_C
#include <ctype.h>
#include <string.h>
#case
//////////////////////
/// ///
/// Useful Defines ///
/// ///
//////////////////////
/// Define your FAT type here ///
#define FAT16
//#define FAT32
/// For faster single-file writing, uncomment this line below ///
//#define FAST_FAT
/// Everything else ///
#define MAX_FILE_NAME_LENGTH 0x20 // the maximum length of a file name for our FAT, including /0
terminator
#define STREAM_BUF_SIZE 0x20 // how big the FILE buffer is. 0x20 is optimal
//////////////////////////////////////////////////////////////////
#define
#define
#define
#define
#define
#define
EOF -1
GOODEC 0
fatpos_t int32
SEEK_CUR 0
SEEK_END 1
SEEK_SET 2
////////////////////////
/// ///
/// Global Variables ///
/// ///
////////////////////////
unsigned int16
Bytes_Per_Cluster, // number of addressable bytes per cluster
FAT_Start; // when the first FAT begins
unsigned int32
Data_Start, // when data starts
FAT_Length, // the length of one FAT
Next_Free_Clust, // where the next free cluster is
Root_Dir; // when the root directory starts
enum filetype
{
Data_File, // the stream is pointing to a binary, data file
Directory, // the stream is pointing to a directory
None // the stream isn't currently pointing to anything
};
enum ioflags
{
3/17/2015 3:49 PM
31 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
Closed = 0x00,
Read = 0x01,
Write = 0x02,
Append = 0x04,
Binary = 0x08,
EOF_Reached = 0x10,
Read_Error = 0x20,
Write_Error = 0x40,
File_Not_Found = 0x80
};
struct iobuf
{
fatpos_t
Bytes_Until_EOF, // how many bytes until the stream's end of file
Cur_Char, // the current byte that the stream is pointing at
Entry_Addr, // the entry address of the file that is associated with the stream
Parent_Start_Addr, // the parent's start adddress of the file that is associated with the stream
Size, // the size of the file that is associated with the stream
Start_Addr; // the beginning of the data in the file that is associated with the stream
enum filetype File_Type; // the type of file that is associated with the stream
enum ioflags Flags; // any associated input/output flag
int Buf[STREAM_BUF_SIZE]; // this is a buffer so that during fatputc() or fatgetc()
// the media won't have to be read at every character
};
typedef struct iobuf FILE;
///////////////////////////
/// ///
/// Function Prototypes ///
/// ///
///////////////////////////
/// Standard C Functions ///
signed int fatopen(char fname[], char mode[], FILE* stream);
signed int fatreopen(char fname[], char mode[], FILE* stream);
signed int fatclose(FILE* stream);
signed int fatgetc(FILE* stream);
signed int fatputc(int ch, FILE* stream);
char* fatgets(char* str, int num, FILE* stream);
signed int fatputs(char* str, FILE* stream);
signed int fatprintf(FILE* stream);
signed int fatgetpos(FILE* stream, fatpos_t* position);
signed int fatsetpos(FILE* stream, fatpos_t* position);
signed int fatseek(FILE* stream, int32 offset, int origin);
signed int fateof(FILE* stream);
signed int faterror(FILE* stream);
signed int fatread(void* buffer, int size, int32 num, FILE* stream);
signed int fatwrite(void* buffer, int size, int32 count, FILE* stream );
signed int fatflush(FILE* stream);
signed int remove(char* fname);
void clearerr(FILE* stream);
void rewind(FILE* stream);
fatpos_t fattell(FILE* stream);
/// Non-Standard C Functions ///
3/17/2015 3:49 PM
32 of 54
signed
signed
signed
signed
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
int
int
int
int
rm_file(char fname[]);
rm_dir(char dname[]);
mk_file(char fname[]);
mk_dir(char dname[]);
3/17/2015 3:49 PM
33 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
void disp_fat_stats();
signed int fatprintfinfo(FILE* stream);
////////////////////////////////
/// ///
/// Function Implementations ///
/// ///
////////////////////////////////
/// Standard C Functions ///
/*
signed int fatopen(char fname[], char mode[], FILE* stream)
Summary: This will open up a file stream for reading, writing, or appending.
Param fname: The full path of the file to open.
Param mode: The mode to open up the stream into.
"r" = Read
"w" = Write
"a" = Append
"rb", "wb", "ab" = Read, Write, or Append in Binary mode
Param stream: The stream to open up.
Returns: EOF if there was a problem, GOODEC if everything went okay.
Note: fname must be in the form of /filename.fil for a file in the root directory
/Directory/filename.fil for a file in a subdirectory of root
/Directory/Subdirectory/filename.fil and so on...
Note: Standard C will make a file in case a file isn't found,
however due to recursion this is not possible in CCSC.
*/
signed int fatopen(char fname[], char mode[], FILE* stream)
{
int fname_parse_pos = 1; // the current index of the fname character
char target_file[MAX_FILE_NAME_LENGTH]; // temporary buffer to hold names of files
FILE cur_stream; // this will be the stream that will be returned if all goes well
#ifndef FAST_FAT
int
depth = 0, // how many subdirectories deep the file is
target_file_parse_pos; // the current index of the target_file character
#endif // #ifndef FAST_FAT
// set flags
#ifdef FAST_FAT
switch(mode[0])
{
case 'w':
cur_stream.Flags = Write;
break;
case 'a':
cur_stream.Flags = Append;
break;
default:
return EOF;
}
// start looking for the file, start at root
cur_stream.Start_Addr = cur_stream.Parent_Start_Addr = Root_Dir;
3/17/2015 3:49 PM
34 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
while(fname[fname_parse_pos] != '\0')
{
target_file[fname_parse_pos - 1] = fname[fname_parse_pos];
fname_parse_pos += 1;
}
target_file[fname_parse_pos] = '\0';
// find the file inside of its subdirectory
if(set_file(target_file, 0x20, &cur_stream) != GOODEC)
{
cur_stream.Flags |= File_Not_Found;
*stream = cur_stream;
return EOF;
}
// at this point, we've found the file
*stream = cur_stream;
return GOODEC;
#else // NO FAST_FAT
switch(mode[0])
{
case 'r':
cur_stream.Flags = Read;
break;
case 'w':
cur_stream.Flags = Write;
break;
case 'a':
cur_stream.Flags = Append;
break;
default:
return EOF;
}
if(mode[1] == 'b')
cur_stream.Flags |= Binary;
// start looking for the file, start at root
cur_stream.Start_Addr = cur_stream.Parent_Start_Addr = Root_Dir;
//printf("fatopen:cur_stream.Start_Addr--> %lX \n\r", cur_stream.Start_Addr);
// figure out how deep we have to go, count how many '/' we have in the string
while(fname[fname_parse_pos] != '\0')
{
if(fname[fname_parse_pos] == '/')
depth++;
fname_parse_pos += 1;
}
// start the fname index at 1 to skip over the '/'
fname_parse_pos = 1;
// open up to the subdirectory, if possible
while(depth > 0)
{
// find the name of our next target directory
target_file_parse_pos = 0;
while(fname[fname_parse_pos] != '/')
{
3/17/2015 3:49 PM
35 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
// check to make sure that we're not at the end of a poorly formatted string
if(fname[fname_parse_pos] == '\0')
return EOF;
// fill up the buffer and increment the indexes
target_file[target_file_parse_pos] = fname[fname_parse_pos];
fname_parse_pos += 1;
target_file_parse_pos += 1;
}
// increment the fname index one more because it's currently pointing at the '/'
fname_parse_pos += 1;
// tack on a \0 to the end of the target file to terminate the string
target_file[target_file_parse_pos] = '\0';
// printf("SET FILE\n\r") ;
// check to see if the directory exists and open it if possible, otherwise exit because the directory
doesn't exist
if(set_file(target_file, 0x10, &cur_stream) != GOODEC)
{
cur_stream.Flags |= File_Not_Found;
*stream = cur_stream;
return EOF;
}
depth -= 1;
}
// check to see if we're trying to open just a directory
if(fname[fname_parse_pos] == '\0')
{
*stream = cur_stream;
return GOODEC;
}
// now that we have the location of the subdirectory that the file is in, attempt to open the file
target_file_parse_pos = 0;
while(fname[fname_parse_pos] != '\0')
{
// fill up the buffer and increment the indexes
target_file[target_file_parse_pos] = fname[fname_parse_pos];
fname_parse_pos += 1;
target_file_parse_pos += 1;
}
// tack on a \0 to the end of the target file to terminate the string
target_file[target_file_parse_pos] = '\0';
//printf("target file : %s \n\r",target_file) ;
// find the file inside of its subdirectory
if(set_file(target_file, 0x20, &cur_stream) != GOODEC)
{
cur_stream.Flags |= File_Not_Found;
*stream = cur_stream;
return EOF;
}
// at this point, we've found the file
3/17/2015 3:49 PM
36 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
*stream = cur_stream;
return GOODEC;
#endif // #ifdef FAST_FAT
}
/*
signed int fatreopen(char fname[], char mode[], FILE* old_stream, FILE* new_stream)
Summary: This will close a stream and then reopen it using new parameters.
Param fname: The full path of the file to open.
Param mode: The mode to open up the stream into.
"r" = Read
"w" = Write
"a" = Append
"rb", "wb", "ab" = Read, Write, or Append in Binary mode
Param stream: The stream to close and reopen.
Returns: EOF if there was a problem, GOODEC if everything went okay.
Note: fname must be in the form of /filename.fil for a file in the root directory
/Directory/filename.fil for a file in a subdirectory of root
/Directory/Subdirectory/filename.fil and so on...
Note: Standard C will make a file in case a file isn't found,
however due to recursion this is not possible in CCSC.
*/
signed int fatreopen(char fname[], char mode[], FILE* stream)
{
// close the old stream
if(fatclose(stream) == EOF)
return EOF;
// open the new stream
if(fatopen(fname, mode, stream) == EOF)
return EOF;
return GOODEC;
}
/*
signed int fatclose(FILE* stream)
Summary: Closes a stream and commits any changes done to the file.
Param: The stream to close.
Returns: EOF if there was a problem, 0 if everything went okay.
*/
signed int fatclose(FILE* stream)
{
int ec = 0;
int value,address;
int32 first_cluster;
//for(address= 0 ; address <= 0x20 ; address++)
// while (value != 'R')
// { mmcsd_read_data(stream->Entry_Addr + address, 1, &value);
// printf(" fatclose: stream->Entry_Addr --> %lX , HexVal --> %X, AsciiVal--> %c\n\r",
stream->Entry_Addr+address, value, value) ;
// }
// commit data back to the stream's entry, if needed
if((stream->Flags & Write) || (stream->Flags & Append))
{
3/17/2015 3:49 PM
37 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
3/17/2015 3:49 PM
38 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
EOF if the stream has reached the end of the file or doesn't have permissions to read,
*/
signed int fatgetc(FILE* stream)
{
char ch; // character read in
// check to see if the stream has proper permissions to read
if(stream->Flags & Read)
{
// when the number of bytes until eof hit zero, we know we are at the end of any file
if(stream->Bytes_Until_EOF == 0)
{
stream->Flags |= EOF_Reached;
return EOF;
}
// read in the next byte in the buffer
if(read_buffer(stream, &ch) == EOF)
return EOF;
// a 0x00 will signify the end of a non-binary file
if((ch == '\0') && !(stream->Flags & Binary))
{
stream->Flags |= EOF_Reached;
return EOF;
}
// get the next contiguous address of the stream
if(get_next_addr(&(stream->Cur_Char)) != GOODEC)
return EOF;
// we just got 1 byte closer to the end of the file
stream->Bytes_Until_EOF -= 1;
return ch;
}
// if the stream doesn't have proper permissions to read, return an EOF
else
return EOF;
}
/*
signed int fatputc(int ch, FILE* stream)
Summary: Puts a character into a stream.
Param ch: The character to put into the stream.
Param stream: The stream to put a character into.
Returns: The character that was put into the stream,
EOF if the stream doesn't have permissions to write, or if a problem happened.
*/
signed int fatputc(int ch, FILE* stream)
{
// check to see if the stream has proper permissions to write
if(((stream->Flags & Write) || (stream->Flags & Append)) && (stream->File_Type == Data_File))
{ //printf("\r\n Cur_Char = %lX ; Data_Start : %lX",stream->Cur_Char, Data_Start);
// if there isn't any space allocated yet, allocate some
if(stream->Cur_Char < Data_Start)
{ // printf("\r\n Get new cluster : ");
// printf("\r\n next free cluster = %X\r\n",Next_Free_Clust);
3/17/2015 3:49 PM
39 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
if(get_next_free_cluster(&Next_Free_Clust) == EOF)
return EOF;
// printf("Next_Free_Clust %X",Next_Free_Clust);
#ifdef FAT32
if(write_fat(Next_Free_Clust, 0x0FFFFFFF) == EOF)
return EOF;
#else // FAT16
if(write_fat(Next_Free_Clust, 0xFFFF) == EOF)
return EOF;
#endif // #ifdef FAT32
if(clear_cluster(Next_Free_Clust) == EOF)
return EOF;
stream->Cur_Char = stream->Start_Addr = cluster_to_addr(Next_Free_Clust);
}
// write the next character to the buffer
if(write_buffer(stream, ch) == EOF)
return EOF;
// get the next address, increment Cur_Char
if(get_next_addr(&(stream->Cur_Char)) == EOF)
{
// write the current buffer to the end of the current cluster
if(mmcsd_write_data(stream->Cur_Char - STREAM_BUF_SIZE + 1, STREAM_BUF_SIZE, stream->Buf)
!= GOODEC)
{
stream->Flags |= Write_Error;
return EOF;
}
// start looking for a new cluster to allocate
if(alloc_clusters(addr_to_cluster(stream->Cur_Char), &(stream->Cur_Char)) == EOF)
return EOF;
}
// our file just got bigger by 1 byte
stream->Size += 1;
return ch;
}
// if the stream doesn't have proper permissions to write, return an EOF
else
return EOF;
}
/*
char* fatgets(char* str, int num, FILE* stream)
Summary: Reads characters from a stream into a string.
Param str: A pointer to the beginning of the string to put characters into.
Param num: The number of characters to put into the string - 1.
Param stream: The stream to read from.
Returns: A pointer to the most recently added character, or NULL if there was an error.
Note: If a newline is read from the stream, then str will be terminated with a newline.
If num - 1 or EOF is reached, then str will be null terminated.
*/
char* fatgets(char* str, int num, FILE* stream)
{
int i; // counter for loops
3/17/2015 3:49 PM
40 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
3/17/2015 3:49 PM
41 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
/*
signed int fatgetpos(FILE* stream, fatpos_t* position)
Summary: Returns the current position of where the stream is pointing to relative to the beginning of
the stream.
Param stream: The stream to get the position of.
Param position: A pointer to a variable put the current position of the pointer into.
Returns: 0 on success.
*/
signed int fatgetpos(FILE* stream, fatpos_t* position)
{
*position = stream->Size - stream->Bytes_Until_EOF;
return 0;
}
/*
signed int fatsetpos(FILE* stream, fatpos_t* position)
Summary: Sets the current position of where the stream is pointing to in memory relative to the
beginning of the stream.
Param stream: The stream to set the position of.
Param position: A pointer the a variable that has the value of the new position.
Returns: 0 on success, or EOF if there was error.
*/
signed int fatsetpos(FILE* stream, fatpos_t* position)
{
#ifndef FAST_FAT
#ifdef FAT32
int32 cur_cluster; // the current cluster we're pointing to
#else // FAT16
int16 cur_cluster; // the current cluster we're pointing to
#endif // #ifdef FAT32
int32 i; // pointer to memory
#endif // #ifndef FAST_FAT
// check to see if we want to just rewind the file
if(*position == 0)
{
rewind(stream);
return GOODEC;
}
// this whole process is much different and easier if we're writing or appending at a spot after EOF
// this will essentially write null characters to the file from EOF to the desired position
if(((stream->Flags & Write) || (stream->Flags & Append)) && (stream->Size < *position))
{
while(stream->Size < *position)
if(fatputc('\0', stream) == EOF)
return EOF;
return 0;
}
#ifdef FAST_FAT
stream->Cur_Char = stream->Start_Addr + *position;
#else // NO FAST_FAT
// figure out how many clusters into the file the position is to be set to
i = *position / Bytes_Per_Cluster;
cur_cluster = addr_to_cluster(stream->Start_Addr);
3/17/2015 3:49 PM
42 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
3/17/2015 3:49 PM
43 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
return EOF;
break;
case SEEK_SET:
myoffset = offset;
if(fatsetpos(stream, &myoffset) != 0)
return EOF;
break;
default:
return EOF;
}
// clear the EOF flag
stream->Flags &= 0xEF;
return GOODEC;
}
/*
signed int fateof(FILE* stream)
Summary: Determines whether or not the stream is at the end of the file.
Param: The stream to query for EOF.
Returns: A non-zero value if the file is at EOF,
0 if the file is not at EOF.
*/
signed int fateof(FILE* stream)
{
return stream->Flags & EOF_Reached;
}
/*
signed int fatread(void* buffer, int size, int32 num, FILE* stream)
Summary: Fills up an array with data from a stream.
Param buffer: A pointer to the beginning of an array of any type.
Param size: How many bytes each element in the array is.
Param num: How many elements to fill in the array.
Param stream: The stream to read from.
Returns: How many values were written to the array.
*/
signed int fatread(void* buffer, int size, int32 num, FILE* stream)
{
int32 i; // counter for loop
// fill up every byte
for(i = 0; i < (num * size); i += 1)
buffer[i] = fatgetc(stream);
return i;
}
/*
signed int fatwrite(void* buffer, int size, int32 count, FILE* stream )
Summary: Fills up a stream with data from an array
Param buffer: A pointer to the beginning of an array of any type.
Param size: How many bytes each element in the array is.
Param num: How many elements to write to the stream.
Param stream: The stream to write to.
Returns: How many values were written to the stream.
*/
signed int fatwrite(void* buffer, int size, int32 count, FILE* stream )
3/17/2015 3:49 PM
44 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
{
int32 i; // counter for loop
// write every byte
for(i = 0; i < (count * (int32)size); i += 1)
if(fatputc(buffer[i], stream) == EOF)
return EOF;
return i;
}
/*
signed int fatflush(FILE* stream)
Summary: Flushes the buffer of a given stream.
Param: The stream to flush the buffer of.
Returns: EOF if there was a problem, 0 if everything went okay
*/
signed int fatflush(FILE* stream)
{ int address;
// check to see if we have a buffer
if((stream->Flags & Write) || (stream->Flags & Append))
{
// for( address =0; address <= STREAM_BUF_SIZE; address++)
// { printf ("stream->Cur_Char : %lX, %c\r\n",stream->Cur_Char-address,stream->Buf[address] );}
// { printf (" %X", stream->Buf[address] );}
3/17/2015 3:49 PM
45 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
3/17/2015 3:49 PM
46 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
{
fatpos_t retval;
if(fatgetpos(stream, &retval) != 0)
return 0;
return retval;
}
/// Non-Standard C Functions ///
/*
signed int rm_file(char fname[])
Summary: Deletes a file.
Param: The full path of the file to delete.
Returns: GOODEC if everything went okay, EOF if there was a problem.
Note: fname must be in the form of /filename.fil for a file in the root directory
/Directory/filename.fil for a file in a subdirectory of root
/Directory/Subdirectory/filename.fil and so on...
*/
signed int rm_file(char fname[])
{
int
order,
ulinked_entry = 0xE5; // 0xE5 is put into the file's entry to indicate unlinking
int32 i;
char mode[] = "r"; // r is the safest mode to remove files with
FILE stream; // the stream that we'll be working with
// attempt to open the stream
if(fatopen(fname, mode, &stream) == EOF)
return EOF;
// we need to un-link the file's clusters from the FAT if there are clusters allocated
if(stream.Start_Addr > Root_Dir)
{
if(dealloc_clusters(addr_to_cluster(stream.Start_Addr)) == EOF)
return EOF;
}
// get rid of the first entry
i = stream.Entry_Addr;
if(mmcsd_write_data(i, 1, &ulinked_entry) == EOF)
return EOF;
// check to see if there is a long file name
get_prev_entry(&i);
if(mmcsd_read_data(i + 11, 1, &order) == EOF)
return EOF;
// get rid of all of the long file name entries if they're there
while(order == 0x0F)
{
if(mmcsd_write_data(i, 1, &ulinked_entry) == EOF)
return EOF;
if(get_prev_entry(&i) == EOF)
3/17/2015 3:49 PM
47 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
return EOF;
if(mmcsd_read_data(i + 11, 1, &order) == EOF)
return EOF;
}
if(fatclose(&stream) == EOF)
return EOF;
return GOODEC;
}
/*
signed int rm_dir(char dname[])
Summary: Deletes a directory.
Param: The full path of the directory to delete.
Returns: GOODEC if everything went okay, EOF if there was a problem.
Note: dname must be in the form of /Dirname/ for a directory in the root directory
/Dirname/Subdirname/ for a directory in a subdirectory of root and so on...
Note: This function cannot remove all of the files
and subdirectories of the directory. Manually remove all subdirectories
and files before calling this command.
*/
signed int rm_dir(char dname[])
{
char mode[] = "r"; // r is the safest mode to remove files with
FILE stream; // the stream that we'll be working with
// attempt to open the stream
if(fatopen(dname, mode, &stream) == EOF)
return EOF;
// jump over the . and .. entries in the directory
stream.Entry_Addr = stream.Start_Addr + 64;
// check to make sure that there isn't stuff in this directory
if(get_next_file(&stream) != EOF)
return EOF;
// since removing files is a lot like removing directories, we
// can just call rm_file
if(rm_file(dname) == EOF)
return EOF;
return GOODEC;
}
/*
signed int mk_file(char fname[])
Summary: Creates a file.
Param: The full path of the file to create.
Returns: GOODEC if everything went okay, EOF if there was a problem.
Note: This function will not create directories if parent directories don't exist.
Note: fname must be in the form of /filename.fil for a file in the root directory
/Directory/filename.fil for a file in a subdirectory of root
/Directory/Subdirectory/filename.fil and so on...
*/
signed int mk_file(char fname[])
3/17/2015 3:49 PM
48 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
{
char
filename[MAX_FILE_NAME_LENGTH], // the file name we're trying to make
mode[] = "r"; // reading is the safest mode to work in
int
buf, value, // buffer to hold values
entire_entry[0x20],// entire first entry
filename_pos = 0, // the current parse position of the file name we're trying to create
fname_pos; // the current parse position of the input the the function
int32 i; // pointer to memory
FILE stream; // the stream that we'll be working with
// attempt to open up to the directory
if(fatopen(fname, mode, &stream) == GOODEC)
return EOF; // we shouldn't get an GOODEC back from fatopen()
// printf("fatopen OK\r\n");
// check to see if the file is already there.
if(!(stream.Flags & File_Not_Found))
return EOF;
// make a file name
fname_pos = strrchr(fname, '/') - fname + 1;
while((fname[fname_pos] != '\0') && (filename_pos < MAX_FILE_NAME_LENGTH))
{
filename[filename_pos] = fname[fname_pos];
fname_pos += 1;
filename_pos += 1;
// printf("set file name %c", &filename[filename_pos]);
}
filename[filename_pos] = '\0';
// write the name
if(set_file_name(stream.Start_Addr, &i, filename) == EOF)
return EOF;
// throw in some values in the file's first entry
for(buf = 0; buf < 0x20; buf += 1)
entire_entry[buf] = 0;
// this is a file
entire_entry[0x0B] = 0x20;
// entire_entry[14] = 0x40;
// entire_entry[15] = 0x92;
entire_entry[16] = 0xD3;
entire_entry[17] = 0x40;
entire_entry[18] = 0xD3;
entire_entry[19] = 0x40;
entire_entry[24] = 0xD3;
entire_entry[25] = 0x40;
3/17/2015 3:49 PM
49 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
return EOF;
if(fatclose(&stream) != GOODEC)
{
printf("Error closing file");
return EOF;
}
*/ g_MMCSDBufferChanged=TRUE;
mmcsd_flush_buffer();
// for ( i=0; i <= 0x20; i++)
// printf ("g_mmcsd_buffer[%X]: %X \r\n", i, g_mmcsd_buffer[i]);
// mmcsd_read_block(i, MAX_FILE_NAME_LENGTH, entire_entry);
// for (value = 0 ; value <= 0x0B; value++)
// {
// mmcsd_read_data(i+value, 1, entire_entry[i]);
// printf(" read from write addr = %lX, HexVal --> %X, AsciiVal--> %c\n\r", i+value,
entire_entry[value], entire_entry[value]) ;
// value++;
// }
return GOODEC;
}
/*
signed int mk_dir(char dname[])
Summary: Creates a directory.
Param: The full path of the directory to create.
Returns: GOODEC if everything went okay, EOF if there was a problem.
Note: This function will not create directories if parent directories don't exist.
Note: dname must be in the form of /Dirname/ for a directory in the root directory
/Dirname/Subdirname/ for a directory in a subdirectory of root and so on...
*/
signed int mk_dir(char dname[])
{
char
dirname[MAX_FILE_NAME_LENGTH], // the directory name we're trying to make
entire_entry[0x20], // used to hold the link entries (. and ..) to the directory and its parent
mode[] = "r"; // reading is the safest mode to work in
int
dirname_pos = 0, // the current parse position of the directory name we're trying to create
dname_pos, // the current parse position of the input the the function
j; // counter for loops
int32 i; // pointer to memory
3/17/2015 3:49 PM
50 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
0);
1);
2);
3);
3/17/2015 3:49 PM
51 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
return EOF;
// make the two links that point to the directory and the directory's parent
i = cluster_to_addr(Next_Free_Clust);
// put in the first link that points to the directory itself
for(j = 0; j < 0x20; j += 1)
{
if(j < 0x01)
entire_entry[j] = '.';
else if(j < 0x0B)
entire_entry[j] = 0x20;
else if(j == 0x0B)
entire_entry[j] = 0x10;
else
entire_entry[j] = 0x00;
}
entire_entry[0x1A] = make8(Next_Free_Clust,
entire_entry[0x1B] = make8(Next_Free_Clust,
#ifdef FAT32
entire_entry[0x14] = make8(Next_Free_Clust,
entire_entry[0x15] = make8(Next_Free_Clust,
#endif // #ifdef FAT32
0);
1);
2);
3);
3/17/2015 3:49 PM
52 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
}
/// Functions' Utility Functions ///
/// NOTE: A library user should not need to use any of the functions in this section ///
/*
signed int set_file(char fname[], int attrib, FILE* stream)
Summary: This will set the stream to point to the specified file.
Param fname: The file name to search for.
Param attrib: The file attributes to search for. 0x10 is a directory, 0x20 is a file.
Param stream: The stream to set.
Returns: EOF if there was a problem, GOODEC if everything went okay.
Note: The stream has to be pointing to the parent directory's start address when coming in to this
function.
*/
signed int set_file(char fname[], int attrib, FILE* stream)
{
int
cur_attrib, // the attribute of the most recently read entry
cur_state, // the state of the most recently read entry
ec = 0; // error checking byte
int32 i;
int16 last_data_cluster,address;
// pointer to memory
#ifndef FAST_FAT
char name_buffer[MAX_FILE_NAME_LENGTH]; // buffer to hold in the most recently read in name
#endif // #ifndef FAST_FAT
last_data_cluster=0;
// set the memory pointer to the parent start address
i = stream->Start_Addr;
// printf("\r\nSet file : Start_Addr --> %lX attrib: %X \n\r", i,attrib) ;
// last_data_cluster =addr_to_cluster(Data_Start);
// mmcsd_read_block(i, MMCSD_MAX_BLOCK_SIZE, g_mmcsd_buffer);
// search for the name of our target file inside of the parent directory
do
{
// read the state and the attribute of the current entry
ec += mmcsd_read_data(i, 1, &cur_state);
// cur_state = g_mmcsd_buffer[0];
// printf("\r\set file read_Addr --> %lX, cur_state-> %X \n\r", i,cur_state) ;
ec += mmcsd_read_data(i + 0x0B, 1, &cur_attrib);
// cur_state = g_mmcsd_buffer[0+0x0B];
// printf("\r\set file read_Addr --> %lX, cur_state--> %X cur_attrib-> %X \n\r", i+ 0x0B,cur_state,
cur_attrib) ;
//looking for the last data sector adress
ec += mmcsd_read_data(i + 0x1A, 2, &address);
neochrome32
incomplete fat.c
Posted: Sun Jun 09, 2013 9:14 pm
3/17/2015 3:49 PM
53 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
I've found a new bug in fat.c. Short file names are processed as if they have the type of the directory
entry immediately before them, except if that entry is a long file name. Example: a sub-directory with
only short file names. The first short file name is actually treated as if it were a sub-directory name
(since the first two entries in a sub-directory are '.' and '..').
The function get_file_name() at about line 1563 needs to be changed as follows:
Code:
// check to make sure that this file has a long file name
if(mmcsd_read_data(i - 0x15, 1, &type) != GOODEC)
return EOF;
if(type != 0x0F)
{
// this file doesn't have a long file name
if(mmcsd_read_data(i + 0x0B, 1, &type) != GOODEC) /* NEW */
return EOF; /* NEW */
if(get_short_file_name(i, name, type) == EOF)
return EOF;
return GOODEC;
}
hello OPAS,
I am using evaluation version of CCS compiler.
I have used both the codes which you have provided (mmcsd.c & fat .c) but it is not working.
on the hyper terminal it is showing "Error Initializing FAT".
Oldest First
Go
All times are GMT - 6 Hours
Go
in
in
in
in
this
this
this
this
forum
forum
forum
forum
3/17/2015 3:49 PM
54 of 54
http://www.ccsinfo.com/forum/viewtopic.php?t=43417
3/17/2015 3:49 PM