lot of work connecting SD I/O with FAT lib, FAT improvements.

pull/1/head v2.0.0
Ondřej Hruška 10 years ago
parent d3dce4ffa7
commit d8e53ac598
  1. 54
      lib/blockdev.h
  2. 66
      lib/fat16.c
  3. 54
      lib/fat16.h
  4. 1
      lib/fat16_internal.h
  5. 6
      lib/sd.c
  6. 6
      lib/sd.h
  7. 172
      lib/sd_blockdev.c
  8. 14
      lib/sd_blockdev.h
  9. 34
      lib/sd_fat.c
  10. 19
      lib/sd_fat.h
  11. 7
      lib/spi.c
  12. 2
      lib/spi.h
  13. 2
      lib/stream.c
  14. 4
      lib/uart.c

@ -0,0 +1,54 @@
#pragma once
//
// Block device interface, somewhat akin to stream.h
// Used for filesystem implementations.
//
#include <stdint.h>
/** Abstract block device interface
*
* Populate an instance of this with pointers to your I/O functions.
*/
typedef struct
{
/** Sequential read at cursor
* @param dest destination memory structure
* @param len number of bytes to load and store in {dest}
*/
void (*load)(void* dest, const uint16_t len);
/** Sequential write at cursor
* @param src source memory structure
* @param len number of bytes to write
*/
void (*store)(const void* src, const uint16_t len);
/** Write one byte at cursor
* @param b byte to write
*/
void (*write)(const uint8_t b);
/** Read one byte at cursor
* @return the read byte
*/
uint8_t (*read)(void);
/** Absolute seek - set cursor
* @param addr new cursor address
*/
void (*seek)(const uint32_t addr);
/** Relative seek - move cursor
* @param offset cursor address change
*/
void (*rseek)(const int16_t offset);
} BLOCKDEV;

@ -103,7 +103,10 @@ uint32_t find_bs(const BLOCKDEV* dev)
// Verify that the boot sector has a valid signature mark // Verify that the boot sector has a valid signature mark
dev->seek(tmp + 510); dev->seek(tmp + 510);
dev->load(&tmp2, 2); dev->load(&tmp2, 2);
if (tmp2 != 0xAA55) continue; // continue to next entry if (tmp2 != 0xAA55)
{
continue; // continue to next entry
}
// return absolute MBR address // return absolute MBR address
return tmp; return tmp;
@ -439,9 +442,12 @@ void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t at
// =============== PUBLIC FUNCTION IMPLEMENTATIONS ================= // =============== PUBLIC FUNCTION IMPLEMENTATIONS =================
/** Initialize a FAT16 handle */ /** Initialize a FAT16 handle */
void fat16_init(const BLOCKDEV* dev, FAT16* fat) bool fat16_init(const BLOCKDEV* dev, FAT16* fat)
{ {
const uint32_t bs_a = find_bs(dev); const uint32_t bs_a = find_bs(dev);
if (bs_a == 0) return false;
fat->dev = dev; fat->dev = dev;
read_bs(dev, &(fat->bs), bs_a); read_bs(dev, &(fat->bs), bs_a);
fat->fat_addr = bs_a + (fat->bs.reserved_sectors * 512); fat->fat_addr = bs_a + (fat->bs.reserved_sectors * 512);
@ -449,6 +455,8 @@ void fat16_init(const BLOCKDEV* dev, FAT16* fat)
fat->data_addr = fat->rd_addr + (fat->bs.root_entries * 32); // entry is 32B long fat->data_addr = fat->rd_addr + (fat->bs.root_entries * 32); // entry is 32B long
fat->bs.bytes_per_cluster = (fat->bs.sectors_per_cluster * 512); fat->bs.bytes_per_cluster = (fat->bs.sectors_per_cluster * 512);
return true;
} }
@ -522,13 +530,19 @@ bool fat16_is_regular(const FAT16_FILE* file)
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
bool fat16_read(FAT16_FILE* file, void* target, uint32_t len) uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len)
{ {
if (file->cur_abs == 0xFFFF) if (file->cur_abs == 0xFFFF)
return false; // file at the end already return 0; // file at the end already
if (file->cur_rel + len > file->size) if (file->cur_rel + len > file->size)
return false; // Attempt to read more than what is available {
if (file->cur_rel > file->size) return 0;
len = file->size - file->cur_rel;
//return false; // Attempt to read more than what is available
}
const uint16_t len_orig = len;
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev; const BLOCKDEV* dev = fat->dev;
@ -562,7 +576,7 @@ bool fat16_read(FAT16_FILE* file, void* target, uint32_t len)
len -= chunk; len -= chunk;
} }
return true; return len_orig;
} }
@ -1000,6 +1014,23 @@ char* fat16_rawname(const char* disp_in, char* raw_out)
} }
FSAVEPOS fat16_savepos(const FAT16_FILE* file)
{
FSAVEPOS fsp;
fsp.clu = file->clu;
fsp.num = file->num;
fsp.cur_rel = file->cur_rel;
return fsp;
}
void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos)
{
open_file(file->fat, file, pos->clu, pos->num);
fat16_seek(file, pos->cur_rel);
}
/** Write new file size (also to the disk). Does not allocate clusters. */ /** Write new file size (also to the disk). Does not allocate clusters. */
void fat16_resize(FAT16_FILE* file, uint32_t size) void fat16_resize(FAT16_FILE* file, uint32_t size)
{ {
@ -1073,11 +1104,7 @@ bool fat16_rmdir(FAT16_FILE* file)
if (file->type != FT_SUBDIR) if (file->type != FT_SUBDIR)
return false; // not a subdirectory entry return false; // not a subdirectory entry
const FAT16* fat = file->fat; const FSAVEPOS orig = fat16_savepos(file);
const uint16_t clu1 = file->clu;
const uint16_t num1 = file->num;
// Open the subdir // Open the subdir
if (!fat16_opendir(file)) if (!fat16_opendir(file))
@ -1097,7 +1124,7 @@ bool fat16_rmdir(FAT16_FILE* file)
{ {
// Valid child file was found, aborting. // Valid child file was found, aborting.
// reopen original file // reopen original file
open_file(fat, file, clu1, num1); fat16_reopen(file, &orig);
return false; return false;
} }
@ -1106,7 +1133,7 @@ bool fat16_rmdir(FAT16_FILE* file)
while (fat16_next(file)); while (fat16_next(file));
// reopen original file // reopen original file
open_file(fat, file, clu1, num1); fat16_reopen(file, &orig);
// and delete as ordinary file // and delete as ordinary file
delete_file_do(file); delete_file_do(file);
@ -1126,8 +1153,7 @@ bool fat16_delete(FAT16_FILE* file)
case FT_SUBDIR:; // semicolon needed to allow declaration after "case" case FT_SUBDIR:; // semicolon needed to allow declaration after "case"
// store original file location // store original file location
const uint16_t clu1 = file->clu; const FSAVEPOS orig = fat16_savepos(file);
const uint16_t num1 = file->num;
// open the directory (skip "." and "..") // open the directory (skip "." and "..")
open_file(file->fat, file, file->clu_start, 2); open_file(file->fat, file, file->clu_start, 2);
@ -1139,14 +1165,14 @@ bool fat16_delete(FAT16_FILE* file)
{ {
// failure // failure
// reopen original file // reopen original file
open_file(file->fat, file, clu1, num1); fat16_reopen(file, &orig);
return false; return false;
} }
} }
while (fat16_next(file)); while (fat16_next(file));
// go up and delete the dir // go up and delete the dir
open_file(file->fat, file, clu1, num1); fat16_reopen(file, &orig);
return fat16_rmdir(file); return fat16_rmdir(file);
default: default:
@ -1158,11 +1184,9 @@ bool fat16_delete(FAT16_FILE* file)
bool fat16_parent(FAT16_FILE* file) bool fat16_parent(FAT16_FILE* file)
{ {
const uint16_t clu1 = file->clu;
const uint16_t num1 = file->num;
// open second entry of the directory // open second entry of the directory
open_file(file->fat, file, file->clu, 1); open_file(file->fat, file, file->clu, 1);
const FSAVEPOS orig = fat16_savepos(file);
// if it's a valid PARENT link, follow it. // if it's a valid PARENT link, follow it.
if (file->type == FT_PARENT) if (file->type == FT_PARENT)
@ -1174,7 +1198,7 @@ bool fat16_parent(FAT16_FILE* file)
{ {
// in root already? // in root already?
// reopen original file // reopen original file
open_file(file->fat, file, clu1, num1); fat16_reopen(file, &orig);
return false; return false;
} }
} }

@ -10,26 +10,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/** #include "blockdev.h"
* Abstract block device interface
*
* Populate this with pointers to your I/O functions.
*/
typedef struct
{
// Sequential read
void (*load)(void* dest, const uint16_t len);
// Sequential write
void (*store)(const void* src, const uint16_t len);
// Sequential byte write
void (*write)(const uint8_t b);
// Sequential byte read
uint8_t (*read)(void);
// Absolute seek
void (*seek)(const uint32_t);
// Relative seek
void (*rseek)(const int16_t);
} BLOCKDEV;
// ------------------------------- // -------------------------------
@ -52,6 +33,15 @@ typedef enum
} FAT16_FT; } FAT16_FT;
/** "File address" for saving and restoring file */
typedef struct
{
uint16_t clu;
uint16_t num;
uint32_t cur_rel;
} FSAVEPOS;
// Include definitions of fully internal structs // Include definitions of fully internal structs
#include "fat16_internal.h" #include "fat16_internal.h"
@ -111,9 +101,22 @@ typedef struct __attribute__((packed))
} }
FAT16_FILE; FAT16_FILE;
/**
* Save a file "position" into a struct, for later restoration.
* Cursor is also saved.
*/
FSAVEPOS fat16_savepos(const FAT16_FILE* file);
/** Initialize the file system - store into "fat" */ /**
void fat16_init(const BLOCKDEV* dev, FAT16* fat); * Restore a file from a saved position.
*/
void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos);
/**
* Initialize the file system - store into "fat"
*/
bool fat16_init(const BLOCKDEV* dev, FAT16* fat);
/** /**
@ -127,6 +130,9 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file);
/** /**
* Resolve the disk label. * Resolve the disk label.
* That can be in the Boot Sector, or in the first root directory entry. * That can be in the Boot Sector, or in the first root directory entry.
*
* @param fat the FAT handle
* @param label_out string to store the label in. Should have at least 12 bytes.
*/ */
char* fat16_disk_label(const FAT16* fat, char* label_out); char* fat16_disk_label(const FAT16* fat, char* label_out);
@ -143,9 +149,9 @@ bool fat16_seek(FAT16_FILE* file, uint32_t addr);
/** /**
* Read bytes from file into memory * Read bytes from file into memory
* Returns false on I/O error (bad file, out of range...) * Returns number of bytes read, 0 on error.
*/ */
bool fat16_read(FAT16_FILE* file, void* target, uint32_t len); uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len);
/** /**

@ -9,7 +9,6 @@
/** Boot Sector structure */ /** Boot Sector structure */
typedef struct __attribute__((packed)) typedef struct __attribute__((packed))
{ {
// Fields loaded directly from disk: // Fields loaded directly from disk:
// 13 bytes skipped // 13 bytes skipped

@ -1,5 +1,4 @@
#include <avr/io.h> #include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h> #include <util/delay.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
@ -15,8 +14,13 @@
#define SD_WRITE_BLOCK 0x58 // write single block #define SD_WRITE_BLOCK 0x58 // write single block
bool sd_inited = false;
bool sd_init() bool sd_init()
{ {
if (sd_inited) return true;
sd_inited = true;
uint8_t i; uint8_t i;
spi_init(); spi_init();

@ -29,7 +29,7 @@ bool sd_init();
* @param arg command argument * @param arg command argument
* @return return value on success, 0xFF if nothing received back. * @return return value on success, 0xFF if nothing received back.
*/ */
uint8_t sd_command(const uint8_t cmd, const uint32_t arg); uint8_t sd_command(uint8_t cmd, uint32_t arg);
/** /**
@ -42,7 +42,7 @@ uint8_t sd_command(const uint8_t cmd, const uint32_t arg);
* @param len number of bytes to read * @param len number of bytes to read
* @return true on success * @return true on success
*/ */
bool sd_read(const uint32_t sector, const uint16_t read_at, uint8_t * buffer, const uint16_t write_at, const uint16_t len); bool sd_read(uint32_t sector, uint16_t read_at, uint8_t * buffer, uint16_t write_at, uint16_t len);
/** /**
@ -52,4 +52,4 @@ bool sd_read(const uint32_t sector, const uint16_t read_at, uint8_t * buffer, co
* @param buffer512 source buffer * @param buffer512 source buffer
* @return true on success * @return true on success
*/ */
bool sd_write(const uint32_t sector, const uint8_t * buffer512); bool sd_write(uint32_t sector, const uint8_t * buffer512);

@ -0,0 +1,172 @@
#include <stdint.h>
#include <stdbool.h>
#include "sd_blockdev.h"
#include "sd.h"
// helpers
void load_sector(const uint32_t addr);
void store_sector();
void handle_cursor_ov();
// blockdev methods
void dev_load(void* dest, const uint16_t len);
void dev_store(const void* src, const uint16_t len);
uint8_t dev_read();
void dev_write(const uint8_t b);
void dev_seek(const uint32_t addr);
void dev_rseek(const int16_t offset);
/** Sector buffer */
uint8_t buff[512];
/** Address of the buffered sector */
uint32_t buff_addr;
/** Buffer needs to be flushed before next read */
bool buff_dirty = false;
/** Buffer holds a valid sector */
bool buff_valid = false;
/** seek cursor */
uint32_t cursor_sec;
uint16_t cursor_offs;
/** Flush the buffer, if it's dirty */
void sdb_flush()
{
if (buff_dirty)
{
store_sector();
buff_dirty = false;
}
}
void load_sector(const uint32_t addr)
{
// do not load if already loaded
if (buff_valid && buff_addr == addr) {
return;
}
sdb_flush();
// read entire sector
sd_read(addr, 0, buff, 0, 512);
buff_valid = true;
buff_addr = addr;
}
void store_sector()
{
// Do not store if not laoded.
if (!buff_dirty) return;
if (!buff_valid) return;
sd_write(buff_addr, buff);
}
/**
* Handle cursor overflow.
* MUST ABSOLUTELY NOT load/store buffer or change buffer addr!
*/
inline void handle_cursor_ov()
{
if (cursor_offs >= 512)
{
cursor_sec++;
cursor_offs = 0;
}
}
void dev_write(const uint8_t b)
{
load_sector(cursor_sec);
buff[cursor_offs++] = b;
buff_dirty = true;
handle_cursor_ov();
}
uint8_t dev_read()
{
load_sector(cursor_sec);
const uint8_t b = buff[cursor_offs++];
handle_cursor_ov();
return b;
}
void dev_load(void* dest, const uint16_t len)
{
for (uint16_t a = 0; a < len; a++)
{
*((uint8_t*)dest++) = dev_read();
}
}
void dev_store(const void* src, const uint16_t len)
{
for (uint16_t a = 0; a < len; a++)
{
dev_write(*((uint8_t*)src++));
}
}
void dev_seek(const uint32_t addr)
{
// compute sector and offset counters
cursor_sec = addr >> 9;
cursor_offs = addr & 0x1FF;
}
void dev_rseek(const int16_t offset)
{
// add WITHIN the same sector
if (offset > 0 && cursor_offs + offset < 512)
{
cursor_offs += offset;
return;
}
// subtract WITHIN the same sector
if (offset < 0 && ((uint16_t)(-offset) <= cursor_offs))
{
cursor_offs += offset;
return;
}
// abs addr change
dev_seek(((cursor_sec << 9) + cursor_offs) + offset);
}
/** Init SD card block device */
bool sdb_init(BLOCKDEV* dev)
{
if(!sd_init()) return false;
dev->load = &dev_load;
dev->store = &dev_store;
dev->read = &dev_read;
dev->write = &dev_write;
dev->seek = &dev_seek;
dev->rseek = &dev_rseek;
return true;
}

@ -0,0 +1,14 @@
#pragma once
#include "blockdev.h"
/**
* Flush the sector buffer if it's dirty.
*
* Should be called after each sequence of writes,
* to avoid data loss.
*/
void sdb_flush();
/** Initialize the SD card block device */
bool sdb_init(BLOCKDEV* dev);

@ -0,0 +1,34 @@
#include <stdint.h>
#include <stdbool.h>
#include "sd_blockdev.h"
#include "sd_fat.h"
#include "fat16.h"
FAT16 _fat;
BLOCKDEV _dev;
bool sdfat_inited = false;
bool sdfat_init()
{
if (sdfat_inited) return true;
sdfat_inited = true;
if (!sdb_init(&_dev)) return false;
if (!fat16_init(&_dev, &_fat)) return false;
return true;
}
void sdfat_root(FAT16_FILE* file)
{
fat16_root(&_fat, file);
}
void sdfat_disk_label(char* str)
{
fat16_disk_label(&_fat, str);
}

@ -0,0 +1,19 @@
#pragma once
//
// FAT-on-SD helpers
//
#include "fat16.h"
/** Initialize FAT16 filesystem on a SPI-connected SD card */
bool sdfat_init();
/** Get first file of the root folder. */
void sdfat_root(FAT16_FILE* file);
/** Get a disk label. Str should have 12 chars. */
void sdfat_disk_label(char* str);
/** Flush the SD buffer (alis of sdb_flush()) */
#define sdfat_flush() sdb_flush()

@ -5,9 +5,14 @@
#include "iopins.h" #include "iopins.h"
#include "spi.h" #include "spi.h"
bool spi_inited = false;
/** Init SPI (for SD card communication) */ /** Init SPI (for SD card communication) */
void spi_init() void spi_init()
{ {
if (spi_inited) return;
spi_inited = true;
// Pin configuration // Pin configuration
as_output(PIN_SS); as_output(PIN_SS);
as_output(PIN_MOSI); as_output(PIN_MOSI);
@ -20,7 +25,7 @@ void spi_init()
/** Write a byte to SPI. Returns received byte. */ /** Write a byte to SPI. Returns received byte. */
uint8_t spi_write(const uint8_t b) uint8_t spi_write(uint8_t b)
{ {
SPDR = b; SPDR = b;
while (!(SPSR & _BV(SPIF))); while (!(SPSR & _BV(SPIF)));

@ -26,5 +26,5 @@ void spi_init();
* @param ch the written byte * @param ch the written byte
* @return received byte * @return received byte
*/ */
uint8_t spi_write(const uint8_t b); uint8_t spi_write(uint8_t b);

@ -6,7 +6,7 @@
#include "calc.h" #include "calc.h"
static char tmpstr[12]; // buffer for number rendering static char tmpstr[16]; // buffer for number rendering
void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len) void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len)

@ -11,7 +11,7 @@
// Shared stream instance // Shared stream instance
static STREAM _uart_singleton; static STREAM _uart_singleton;
STREAM* uart; STREAM* uart = &_uart_singleton;
void _uart_init_do(uint16_t ubrr) void _uart_init_do(uint16_t ubrr)
@ -28,8 +28,6 @@ void _uart_init_do(uint16_t ubrr)
_uart_singleton.tx = &uart_tx; _uart_singleton.tx = &uart_tx;
_uart_singleton.rx = &uart_rx; _uart_singleton.rx = &uart_rx;
uart = &_uart_singleton;
} }

Loading…
Cancel
Save