diff --git a/lib/blockdev.h b/lib/blockdev.h index 944bccf..ee422e8 100644 --- a/lib/blockdev.h +++ b/lib/blockdev.h @@ -50,5 +50,17 @@ typedef struct */ void (*rseek)(const int16_t offset); + + + /** Flush the data buffer if it's dirty. + * + * Should be called after each sequence of writes, + * to avoid data loss. + * + * Tmplementations that do not need this should provide + * a no-op function. + */ + void (*flush)(void); + } BLOCKDEV; diff --git a/lib/fat16.c b/lib/fat16.c index 6ea4e44..0866529 100644 --- a/lib/fat16.c +++ b/lib/fat16.c @@ -24,7 +24,7 @@ uint16_t next_clu(const FAT16* fat, uint16_t cluster); uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr); /** Read a file entry from directory (dir starting cluster, entry number) */ -void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num); +void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num); /** Allocate and chain new cluster to a chain starting at given cluster */ bool append_cluster(const FAT16* fat, const uint16_t clu); @@ -42,7 +42,7 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu); * Check if there is already a file of given RAW name * Raw name - name as found on disk, not "display name". */ -bool dir_find_file_raw(FAT16_FILE* dir, const char* fname); +bool dir_find_file_raw(FFILE* dir, const char* fname); /** Write a value into FAT */ void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value); @@ -276,10 +276,10 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu) * Check if there is already a file of given RAW name * Raw name - name as found on disk, not "display name". */ -bool dir_find_file_raw(FAT16_FILE* dir, const char* fname) +bool dir_find_file_raw(FFILE* dir, const char* fname) { // rewind - fat16_first(dir); + ff_first(dir); do { @@ -299,7 +299,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname) return true; // file is already open. } } - while (fat16_next(dir)); + while (ff_next(dir)); return false; } @@ -311,7 +311,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname) * dir_cluster ... directory start cluster * num ... entry number in the directory */ -void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num) +void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num) { // Resolve starting address uint32_t addr; @@ -397,7 +397,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c } // Init cursors - fat16_seek(file, 0); + ff_seek(file, 0); } @@ -406,7 +406,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c * Write information into a file header. * "file" is an open handle. */ -void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start) +void write_file_header(FFILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start) { const BLOCKDEV* dev = file->fat->dev; @@ -442,7 +442,7 @@ void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t at // =============== PUBLIC FUNCTION IMPLEMENTATIONS ================= /** Initialize a FAT16 handle */ -bool fat16_init(const BLOCKDEV* dev, FAT16* fat) +bool ff_init(const BLOCKDEV* dev, FAT16* fat) { const uint32_t bs_a = find_bs(dev); @@ -464,7 +464,7 @@ bool fat16_init(const BLOCKDEV* dev, FAT16* fat) * Move file cursor to a position relative to file start * Allows seek past end of file, will allocate new cluster if needed. */ -bool fat16_seek(FAT16_FILE* file, uint32_t addr) +bool ff_seek(FFILE* file, uint32_t addr) { const FAT16* fat = file->fat; @@ -512,7 +512,7 @@ bool fat16_seek(FAT16_FILE* file, uint32_t addr) * Check if file is a regular file or directory entry. * Those files can be shown to user. */ -bool fat16_is_regular(const FAT16_FILE* file) +bool ff_is_regular(const FFILE* file) { switch (file->type) { @@ -530,7 +530,7 @@ bool fat16_is_regular(const FAT16_FILE* file) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) -uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len) +uint16_t ff_read(FFILE* file, void* target, uint16_t len) { if (file->cur_abs == 0xFFFF) return 0; // file at the end already @@ -580,14 +580,23 @@ uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len) } -bool fat16_write(FAT16_FILE* file, void* source, uint32_t len) +bool ff_write_str(FFILE* file, const char* source) +{ + uint16_t len = 0; + for (; source[len] != 0; len++); + + return ff_write(file, source, len); +} + + +bool ff_write(FFILE* file, const void* source, uint32_t len) { const FAT16* fat = file->fat; const BLOCKDEV* dev = fat->dev; if (file->cur_abs == 0xFFFF) - return false; // file at the end already + return false; // file past it's end (rare) // Attempt to write past end of file if (file->cur_rel + len >= file->size) @@ -596,14 +605,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len) // Seek to the last position // -> fseek will allocate clusters - if (!fat16_seek(file, pos_start + len)) + if (!ff_seek(file, pos_start + len)) return false; // error in seek // Write starts beyond EOF - creating a zero-filled "hole" - if (file->cur_rel > file->size) + if (pos_start > file->size + 1) { // Seek to the end of valid data - fat16_seek(file, file->size); + ff_seek(file, file->size); // fill space between EOF and start-of-write with zeros uint32_t fill = pos_start - file->size; @@ -631,31 +640,44 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len) } } - // Save new size - fat16_resize(file, pos_start + len); + // Store new size + file->size = pos_start + len; // Seek back to where it was before - fat16_seek(file, pos_start); + ff_seek(file, pos_start); } // (end zerofill) // write the data while (len > 0) { - // How much can be stored in this cluster - const uint16_t chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len); - - // store the chunk dev->seek(file->cur_abs); - dev->store(source, chunk); + uint16_t chunk; - // advance cursors - file->cur_abs += chunk; - file->cur_rel += chunk; - file->cur_ofs += chunk; + if (len == 1) + { + dev->write(*((uint8_t*)source)); + file->cur_abs++; + file->cur_rel++; + file->cur_ofs++; + chunk = 1; - // Pointer arith! - source += chunk; // advance the source pointer + } + else + { + // How much can be stored in this cluster + chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len); + + dev->store(source, chunk); + + // advance cursors + file->cur_abs += chunk; + file->cur_rel += chunk; + file->cur_ofs += chunk; + + // Pointer arith! + source += chunk; // advance the source pointer + } // detect cluster overflow if (file->cur_ofs >= fat->bs.bytes_per_cluster) @@ -676,7 +698,7 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len) /** Open next file in the directory */ -bool fat16_next(FAT16_FILE* file) +bool ff_next(FFILE* file) { const FAT16* fat = file->fat; const BLOCKDEV* dev = fat->dev; @@ -700,7 +722,7 @@ bool fat16_next(FAT16_FILE* file) /** Open previous file in the directory */ -bool fat16_prev(FAT16_FILE* file) +bool ff_prev(FFILE* file) { if (file->num == 0) return false; // first file already @@ -712,14 +734,14 @@ bool fat16_prev(FAT16_FILE* file) /** Rewind to first file in directory */ -void fat16_first(FAT16_FILE* file) +void ff_first(FFILE* file) { open_file(file->fat, file, file->clu, 0); } /** Open a directory denoted by the file. */ -bool fat16_opendir(FAT16_FILE* dir) +bool ff_opendir(FFILE* dir) { // Don't open non-dirs and "." directory. if (!(dir->attribs & FA_DIR) || dir->type == FT_SELF) @@ -730,7 +752,7 @@ bool fat16_opendir(FAT16_FILE* dir) } -void fat16_root(const FAT16* fat, FAT16_FILE* file) +void ff_root(const FAT16* fat, FFILE* file) { open_file(fat, file, 0, 0); } @@ -741,16 +763,16 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file) * If file is found, "dir" will contain it's handle. * Either way, "dir" gets modified and you may need to rewind it afterwards. */ -bool fat16_find(FAT16_FILE* dir, const char* name) +bool ff_open(FFILE* dir, const char* name) { char fname[11]; - fat16_rawname(name, fname); + ff_rawname(name, fname); return dir_find_file_raw(dir, fname); } /** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */ -bool find_empty_file_slot(FAT16_FILE* file) +bool find_empty_file_slot(FFILE* file) { const uint16_t clu = file->clu; const FAT16* fat = file->fat; @@ -795,15 +817,15 @@ bool find_empty_file_slot(FAT16_FILE* file) -bool fat16_mkfile(FAT16_FILE* file, const char* name) +bool ff_newfile(FFILE* file, const char* name) { // Convert filename to zero padded raw string char fname[11]; - fat16_rawname(name, fname); + ff_rawname(name, fname); // Abort if file already exists bool exists = dir_find_file_raw(file, fname); - fat16_first(file); // rewind dir + ff_first(file); // rewind dir if (exists) return false; // file already exists in the dir. @@ -823,15 +845,15 @@ bool fat16_mkfile(FAT16_FILE* file, const char* name) * Create a sub-directory of given name. * Directory is allocated and populated with entries "." and ".." */ -bool fat16_mkdir(FAT16_FILE* file, const char* name) +bool ff_mkdir(FFILE* file, const char* name) { // Convert filename to zero padded raw string char fname[11]; - fat16_rawname(name, fname); + ff_rawname(name, fname); // Abort if file already exists bool exists = dir_find_file_raw(file, fname); - fat16_first(file); // rewind dir + ff_first(file); // rewind dir if (exists) return false; // file already exusts in the dir. @@ -854,20 +876,20 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name) write_file_header(file, ".. ", FA_DIR, parent_clu); // rewind. - fat16_first(file); + ff_first(file); return true; } -char* fat16_disk_label(const FAT16* fat, char* label_out) +char* ff_disk_label(const FAT16* fat, char* label_out) { - FAT16_FILE first; - fat16_root(fat, &first); + FFILE first; + ff_root(fat, &first); if (first.type == FT_LABEL) { - return fat16_dispname(&first, label_out); + return ff_dispname(&first, label_out); } // find where spaces end @@ -890,7 +912,7 @@ char* fat16_disk_label(const FAT16* fat, char* label_out) } -char* fat16_dispname(const FAT16_FILE* file, char* disp_out) +char* ff_dispname(const FFILE* file, char* disp_out) { // Cannot get name for special files if (file->type == FT_NONE || // not-yet-used directory location @@ -940,7 +962,7 @@ char* fat16_dispname(const FAT16_FILE* file, char* disp_out) } -char* fat16_rawname(const char* disp_in, char* raw_out) +char* ff_rawname(const char* disp_in, char* raw_out) { uint8_t name_c = 0, wr_c = 0; bool filling = false; @@ -1014,7 +1036,7 @@ char* fat16_rawname(const char* disp_in, char* raw_out) } -FSAVEPOS fat16_savepos(const FAT16_FILE* file) +FSAVEPOS ff_savepos(const FFILE* file) { FSAVEPOS fsp; fsp.clu = file->clu; @@ -1024,28 +1046,31 @@ FSAVEPOS fat16_savepos(const FAT16_FILE* file) } -void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos) +void ff_reopen(FFILE* file, const FSAVEPOS* pos) { open_file(file->fat, file, pos->clu, pos->num); - fat16_seek(file, pos->cur_rel); + ff_seek(file, pos->cur_rel); } -/** Write new file size (also to the disk). Does not allocate clusters. */ -void fat16_resize(FAT16_FILE* file, uint32_t size) +void ff_flush_file(FFILE* file) { const FAT16* fat = file->fat; const BLOCKDEV* dev = file->fat->dev; + // Store open page + dev->flush(); + + // Store file size + // Find address for storing the size const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28); - file->size = size; dev->seek(addr); - dev->store(&size, 4); + dev->store(&(file->size), 4); // Seek to the end of the file, to make sure clusters are allocated - fat16_seek(file, size - 1); + ff_seek(file, file->size - 1); const uint16_t next = next_clu(fat, file->cur_clu); if (next != 0xFFFF) @@ -1057,8 +1082,10 @@ void fat16_resize(FAT16_FILE* file, uint32_t size) } } + + /** Low level no-check file delete and free */ -void delete_file_do(FAT16_FILE* file) +void delete_file_do(FFILE* file) { const FAT16* fat = file->fat; @@ -1080,7 +1107,7 @@ void delete_file_do(FAT16_FILE* file) /** Delete a simple file */ -bool fat16_rmfile(FAT16_FILE* file) +bool ff_rmfile(FFILE* file) { switch (file->type) { @@ -1099,15 +1126,15 @@ bool fat16_rmfile(FAT16_FILE* file) /** Delete an empty directory */ -bool fat16_rmdir(FAT16_FILE* file) +bool ff_rmdir(FFILE* file) { if (file->type != FT_SUBDIR) return false; // not a subdirectory entry - const FSAVEPOS orig = fat16_savepos(file); + const FSAVEPOS orig = ff_savepos(file); // Open the subdir - if (!fat16_opendir(file)) + if (!ff_opendir(file)) return false; // could not open // Look for valid files and subdirs in the directory @@ -1124,16 +1151,16 @@ bool fat16_rmdir(FAT16_FILE* file) { // Valid child file was found, aborting. // reopen original file - fat16_reopen(file, &orig); + ff_reopen(file, &orig); return false; } if (cnt < 2) cnt++; } - while (fat16_next(file)); + while (ff_next(file)); // reopen original file - fat16_reopen(file, &orig); + ff_reopen(file, &orig); // and delete as ordinary file delete_file_do(file); @@ -1142,7 +1169,7 @@ bool fat16_rmdir(FAT16_FILE* file) } -bool fat16_delete(FAT16_FILE* file) +bool ff_delete(FFILE* file) { switch (file->type) { @@ -1153,7 +1180,7 @@ bool fat16_delete(FAT16_FILE* file) case FT_SUBDIR:; // semicolon needed to allow declaration after "case" // store original file location - const FSAVEPOS orig = fat16_savepos(file); + const FSAVEPOS orig = ff_savepos(file); // open the directory (skip "." and "..") open_file(file->fat, file, file->clu_start, 2); @@ -1161,32 +1188,32 @@ bool fat16_delete(FAT16_FILE* file) // delete all children do { - if (!fat16_delete(file)) + if (!ff_delete(file)) { // failure // reopen original file - fat16_reopen(file, &orig); + ff_reopen(file, &orig); return false; } } - while (fat16_next(file)); + while (ff_next(file)); // go up and delete the dir - fat16_reopen(file, &orig); - return fat16_rmdir(file); + ff_reopen(file, &orig); + return ff_rmdir(file); default: // try to delete as a regular file - return fat16_rmfile(file); + return ff_rmfile(file); } } -bool fat16_parent(FAT16_FILE* file) +bool ff_parent(FFILE* file) { // open second entry of the directory open_file(file->fat, file, file->clu, 1); - const FSAVEPOS orig = fat16_savepos(file); + const FSAVEPOS orig = ff_savepos(file); // if it's a valid PARENT link, follow it. if (file->type == FT_PARENT) @@ -1198,7 +1225,7 @@ bool fat16_parent(FAT16_FILE* file) { // in root already? // reopen original file - fat16_reopen(file, &orig); + ff_reopen(file, &orig); return false; } } diff --git a/lib/fat16.h b/lib/fat16.h index c0cdee7..149daec 100644 --- a/lib/fat16.h +++ b/lib/fat16.h @@ -99,24 +99,31 @@ typedef struct __attribute__((packed)) // Pointer to the FAT16 handle. (internal) const FAT16* fat; } -FAT16_FILE; +FFILE; + + +/** + * Store modified file metadata and flush it to disk. + */ +void ff_flush_file(FFILE* file); + /** * Save a file "position" into a struct, for later restoration. * Cursor is also saved. */ -FSAVEPOS fat16_savepos(const FAT16_FILE* file); +FSAVEPOS ff_savepos(const FFILE* file); /** * Restore a file from a saved position. */ -void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos); +void ff_reopen(FFILE* file, const FSAVEPOS* pos); /** * Initialize the file system - store into "fat" */ -bool fat16_init(const BLOCKDEV* dev, FAT16* fat); +bool ff_init(const BLOCKDEV* dev, FAT16* fat); /** @@ -124,7 +131,7 @@ bool fat16_init(const BLOCKDEV* dev, FAT16* fat); * The file may be invalid (eg. a volume label, deleted etc), * or blank (type FT_NONE) if the filesystem is empty. */ -void fat16_root(const FAT16* fat, FAT16_FILE* file); +void ff_root(const FAT16* fat, FFILE* file); /** @@ -134,7 +141,7 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file); * @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* ff_disk_label(const FAT16* fat, char* label_out); // ----------- FILE I/O ------------- @@ -144,21 +151,26 @@ char* fat16_disk_label(const FAT16* fat, char* label_out); * Move file cursor to a position relative to file start * Returns false on I/O error (bad file, out of range...) */ -bool fat16_seek(FAT16_FILE* file, uint32_t addr); +bool ff_seek(FFILE* file, uint32_t addr); /** * Read bytes from file into memory * Returns number of bytes read, 0 on error. */ -uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len); +uint16_t ff_read(FFILE* file, void* target, uint16_t len); /** * Write into file at a "seek" position. - * "seek" cursor must be within (0..filesize) */ -bool fat16_write(FAT16_FILE* file, void* source, uint32_t len); +bool ff_write(FFILE* file, const void* source, uint32_t len); + + +/** + * Store a 0-terminated string at cursor. + */ +bool ff_write_str(FFILE* file, const char* source); /** @@ -167,14 +179,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len); * file ... open directory; new file is opened into this handle. * name ... name of the new file, including extension */ -bool fat16_mkfile(FAT16_FILE* file, const char* name); +bool ff_newfile(FFILE* file, const char* name); /** * Create a sub-directory of given name. * Directory is allocated and populated with entries "." and ".." */ -bool fat16_mkdir(FAT16_FILE* file, const char* name); +bool ff_mkdir(FFILE* file, const char* name); /** @@ -183,26 +195,26 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name); * * Useful mainly for shrinking. */ -void fat16_resize(FAT16_FILE* file, uint32_t size); +void set_file_size(FFILE* file, uint32_t size); /** * Delete a *FILE* and free it's clusters. */ -bool fat16_rmfile(FAT16_FILE* file); +bool ff_rmfile(FFILE* file); /** * Delete an empty *DIRECTORY* and free it's clusters. */ -bool fat16_rmdir(FAT16_FILE* file); +bool ff_rmdir(FFILE* file); /** * Delete a file or directory, even FT_LFN and FT_INVALID. * Directories are deleted recursively (!) */ -bool fat16_delete(FAT16_FILE* file); +bool ff_delete(FFILE* file); @@ -210,55 +222,55 @@ bool fat16_delete(FAT16_FILE* file); /** Go to previous file in the directory (false = no prev file) */ -bool fat16_prev(FAT16_FILE* file); +bool ff_prev(FFILE* file); /** Go to next file in directory (false = no next file) */ -bool fat16_next(FAT16_FILE* file); +bool ff_next(FFILE* file); /** * Open a subdirectory denoted by the file. * Provided handle changes to the first entry of the directory. */ -bool fat16_opendir(FAT16_FILE* dir); +bool ff_opendir(FFILE* dir); /** * Open a parent directory. Fails in root. * Provided handle changes to the first entry of the parent directory. */ -bool fat16_parent(FAT16_FILE* file); +bool ff_parent(FFILE* file); /** Jump to first file in this directory */ -void fat16_first(FAT16_FILE* file); +void ff_first(FFILE* file); /** - * Find a file with given "display name" in this directory. + * Find a file with given "display name" in this directory, and open it. * If file is found, "dir" will contain it's handle. * If file is NOT found, the handle points to the last entry of the directory. */ -bool fat16_find(FAT16_FILE* dir, const char* name); +bool ff_open(FFILE* dir, const char* name); // -------- FILE INSPECTION ----------- /** Check if file is a valid entry, or long-name/label/deleted */ -bool fat16_is_regular(const FAT16_FILE* file); +bool ff_is_regular(const FFILE* file); /** * Resolve a file name, trim spaces and add null terminator. * Returns the passed char*, or NULL on error. */ -char* fat16_dispname(const FAT16_FILE* file, char* disp_out); +char* ff_dispname(const FFILE* file, char* disp_out); /** * Convert filename to zero-padded fixed length one * Returns the passed char*. */ -char* fat16_rawname(const char* disp_in, char* raw_out); +char* ff_rawname(const char* disp_in, char* raw_out); diff --git a/lib/sd.h b/lib/sd.h index 73fb8db..c57fc51 100644 --- a/lib/sd.h +++ b/lib/sd.h @@ -15,8 +15,6 @@ #include "iopins.h" #include "spi.h" -#include "uart.h" -#include "stream.h" /** Init SD card on SPI */ bool sd_init(); diff --git a/lib/sd_blockdev.c b/lib/sd_blockdev.c index 574f7dd..f363f47 100644 --- a/lib/sd_blockdev.c +++ b/lib/sd_blockdev.c @@ -16,6 +16,7 @@ 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); +void dev_flush(); /** Sector buffer */ @@ -36,7 +37,7 @@ uint16_t cursor_offs; /** Flush the buffer, if it's dirty */ -void sdb_flush() +void dev_flush() { if (buff_dirty) { @@ -49,11 +50,12 @@ void sdb_flush() void load_sector(const uint32_t addr) { // do not load if already loaded - if (buff_valid && buff_addr == addr) { + if (buff_valid && buff_addr == addr) + { return; } - sdb_flush(); + dev_flush(); // read entire sector sd_read(addr, 0, buff, 0, 512); @@ -90,8 +92,17 @@ inline void handle_cursor_ov() void dev_write(const uint8_t b) { load_sector(cursor_sec); - buff[cursor_offs++] = b; - buff_dirty = true; + + // dirty only if changed + if (buff[cursor_offs] != b) + { + buff[cursor_offs++] = b; + buff_dirty = true; + } + else + { + cursor_offs++; + } handle_cursor_ov(); } @@ -158,7 +169,7 @@ void dev_rseek(const int16_t offset) /** Init SD card block device */ bool sdb_init(BLOCKDEV* dev) { - if(!sd_init()) return false; + if (!sd_init()) return false; dev->load = &dev_load; dev->store = &dev_store; @@ -166,6 +177,7 @@ bool sdb_init(BLOCKDEV* dev) dev->write = &dev_write; dev->seek = &dev_seek; dev->rseek = &dev_rseek; + dev->flush = &dev_flush; return true; } diff --git a/lib/sd_blockdev.h b/lib/sd_blockdev.h index 66fce6c..68e53b8 100644 --- a/lib/sd_blockdev.h +++ b/lib/sd_blockdev.h @@ -2,13 +2,5 @@ #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); diff --git a/lib/sd_fat.c b/lib/sd_fat.c index 85117bb..519034d 100644 --- a/lib/sd_fat.c +++ b/lib/sd_fat.c @@ -8,27 +8,60 @@ FAT16 _fat; BLOCKDEV _dev; + +static STREAM _s; +STREAM* sdf_stream = &_s; + +FFILE* stream_file; +bool stream_active = false; + +void stream_tx(uint8_t b) +{ + if (!stream_active) return; + ff_write(stream_file, &b, 1); +} + + +uint8_t stream_rx() +{ + if (!stream_active) return 0; + + uint8_t b; + ff_read(stream_file, &b, 1); + return b; +} + +void sdf_open_stream(FFILE* file) +{ + stream_active = true; + stream_file = file; +} + + bool sdfat_inited = false; -bool sdfat_init() +bool sdf_init() { if (sdfat_inited) return true; sdfat_inited = true; if (!sdb_init(&_dev)) return false; - if (!fat16_init(&_dev, &_fat)) return false; + if (!ff_init(&_dev, &_fat)) return false; + + sdf_stream->rx = &stream_rx; + sdf_stream->tx = &stream_tx; return true; } -void sdfat_root(FAT16_FILE* file) +void sdf_root(FFILE* file) { - fat16_root(&_fat, file); + ff_root(&_fat, file); } -void sdfat_disk_label(char* str) +void sdf_disk_label(char* str) { - fat16_disk_label(&_fat, str); + ff_disk_label(&_fat, str); } diff --git a/lib/sd_fat.h b/lib/sd_fat.h index 2cf835b..1940ca0 100644 --- a/lib/sd_fat.h +++ b/lib/sd_fat.h @@ -1,19 +1,30 @@ #pragma once // -// FAT-on-SD helpers +// FAT-on-SD helpers. +// +// This can be used for convenience, as it does all the init for you +// and hides the implementation. All regular ff_* functions will work on the FFILE. // #include "fat16.h" +#include "stream.h" /** Initialize FAT16 filesystem on a SPI-connected SD card */ -bool sdfat_init(); +bool sdf_init(); /** Get first file of the root folder. */ -void sdfat_root(FAT16_FILE* file); +void sdf_root(FFILE* file); /** Get a disk label. Str should have 12 chars. */ -void sdfat_disk_label(char* str); +void sdf_disk_label(char* str); + +extern STREAM* sdf_stream; -/** Flush the SD buffer (alis of sdb_flush()) */ -#define sdfat_flush() sdb_flush() +/** + * Open a stream for a file. There can be only one stream at a time. + * + * The stream will operate at the current file's cursor, just like + * ff_read and ff_write. +*/ +void sdf_open_stream(FFILE* file); diff --git a/lib/stream.c b/lib/stream.c index ae7567b..fdf4bcb 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -18,7 +18,7 @@ void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len) } -void put_str(const STREAM *p, char* str) +void put_str(const STREAM *p, const char *str) { char c; while ((c = *str++)) @@ -41,6 +41,11 @@ void put_str_P(const STREAM *p, const char* str) static void _putnf(const STREAM *p, const uint8_t places); +void put_c(const STREAM *p, const uint8_t c) +{ + p->tx(c); +} + /** Send signed int8 */ void put_u8(const STREAM *p, const uint8_t num) { diff --git a/lib/stream.h b/lib/stream.h index 9d7ff0f..96f13a8 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -31,74 +31,75 @@ typedef struct /** Send bytes to stream */ -void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len); +void put_bytes(const STREAM *p, const uint8_t* str, uint16_t len); /** Print string into a stream */ -void put_str(const STREAM *p, char* str); +void put_str(const STREAM *p, const char *str); /** Print a programspace string into a stream */ void put_str_P(const STREAM *p, const char* str); +/** Put a char/byte. Basically the same as p->tx() */ +void put_c(const STREAM *p, uint8_t c); /** Send signed int8 */ -#define put_char(p, c) (p)->tx((c)) -void put_u8(const STREAM *p, const uint8_t num); +void put_u8(const STREAM *p, uint8_t num); /** Send unsigned int8 */ -void put_i8(const STREAM *p, const int8_t num); +void put_i8(const STREAM *p, int8_t num); /** Send unsigned int */ -void put_u16(const STREAM *p, const uint16_t num); +void put_u16(const STREAM *p, uint16_t num); /** Send signed int */ -void put_i16(const STREAM *p, const int16_t num); +void put_i16(const STREAM *p, int16_t num); /** Send unsigned long */ -void put_u32(const STREAM *p, const uint32_t num); +void put_u32(const STREAM *p, uint32_t num); /** Send signed long */ -void put_i32(const STREAM *p, const int32_t num); +void put_i32(const STREAM *p, int32_t num); /** Send unsigned int8 */ -void put_x8(const STREAM *p, const uint8_t num); +void put_x8(const STREAM *p, uint8_t num); /** Send int as hex */ -void put_x16(const STREAM *p, const uint16_t num); +void put_x16(const STREAM *p, uint16_t num); /** Send long as hex */ -void put_x32(const STREAM *p, const uint32_t num); +void put_x32(const STREAM *p, uint32_t num); /** Send long long as hex */ -void put_x64(const STREAM *p, const uint64_t num); +void put_x64(const STREAM *p, uint64_t num); // float variant doesn't make sense for 8-bit int /** Send unsigned int as float */ -void put_u16f(const STREAM *p, const uint16_t num, const uint8_t places); +void put_u16f(const STREAM *p, uint16_t num, uint8_t places); /** Send signed int as float */ -void put_i16f(const STREAM *p, const int16_t num, const uint8_t places); +void put_i16f(const STREAM *p, int16_t num, uint8_t places); /** Send unsigned long as float */ -void put_u32f(const STREAM *p, const uint32_t num, const uint8_t places); +void put_u32f(const STREAM *p, uint32_t num, uint8_t places); /** Send signed long as float */ -void put_i32f(const STREAM *p, const int32_t num, const uint8_t places); +void put_i32f(const STREAM *p, int32_t num, uint8_t places); /** Print CR LF */