mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-06 07:37:37 +03:00
Refactor image rendering and add Bluetooth setting
- Added logic to render images only in BW mode in Page.cpp. - Implemented getRenderMode() in GfxRenderer.h. - Increased SETTINGS_COUNT and added bluetoothEnabled field in CrossPointSettings. - Updated saveToFile and loadFromFile methods to handle the new Bluetooth setting. - Added Bluetooth toggle in SettingsActivity.
This commit is contained in:
parent
9db4ef6f4b
commit
1f2380be56
@ -29,8 +29,13 @@ std::unique_ptr<PageLine> PageLine::deserialize(FsFile& file) {
|
||||
}
|
||||
|
||||
void PageImage::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) {
|
||||
// Only render images in BW mode, skip grayscale passes to keep images sharp
|
||||
if (renderer.getRenderMode() != GfxRenderer::BW) {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile imageFile;
|
||||
if (!SdMan.openFileForRead("PGI", cachePath, imageFile)) {
|
||||
if (!SdMan.openFileForRead("PGI", cachePath.c_str(), imageFile)) {
|
||||
Serial.printf("[%lu] [PGI] Failed to open image: %s\n", millis(), cachePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -83,6 +83,7 @@ class GfxRenderer {
|
||||
|
||||
// Grayscale functions
|
||||
void setRenderMode(const RenderMode mode) { this->renderMode = mode; }
|
||||
RenderMode getRenderMode() const { return renderMode; }
|
||||
void copyGrayscaleLsbBuffers() const;
|
||||
void copyGrayscaleMsbBuffers() const;
|
||||
void displayGrayBuffer() const;
|
||||
|
||||
@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance;
|
||||
namespace {
|
||||
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
||||
// Increment this when adding new persisted settings fields
|
||||
constexpr uint8_t SETTINGS_COUNT = 10;
|
||||
constexpr uint8_t SETTINGS_COUNT = 11;
|
||||
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
||||
} // namespace
|
||||
|
||||
@ -37,6 +37,7 @@ bool CrossPointSettings::saveToFile() const {
|
||||
serialization::writePod(outputFile, fontFamily);
|
||||
serialization::writePod(outputFile, fontSize);
|
||||
serialization::writePod(outputFile, lineSpacing);
|
||||
serialization::writePod(outputFile, bluetoothEnabled);
|
||||
outputFile.close();
|
||||
|
||||
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
||||
@ -83,6 +84,8 @@ bool CrossPointSettings::loadFromFile() {
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
serialization::readPod(inputFile, lineSpacing);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
serialization::readPod(inputFile, bluetoothEnabled);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
} while (false);
|
||||
|
||||
inputFile.close();
|
||||
|
||||
@ -62,6 +62,8 @@ class CrossPointSettings {
|
||||
uint8_t fontFamily = BOOKERLY;
|
||||
uint8_t fontSize = MEDIUM;
|
||||
uint8_t lineSpacing = NORMAL;
|
||||
// Bluetooth settings
|
||||
uint8_t bluetoothEnabled = 0;
|
||||
|
||||
~CrossPointSettings() = default;
|
||||
|
||||
|
||||
@ -8,9 +8,11 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "NetworkModeSelectionActivity.h"
|
||||
#include "WifiSelectionActivity.h"
|
||||
#include "activities/util/FullScreenMessageActivity.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
namespace {
|
||||
@ -128,6 +130,15 @@ void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode)
|
||||
Serial.printf("[%lu] [WEBACT] Network mode selected: %s\n", millis(),
|
||||
mode == NetworkMode::JOIN_NETWORK ? "Join Network" : "Create Hotspot");
|
||||
|
||||
// Check for WiFi/BLE mutual exclusion
|
||||
if (SETTINGS.bluetoothEnabled) {
|
||||
Serial.printf("[%lu] [WEBACT] ERROR: Cannot start WiFi while Bluetooth is enabled\n", millis());
|
||||
exitActivity();
|
||||
enterNewActivity(new FullScreenMessageActivity(
|
||||
renderer, mappedInput, "Disable Bluetooth first\n\nGo to Settings > Bluetooth"));
|
||||
return;
|
||||
}
|
||||
|
||||
networkMode = mode;
|
||||
isApMode = (mode == NetworkMode::CREATE_HOTSPOT);
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
// Define the static settings list
|
||||
namespace {
|
||||
constexpr int settingsCount = 11;
|
||||
constexpr int settingsCount = 12;
|
||||
const SettingInfo settingsList[settingsCount] = {
|
||||
// Should match with SLEEP_SCREEN_MODE
|
||||
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
|
||||
@ -34,6 +34,7 @@ const SettingInfo settingsList[settingsCount] = {
|
||||
{"Bookerly", "Noto Sans", "Open Dyslexic"}},
|
||||
{"Reader Font Size", SettingType::ENUM, &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}},
|
||||
{"Reader Line Spacing", SettingType::ENUM, &CrossPointSettings::lineSpacing, {"Tight", "Normal", "Wide"}},
|
||||
{"Bluetooth", SettingType::TOGGLE, &CrossPointSettings::bluetoothEnabled, {}},
|
||||
{"Check for updates", SettingType::ACTION, nullptr, {}},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
188
src/bluetooth/BleFileTransfer.cpp
Normal file
188
src/bluetooth/BleFileTransfer.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
#include "BleFileTransfer.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <SDCardManager.h>
|
||||
|
||||
namespace {
|
||||
// BLE Service UUIDs (custom UUIDs for CrossPoint file transfer)
|
||||
constexpr const char* SERVICE_UUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
|
||||
constexpr const char* FILE_LIST_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";
|
||||
constexpr const char* FILE_DATA_UUID = "1c95d5e3-d8f7-413a-bf3d-7a2e5d7be87e";
|
||||
constexpr const char* CONTROL_UUID = "d7e72d4c-3f8e-4b4a-9c5d-8e3f7a2b1c9d";
|
||||
|
||||
constexpr int BLE_MTU = 512; // BLE Maximum Transmission Unit
|
||||
} // namespace
|
||||
|
||||
BleFileTransfer::BleFileTransfer()
|
||||
: running(false), pServer(nullptr), pFileService(nullptr), pFileListChar(nullptr), pFileDataChar(nullptr),
|
||||
pControlChar(nullptr) {}
|
||||
|
||||
BleFileTransfer::~BleFileTransfer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
bool BleFileTransfer::begin(const std::string& deviceName) {
|
||||
if (running) {
|
||||
Serial.printf("[%lu] [BLE] Already running\n", millis());
|
||||
return true;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [BLE] Starting BLE service...\n", millis());
|
||||
Serial.printf("[%lu] [BLE] [MEM] Free heap before init: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
|
||||
// Initialize BLE
|
||||
BLEDevice::init(deviceName);
|
||||
|
||||
// Set MTU size for larger transfers
|
||||
BLEDevice::setMTU(BLE_MTU);
|
||||
|
||||
// Create BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
if (!pServer) {
|
||||
Serial.printf("[%lu] [BLE] ERROR: Failed to create server\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
serverCallbacks.reset(new ServerCallbacks(this));
|
||||
pServer->setCallbacks(serverCallbacks.get());
|
||||
|
||||
// Create File Transfer Service
|
||||
pFileService = pServer->createService(SERVICE_UUID);
|
||||
if (!pFileService) {
|
||||
Serial.printf("[%lu] [BLE] ERROR: Failed to create service\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create File List Characteristic (READ)
|
||||
pFileListChar = pFileService->createCharacteristic(FILE_LIST_UUID, BLECharacteristic::PROPERTY_READ);
|
||||
fileListCallbacks.reset(new FileListCallbacks(this));
|
||||
pFileListChar->setCallbacks(fileListCallbacks.get());
|
||||
|
||||
// Create File Data Characteristic (READ | WRITE | NOTIFY)
|
||||
pFileDataChar =
|
||||
pFileService->createCharacteristic(FILE_DATA_UUID, BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE |
|
||||
BLECharacteristic::PROPERTY_NOTIFY);
|
||||
pFileDataChar->addDescriptor(new BLE2902());
|
||||
|
||||
// Create Control Characteristic (WRITE)
|
||||
pControlChar = pFileService->createCharacteristic(CONTROL_UUID, BLECharacteristic::PROPERTY_WRITE);
|
||||
controlCallbacks.reset(new ControlCallbacks(this));
|
||||
pControlChar->setCallbacks(controlCallbacks.get());
|
||||
|
||||
// Start the service
|
||||
pFileService->start();
|
||||
|
||||
// Start advertising
|
||||
BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(true);
|
||||
pAdvertising->setMinPreferred(0x06); // helps with iPhone connections
|
||||
pAdvertising->setMinPreferred(0x12);
|
||||
BLEDevice::startAdvertising();
|
||||
|
||||
running = true;
|
||||
Serial.printf("[%lu] [BLE] Service started successfully\n", millis());
|
||||
Serial.printf("[%lu] [BLE] Device name: %s\n", millis(), deviceName.c_str());
|
||||
Serial.printf("[%lu] [BLE] [MEM] Free heap after init: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BleFileTransfer::stop() {
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [BLE] Stopping BLE service...\n", millis());
|
||||
|
||||
running = false;
|
||||
|
||||
// Stop advertising
|
||||
BLEDevice::getAdvertising()->stop();
|
||||
|
||||
// Clean up characteristics
|
||||
pFileListChar = nullptr;
|
||||
pFileDataChar = nullptr;
|
||||
pControlChar = nullptr;
|
||||
|
||||
// Clean up service
|
||||
pFileService = nullptr;
|
||||
|
||||
// Clean up server
|
||||
pServer = nullptr;
|
||||
|
||||
// Clean up callbacks
|
||||
serverCallbacks.reset();
|
||||
controlCallbacks.reset();
|
||||
fileListCallbacks.reset();
|
||||
|
||||
// Deinitialize BLE
|
||||
BLEDevice::deinit(true);
|
||||
|
||||
Serial.printf("[%lu] [BLE] Service stopped\n", millis());
|
||||
Serial.printf("[%lu] [BLE] [MEM] Free heap after cleanup: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
}
|
||||
|
||||
uint32_t BleFileTransfer::getConnectedCount() const {
|
||||
if (pServer) {
|
||||
return pServer->getConnectedCount();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string BleFileTransfer::getFileList() {
|
||||
// Return a simple JSON-like list of files in the root directory
|
||||
// Format: "file1.epub,file2.epub,file3.epub"
|
||||
// For a full implementation, this would traverse SD card directories
|
||||
|
||||
// Placeholder implementation - would need to integrate with SDCardManager
|
||||
return "example1.epub,example2.epub,example3.epub";
|
||||
}
|
||||
|
||||
void BleFileTransfer::handleControlCommand(const std::string& command) {
|
||||
Serial.printf("[%lu] [BLE] Control command: %s\n", millis(), command.c_str());
|
||||
|
||||
// Parse and handle commands
|
||||
// Commands could be: "LIST", "GET:filename", "PUT:filename", "DELETE:filename", etc.
|
||||
// For a full implementation, this would handle file operations via SDCardManager
|
||||
|
||||
if (command == "LIST") {
|
||||
// Refresh file list
|
||||
Serial.printf("[%lu] [BLE] Refreshing file list\n", millis());
|
||||
} else if (command.rfind("GET:", 0) == 0) {
|
||||
std::string filename = command.substr(4);
|
||||
Serial.printf("[%lu] [BLE] Request to download: %s\n", millis(), filename.c_str());
|
||||
// Would implement file read and send via pFileDataChar notifications
|
||||
} else if (command.rfind("PUT:", 0) == 0) {
|
||||
std::string filename = command.substr(4);
|
||||
Serial.printf("[%lu] [BLE] Request to upload: %s\n", millis(), filename.c_str());
|
||||
// Would implement file write from pFileDataChar writes
|
||||
}
|
||||
}
|
||||
|
||||
// Server callbacks
|
||||
void BleFileTransfer::ServerCallbacks::onConnect(BLEServer* pServer) {
|
||||
Serial.printf("[%lu] [BLE] Client connected (total: %u)\n", millis(), pServer->getConnectedCount());
|
||||
}
|
||||
|
||||
void BleFileTransfer::ServerCallbacks::onDisconnect(BLEServer* pServer) {
|
||||
Serial.printf("[%lu] [BLE] Client disconnected (total: %u)\n", millis(), pServer->getConnectedCount());
|
||||
// Restart advertising to allow new connections
|
||||
BLEDevice::startAdvertising();
|
||||
}
|
||||
|
||||
// Control callbacks
|
||||
void BleFileTransfer::ControlCallbacks::onWrite(BLECharacteristic* pCharacteristic) {
|
||||
std::string value = pCharacteristic->getValue();
|
||||
if (value.length() > 0) {
|
||||
parent->handleControlCommand(value);
|
||||
}
|
||||
}
|
||||
|
||||
// File list callbacks
|
||||
void BleFileTransfer::FileListCallbacks::onRead(BLECharacteristic* pCharacteristic) {
|
||||
std::string fileList = parent->getFileList();
|
||||
pCharacteristic->setValue(fileList);
|
||||
Serial.printf("[%lu] [BLE] File list requested (%zu bytes)\n", millis(), fileList.length());
|
||||
}
|
||||
77
src/bluetooth/BleFileTransfer.h
Normal file
77
src/bluetooth/BleFileTransfer.h
Normal file
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// BLE File Transfer Service
|
||||
// Provides file upload/download over Bluetooth Low Energy
|
||||
// Designed for memory-constrained ESP32-C3 environment
|
||||
class BleFileTransfer {
|
||||
public:
|
||||
BleFileTransfer();
|
||||
~BleFileTransfer();
|
||||
|
||||
// Start the BLE service
|
||||
bool begin(const std::string& deviceName = "CrossPoint-Reader");
|
||||
|
||||
// Stop the BLE service and free resources
|
||||
void stop();
|
||||
|
||||
// Check if service is running
|
||||
bool isRunning() const { return running; }
|
||||
|
||||
// Get number of connected clients
|
||||
uint32_t getConnectedCount() const;
|
||||
|
||||
private:
|
||||
bool running;
|
||||
BLEServer* pServer;
|
||||
BLEService* pFileService;
|
||||
BLECharacteristic* pFileListChar;
|
||||
BLECharacteristic* pFileDataChar;
|
||||
BLECharacteristic* pControlChar;
|
||||
|
||||
// Server callbacks
|
||||
class ServerCallbacks : public BLEServerCallbacks {
|
||||
public:
|
||||
ServerCallbacks(BleFileTransfer* parent) : parent(parent) {}
|
||||
void onConnect(BLEServer* pServer) override;
|
||||
void onDisconnect(BLEServer* pServer) override;
|
||||
|
||||
private:
|
||||
BleFileTransfer* parent;
|
||||
};
|
||||
|
||||
// Control characteristic callbacks
|
||||
class ControlCallbacks : public BLECharacteristicCallbacks {
|
||||
public:
|
||||
ControlCallbacks(BleFileTransfer* parent) : parent(parent) {}
|
||||
void onWrite(BLECharacteristic* pCharacteristic) override;
|
||||
|
||||
private:
|
||||
BleFileTransfer* parent;
|
||||
};
|
||||
|
||||
// File list characteristic callbacks
|
||||
class FileListCallbacks : public BLECharacteristicCallbacks {
|
||||
public:
|
||||
FileListCallbacks(BleFileTransfer* parent) : parent(parent) {}
|
||||
void onRead(BLECharacteristic* pCharacteristic) override;
|
||||
|
||||
private:
|
||||
BleFileTransfer* parent;
|
||||
};
|
||||
|
||||
void handleControlCommand(const std::string& command);
|
||||
std::string getFileList();
|
||||
|
||||
std::unique_ptr<ServerCallbacks> serverCallbacks;
|
||||
std::unique_ptr<ControlCallbacks> controlCallbacks;
|
||||
std::unique_ptr<FileListCallbacks> fileListCallbacks;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user