Teacup_Firmware/sd.c

126 lines
2.9 KiB
C

/** \file Coordinating reading and writing of SD cards.
*/
#include "sd.h"
#ifdef SD
#include "delay.h"
#include "serial.h"
#include "sersendf.h"
#define SD_BUFFER_SIZE 16
static FATFS sdfile;
static FRESULT result;
static uint8_t sd_buffer[SD_BUFFER_SIZE];
static uint8_t sd_buffer_ptr = SD_BUFFER_SIZE;
/** Initialize SPI for SD card reading.
*/
void sd_init(void) {
WRITE(SD_CARD_SELECT_PIN, 1);
SET_OUTPUT(SD_CARD_SELECT_PIN);
}
/** Mount the SD card.
*/
void sd_mount(void) {
result = pf_mount(&sdfile);
if (result != FR_OK)
sersendf_P(PSTR("E: SD init failed. (%su)"), result);
}
/** Unmount the SD card.
This makes just sure subsequent reads to the card do nothing, instead of
trying and failing. Not mandatory, just removing the card is fine, as well
as inserting and mounting another one without previous unmounting.
*/
void sd_unmount(void) {
pf_unmount(&sdfile);
}
/** List a given directory.
\param path The path to list. Toplevel path is "/".
A slash is added to directory names, to make it easier for users to
recognize them.
*/
void sd_list(const char* path) {
FILINFO fno;
DIR dir;
serial_writechar('\n');
result = pf_opendir(&dir, path);
if (result == FR_OK) {
for (;;) {
result = pf_readdir(&dir, &fno);
if (result != FR_OK || fno.fname[0] == 0)
break;
serial_writestr((uint8_t *)fno.fname);
if (fno.fattrib & AM_DIR)
serial_writechar('/');
serial_writechar('\n');
delay_ms(2); // Time for sending the characters.
}
}
else {
sersendf_P(PSTR("E: failed to open dir. (%su)"), result);
}
}
/** Open a file for reading.
\param filename Name of the file to open and to read G-code from.
Before too long this will cause the printer to read G-code from this file
until done or until stopped by G-code coming in over the serial line.
*/
void sd_open(const char* filename) {
result = pf_open(filename);
if (result != FR_OK) {
sersendf_P(PSTR("E: failed to open file. (%su)"), result);
}
}
/** Read a character from a file.
\return The character read, or zero if there is no such character (e.g. EOF).
In principle it'd be possible to read the file character by character.
However, Before too long this will cause the printer to read G-code from this file
until done or until stopped by G-code coming in over the serial line.
*/
uint8_t sd_read_char(void) {
UINT read;
uint8_t this_char;
if (sd_buffer_ptr == SD_BUFFER_SIZE) {
result = pf_read(sd_buffer, SD_BUFFER_SIZE, &read);
if (result != FR_OK) {
sersendf_P(PSTR("E: failed to read from file. (%su)"), result);
return 0;
}
if (read < SD_BUFFER_SIZE) {
sd_buffer[read] = 0; // A zero marks EOF.
}
sd_buffer_ptr = 0;
}
this_char = sd_buffer[sd_buffer_ptr];
if (this_char == 0)
sd_buffer_ptr = SD_BUFFER_SIZE; // Start over, perhaps with next file.
else
sd_buffer_ptr++;
return this_char;
}
#endif /* SD */