mirror of
https://github.com/marqs85/ossc.git
synced 2024-06-15 17:29:46 +00:00
1909 lines
69 KiB
C
1909 lines
69 KiB
C
|
/******************************************************************************
|
||
|
* *
|
||
|
* License Agreement *
|
||
|
* *
|
||
|
* Copyright (c) 2006 Altera Corporation, San Jose, California, USA. *
|
||
|
* All rights reserved. *
|
||
|
* *
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a *
|
||
|
* copy of this software and associated documentation files (the "Software"), *
|
||
|
* to deal in the Software without restriction, including without limitation *
|
||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
|
||
|
* and/or sell copies of the Software, and to permit persons to whom the *
|
||
|
* Software is furnished to do so, subject to the following conditions: *
|
||
|
* *
|
||
|
* The above copyright notice and this permission notice shall be included in *
|
||
|
* all copies or substantial portions of the Software. *
|
||
|
* *
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
|
||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
|
||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
|
||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
|
||
|
* DEALINGS IN THE SOFTWARE. *
|
||
|
* *
|
||
|
* This agreement shall be governed in all respects by the laws of the State *
|
||
|
* of California and by the laws of the United States of America. *
|
||
|
* *
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <priv/alt_file.h>
|
||
|
#include <io.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include "Altera_UP_SD_Card_Avalon_Interface_mod.h"
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Local Define Statements
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define CHAR_TO_UPPER(ch) ((char) (((ch >= 'a') && (ch <= 'z')) ? ((ch-'a')+'A'): ch))
|
||
|
|
||
|
// Data Buffer Address
|
||
|
#define SD_CARD_BUFFER(base, x) (base + x)
|
||
|
// 128-bit Card Identification Number
|
||
|
#define SD_CARD_CID(base, x) (base + 0x0200 + x)
|
||
|
// 128-bit Card Specific Data Register
|
||
|
#define SD_CARD_CSD(base, x) (base + 0x0210 + x)
|
||
|
// 32-bit Operating Conditions Register
|
||
|
#define SD_CARD_OCR(base) (base + 0x0220)
|
||
|
// 32-bit Card Status Register
|
||
|
#define SD_CARD_STATUS(base) (base + 0x0224)
|
||
|
// 16-bit Relative Card Address Register
|
||
|
#define SD_CARD_RCA(base) (base + 0x0228)
|
||
|
// 32-bit Card Argument Register
|
||
|
#define SD_CARD_ARGUMENT(base) (base + 0x022C)
|
||
|
// 16-bit Card Command Register
|
||
|
#define SD_CARD_COMMAND(base) (base + 0x0230)
|
||
|
// 16-bit Card Auxiliary Status Register
|
||
|
#define SD_CARD_AUX_STATUS(base) (base + 0x0234)
|
||
|
// 32-bit R1 Response Register
|
||
|
#define SD_CARD_R1_RESPONSE(base) (base + 0x0238)
|
||
|
|
||
|
#define CMD_READ_BLOCK 17
|
||
|
#define CMD_WRITE_BLOCK 24
|
||
|
|
||
|
// FAT 12/16 related stuff
|
||
|
//#define BOOT_SECTOR_DATA_SIZE 0x005A
|
||
|
#define MAX_FILES_OPENED 2
|
||
|
|
||
|
/******************************************************************************/
|
||
|
/****** LOCAL DATA STRUCTURES ***********************************************/
|
||
|
/******************************************************************************/
|
||
|
|
||
|
|
||
|
typedef struct s_FAT_12_16_boot_sector {
|
||
|
unsigned char jump_instruction[3];
|
||
|
char OEM_name[8];
|
||
|
unsigned short int sector_size_in_bytes;
|
||
|
unsigned char sectors_per_cluster;
|
||
|
unsigned short int reserved_sectors;
|
||
|
unsigned char number_of_FATs;
|
||
|
unsigned short int max_number_of_dir_entires;
|
||
|
unsigned short int number_of_sectors_in_partition;
|
||
|
unsigned char media_descriptor;
|
||
|
unsigned short int number_of_sectors_per_table;
|
||
|
unsigned short int number_of_sectors_per_track;
|
||
|
unsigned short int number_of_heads;
|
||
|
unsigned int number_of_hidden_sectors;
|
||
|
unsigned int total_sector_count_if_above_32MB;
|
||
|
unsigned char drive_number;
|
||
|
unsigned char current_head;
|
||
|
unsigned char boot_signature;
|
||
|
unsigned char volume_id[4];
|
||
|
char volume_label[11];
|
||
|
unsigned char file_system_type[8];
|
||
|
unsigned char bits_for_cluster_index;
|
||
|
unsigned int first_fat_sector_offset;
|
||
|
unsigned int second_fat_sector_offset;
|
||
|
unsigned int root_directory_sector_offset;
|
||
|
unsigned int data_sector_offset;
|
||
|
} t_FAT_12_16_boot_sector;
|
||
|
|
||
|
|
||
|
typedef struct s_file_record {
|
||
|
unsigned char name[8];
|
||
|
unsigned char extension[3];
|
||
|
unsigned char attributes;
|
||
|
unsigned short int create_time;
|
||
|
unsigned short int create_date;
|
||
|
unsigned short int last_access_date;
|
||
|
unsigned short int last_modified_time;
|
||
|
unsigned short int last_modified_date;
|
||
|
unsigned short int start_cluster_index;
|
||
|
unsigned int file_size_in_bytes;
|
||
|
/* The following fields are only used when a file has been created or opened. */
|
||
|
unsigned int current_cluster_index;
|
||
|
unsigned int current_sector_in_cluster;
|
||
|
unsigned int current_byte_position;
|
||
|
// Absolute location of the file record on the SD Card.
|
||
|
unsigned int file_record_cluster;
|
||
|
unsigned int file_record_sector_in_cluster;
|
||
|
short int file_record_offset;
|
||
|
// Is this record in use and has the file been modified.
|
||
|
unsigned int home_directory_cluster;
|
||
|
bool modified;
|
||
|
bool in_use;
|
||
|
} t_file_record;
|
||
|
|
||
|
|
||
|
typedef struct s_find_data {
|
||
|
unsigned int directory_root_cluster; // 0 means root directory.
|
||
|
unsigned int current_cluster_index;
|
||
|
unsigned int current_sector_in_cluster;
|
||
|
short int file_index_in_sector;
|
||
|
bool valid;
|
||
|
} t_find_data;
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Local Variables
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
bool initialized = false;
|
||
|
bool is_sd_card_formated_as_FAT16 = false;
|
||
|
volatile short int *aux_status_register = NULL;
|
||
|
volatile int *status_register = NULL;
|
||
|
volatile short int *CSD_register_w0 = NULL;
|
||
|
volatile short int *command_register = NULL;
|
||
|
volatile int *command_argument_register = NULL;
|
||
|
volatile char *buffer_memory = NULL;
|
||
|
int fat_partition_offset_in_512_byte_sectors = 0;
|
||
|
int fat_partition_size_in_512_byte_sectors = 0;
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
t_FAT_12_16_boot_sector boot_sector_data;
|
||
|
#endif
|
||
|
|
||
|
alt_up_sd_card_dev *device_pointer = NULL;
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
// Pointers to currently opened files.
|
||
|
t_file_record active_files[MAX_FILES_OPENED];
|
||
|
#endif
|
||
|
bool current_sector_modified = false;
|
||
|
unsigned int current_sector_index = 0;
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
t_find_data search_data;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Local Functions
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
static bool Write_Sector_Data(int sector_index, int partition_offset)
|
||
|
#else
|
||
|
bool Write_Sector_Data(int sector_index, int partition_offset)
|
||
|
#endif
|
||
|
// This function writes a sector at the specified address on the SD Card.
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if (alt_up_sd_card_is_Present())
|
||
|
{
|
||
|
short int reg_state = 0xff;
|
||
|
|
||
|
/* Multiply sector offset by sector size to get the address. Sector size is 512. Also,
|
||
|
* the SD card reads data in 512 byte chunks, so the address must be a multiple of 512. */
|
||
|
IOWR_32DIRECT(command_argument_register, 0, (sector_index + partition_offset)*512);
|
||
|
IOWR_16DIRECT(command_register, 0, CMD_WRITE_BLOCK);
|
||
|
do {
|
||
|
reg_state = (short int) IORD_16DIRECT(aux_status_register,0);
|
||
|
} while ((reg_state & 0x04)!=0);
|
||
|
// Make sure the request did not time out.
|
||
|
if ((reg_state & 0x10) == 0)
|
||
|
{
|
||
|
result = true;
|
||
|
current_sector_modified = false;
|
||
|
current_sector_index = sector_index+partition_offset;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
static bool Save_Modified_Sector()
|
||
|
#else
|
||
|
bool Save_Modified_Sector()
|
||
|
#endif
|
||
|
// If the sector has been modified, then save it to the SD Card.
|
||
|
{
|
||
|
bool result = true;
|
||
|
if (current_sector_modified)
|
||
|
{
|
||
|
result = Write_Sector_Data(current_sector_index, 0);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
static bool Read_Sector_Data(int sector_index, int partition_offset)
|
||
|
#else
|
||
|
bool Read_Sector_Data(int sector_index, int partition_offset)
|
||
|
#endif
|
||
|
// This function reads a sector at the specified address on the SD Card.
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if (alt_up_sd_card_is_Present())
|
||
|
{
|
||
|
short int reg_state = 0xff;
|
||
|
|
||
|
/* Write data to the SD card if the current buffer is out of date. */
|
||
|
if (current_sector_modified)
|
||
|
{
|
||
|
if (Write_Sector_Data(current_sector_index, 0) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
/* Multiply sector offset by sector size to get the address. Sector size is 512. Also,
|
||
|
* the SD card reads data in 512 byte chunks, so the address must be a multiple of 512. */
|
||
|
IOWR_32DIRECT(command_argument_register, 0, (sector_index + partition_offset)*512);
|
||
|
IOWR_16DIRECT(command_register, 0, CMD_READ_BLOCK);
|
||
|
do {
|
||
|
reg_state = (short int) IORD_16DIRECT(aux_status_register,0);
|
||
|
} while ((reg_state & 0x04)!=0);
|
||
|
// Make sure the request did not time out.
|
||
|
if ((reg_state & 0x10) == 0)
|
||
|
{
|
||
|
result = true;
|
||
|
current_sector_modified = false;
|
||
|
current_sector_index = sector_index+partition_offset;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
static bool get_cluster_flag(unsigned int cluster_index, unsigned short int *flag)
|
||
|
// Read a cluster flag.
|
||
|
{
|
||
|
unsigned int sector_index = (cluster_index / 256) + fat_partition_offset_in_512_byte_sectors;
|
||
|
|
||
|
sector_index = sector_index + boot_sector_data.first_fat_sector_offset;
|
||
|
|
||
|
if (sector_index != current_sector_index)
|
||
|
{
|
||
|
if (Read_Sector_Data(sector_index, 0) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
*flag = (unsigned short int) IORD_16DIRECT(device_pointer->base, 2*(cluster_index % 256));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool mark_cluster(unsigned int cluster_index, short int flag, bool first_fat)
|
||
|
// Place a marker on the specified cluster in a given FAT.
|
||
|
{
|
||
|
unsigned int sector_index = (cluster_index / 256) + fat_partition_offset_in_512_byte_sectors;
|
||
|
|
||
|
if (first_fat)
|
||
|
{
|
||
|
sector_index = sector_index + boot_sector_data.first_fat_sector_offset;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sector_index = sector_index + boot_sector_data.second_fat_sector_offset;
|
||
|
}
|
||
|
|
||
|
if (sector_index != current_sector_index)
|
||
|
{
|
||
|
if (Read_Sector_Data(sector_index, 0) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
IOWR_16DIRECT(device_pointer->base, 2*(cluster_index % 256), flag);
|
||
|
current_sector_modified = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool Check_for_Master_Boot_Record(void)
|
||
|
// This function reads the first 512 bytes on the SD Card. This data should
|
||
|
// contain the Master Boot Record. If it does, then print
|
||
|
// relevant information and return true. Otherwise, return false.
|
||
|
{
|
||
|
bool result = false;
|
||
|
int index;
|
||
|
int end, offset, partition_size;
|
||
|
|
||
|
/* Load the first 512 bytes of data from SD card. */
|
||
|
if (Read_Sector_Data(0, 0))
|
||
|
{
|
||
|
end = (short int) IORD_16DIRECT(device_pointer->base,0x1fe);
|
||
|
|
||
|
// Check if the end of the sector contains an end string 0xaa55.
|
||
|
if ((end & 0x0000ffff) == 0x0000aa55)
|
||
|
{
|
||
|
// Check four partition entries and see if any are valid
|
||
|
for (index = 0; index < 4; index++)
|
||
|
{
|
||
|
int partition_data_offset = (index * 16) + 0x01be;
|
||
|
char type;
|
||
|
|
||
|
// Read Partition type
|
||
|
type = (unsigned char) IORD_8DIRECT(device_pointer->base,partition_data_offset + 0x04);
|
||
|
|
||
|
// Check if this is an FAT parition
|
||
|
if ((type == 1) || (type == 4) || (type == 6) || (type == 14))
|
||
|
{
|
||
|
// Get partition offset and size.
|
||
|
offset = (((unsigned short int) IORD_16DIRECT(device_pointer->base,partition_data_offset + 0x0A)) << 16) | ((unsigned short int) IORD_16DIRECT(device_pointer->base,partition_data_offset + 0x08));
|
||
|
partition_size = (((unsigned short int) IORD_16DIRECT(device_pointer->base,partition_data_offset + 0x0E)) << 16) | ((unsigned short int) IORD_16DIRECT(device_pointer->base,partition_data_offset + 0x0C));
|
||
|
|
||
|
// Check if the partition is valid
|
||
|
if (partition_size > 0)
|
||
|
{
|
||
|
result = true;
|
||
|
fat_partition_size_in_512_byte_sectors = partition_size;
|
||
|
fat_partition_offset_in_512_byte_sectors = offset;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool Read_File_Record_At_Offset(int offset, t_file_record *record, unsigned int cluster_index, unsigned int sector_in_cluster)
|
||
|
// This function reads a file record
|
||
|
{
|
||
|
bool result = false;
|
||
|
if (((offset & 0x01f) == 0) && (alt_up_sd_card_is_Present()) && (is_sd_card_formated_as_FAT16))
|
||
|
{
|
||
|
int counter;
|
||
|
|
||
|
for (counter = 0; counter < 8; counter++)
|
||
|
{
|
||
|
record->name[counter] = (char) IORD_8DIRECT(device_pointer->base, offset+counter);
|
||
|
}
|
||
|
for (counter = 0; counter < 3; counter++)
|
||
|
{
|
||
|
record->extension[counter] = (char) IORD_8DIRECT(device_pointer->base, offset+counter+8);
|
||
|
}
|
||
|
record->attributes = (char) IORD_8DIRECT(device_pointer->base, offset+11);
|
||
|
/* Ignore reserved bytes at locations 12 and 13. */
|
||
|
record->create_time = (unsigned short int) IORD_16DIRECT(device_pointer->base, offset+14);
|
||
|
record->create_date = (unsigned short int) IORD_16DIRECT(device_pointer->base, offset+16);
|
||
|
record->last_access_date = (unsigned short int) IORD_16DIRECT(device_pointer->base, offset+18);
|
||
|
/* Ignore reserved bytes at locations 20 and 21. */
|
||
|
record->last_modified_time = (unsigned short int) IORD_16DIRECT(device_pointer->base, offset+22);
|
||
|
record->last_modified_date = (unsigned short int) IORD_16DIRECT(device_pointer->base, offset+24);
|
||
|
record->start_cluster_index = (unsigned short int) IORD_16DIRECT(device_pointer->base, offset+26);
|
||
|
record->file_size_in_bytes = (unsigned int) IORD_32DIRECT(device_pointer->base, offset+28);
|
||
|
record->file_record_cluster = cluster_index;
|
||
|
record->file_record_sector_in_cluster = sector_in_cluster;
|
||
|
record->file_record_offset = offset;
|
||
|
result = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool Write_File_Record_At_Offset(int offset, t_file_record *record)
|
||
|
// This function writes a file record at a given offset. The offset is given in bytes.
|
||
|
{
|
||
|
bool result = false;
|
||
|
if (((offset & 0x01f) == 0) && (alt_up_sd_card_is_Present()) && (is_sd_card_formated_as_FAT16))
|
||
|
{
|
||
|
int counter;
|
||
|
|
||
|
for (counter = 0; counter < 8; counter=counter+2)
|
||
|
{
|
||
|
short int two_chars = (short int) record->name[counter+1];
|
||
|
two_chars = two_chars << 8;
|
||
|
two_chars = two_chars | record->name[counter];
|
||
|
IOWR_16DIRECT(device_pointer->base, offset+counter, two_chars);
|
||
|
}
|
||
|
for (counter = 0; counter < 3; counter++)
|
||
|
{
|
||
|
IOWR_8DIRECT(device_pointer->base, offset+counter+8, record->extension[counter]);
|
||
|
}
|
||
|
IOWR_8DIRECT(device_pointer->base, offset+11, record->attributes);
|
||
|
/* Ignore reserved bytes at locations 12 and 13. */
|
||
|
IOWR_16DIRECT(device_pointer->base, offset+14, record->create_time);
|
||
|
IOWR_16DIRECT(device_pointer->base, offset+16, record->create_date);
|
||
|
IOWR_16DIRECT(device_pointer->base, offset+18, record->last_access_date);
|
||
|
/* Ignore reserved bytes at locations 20 and 21. */
|
||
|
IOWR_16DIRECT(device_pointer->base, offset+22, record->last_modified_time);
|
||
|
IOWR_16DIRECT(device_pointer->base, offset+24, record->last_modified_date);
|
||
|
IOWR_16DIRECT(device_pointer->base, offset+26, record->start_cluster_index);
|
||
|
IOWR_32DIRECT(device_pointer->base, offset+28, record->file_size_in_bytes);
|
||
|
current_sector_modified = true;
|
||
|
result = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool Check_for_DOS_FAT(int FAT_partition_start_sector)
|
||
|
// This function reads the boot sector for the FAT file system on the SD Card.
|
||
|
// The offset_address should point to the sector on the card where the boot sector is located.
|
||
|
// The sector number is specified either in the master Boot Record, or is 0 by default for a purely FAT
|
||
|
// based file system. If the specified sector contains a FAT boot sector, then this function prints the
|
||
|
// relevant information and returns 1. Otherwise, it returns 0.
|
||
|
{
|
||
|
bool result = false;
|
||
|
int counter = 0;
|
||
|
short int end;
|
||
|
|
||
|
result = Read_Sector_Data(0, FAT_partition_start_sector);
|
||
|
end = (short int) IORD_16DIRECT(device_pointer->base, 0x1fe);
|
||
|
if (((end & 0x0000ffff) == 0x0000aa55) && (result))
|
||
|
{
|
||
|
int num_clusters = 0;
|
||
|
|
||
|
boot_sector_data.jump_instruction[0] = (char) IORD_8DIRECT(device_pointer->base, 0);
|
||
|
boot_sector_data.jump_instruction[1] = (char) IORD_8DIRECT(device_pointer->base, 1);
|
||
|
boot_sector_data.jump_instruction[2] = (char) IORD_8DIRECT(device_pointer->base, 2);
|
||
|
for (counter = 0; counter < 8; counter++)
|
||
|
{
|
||
|
boot_sector_data.OEM_name[counter] = (char) IORD_8DIRECT(device_pointer->base, 3+counter);
|
||
|
}
|
||
|
boot_sector_data.sector_size_in_bytes = (((unsigned char) IORD_8DIRECT(device_pointer->base, 12)) << 8 ) | ((char) IORD_8DIRECT(device_pointer->base, 11));
|
||
|
boot_sector_data.sectors_per_cluster = ((unsigned char) IORD_8DIRECT(device_pointer->base, 13));
|
||
|
boot_sector_data.reserved_sectors = ((unsigned short int) IORD_16DIRECT(device_pointer->base, 14));
|
||
|
boot_sector_data.number_of_FATs = ((unsigned char) IORD_8DIRECT(device_pointer->base, 16));
|
||
|
boot_sector_data.max_number_of_dir_entires = (((unsigned short int)(((unsigned char) IORD_8DIRECT(device_pointer->base, 18)))) << 8 ) | ((unsigned char) IORD_8DIRECT(device_pointer->base, 17));
|
||
|
boot_sector_data.number_of_sectors_in_partition = (((unsigned short int)(((unsigned char) IORD_8DIRECT(device_pointer->base, 20)))) << 8 ) | ((unsigned char) IORD_8DIRECT(device_pointer->base, 19));
|
||
|
boot_sector_data.media_descriptor = ((unsigned char) IORD_8DIRECT(device_pointer->base, 21));
|
||
|
boot_sector_data.number_of_sectors_per_table = ((unsigned short int) IORD_16DIRECT(device_pointer->base, 22));
|
||
|
boot_sector_data.number_of_sectors_per_track = ((unsigned short int) IORD_16DIRECT(device_pointer->base, 24));
|
||
|
boot_sector_data.number_of_heads = ((unsigned short int) IORD_16DIRECT(device_pointer->base, 26));
|
||
|
boot_sector_data.number_of_hidden_sectors = ((unsigned int) IORD_32DIRECT(device_pointer->base, 28));
|
||
|
boot_sector_data.total_sector_count_if_above_32MB = ((unsigned int) IORD_32DIRECT(device_pointer->base, 32));
|
||
|
boot_sector_data.drive_number = ((unsigned char) IORD_8DIRECT(device_pointer->base, 36));
|
||
|
boot_sector_data.current_head = ((unsigned char) IORD_8DIRECT(device_pointer->base, 37));
|
||
|
boot_sector_data.boot_signature = ((unsigned char) IORD_8DIRECT(device_pointer->base, 38));
|
||
|
boot_sector_data.first_fat_sector_offset = boot_sector_data.reserved_sectors;
|
||
|
boot_sector_data.second_fat_sector_offset = boot_sector_data.first_fat_sector_offset + boot_sector_data.number_of_sectors_per_table;
|
||
|
boot_sector_data.root_directory_sector_offset = boot_sector_data.second_fat_sector_offset + boot_sector_data.number_of_sectors_per_table;
|
||
|
boot_sector_data.data_sector_offset = boot_sector_data.root_directory_sector_offset + (32*boot_sector_data.max_number_of_dir_entires / boot_sector_data.sector_size_in_bytes);
|
||
|
|
||
|
if (boot_sector_data.number_of_sectors_in_partition > 0)
|
||
|
{
|
||
|
num_clusters = (boot_sector_data.number_of_sectors_in_partition / boot_sector_data.sectors_per_cluster);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
num_clusters = (boot_sector_data.total_sector_count_if_above_32MB / boot_sector_data.sectors_per_cluster);
|
||
|
}
|
||
|
if (num_clusters < 4087)
|
||
|
{
|
||
|
boot_sector_data.bits_for_cluster_index = 12;
|
||
|
}
|
||
|
else if (num_clusters <= 65517)
|
||
|
{
|
||
|
boot_sector_data.bits_for_cluster_index = 16;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
boot_sector_data.bits_for_cluster_index = 32;
|
||
|
}
|
||
|
|
||
|
for (counter = 0; counter < 4; counter++)
|
||
|
{
|
||
|
boot_sector_data.volume_id[counter] = ((char) IORD_8DIRECT(device_pointer->base, 39+counter));
|
||
|
}
|
||
|
for (counter = 0; counter < 11; counter++)
|
||
|
{
|
||
|
boot_sector_data.volume_label[counter] = ((char) IORD_8DIRECT(device_pointer->base, 43+counter));
|
||
|
}
|
||
|
for (counter = 0; counter < 8; counter++)
|
||
|
{
|
||
|
boot_sector_data.file_system_type[counter] = ((char) IORD_8DIRECT(device_pointer->base, 54+counter));
|
||
|
}
|
||
|
// Clear file records
|
||
|
for (counter = 0; counter < MAX_FILES_OPENED; counter++)
|
||
|
{
|
||
|
active_files[counter].in_use = false;
|
||
|
}
|
||
|
result = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = false;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool Look_for_FAT16(void)
|
||
|
// Read the SD card to determine if it contains a FAT16 partition.
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if (alt_up_sd_card_is_Present())
|
||
|
{
|
||
|
short int csd_file_format = *CSD_register_w0;
|
||
|
|
||
|
fat_partition_offset_in_512_byte_sectors = 0;
|
||
|
fat_partition_size_in_512_byte_sectors = 0;
|
||
|
|
||
|
if (((csd_file_format & 0x8000) == 0) && ((csd_file_format & 0x0c00) != 0x0c00))
|
||
|
{
|
||
|
if ((csd_file_format & 0x0c00) == 0x0400)
|
||
|
{
|
||
|
/* SD Card contains files stored in a DOS FAT (floppy like) file format, without a partition table */
|
||
|
result = Check_for_DOS_FAT(0);
|
||
|
}
|
||
|
if ((csd_file_format & 0x0c00) == 0x0000)
|
||
|
{
|
||
|
/* SD Card contains files stored in a Hard disk-like file format that contains a partition table */
|
||
|
if (Check_for_Master_Boot_Record())
|
||
|
{
|
||
|
result = Check_for_DOS_FAT(fat_partition_offset_in_512_byte_sectors);
|
||
|
}
|
||
|
}
|
||
|
if (result == true)
|
||
|
{
|
||
|
// Accept only FAT16, not FAT12.
|
||
|
if (boot_sector_data.bits_for_cluster_index != 16)
|
||
|
{
|
||
|
result = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fat_partition_size_in_512_byte_sectors = boot_sector_data.number_of_sectors_in_partition;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void filename_to_upper_case(char *file_name)
|
||
|
// Change file name to upper case.
|
||
|
{
|
||
|
int index;
|
||
|
int length = strlen(file_name);
|
||
|
|
||
|
for (index = 0; index < length; index++)
|
||
|
{
|
||
|
if ((file_name[index] >= 'a') && (file_name[index] <= 'z'))
|
||
|
{
|
||
|
file_name[index] = (file_name[index] - 'a') + 'A';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool check_file_name_for_FAT16_compliance(char *file_name)
|
||
|
// Check if the file complies with FAT16 naming convention.
|
||
|
{
|
||
|
int length = strlen(file_name);
|
||
|
int index;
|
||
|
int last_dir_break_position = -1;
|
||
|
int last_period = -1;
|
||
|
bool result = true;
|
||
|
|
||
|
for(index = 0; index < length; index++)
|
||
|
{
|
||
|
if ((file_name[index] == ' ') ||
|
||
|
((last_dir_break_position == (index - 1)) && ((file_name[index] == '\\') || (file_name[index] == '/'))) ||
|
||
|
((index - last_period == 9) && (file_name[index] != '.')) ||
|
||
|
((last_dir_break_position != last_period) && (index - last_period > 3) &&
|
||
|
(file_name[index] != '\\') && (file_name[index] != '/'))
|
||
|
)
|
||
|
{
|
||
|
result = false;
|
||
|
break;
|
||
|
}
|
||
|
if ((file_name[index] == '\\') || (file_name[index] == '/'))
|
||
|
{
|
||
|
last_period = index;
|
||
|
last_dir_break_position = index;
|
||
|
}
|
||
|
if (file_name[index] == '.')
|
||
|
{
|
||
|
last_period = index;
|
||
|
}
|
||
|
}
|
||
|
if ((file_name[length-1] == '\\') || (file_name[length-1] == '/'))
|
||
|
{
|
||
|
result = false;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int get_dir_divider_location(char *name)
|
||
|
// Find a directory divider location.
|
||
|
{
|
||
|
int index = 0;
|
||
|
int length = strlen(name);
|
||
|
|
||
|
for(index = 0; index < length; index++)
|
||
|
{
|
||
|
if ((name[index] == '\\') || (name[index] == '/'))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (index == length)
|
||
|
{
|
||
|
index = -1;
|
||
|
}
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool match_file_record_to_name_ext(t_file_record *file_record, char *name, char *extension)
|
||
|
/* See if the given name and extension match the file record. Return true if this is so, false otherwise. */
|
||
|
{
|
||
|
bool match = true;
|
||
|
int index;
|
||
|
|
||
|
for (index = 0; index < 8; index++)
|
||
|
{
|
||
|
if (CHAR_TO_UPPER(file_record->name[index]) != CHAR_TO_UPPER(name[index]))
|
||
|
{
|
||
|
match = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
for (index = 0; index < 3; index++)
|
||
|
{
|
||
|
if (CHAR_TO_UPPER(file_record->extension[index]) != CHAR_TO_UPPER(extension[index]))
|
||
|
{
|
||
|
match = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return match;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool get_home_directory_cluster_for_file(char *file_name, int *home_directory_cluster, t_file_record *file_record)
|
||
|
// Scan the directories in given in the file name and find the root directory for the file.
|
||
|
{
|
||
|
bool result = false;
|
||
|
int home_dir_cluster = 0;
|
||
|
int location, index;
|
||
|
int start_location = 0;
|
||
|
|
||
|
/* Get Next Directory. */
|
||
|
location = get_dir_divider_location( file_name );
|
||
|
while (location > 0)
|
||
|
{
|
||
|
char name[8] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
||
|
char extension[3] = { ' ', ' ', ' ' };
|
||
|
int ext_index = -1;
|
||
|
int new_cluster = home_dir_cluster;
|
||
|
|
||
|
// Get the name of the directory in name/extension format.
|
||
|
for (index = 0; index < location; index++)
|
||
|
{
|
||
|
if (file_name[index+start_location] == '.')
|
||
|
{
|
||
|
ext_index = index;
|
||
|
}
|
||
|
else if (ext_index < 0)
|
||
|
{
|
||
|
name[index] = file_name[index+start_location];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
extension[index-ext_index] = file_name[index+start_location];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (home_dir_cluster == 0)
|
||
|
{
|
||
|
/* We are in the root directory. Scan the directory (of predefined size) and see if you can find the specified file. */
|
||
|
int max_root_dir_sectors = ((32*boot_sector_data.max_number_of_dir_entires) / boot_sector_data.sector_size_in_bytes);
|
||
|
int sector_index;
|
||
|
|
||
|
for (sector_index = 0; sector_index < max_root_dir_sectors; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data(sector_index+boot_sector_data.root_directory_sector_offset, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
int file_counter;
|
||
|
|
||
|
for (file_counter = 0; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
|
||
|
// Read file record.
|
||
|
Read_File_Record_At_Offset(file_counter*32, file_record, 0, sector_index);
|
||
|
if ((file_record->name[0] != 0xe5) && (file_record->name[0] != 0x00))
|
||
|
{
|
||
|
bool match = match_file_record_to_name_ext(file_record, name, extension);
|
||
|
if (match)
|
||
|
{
|
||
|
new_cluster = file_record->start_cluster_index;
|
||
|
file_record->file_record_cluster = 1; // Home directory is a subdirectory in the root directory.
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if (new_cluster != home_dir_cluster)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (new_cluster != home_dir_cluster)
|
||
|
{
|
||
|
// A valid directory is found, so go to it.
|
||
|
home_dir_cluster = new_cluster;
|
||
|
start_location = start_location+location+1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Directory path is invalid.
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
// This is a subdirectory that can have any number of elements. So scan through it as though it was a file
|
||
|
// and see if you can find the directory of interest.
|
||
|
int cluster = home_dir_cluster;
|
||
|
|
||
|
do {
|
||
|
int start_sector = ( cluster - 2 ) * ( boot_sector_data.sectors_per_cluster ) + boot_sector_data.data_sector_offset;
|
||
|
int sector_index;
|
||
|
|
||
|
for (sector_index = 0; sector_index < boot_sector_data.sectors_per_cluster; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data(sector_index + start_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
int file_counter;
|
||
|
|
||
|
for (file_counter = 0; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
// Read file record.
|
||
|
Read_File_Record_At_Offset(file_counter*32, file_record, cluster, sector_index);
|
||
|
if ((file_record->name[0] != 0xe5) && (file_record->name[0] != 0x00))
|
||
|
{
|
||
|
bool match = match_file_record_to_name_ext(file_record, name, extension);
|
||
|
if (match)
|
||
|
{
|
||
|
new_cluster = file_record->start_cluster_index;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if (new_cluster != home_dir_cluster)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// If this is the end of the cluster and the directory has not been found, then see if there is another cluster
|
||
|
// that holds data for the current directory.
|
||
|
if (new_cluster == home_dir_cluster)
|
||
|
{
|
||
|
unsigned short int next_cluster;
|
||
|
|
||
|
if (get_cluster_flag(new_cluster, &next_cluster))
|
||
|
{
|
||
|
// The directory needs to be expanded to store more files.
|
||
|
if ((next_cluster & 0x0000fff8) == 0x0000fff8)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
new_cluster = (next_cluster & 0x0000fff8);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Directory path is invalid.
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
} while ((cluster < 0x0000fff8) && (new_cluster == home_dir_cluster));
|
||
|
if (new_cluster != home_dir_cluster)
|
||
|
{
|
||
|
// A valid directory is found, so go to it.
|
||
|
home_dir_cluster = new_cluster;
|
||
|
start_location = start_location+location+1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Directory path is invalid.
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
location = get_dir_divider_location(&(file_name[start_location]));
|
||
|
if (location < 0)
|
||
|
{
|
||
|
// Directory has been located.
|
||
|
result = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*home_directory_cluster = home_dir_cluster;
|
||
|
if (home_dir_cluster == 0)
|
||
|
{
|
||
|
file_record->file_record_cluster = 0; // Home directory is the root directory.
|
||
|
result = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool find_file_in_directory(int directory_start_cluster, char *file_name, t_file_record *file_record)
|
||
|
// Given a cluster and a file name, check if the file already exists. Return the file record if the file is found.
|
||
|
{
|
||
|
int location = get_dir_divider_location( file_name );
|
||
|
int last_dir_separator = 0;
|
||
|
char name[8] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
||
|
char extension[3] = { ' ', ' ', ' ' };
|
||
|
int ext_index = -1;
|
||
|
int cluster = directory_start_cluster;
|
||
|
int index;
|
||
|
int length = strlen(file_name);
|
||
|
bool result = false;
|
||
|
|
||
|
// Skip through all directory separators.
|
||
|
while (location > 0)
|
||
|
{
|
||
|
last_dir_separator = last_dir_separator+location+1;
|
||
|
location = get_dir_divider_location( &(file_name[last_dir_separator]) );
|
||
|
}
|
||
|
|
||
|
// Get the name of the file in name/extension format.
|
||
|
for (index = last_dir_separator; index < length; index++)
|
||
|
{
|
||
|
if (file_name[index] == '.')
|
||
|
{
|
||
|
ext_index = index;
|
||
|
}
|
||
|
else if (ext_index < 0)
|
||
|
{
|
||
|
name[index-last_dir_separator] = file_name[index];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
extension[index-ext_index-1] = file_name[index];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Look for the file.
|
||
|
if (directory_start_cluster == 0)
|
||
|
{
|
||
|
/* We are in the root directory. Scan the directory (of predefined size) and see if you can find the specified file. */
|
||
|
int max_root_dir_sectors = ((32*boot_sector_data.max_number_of_dir_entires) / boot_sector_data.sector_size_in_bytes);
|
||
|
int sector_index;
|
||
|
|
||
|
for (sector_index = 0; sector_index < max_root_dir_sectors; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data( sector_index + boot_sector_data.root_directory_sector_offset,
|
||
|
fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
int file_counter;
|
||
|
|
||
|
for (file_counter = 0; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
// Read file record.
|
||
|
Read_File_Record_At_Offset(file_counter*32, file_record, 0, sector_index);
|
||
|
if ((file_record->name[0] != 0xe5) && (file_record->name[0] != 0x00))
|
||
|
{
|
||
|
bool match = match_file_record_to_name_ext(file_record, name, extension);
|
||
|
|
||
|
if (match)
|
||
|
{
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if (result)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
do {
|
||
|
int start_sector = ( cluster - 2 ) * ( boot_sector_data.sectors_per_cluster ) + boot_sector_data.data_sector_offset;
|
||
|
int sector_index;
|
||
|
|
||
|
for (sector_index = 0; sector_index < boot_sector_data.sectors_per_cluster; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data(sector_index + start_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
int file_counter;
|
||
|
|
||
|
for (file_counter = 0; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
// Read file record.
|
||
|
Read_File_Record_At_Offset(file_counter*32, file_record, cluster, sector_index);
|
||
|
if ((file_record->name[0] != 0xe5) && (file_record->name[0] != 0x00))
|
||
|
{
|
||
|
bool match = match_file_record_to_name_ext(file_record, name, extension);
|
||
|
|
||
|
if (match)
|
||
|
{
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if (result)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// If this is the end of the cluster and the file has not been found, then see if there is another cluster
|
||
|
// that holds data for the current directory.
|
||
|
if (result == false)
|
||
|
{
|
||
|
unsigned short int new_cluster;
|
||
|
|
||
|
if (get_cluster_flag(cluster, &new_cluster))
|
||
|
{
|
||
|
// The directory needs to be expanded to store more files.
|
||
|
if ((new_cluster & 0x0000fff8) == 0x0000fff8)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
cluster = (new_cluster & 0x0000fff8);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Directory path is invalid.
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
} while ((cluster < 0x0000fff8) && (result == false));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static bool find_first_empty_cluster(unsigned int *cluster_number)
|
||
|
// Find the first empty cluster. It will be marked by a 0 entry in the File Allocation Table.
|
||
|
{
|
||
|
unsigned int sector = boot_sector_data.first_fat_sector_offset;
|
||
|
unsigned int cluster_index = 2;
|
||
|
short int cluster = -1;
|
||
|
bool result = false;
|
||
|
unsigned max_cluster_index = 0;
|
||
|
unsigned int non_data_sectors = boot_sector_data.data_sector_offset;
|
||
|
unsigned int less_than_32 = boot_sector_data.number_of_sectors_in_partition;
|
||
|
unsigned int greater_than_32 = boot_sector_data.total_sector_count_if_above_32MB;
|
||
|
|
||
|
if (less_than_32 > greater_than_32)
|
||
|
{
|
||
|
max_cluster_index = ((less_than_32 - non_data_sectors) / boot_sector_data.sectors_per_cluster) + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
max_cluster_index = ((greater_than_32 - non_data_sectors) / boot_sector_data.sectors_per_cluster) + 1;
|
||
|
}
|
||
|
// Find an empty cluster for the file.
|
||
|
while (sector != boot_sector_data.second_fat_sector_offset)
|
||
|
{
|
||
|
if (Read_Sector_Data( sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
do {
|
||
|
cluster = ((unsigned short int) IORD_16DIRECT(device_pointer->base, 2*(cluster_index % 256)));
|
||
|
if (cluster == 0)
|
||
|
{
|
||
|
// Free cluster found.
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cluster_index++;
|
||
|
}
|
||
|
} while ((cluster_index % 256) != 0);
|
||
|
}
|
||
|
if (cluster == 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
sector++;
|
||
|
}
|
||
|
if ((cluster == 0) && (cluster <= max_cluster_index))
|
||
|
{
|
||
|
*cluster_number = cluster_index;
|
||
|
result = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int find_first_empty_record_in_a_subdirectory(int start_cluster_index)
|
||
|
// Search for a free spot in a subdirectory. Return an encoded location for the file record.
|
||
|
{
|
||
|
int result = -1;
|
||
|
int cluster = start_cluster_index;
|
||
|
do {
|
||
|
int start_sector = ( cluster - 2 ) * ( boot_sector_data.sectors_per_cluster ) + boot_sector_data.data_sector_offset;
|
||
|
int sector_index;
|
||
|
|
||
|
for (sector_index = 0; sector_index < boot_sector_data.sectors_per_cluster; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data(sector_index + start_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
int file_counter;
|
||
|
|
||
|
for (file_counter = 0; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
unsigned short int leading_char;
|
||
|
|
||
|
// Read file record.
|
||
|
leading_char = ((unsigned char) IORD_8DIRECT(device_pointer->base, file_counter*32));
|
||
|
if ((leading_char == 0x00e5) || (leading_char == 0))
|
||
|
{
|
||
|
result = (cluster) | ((sector_index*16 + file_counter) << 16);
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// If this is the end of the cluster and the file has not been found, then see if there is another cluster
|
||
|
// that holds data for the current directory.
|
||
|
if (result < 0)
|
||
|
{
|
||
|
unsigned short int new_cluster;
|
||
|
if (get_cluster_flag(cluster, &new_cluster))
|
||
|
{
|
||
|
// The directory needs to be expanded to store more files.
|
||
|
if ((new_cluster & 0x0000fff8) == 0x0000fff8)
|
||
|
{
|
||
|
unsigned int new_dir_cluster;
|
||
|
if (find_first_empty_cluster(&new_dir_cluster))
|
||
|
{
|
||
|
// Add the new cluster to the linked list of the given directory.
|
||
|
if (mark_cluster(cluster, ((short int) (new_dir_cluster)), true) &&
|
||
|
mark_cluster(new_dir_cluster, ((short int) (0xffff)), true) &&
|
||
|
mark_cluster(cluster, ((short int) (new_dir_cluster)), false) &&
|
||
|
mark_cluster(new_dir_cluster, ((short int) (0xffff)), false))
|
||
|
{
|
||
|
Save_Modified_Sector();
|
||
|
// The new file will begin at the first entry of the directory.
|
||
|
result = new_dir_cluster;
|
||
|
}
|
||
|
}
|
||
|
cluster = (new_cluster & 0x0000fff8);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Error encountered.
|
||
|
result = -1;
|
||
|
}
|
||
|
}
|
||
|
} while ((cluster < 0x0000fff8) && (result == -1));
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int find_first_empty_record_in_root_directory()
|
||
|
// Find a first unused record location to use. Return -1 if none is found.
|
||
|
{
|
||
|
int max_root_dir_sectors = ((32*boot_sector_data.max_number_of_dir_entires) / boot_sector_data.sector_size_in_bytes);
|
||
|
int sector_index;
|
||
|
int result = -1;
|
||
|
|
||
|
for (sector_index = 0; sector_index < max_root_dir_sectors; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data( sector_index + boot_sector_data.root_directory_sector_offset,
|
||
|
fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
int file_counter;
|
||
|
|
||
|
for (file_counter = 0; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
unsigned short int leading_char;
|
||
|
|
||
|
// Read first character of the file record.
|
||
|
leading_char = ((unsigned char) IORD_8DIRECT(device_pointer->base, file_counter*32));
|
||
|
if ((leading_char == 0x00e5) || (leading_char == 0))
|
||
|
{
|
||
|
result = (sector_index*16 + file_counter) << 16;
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static void convert_filename_to_name_extension(char *filename, char *name, char *extension)
|
||
|
// This function converts the file name into a name . extension format.
|
||
|
{
|
||
|
int counter;
|
||
|
int local = 0;
|
||
|
|
||
|
for(counter = 0; counter < 8; counter++)
|
||
|
{
|
||
|
if (filename[local] != '.')
|
||
|
{
|
||
|
name[counter] = filename[local];
|
||
|
if (filename[local] != 0) local++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
name[counter] = ' ';
|
||
|
}
|
||
|
}
|
||
|
if (filename[local] == '.') local++;
|
||
|
for(counter = 0; counter < 3; counter++)
|
||
|
{
|
||
|
if (filename[local] != 0)
|
||
|
{
|
||
|
extension[counter] = filename[local];
|
||
|
local++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
extension[counter] = ' ';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
static bool create_file(char *name, t_file_record *file_record, t_file_record *home_dir)
|
||
|
// Create a file in a given directory. Expand the directory if needed.
|
||
|
{
|
||
|
unsigned int cluster_number;
|
||
|
bool result = false;
|
||
|
|
||
|
if (find_first_empty_cluster(&cluster_number))
|
||
|
{
|
||
|
int record_index;
|
||
|
|
||
|
if (home_dir->file_record_cluster == 0)
|
||
|
{
|
||
|
// Put a file in the root directory.
|
||
|
record_index = find_first_empty_record_in_root_directory();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Put a file in a subdirectory.
|
||
|
record_index = find_first_empty_record_in_a_subdirectory(home_dir->start_cluster_index);
|
||
|
}
|
||
|
if (record_index >= 0)
|
||
|
{
|
||
|
unsigned int file_record_sector;
|
||
|
int location = get_dir_divider_location( name );
|
||
|
int last_dir_separator = 0;
|
||
|
|
||
|
// Skip through all directory separators.
|
||
|
while (location > 0)
|
||
|
{
|
||
|
last_dir_separator = last_dir_separator+location+1;
|
||
|
location = get_dir_divider_location( &(name[last_dir_separator]) );
|
||
|
}
|
||
|
|
||
|
convert_filename_to_name_extension(&(name[last_dir_separator]), (char *)file_record->name, (char *)file_record->extension);
|
||
|
|
||
|
file_record->attributes = 0;
|
||
|
file_record->create_time = 0;
|
||
|
file_record->create_date = 0;
|
||
|
file_record->last_access_date = 0;
|
||
|
file_record->last_modified_time = 0;
|
||
|
file_record->last_modified_date = 0;
|
||
|
file_record->start_cluster_index = cluster_number;
|
||
|
file_record->file_size_in_bytes = 0;
|
||
|
file_record->current_cluster_index = cluster_number;
|
||
|
file_record->current_sector_in_cluster = 0;
|
||
|
file_record->current_byte_position = 0;
|
||
|
file_record->file_record_cluster = record_index & 0x0000ffff;
|
||
|
file_record->file_record_sector_in_cluster = ((record_index >> 16) & 0x0000ffff) / 16;
|
||
|
file_record->file_record_offset = (((record_index >> 16) & 0x0000ffff) % 16)*32;
|
||
|
file_record->home_directory_cluster = home_dir->start_cluster_index;
|
||
|
file_record->in_use = true;
|
||
|
file_record->modified = true;
|
||
|
// Now write the record at the specified location.
|
||
|
file_record_sector = (file_record->file_record_cluster == 0) ?
|
||
|
(boot_sector_data.root_directory_sector_offset + file_record->file_record_sector_in_cluster):
|
||
|
(boot_sector_data.data_sector_offset + (file_record->file_record_cluster-2)*boot_sector_data.sectors_per_cluster +
|
||
|
file_record->file_record_sector_in_cluster);
|
||
|
|
||
|
if (Read_Sector_Data(file_record_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
if (Write_File_Record_At_Offset(file_record->file_record_offset, file_record))
|
||
|
{
|
||
|
Save_Modified_Sector();
|
||
|
// Mark the first cluster of the file as the last cluster at first.
|
||
|
mark_cluster(cluster_number, ((short int) (0xffff)), true);
|
||
|
if (mark_cluster(cluster_number, ((short int) (0xffff)), false))
|
||
|
{
|
||
|
result = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void copy_file_record_name_to_string(t_file_record *file_record, char *file_name)
|
||
|
/* Copy a file name from the file record to a given string */
|
||
|
{
|
||
|
int index;
|
||
|
int flength = 0;
|
||
|
|
||
|
/* Copy file name.*/
|
||
|
for (index = 0; index < 8; index++)
|
||
|
{
|
||
|
if (file_record->name[index] != ' ')
|
||
|
{
|
||
|
file_name[flength] = file_record->name[index];
|
||
|
flength = flength + 1;
|
||
|
}
|
||
|
}
|
||
|
if (file_record->extension[0] != ' ')
|
||
|
{
|
||
|
file_name[flength] = '.';
|
||
|
flength = flength + 1;
|
||
|
for (index = 0; index < 3; index++)
|
||
|
{
|
||
|
if (file_record->extension[index] != ' ')
|
||
|
{
|
||
|
file_name[flength] = file_record->extension[index];
|
||
|
flength = flength + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
file_name[flength] = 0;
|
||
|
}
|
||
|
#endif //SD_RAW_IFACE
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Direct functions
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
alt_up_sd_card_dev* alt_up_sd_card_open_dev(const char* name)
|
||
|
{
|
||
|
// find the device from the device list
|
||
|
// (see altera_hal/HAL/inc/priv/alt_file.h
|
||
|
// and altera_hal/HAL/src/alt_find_dev.c
|
||
|
// for details)
|
||
|
alt_up_sd_card_dev *dev = (alt_up_sd_card_dev *) alt_find_dev(name, &alt_dev_list);
|
||
|
|
||
|
if (dev != NULL)
|
||
|
{
|
||
|
aux_status_register = ((short int *) SD_CARD_AUX_STATUS(dev->base));
|
||
|
status_register = ((int *) SD_CARD_STATUS(dev->base));
|
||
|
CSD_register_w0 = ((short int *) SD_CARD_CSD(dev->base, 0));
|
||
|
command_register = ((short int *) SD_CARD_COMMAND(dev->base));
|
||
|
command_argument_register = ((int *) SD_CARD_ARGUMENT(dev->base));
|
||
|
buffer_memory = (char *) SD_CARD_BUFFER(dev->base, 0);
|
||
|
device_pointer = dev;
|
||
|
initialized = false;
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
is_sd_card_formated_as_FAT16 = false;
|
||
|
search_data.valid = false;
|
||
|
#endif
|
||
|
}
|
||
|
return dev;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool alt_up_sd_card_is_Present(void)
|
||
|
// Check if there is an SD Card insterted into the SD Card socket.
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if ((device_pointer != NULL) && ((IORD_16DIRECT(aux_status_register,0) & 0x02) != 0))
|
||
|
{
|
||
|
result = true;
|
||
|
}
|
||
|
else if (initialized == true)
|
||
|
{
|
||
|
int index;
|
||
|
|
||
|
initialized = false;
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
search_data.valid = false;
|
||
|
is_sd_card_formated_as_FAT16 = false;
|
||
|
|
||
|
for(index = 0; index < MAX_FILES_OPENED; index++)
|
||
|
{
|
||
|
active_files[index].in_use = false;
|
||
|
active_files[index].modified = false;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#ifndef SD_RAW_IFACE
|
||
|
bool alt_up_sd_card_is_FAT16(void)
|
||
|
/* This function reads the SD card data in an effort to determine if the card is formated as a FAT16
|
||
|
* volume. Please note that FAT12 has a similar format, but will not be supported by this driver.
|
||
|
* If the card contains a FAT16 volume, the local data structures will be initialized to allow reading and writing
|
||
|
* to the SD card as though it was a hard drive.
|
||
|
*/
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if (alt_up_sd_card_is_Present())
|
||
|
{
|
||
|
// Check if an SD Card is in the SD Card slot.
|
||
|
if (initialized == false)
|
||
|
{
|
||
|
// Now determine if the card is formatted as FAT 16.
|
||
|
is_sd_card_formated_as_FAT16 = Look_for_FAT16();
|
||
|
initialized = is_sd_card_formated_as_FAT16;
|
||
|
search_data.valid = false;
|
||
|
}
|
||
|
result = is_sd_card_formated_as_FAT16;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If not then you may as well not open the device.
|
||
|
initialized = false;
|
||
|
is_sd_card_formated_as_FAT16 = false;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
short int alt_up_sd_card_find_first(char *directory_to_search_through, char *file_name)
|
||
|
/* This function sets up a search algorithm to go through a given directory looking for files.
|
||
|
* If the search directory is valid, then the function searches for the first file it finds.
|
||
|
* Inputs:
|
||
|
* directory_to_search_through - name of the directory to search through
|
||
|
* file_name - an array to store a name of the file found. Must be 13 bytes long (12 bytes for file name and 1 byte of NULL termination).
|
||
|
* Outputs:
|
||
|
* 0 - success
|
||
|
* 1 - invalid directory
|
||
|
* 2 - No card or incorrect card format.
|
||
|
*
|
||
|
* To specify a directory give the name in a format consistent with the following regular expression:
|
||
|
* [{[valid_chars]+}/]*.
|
||
|
*
|
||
|
* In other words, give a path name starting at the root directory, where each directory name is followed by a '/'.
|
||
|
* Then, append a '.' to the directory name. Examples:
|
||
|
* "." - look through the root directory
|
||
|
* "first/." - look through a directory named "first" that is located in the root directory.
|
||
|
* "first/sub/." - look through a directory named "sub", that is located within the subdirectory named "first". "first" is located in the root directory.
|
||
|
* Invalid examples include:
|
||
|
* "/.", "/////." - this is not the root directory.
|
||
|
* "/first/." - the first character may not be a '/'.
|
||
|
*/
|
||
|
{
|
||
|
short int result = 2;
|
||
|
if ((alt_up_sd_card_is_Present()) && (is_sd_card_formated_as_FAT16))
|
||
|
{
|
||
|
int home_directory_cluster;
|
||
|
t_file_record file_record;
|
||
|
|
||
|
if (get_home_directory_cluster_for_file(directory_to_search_through, &home_directory_cluster, &file_record))
|
||
|
{
|
||
|
search_data.directory_root_cluster = home_directory_cluster;
|
||
|
search_data.current_cluster_index = home_directory_cluster;
|
||
|
search_data.current_sector_in_cluster = 0;
|
||
|
search_data.file_index_in_sector = -1;
|
||
|
search_data.valid = true;
|
||
|
result = alt_up_sd_card_find_next(file_name);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = 1;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
short int alt_up_sd_card_find_next(char *file_name)
|
||
|
/* This function searches for the next file in a given directory, as specified by the find_first function.
|
||
|
* Inputs:
|
||
|
* file_name - an array to store a name of the file found. Must be 13 bytes long (12 bytes for file name and 1 byte of NULL termination).
|
||
|
* Outputs:
|
||
|
* -1 - end of directory.
|
||
|
* 0 - success
|
||
|
* 2 - No card or incorrect card format.
|
||
|
* 3 - find_first has not been called successfully.
|
||
|
*/
|
||
|
{
|
||
|
short int result = 2;
|
||
|
if ((alt_up_sd_card_is_Present()) && (is_sd_card_formated_as_FAT16))
|
||
|
{
|
||
|
if (search_data.valid)
|
||
|
{
|
||
|
t_file_record file_record;
|
||
|
int cluster = search_data.current_cluster_index;
|
||
|
|
||
|
if (cluster == 0)
|
||
|
{
|
||
|
// Searching through the root directory
|
||
|
int max_root_dir_sectors = ((32*boot_sector_data.max_number_of_dir_entires) / boot_sector_data.sector_size_in_bytes);
|
||
|
int sector_index = search_data.current_sector_in_cluster;
|
||
|
int file_counter = search_data.file_index_in_sector+1;
|
||
|
|
||
|
for (; sector_index < max_root_dir_sectors; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data( sector_index + boot_sector_data.root_directory_sector_offset,
|
||
|
fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
for (; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
if (Read_File_Record_At_Offset(file_counter*32, &file_record, 0, sector_index))
|
||
|
{
|
||
|
if ((file_record.name[0] != 0) && (file_record.name[0] != 0xe5))
|
||
|
{
|
||
|
/* Update search structure. */
|
||
|
search_data.file_index_in_sector = file_counter;
|
||
|
search_data.current_sector_in_cluster = sector_index;
|
||
|
|
||
|
/* Copy file name.*/
|
||
|
copy_file_record_name_to_string(&file_record, file_name);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
file_counter = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
result = -1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int file_counter = search_data.file_index_in_sector+1;
|
||
|
do
|
||
|
{
|
||
|
int start_sector = ( cluster - 2 ) * ( boot_sector_data.sectors_per_cluster ) + boot_sector_data.data_sector_offset;
|
||
|
int sector_index = search_data.current_sector_in_cluster;
|
||
|
|
||
|
for (; sector_index < boot_sector_data.sectors_per_cluster; sector_index++)
|
||
|
{
|
||
|
if (Read_Sector_Data(sector_index + start_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
for (; file_counter < 16; file_counter++)
|
||
|
{
|
||
|
if (Read_File_Record_At_Offset(file_counter*32, &file_record, cluster, sector_index))
|
||
|
{
|
||
|
if ((file_record.name[0] != 0) && (file_record.name[0] != 0xe5))
|
||
|
{
|
||
|
/* Update search structure. */
|
||
|
search_data.current_cluster_index = cluster;
|
||
|
search_data.file_index_in_sector = file_counter;
|
||
|
search_data.current_sector_in_cluster = sector_index;
|
||
|
|
||
|
/* Copy file name.*/
|
||
|
copy_file_record_name_to_string(&file_record, file_name);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
file_counter = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// If this is the end of the cluster and the file has not been found, then see if there is another cluster
|
||
|
// that holds data for the current directory.
|
||
|
if (sector_index >= boot_sector_data.sectors_per_cluster)
|
||
|
{
|
||
|
unsigned short int new_cluster;
|
||
|
|
||
|
if (get_cluster_flag(cluster, &new_cluster))
|
||
|
{
|
||
|
if ((new_cluster & 0x0000fff8) == 0x0000fff8)
|
||
|
{
|
||
|
result = -1;
|
||
|
search_data.valid = false;
|
||
|
}
|
||
|
cluster = ((new_cluster) & 0x0000fff8);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Error encountered.
|
||
|
result = -1;
|
||
|
}
|
||
|
}
|
||
|
} while (cluster < 0x0000fff8);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Call Find_First first.
|
||
|
result = 3;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
short int alt_up_sd_card_fopen(char *name, bool create)
|
||
|
/* This function reads the SD card data in an effort to determine if the card is formated as a FAT16
|
||
|
* volume. Please note that FAT12 has a similar format, but will not be supported by this driver.
|
||
|
*
|
||
|
* Inputs:
|
||
|
* name - a file name including a directory, relative to the root directory
|
||
|
* create - a flag set to true to create a file if it does not already exist
|
||
|
* Output:
|
||
|
* An index to the file record assigned to the specified file. -1 is returned if the file could not be opened.
|
||
|
* Return -2 if the specified file has already been opened previously.
|
||
|
*/
|
||
|
{
|
||
|
short int file_record_index = -1;
|
||
|
|
||
|
if ((alt_up_sd_card_is_Present()) && (is_sd_card_formated_as_FAT16))
|
||
|
{
|
||
|
unsigned int home_directory_cluster = 0;
|
||
|
t_file_record home_dir;
|
||
|
|
||
|
/* First check the file name format. It should not be longer than 12 characters, including a period and the extension.
|
||
|
* Rules:
|
||
|
* - no spaces
|
||
|
* - at most 12 chatacters per name, with a period in 9th position.
|
||
|
* - a / or a \ every at most 12 characters.
|
||
|
*/
|
||
|
filename_to_upper_case(name);
|
||
|
if (check_file_name_for_FAT16_compliance(name))
|
||
|
{
|
||
|
int index;
|
||
|
|
||
|
/* Get home directory cluster location for the specified file. 0 means root directory. */
|
||
|
if (!get_home_directory_cluster_for_file(name, (int *) &home_directory_cluster, &home_dir))
|
||
|
{
|
||
|
return file_record_index;
|
||
|
}
|
||
|
|
||
|
/* Find a free file slot to store file specs in. */
|
||
|
for (index = 0; index < MAX_FILES_OPENED; index++)
|
||
|
{
|
||
|
if (active_files[index].in_use == false)
|
||
|
{
|
||
|
file_record_index = index;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (file_record_index >= 0)
|
||
|
{
|
||
|
/* If file record is found, then look for the specified file. If the create flag is set to true
|
||
|
* and the file is not found, then it should be created in the current directory.
|
||
|
*/
|
||
|
|
||
|
if (find_file_in_directory(home_directory_cluster, name, &(active_files[file_record_index])))
|
||
|
{
|
||
|
if (create)
|
||
|
{
|
||
|
/* Do not allow overwriting existing files for now. */
|
||
|
return -1;
|
||
|
}
|
||
|
active_files[file_record_index].current_cluster_index = active_files[file_record_index].start_cluster_index;
|
||
|
active_files[file_record_index].current_sector_in_cluster = 0;
|
||
|
active_files[file_record_index].current_byte_position = 0;
|
||
|
active_files[file_record_index].in_use = true;
|
||
|
active_files[file_record_index].modified = false;
|
||
|
|
||
|
/* Check if the file has already been opened. */
|
||
|
for (index = 0; index < MAX_FILES_OPENED; index++)
|
||
|
{
|
||
|
if ((file_record_index != index) && (active_files[index].in_use == true))
|
||
|
{
|
||
|
if ((active_files[file_record_index].file_record_cluster == active_files[index].file_record_cluster) &&
|
||
|
(active_files[file_record_index].file_record_sector_in_cluster == active_files[index].file_record_sector_in_cluster) &&
|
||
|
(active_files[file_record_index].file_record_offset == active_files[index].file_record_offset))
|
||
|
{
|
||
|
// file already in use.
|
||
|
file_record_index = -2;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (create)
|
||
|
{
|
||
|
/* Create file if needed. */
|
||
|
if (create_file(name, &(active_files[file_record_index]), &home_dir))
|
||
|
{
|
||
|
active_files[file_record_index].in_use = true;
|
||
|
active_files[file_record_index].modified = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* If file creation fails then return an invalid file handle. */
|
||
|
file_record_index = -1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Otherwise the file could not be opened.*/
|
||
|
file_record_index = -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return file_record_index;
|
||
|
}
|
||
|
|
||
|
|
||
|
void alt_up_sd_card_set_attributes(short int file_handle, short int attributes)
|
||
|
/* Return file attributes, or -1 if the file_handle is invalid.
|
||
|
*/
|
||
|
{
|
||
|
if ((file_handle >= 0) && (file_handle < MAX_FILES_OPENED))
|
||
|
{
|
||
|
if (active_files[file_handle].in_use)
|
||
|
{
|
||
|
active_files[file_handle].attributes = ((char)(attributes & 0x00ff));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
short int alt_up_sd_card_get_attributes(short int file_handle)
|
||
|
/* Return file attributes, or -1 if the file_handle is invalid.
|
||
|
*/
|
||
|
{
|
||
|
short int result = -1;
|
||
|
if ((file_handle >= 0) && (file_handle < MAX_FILES_OPENED))
|
||
|
{
|
||
|
if (active_files[file_handle].in_use)
|
||
|
{
|
||
|
result = ((active_files[file_handle].attributes) & 0x00ff);
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
short int alt_up_sd_card_read(short int file_handle)
|
||
|
/* Read a single character from a given file. Return -1 if at the end of a file. Any other negative number
|
||
|
* means that the file could not be read. A number between 0 and 255 is an ASCII character read from the SD Card. */
|
||
|
{
|
||
|
short int ch = -1;
|
||
|
|
||
|
if ((file_handle >= 0) && (file_handle < MAX_FILES_OPENED))
|
||
|
{
|
||
|
if (active_files[file_handle].in_use)
|
||
|
{
|
||
|
if (active_files[file_handle].current_byte_position < active_files[file_handle].file_size_in_bytes)
|
||
|
{
|
||
|
int data_sector = boot_sector_data.data_sector_offset + (active_files[file_handle].current_cluster_index - 2)*boot_sector_data.sectors_per_cluster +
|
||
|
active_files[file_handle].current_sector_in_cluster;
|
||
|
|
||
|
if ((active_files[file_handle].current_byte_position > 0) && ((active_files[file_handle].current_byte_position % 512) == 0))
|
||
|
{
|
||
|
// Read in a new sector of data.
|
||
|
if (active_files[file_handle].current_sector_in_cluster == boot_sector_data.sectors_per_cluster - 1)
|
||
|
{
|
||
|
// Go to the next cluster.
|
||
|
unsigned short int next_cluster;
|
||
|
if (get_cluster_flag(active_files[file_handle].current_cluster_index, &next_cluster))
|
||
|
{
|
||
|
if ((next_cluster & 0x0000fff8) == 0x0000fff8)
|
||
|
{
|
||
|
/* End of file */
|
||
|
return -1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
active_files[file_handle].current_cluster_index = next_cluster;
|
||
|
active_files[file_handle].current_sector_in_cluster = 0;
|
||
|
data_sector = boot_sector_data.data_sector_offset + (active_files[file_handle].current_cluster_index - 2)*boot_sector_data.sectors_per_cluster +
|
||
|
active_files[file_handle].current_sector_in_cluster;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
active_files[file_handle].current_sector_in_cluster = active_files[file_handle].current_sector_in_cluster + 1;
|
||
|
data_sector = data_sector + 1;
|
||
|
}
|
||
|
}
|
||
|
// Reading te first byte of the file.
|
||
|
if (current_sector_index != (data_sector + fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
if (!Read_Sector_Data(data_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ch = (unsigned char) IORD_8DIRECT(buffer_memory, (active_files[file_handle].current_byte_position % 512));
|
||
|
active_files[file_handle].current_byte_position = active_files[file_handle].current_byte_position + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ch;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool alt_up_sd_card_write(short int file_handle, char byte_of_data)
|
||
|
/* Write a single character to a given file. Return true if successful, and false otherwise. */
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if ((file_handle >= 0) && (file_handle < MAX_FILES_OPENED))
|
||
|
{
|
||
|
if (active_files[file_handle].in_use)
|
||
|
{
|
||
|
int data_sector = boot_sector_data.data_sector_offset + (active_files[file_handle].current_cluster_index - 2)*boot_sector_data.sectors_per_cluster +
|
||
|
active_files[file_handle].current_sector_in_cluster;
|
||
|
short int buffer_offset = active_files[file_handle].current_byte_position % boot_sector_data.sector_size_in_bytes;
|
||
|
|
||
|
if (active_files[file_handle].current_byte_position < active_files[file_handle].file_size_in_bytes)
|
||
|
{
|
||
|
if ((active_files[file_handle].current_byte_position > 0) && (buffer_offset == 0))
|
||
|
{
|
||
|
// Read in a new sector of data.
|
||
|
if (active_files[file_handle].current_sector_in_cluster == boot_sector_data.sectors_per_cluster - 1)
|
||
|
{
|
||
|
// Go to the next cluster.
|
||
|
unsigned short int next_cluster;
|
||
|
if (get_cluster_flag(active_files[file_handle].current_cluster_index, &next_cluster))
|
||
|
{
|
||
|
if (next_cluster < 0x0000fff8)
|
||
|
{
|
||
|
active_files[file_handle].current_cluster_index = next_cluster;
|
||
|
active_files[file_handle].current_sector_in_cluster = 0;
|
||
|
data_sector = boot_sector_data.data_sector_offset + (active_files[file_handle].current_cluster_index - 2)*boot_sector_data.sectors_per_cluster +
|
||
|
active_files[file_handle].current_sector_in_cluster;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
active_files[file_handle].current_sector_in_cluster = active_files[file_handle].current_sector_in_cluster + 1;
|
||
|
data_sector = data_sector + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* You are adding data to the end of the file, so increment its size and look for an additional data cluster if needed. */
|
||
|
if ((active_files[file_handle].current_byte_position > 0) && (buffer_offset == 0))
|
||
|
{
|
||
|
if (active_files[file_handle].current_sector_in_cluster == boot_sector_data.sectors_per_cluster - 1)
|
||
|
{
|
||
|
/* Find a new cluster if possible. */
|
||
|
unsigned int cluster_number;
|
||
|
|
||
|
if (find_first_empty_cluster(&cluster_number))
|
||
|
{
|
||
|
// mark clusters in both File Allocation Tables.
|
||
|
mark_cluster(active_files[file_handle].current_cluster_index, ((unsigned short int) (cluster_number & 0x0000ffff)), true);
|
||
|
mark_cluster(cluster_number, 0xffff, true);
|
||
|
mark_cluster(active_files[file_handle].current_cluster_index, ((unsigned short int) (cluster_number & 0x0000ffff)), false);
|
||
|
mark_cluster(cluster_number, 0xffff, false);
|
||
|
// Change cluster index and sector index to compute a new data sector.
|
||
|
active_files[file_handle].current_cluster_index = cluster_number;
|
||
|
active_files[file_handle].current_sector_in_cluster = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Read the next sector in the cluster and modify it. We only need to change the data_sector value. The actual read happens a few lines below. */
|
||
|
active_files[file_handle].current_sector_in_cluster = active_files[file_handle].current_byte_position / boot_sector_data.sector_size_in_bytes;
|
||
|
}
|
||
|
data_sector = boot_sector_data.data_sector_offset + (active_files[file_handle].current_cluster_index - 2)*boot_sector_data.sectors_per_cluster +
|
||
|
active_files[file_handle].current_sector_in_cluster;
|
||
|
}
|
||
|
}
|
||
|
// Reading a data sector into the buffer. Note that changes to the most recently modified sector will be saved before
|
||
|
// a new sector is read from the SD Card.
|
||
|
if (current_sector_index != data_sector + fat_partition_offset_in_512_byte_sectors)
|
||
|
{
|
||
|
if (!Read_Sector_Data(data_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
// Write a byte of data to the buffer.
|
||
|
IOWR_8DIRECT(buffer_memory, buffer_offset, byte_of_data);
|
||
|
active_files[file_handle].current_byte_position = active_files[file_handle].current_byte_position + 1;
|
||
|
|
||
|
// Modify the file record only when necessary.
|
||
|
if (active_files[file_handle].current_byte_position >= active_files[file_handle].file_size_in_bytes)
|
||
|
{
|
||
|
active_files[file_handle].file_size_in_bytes = active_files[file_handle].file_size_in_bytes + 1;
|
||
|
active_files[file_handle].modified = true;
|
||
|
}
|
||
|
// Invaldiate the buffer to ensure that the buffer contents are written to the SD card whe nthe file is closed.
|
||
|
current_sector_modified = true;
|
||
|
result = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool alt_up_sd_card_fclose(short int file_handle)
|
||
|
// This function closes an opened file and saves data to SD Card if necessary.
|
||
|
{
|
||
|
bool result = false;
|
||
|
if ((alt_up_sd_card_is_Present()) && (is_sd_card_formated_as_FAT16))
|
||
|
{
|
||
|
if (active_files[file_handle].in_use)
|
||
|
{
|
||
|
if (active_files[file_handle].modified)
|
||
|
{
|
||
|
unsigned int record_sector = active_files[file_handle].file_record_sector_in_cluster;
|
||
|
if (active_files[file_handle].file_record_cluster == 0)
|
||
|
{
|
||
|
record_sector = record_sector + boot_sector_data.root_directory_sector_offset;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
record_sector = record_sector + boot_sector_data.data_sector_offset +
|
||
|
(active_files[file_handle].file_record_cluster - 2)*boot_sector_data.sectors_per_cluster;
|
||
|
}
|
||
|
if (Read_Sector_Data(record_sector, fat_partition_offset_in_512_byte_sectors))
|
||
|
{
|
||
|
if (Write_File_Record_At_Offset(active_files[file_handle].file_record_offset, &(active_files[file_handle])))
|
||
|
{
|
||
|
// Make sure that the Data has been saved to the SD Card.
|
||
|
result = Save_Modified_Sector();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
active_files[file_handle].in_use = false;
|
||
|
result = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#endif //SD_RAW_IFACE
|