// ============= LIBRARIES ============= //
#include <SdFat.h>
#include <SPI.h>
SdFat sd;
// ============= PIN DEFINITIONS ============= //
// Push buttons
const int HOME_PB_PIN = 5;
const int PREV_PB_PIN = 3;
const int NEXT_PB_PIN = 2;
// E-ink
const int E_INK_CS_PIN = 10;
const int E_INK_DC_PIN = 9;
const int E_INK_RST_PIN = 8;
const int E_INK_BUSY_PIN = 7;
// SD-card reader
const int SD_CS_PIN = 4;
const int SD_DO_PIN = 12; // data output (MISO)
// Shared pins
// const int MOSI_PIN = 11;
// const int CLK_PIN = 13;
// ============= VARIABLES ============= //
const unsigned long DEBOUNCE_DELAY = 150;
volatile unsigned long homePB_last_interrupt = 0;
volatile unsigned long prevPB_last_interrupt = 0;
volatile unsigned long nextPB_last_interrupt = 0;
volatile bool homePB_pressed = false;
volatile bool prevPB_pressed = false;
volatile bool nextPB_pressed = false;
const int maxBooks = 10;
const int maxLenFileName = 32;
char bookList[maxBooks][maxLenFileName]; // [rows][cols] for bookList array
int bookCount = 0;
int selectedBookIndex = 0;
// ============= STATE MACHINE ============= //
// Prototypes
void stateSleep();
void stateRead();
void stateHome();
void homePB_ISR();
void prevPB_ISR();
void nextPB_ISR();
void loadBookList();
void renderBookList();
void loadBookText();
void renderBookText();
void saveBookPage();
void getBookPage();
// Enumerated list of states
typedef enum {
STATE_SLEEP,
STATE_READ,
STATE_HOME } StateType;
// Function pointer table
static void (*state_table[])(void) = {stateSleep, stateRead, stateHome};
// Global variables
static volatile StateType curr_state;
static volatile bool state_changed;
// ============= SETUP FUNCTION ============= //
void setup() {
Serial.begin(115200);
// Button press
pinMode(HOME_PB_PIN, INPUT_PULLUP);
pinMode(PREV_PB_PIN, INPUT_PULLUP);
pinMode(NEXT_PB_PIN, INPUT_PULLUP);
// Attach interrupts
attachInterrupt(digitalPinToInterrupt(HOME_PB_PIN), homePB_ISR, FALLING);
attachInterrupt(digitalPinToInterrupt(NEXT_PB_PIN), nextPB_ISR, FALLING);
attachInterrupt(digitalPinToInterrupt(PREV_PB_PIN), prevPB_ISR, FALLING);
// Interrupts
homePB_pressed = false;
prevPB_pressed = false;
nextPB_pressed = false;
// Initialize SD card
if (!sd.begin(SD_CS_PIN, SPI_HALF_SPEED)){
Serial.println("SD card error");
while (true);
}
Serial.println("SD card initalized");
curr_state = STATE_HOME;
loadBookList();
initializeSM();
}
// ============= MAIN LOOP ============= //
void loop() {
state_table[curr_state]();
}
// ============= STATE FUNCTIONS ============= //
// Inatialize the state machine
void initializeSM(void){
curr_state = STATE_HOME;
}
// Home state function: used for selecting the book
void stateHome(void){
if (nextPB_pressed){
if (selectedBookIndex < bookCount - 1){
selectedBookIndex++;
}
nextPB_pressed = false;
}
if (prevPB_pressed){
if (selectedBookIndex > 0){
selectedBookIndex--;
}
prevPB_pressed = false;
}
if (homePB_pressed){
loadBookText();
curr_state = STATE_READ;
homePB_pressed = false;
}
}
// Reading state function: used to actually read the book
void stateRead(void){
renderBookText();
if(nextPB_pressed){
nextPB_pressed = false;
}
if (prevPB_pressed){
prevPB_pressed = false;
}
if (homePB_pressed){
homePB_pressed = false;
}
}
// Sleep state function: used to shutdown the device when idle
void stateSleep(void){
}
// ============= HELPER FUNCTIONS ============= //
void loadBookList(){
bookCount = 0;
SdFile root;
SdFile entry;
if (!root.open("/", O_RDONLY)){
Serial.println("Error opening SD card root");
return;
}
while (bookCount < maxBooks && entry.openNext(&root, O_RDONLY)){
if (entry.isDir()){
entry.close();
continue;
}
char name[maxLenFileName];
entry.getName(name, maxLenFileName);
int len = strlen(name);
if (len > 4 && strcmp(name + len - 4, ".TXT") || strcmp(name + len - 4, ".txt") == 0){
strncpy(bookList[bookCount], name, maxLenFileName - 1);
Serial.print("found book: ");
Serial.println(bookList[bookCount]);
bookCount++;
}
entry.close();
}
root.close();
Serial.print("Total books found: ");
Serial.println(bookCount);
}
void renderBookList(){
}
void loadBookText(){
}
void renderBookText(){
}
void saveBookPage(){
}
void getBookPage(){
}
// ============= ISRs ============= //
// Push button ISRs
void homePB_ISR(){
unsigned long curr_time = millis();
if (curr_time - homePB_last_interrupt > DEBOUNCE_DELAY){
homePB_pressed = true;
homePB_last_interrupt = curr_time;
}
}
void prevPB_ISR(){
unsigned long curr_time = millis();
if (curr_time - prevPB_last_interrupt > DEBOUNCE_DELAY){
prevPB_pressed = true;
prevPB_last_interrupt = curr_time;
}
}
void nextPB_ISR(){
unsigned long curr_time = millis();
if (curr_time - nextPB_last_interrupt > DEBOUNCE_DELAY){
nextPB_pressed = true;
nextPB_last_interrupt = curr_time;
}
}Loading
epaper-2in9
epaper-2in9