/* fs.h - SPI file system prototypes and structures from intbasic3.
 *  Copyright (C) 2022 by Jed Marti
 *   This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see https://www.gnu.org/licenses/.
 */

#ifndef fs_h
#define fs_h

#include "spi.h"

// The number of bytes in a sector for the AT45DB081E 1MB chip.
#define SECTORSIZE 256
#define SECTORMASK (SECTORSIZE - 1)

// This is the total number of bytes in the AT45DB081E 1MB chip.
#define MEMSIZE 1048576

// This is the number of sectors per FAT block which is 4 in this case. 
// This allows for a FAT table with 1024 entries in it.
#define SECTORSPERBLOCK        4

#define BLKSIZE (SECTORSIZE * SECTORSPERBLOCK)

// The total number of blocks available.
#define BLOCKSAVAIL (MEMSIZE / (SECTORSIZE * SECTORSPERBLOCK))

// The number of bytes in the FAT table.
#define FATSIZE ((MEMSIZE / (SECTORSIZE * SECTORSPERBLOCK)) / 8)

// This the mask to use when scanning for the next free block.
#define BLOCKMASK ((MEMSIZE / (SECTORSIZE * SECTORSPERBLOCK) - 1))

// The number of directory entries per sector.
#define DIRENTRIES_SECTOR (SECTORSIZE / 32)
#define DIRENTRIES_MASK (SECTORSIZE / 32 - 1)

// The number of directory entries.
#define DIRENTRIES ((SECTORSPERBLOCK - 1) * DIRENTRIES_SECTOR)

// Each entry in the directory table has one of these. We support at
// most 128 files since the top bit in the directory entry number is
// used to indicate read or write. Each entry is 32 bytes. The first byte
// will be 0xFF if the directry entry isn't in use.
typedef struct _dir_ {
  uint8_t  fname[26];            // Zero terminated file name.
  uint16_t blk;                  // The first block address.
  uint32_t fsize;                // The file size in bytes.
} DIR;

// Maximum number of open files.
#define OPENFILES 2

// A bit on the fat_entry to tell what kind of file it is. This is tacked
// onto the dir_entry field of an MFILE.
#define WRITE_FILE 0x80
#define READ_FILE 0x00
#define TYPE_MASK 0x80

// This is the file data storage for the various puts and gets. In the rest of
// the world this is FILE but we can't call it that.
typedef struct _file_ {
  uint8_t  dir_entry;             // The directory entry number.
  uint16_t byte_ptr;              // Runs 0 -> SECTORSPERBLOCK * SECTORSIZE - 1;
  uint16_t next_blk;              // The next block.
  uint32_t fsize;                 // File size in bytes.
  uint8_t  buffer[SECTORSIZE];
} MFILE;


////////////////////////////////////////////////////////////////////////
//                         COMMON ENTRY POINTS

// Clear the open files - during startup and between chained programs.
void clearHandles(void);

// Initialize the file system. Returns 1 for fail, 0 for OK.
void initFS(void);

// Format the file system destroying the contents.
void formatFS(void);

// Locate an free directory entry. Returns 255 if none otherwise index.
uint8_t locateFreeDir(void);

// Returns the first valid file in a directory or NULL for none.
DIR __xdata *dirFirst(void);

// Returns the next valid file in a directory or NULL for none.
DIR __xdata *dirNext(void);

// Locate an empty directory entry or return 255.
uint8_t locateFreeDir(void);

// Create a new file - file number is in FH (0-1).
uint8_t createFile(char __xdata *fname);

// Open an existing file. Returns 255 if you can't
uint8_t openFile(char __xdata *fname);

// get the next character from a file.
int16_t getchFile(uint8_t fh);

// Send the character.
int8_t putchFile(uint8_t c, uint8_t fh);

// Close a file.
int8_t closeFile(uint8_t fh);

// Delete a file.
__bit rmFS(char __xdata *fn);
void deleteFile(void);

// List the directory.
void listDir(void);

// Check file system and repair.
__bit fsck(void);

// Read and display a sector.
void readSector(void);

// Test write sectors.
void testfs(void);
#endif


// EOF
