Compare commits

..

No commits in common. "7b5a63d22093147763b2a13d6bb7770efe743eb5" and "d86b3fe1341007dc2ea3e8105e1481dd106ced1e" have entirely different histories.

8 changed files with 41 additions and 81 deletions

View File

@ -322,11 +322,6 @@ int Epub::getTocItemsCount() const { return toc.size(); }
// work out the section index for a toc index // work out the section index for a toc index
int Epub::getSpineIndexForTocIndex(const int tocIndex) const { int Epub::getSpineIndexForTocIndex(const int tocIndex) const {
if (tocIndex < 0 || tocIndex >= toc.size()) {
Serial.printf("[%lu] [EBP] getSpineIndexForTocIndex: tocIndex %d out of range\n", millis(), tocIndex);
return 0;
}
// the toc entry should have an href that matches the spine item // the toc entry should have an href that matches the spine item
// so we can find the spine index by looking for the href // so we can find the spine index by looking for the href
for (int i = 0; i < spine.size(); i++) { for (int i = 0; i < spine.size(); i++) {
@ -341,11 +336,6 @@ int Epub::getSpineIndexForTocIndex(const int tocIndex) const {
} }
int Epub::getTocIndexForSpineIndex(const int spineIndex) const { int Epub::getTocIndexForSpineIndex(const int spineIndex) const {
if (spineIndex < 0 || spineIndex >= spine.size()) {
Serial.printf("[%lu] [EBP] getTocIndexForSpineIndex: spineIndex %d out of range\n", millis(), spineIndex);
return -1;
}
// the toc entry should have an href that matches the spine item // the toc entry should have an href that matches the spine item
// so we can find the toc index by looking for the href // so we can find the toc index by looking for the href
for (int i = 0; i < toc.size(); i++) { for (int i = 0; i < toc.size(); i++) {
@ -358,21 +348,13 @@ int Epub::getTocIndexForSpineIndex(const int spineIndex) const {
return -1; return -1;
} }
size_t Epub::getBookSize() const { size_t Epub::getBookSize() const { return getCumulativeSpineItemSize(getSpineItemsCount() - 1); }
if (spine.empty()) {
return 0;
}
return getCumulativeSpineItemSize(getSpineItemsCount() - 1);
}
// Calculate progress in book // Calculate progress in book
uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) { uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) {
size_t bookSize = getBookSize();
if (bookSize == 0) {
return 0;
}
size_t prevChapterSize = (currentSpineIndex >= 1) ? getCumulativeSpineItemSize(currentSpineIndex - 1) : 0; size_t prevChapterSize = (currentSpineIndex >= 1) ? getCumulativeSpineItemSize(currentSpineIndex - 1) : 0;
size_t curChapterSize = getCumulativeSpineItemSize(currentSpineIndex) - prevChapterSize; size_t curChapterSize = getCumulativeSpineItemSize(currentSpineIndex) - prevChapterSize;
size_t bookSize = getBookSize();
size_t sectionProgSize = currentSpineRead * curChapterSize; size_t sectionProgSize = currentSpineRead * curChapterSize;
return round(static_cast<float>(prevChapterSize + sectionProgSize) / bookSize * 100.0); return round(static_cast<float>(prevChapterSize + sectionProgSize) / bookSize * 100.0);
} }

View File

@ -62,10 +62,6 @@ long ZipFile::getDataOffset(const mz_zip_archive_file_stat& fileStat) const {
const uint64_t fileOffset = fileStat.m_local_header_ofs; const uint64_t fileOffset = fileStat.m_local_header_ofs;
FILE* file = fopen(filePath.c_str(), "r"); FILE* file = fopen(filePath.c_str(), "r");
if (!file) {
Serial.printf("[%lu] [ZIP] Failed to open file for reading local header\n", millis());
return -1;
}
fseek(file, fileOffset, SEEK_SET); fseek(file, fileOffset, SEEK_SET);
const size_t read = fread(pLocalHeader, 1, localHeaderSize, file); const size_t read = fread(pLocalHeader, 1, localHeaderSize, file);
fclose(file); fclose(file);
@ -108,10 +104,6 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo
} }
FILE* file = fopen(filePath.c_str(), "rb"); FILE* file = fopen(filePath.c_str(), "rb");
if (!file) {
Serial.printf("[%lu] [ZIP] Failed to open file for reading\n", millis());
return nullptr;
}
fseek(file, fileOffset, SEEK_SET); fseek(file, fileOffset, SEEK_SET);
const auto deflatedDataSize = static_cast<size_t>(fileStat.m_comp_size); const auto deflatedDataSize = static_cast<size_t>(fileStat.m_comp_size);
@ -183,10 +175,6 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
} }
FILE* file = fopen(filePath.c_str(), "rb"); FILE* file = fopen(filePath.c_str(), "rb");
if (!file) {
Serial.printf("[%lu] [ZIP] Failed to open file for streaming\n", millis());
return false;
}
fseek(file, fileOffset, SEEK_SET); fseek(file, fileOffset, SEEK_SET);
const auto deflatedDataSize = static_cast<size_t>(fileStat.m_comp_size); const auto deflatedDataSize = static_cast<size_t>(fileStat.m_comp_size);

View File

@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance;
namespace { namespace {
constexpr uint8_t SETTINGS_FILE_VERSION = 1; constexpr uint8_t SETTINGS_FILE_VERSION = 1;
constexpr uint8_t SETTINGS_COUNT = 3; constexpr uint8_t SETTINGS_COUNT = 2;
constexpr char SETTINGS_FILE[] = "/sd/.crosspoint/settings.bin"; constexpr char SETTINGS_FILE[] = "/sd/.crosspoint/settings.bin";
} // namespace } // namespace
@ -25,7 +25,6 @@ bool CrossPointSettings::saveToFile() const {
serialization::writePod(outputFile, SETTINGS_COUNT); serialization::writePod(outputFile, SETTINGS_COUNT);
serialization::writePod(outputFile, whiteSleepScreen); serialization::writePod(outputFile, whiteSleepScreen);
serialization::writePod(outputFile, extraParagraphSpacing); serialization::writePod(outputFile, extraParagraphSpacing);
serialization::writePod(outputFile, shortPwrBtn);
outputFile.close(); outputFile.close();
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis()); Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
@ -52,15 +51,15 @@ bool CrossPointSettings::loadFromFile() {
serialization::readPod(inputFile, fileSettingsCount); serialization::readPod(inputFile, fileSettingsCount);
// load settings that exist // load settings that exist
uint8_t settingsRead = 0; switch (fileSettingsCount) {
do { case 1:
serialization::readPod(inputFile, whiteSleepScreen); serialization::readPod(inputFile, whiteSleepScreen);
if (++settingsRead >= fileSettingsCount) break; break;
serialization::readPod(inputFile, extraParagraphSpacing); case 2:
if (++settingsRead >= fileSettingsCount) break; serialization::readPod(inputFile, whiteSleepScreen);
serialization::readPod(inputFile, shortPwrBtn); serialization::readPod(inputFile, extraParagraphSpacing);
if (++settingsRead >= fileSettingsCount) break; break;
} while (false); }
inputFile.close(); inputFile.close();
Serial.printf("[%lu] [CPS] Settings loaded from file\n", millis()); Serial.printf("[%lu] [CPS] Settings loaded from file\n", millis());

View File

@ -17,18 +17,15 @@ class CrossPointSettings {
// Sleep screen settings // Sleep screen settings
uint8_t whiteSleepScreen = 0; uint8_t whiteSleepScreen = 0;
// Text rendering settings // Text rendering settings
uint8_t extraParagraphSpacing = 1; uint8_t extraParagraphSpacing = 1;
// Duration of the power button press
uint8_t shortPwrBtn = 0;
~CrossPointSettings() = default; ~CrossPointSettings() = default;
// Get singleton instance // Get singleton instance
static CrossPointSettings& getInstance() { return instance; } static CrossPointSettings& getInstance() { return instance; }
uint16_t getPowerButtonDuration() const { return shortPwrBtn ? 10 : 500; }
bool saveToFile() const; bool saveToFile() const;
bool loadFromFile(); bool loadFromFile();
}; };

View File

@ -33,14 +33,13 @@ void EpubReaderActivity::onEnter() {
epub->setupCacheDir(); epub->setupCacheDir();
File f = SD.open((epub->getCachePath() + "/progress.bin").c_str()); if (SD.exists((epub->getCachePath() + "/progress.bin").c_str())) {
if (f) { File f = SD.open((epub->getCachePath() + "/progress.bin").c_str());
uint8_t data[4]; uint8_t data[4];
if (f.read(data, 4) == 4) { f.read(data, 4);
currentSpineIndex = data[0] + (data[1] << 8); currentSpineIndex = data[0] + (data[1] << 8);
nextPageNumber = data[2] + (data[3] << 8); nextPageNumber = data[2] + (data[3] << 8);
Serial.printf("[%lu] [ERS] Loaded cache: %d, %d\n", millis(), currentSpineIndex, nextPageNumber); Serial.printf("[%lu] [ERS] Loaded cache: %d, %d\n", millis(), currentSpineIndex, nextPageNumber);
}
f.close(); f.close();
} }
@ -383,7 +382,7 @@ void EpubReaderActivity::renderStatusBar() const {
const auto tocItem = epub->getTocItem(tocIndex); const auto tocItem = epub->getTocItem(tocIndex);
title = tocItem.title; title = tocItem.title;
titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str());
while (titleWidth > availableTextWidth && title.length() > 11) { while (titleWidth > availableTextWidth) {
title = title.substr(0, title.length() - 8) + "..."; title = title.substr(0, title.length() - 8) + "...";
titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str());
} }

View File

@ -9,8 +9,7 @@
const SettingInfo SettingsActivity::settingsList[settingsCount] = { const SettingInfo SettingsActivity::settingsList[settingsCount] = {
{"White Sleep Screen", &CrossPointSettings::whiteSleepScreen}, {"White Sleep Screen", &CrossPointSettings::whiteSleepScreen},
{"Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing}, {"Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing}};
{"Short Power Button Click", &CrossPointSettings::shortPwrBtn}};
void SettingsActivity::taskTrampoline(void* param) { void SettingsActivity::taskTrampoline(void* param) {
auto* self = static_cast<SettingsActivity*>(param); auto* self = static_cast<SettingsActivity*>(param);

View File

@ -25,7 +25,7 @@ class SettingsActivity final : public Activity {
const std::function<void()> onGoHome; const std::function<void()> onGoHome;
// Static settings list // Static settings list
static constexpr int settingsCount = 3; // Number of settings static constexpr int settingsCount = 2; // Number of settings
static const SettingInfo settingsList[settingsCount]; static const SettingInfo settingsList[settingsCount];
static void taskTrampoline(void* param); static void taskTrampoline(void* param);

View File

@ -57,6 +57,11 @@ EpdFont ubuntu10Font(&ubuntu_10);
EpdFont ubuntuBold10Font(&ubuntu_bold_10); EpdFont ubuntuBold10Font(&ubuntu_bold_10);
EpdFontFamily ubuntuFontFamily(&ubuntu10Font, &ubuntuBold10Font); EpdFontFamily ubuntuFontFamily(&ubuntu10Font, &ubuntuBold10Font);
// Power button timing
// Time required to confirm boot from sleep
constexpr unsigned long POWER_BUTTON_WAKEUP_MS = 500;
// Time required to enter sleep mode
constexpr unsigned long POWER_BUTTON_SLEEP_MS = 500;
// Auto-sleep timeout (10 minutes of inactivity) // Auto-sleep timeout (10 minutes of inactivity)
constexpr unsigned long AUTO_SLEEP_TIMEOUT_MS = 10 * 60 * 1000; constexpr unsigned long AUTO_SLEEP_TIMEOUT_MS = 10 * 60 * 1000;
@ -74,24 +79,23 @@ void enterNewActivity(Activity* activity) {
// Verify long press on wake-up from deep sleep // Verify long press on wake-up from deep sleep
void verifyWakeupLongPress() { void verifyWakeupLongPress() {
// Give the user up to 1000ms to start holding the power button, and must hold for SETTINGS.getPowerButtonDuration() // Give the user up to 1000ms to start holding the power button, and must hold for POWER_BUTTON_WAKEUP_MS
const auto start = millis(); const auto start = millis();
bool abort = false; bool abort = false;
Serial.printf("[%lu] [ ] Verifying power button press\n", millis());
inputManager.update(); inputManager.update();
// Verify the user has actually pressed
while (!inputManager.isPressed(InputManager::BTN_POWER) && millis() - start < 1000) { while (!inputManager.isPressed(InputManager::BTN_POWER) && millis() - start < 1000) {
delay(10); // only wait 10ms each iteration to not delay too much in case of short configured duration. delay(50);
inputManager.update(); inputManager.update();
} }
if (inputManager.isPressed(InputManager::BTN_POWER)) { if (inputManager.isPressed(InputManager::BTN_POWER)) {
do { do {
delay(10); delay(50);
inputManager.update(); inputManager.update();
} while (inputManager.isPressed(InputManager::BTN_POWER) && } while (inputManager.isPressed(InputManager::BTN_POWER) && inputManager.getHeldTime() < POWER_BUTTON_WAKEUP_MS);
inputManager.getHeldTime() < SETTINGS.getPowerButtonDuration()); abort = inputManager.getHeldTime() < POWER_BUTTON_WAKEUP_MS;
abort = inputManager.getHeldTime() < SETTINGS.getPowerButtonDuration();
} else { } else {
abort = true; abort = true;
} }
@ -117,7 +121,7 @@ void enterDeepSleep() {
exitActivity(); exitActivity();
enterNewActivity(new SleepActivity(renderer, inputManager)); enterNewActivity(new SleepActivity(renderer, inputManager));
Serial.printf("[%lu] [ ] Entering deep sleep.\n", millis()); Serial.printf("[%lu] [ ] Power button released after a long press. Entering deep sleep.\n", millis());
delay(1000); // Allow Serial buffer to empty and display to update delay(1000); // Allow Serial buffer to empty and display to update
// Enable Wakeup on LOW (button press) // Enable Wakeup on LOW (button press)
@ -152,25 +156,14 @@ void setup() {
Serial.printf("[%lu] [ ] Starting CrossPoint version " CROSSPOINT_VERSION "\n", millis()); Serial.printf("[%lu] [ ] Starting CrossPoint version " CROSSPOINT_VERSION "\n", millis());
inputManager.begin(); inputManager.begin();
verifyWakeupLongPress();
// Initialize pins // Initialize pins
pinMode(BAT_GPIO0, INPUT); pinMode(BAT_GPIO0, INPUT);
// Initialize SPI with custom pins // Initialize SPI with custom pins
SPI.begin(EPD_SCLK, SD_SPI_MISO, EPD_MOSI, EPD_CS); SPI.begin(EPD_SCLK, SD_SPI_MISO, EPD_MOSI, EPD_CS);
// SD Card Initialization
if (!SD.begin(SD_SPI_CS, SPI, SPI_FQ)) {
Serial.printf("[%lu] [ ] SD card initialization failed\n", millis());
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "SD card error", BOLD));
return;
}
SETTINGS.loadFromFile();
// verify power button press duration after we've read settings.
verifyWakeupLongPress();
// Initialize display // Initialize display
einkDisplay.begin(); einkDisplay.begin();
Serial.printf("[%lu] [ ] Display initialized\n", millis()); Serial.printf("[%lu] [ ] Display initialized\n", millis());
@ -183,6 +176,10 @@ void setup() {
exitActivity(); exitActivity();
enterNewActivity(new BootActivity(renderer, inputManager)); enterNewActivity(new BootActivity(renderer, inputManager));
// SD Card Initialization
SD.begin(SD_SPI_CS, SPI, SPI_FQ);
SETTINGS.loadFromFile();
APP_STATE.loadFromFile(); APP_STATE.loadFromFile();
if (APP_STATE.openEpubPath.empty()) { if (APP_STATE.openEpubPath.empty()) {
onGoHome(); onGoHome();
@ -219,8 +216,7 @@ void loop() {
return; return;
} }
if (inputManager.wasReleased(InputManager::BTN_POWER) && if (inputManager.wasReleased(InputManager::BTN_POWER) && inputManager.getHeldTime() > POWER_BUTTON_SLEEP_MS) {
inputManager.getHeldTime() > SETTINGS.getPowerButtonDuration()) {
enterDeepSleep(); enterDeepSleep();
// This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start // This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start
return; return;