lot of work connecting SD I/O with FAT lib, FAT improvements.
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
+45
-21
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-24
@@ -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);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
|
|||||||
+1
-3
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user