mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 22:57:50 +03:00
add autoopen
This commit is contained in:
parent
6473689e3e
commit
2a1f7873f7
@ -24,11 +24,24 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void BluetoothActivity::taskTrampoline(void* param) {
|
||||
void BluetoothActivity::displayTaskTrampoline(void* param) {
|
||||
auto* self = static_cast<BluetoothActivity*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void BluetoothActivity::reportTaskTrampoline(void* param) {
|
||||
auto* self = static_cast<BluetoothActivity*>(param);
|
||||
self->report();
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
void BluetoothActivity::report() {
|
||||
if (state != STATE_DONE) {
|
||||
return;
|
||||
}
|
||||
onFileReceived(OUTPUT_DIRECTORY "/" + filename);
|
||||
}
|
||||
|
||||
void BluetoothActivity::startAdvertising() {
|
||||
NimBLEDevice::startAdvertising();
|
||||
}
|
||||
@ -65,7 +78,7 @@ void BluetoothActivity::onEnter() {
|
||||
state = STATE_INITIALIZING;
|
||||
intoState(STATE_WAITING);
|
||||
|
||||
xTaskCreate(&BluetoothActivity::taskTrampoline, "BluetoothTask",
|
||||
xTaskCreate(&BluetoothActivity::displayTaskTrampoline, "BluetoothTask",
|
||||
// TODO: figure out how much stack we actually need
|
||||
4096, // Stack size
|
||||
this, // Parameters
|
||||
@ -89,6 +102,16 @@ void BluetoothActivity::intoState(State newState) {
|
||||
// caller sets filename, totalBytes, file, txnId
|
||||
receivedBytes = 0;
|
||||
break;
|
||||
case STATE_DONE:
|
||||
// we cannot call onFileReceived here directly because it might cause onExit to be called,
|
||||
// which calls NimBLEDevice::deinit, which cannot be called from inside a NimBLE callback.
|
||||
xTaskCreate(&BluetoothActivity::reportTaskTrampoline, "BluetoothReportTask",
|
||||
2048, // Stack size
|
||||
this, // Parameters
|
||||
1, // Priority,
|
||||
nullptr
|
||||
);
|
||||
break;
|
||||
case STATE_ERROR:
|
||||
{
|
||||
// caller sets errorMessage
|
||||
@ -131,7 +154,7 @@ void BluetoothActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == STATE_ERROR) {
|
||||
if (state == STATE_ERROR || state == STATE_DONE) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
||||
// restart
|
||||
intoState(STATE_WAITING);
|
||||
@ -207,7 +230,7 @@ void BluetoothActivity::render() const {
|
||||
// Draw help text at bottom
|
||||
const auto labels = mappedInput.mapLabels(
|
||||
"« Back",
|
||||
(state == STATE_ERROR) ? "Restart" : "",
|
||||
(state == STATE_ERROR || state == STATE_DONE) ? "Restart" : "",
|
||||
"",
|
||||
""
|
||||
);
|
||||
@ -227,8 +250,9 @@ void BluetoothActivity::ServerCallbacks::onDisconnect(NimBLEServer* pServer, Nim
|
||||
}
|
||||
|
||||
void BluetoothActivity::onConnected(bool isConnected) {
|
||||
if (state == STATE_ERROR) {
|
||||
// stay in error state so the user can read the error message even after disconnect
|
||||
if (state == STATE_ERROR || state == STATE_DONE) {
|
||||
// stay in error state so the user can read the error message even after disconnect.
|
||||
// stay in done state so the user can see the transfer complete message.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -310,7 +334,6 @@ void BluetoothActivity::onRequest(lfbt_message* msg, size_t msg_len) {
|
||||
if (receivedBytes >= totalBytes) {
|
||||
PROTOCOL_ASSERT(receivedBytes == totalBytes, "Got more bytes than expected: %zu > %zu", receivedBytes, totalBytes);
|
||||
PROTOCOL_ASSERT(file.close(), "Couldn't finalize writing the file");
|
||||
// TODO: automatically open file in reader
|
||||
intoState(STATE_DONE);
|
||||
} else {
|
||||
intoState(STATE_RECEIVING);
|
||||
|
||||
@ -45,17 +45,22 @@ typedef struct __attribute__((packed)) {
|
||||
* BluetoothActivity receives files over a custom BLE protocol and stores them on the SD card.
|
||||
*
|
||||
* The onCancel callback is called if the user presses back.
|
||||
* onFileReceived is called when a file is successfully received with the path to the file.
|
||||
*/
|
||||
class BluetoothActivity final : public Activity {
|
||||
TaskHandle_t displayTaskHandle = nullptr;
|
||||
SemaphoreHandle_t renderingMutex = nullptr;
|
||||
bool updateRequired = false;
|
||||
const std::function<void()> onCancel;
|
||||
const std::function<void(const std::string&)> onFileReceived;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
static void displayTaskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void render() const;
|
||||
|
||||
static void reportTaskTrampoline(void* param);
|
||||
void report();
|
||||
|
||||
void onConnected(bool isConnected);
|
||||
void onRequest(lfbt_message *msg, size_t msg_len);
|
||||
|
||||
@ -113,8 +118,9 @@ class BluetoothActivity final : public Activity {
|
||||
|
||||
public:
|
||||
explicit BluetoothActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
const std::function<void()>& onCancel)
|
||||
: Activity("Bluetooth", renderer, mappedInput), onCancel(onCancel),
|
||||
const std::function<void()>& onCancel,
|
||||
const std::function<void(const std::string&)>& onFileReceived)
|
||||
: Activity("Bluetooth", renderer, mappedInput), onCancel(onCancel), onFileReceived(onFileReceived),
|
||||
serverCallbacks(this), requestCallbacks(this) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
|
||||
13
src/main.cpp
13
src/main.cpp
@ -26,6 +26,7 @@
|
||||
#include "activities/settings/SettingsActivity.h"
|
||||
#include "activities/util/FullScreenMessageActivity.h"
|
||||
#include "fontIds.h"
|
||||
#include "util/StringUtils.h"
|
||||
|
||||
#define SPI_FQ 40000000
|
||||
// Display SPI pins (custom pins for XteinkX4, not hardware SPI defaults)
|
||||
@ -229,7 +230,17 @@ void onGoToFileTransfer() {
|
||||
|
||||
void onGoToBluetooth() {
|
||||
exitActivity();
|
||||
enterNewActivity(new BluetoothActivity(renderer, mappedInputManager, onGoHome));
|
||||
enterNewActivity(new BluetoothActivity(
|
||||
renderer,
|
||||
mappedInputManager,
|
||||
onGoHome,
|
||||
[](const std::string& filepath) {
|
||||
Serial.printf("[%lu] [ ] File received over Bluetooth: %s\n", millis(), filepath.c_str());
|
||||
if (StringUtils::readableFileExtension(filepath)) {
|
||||
onGoToReader(filepath, MyLibraryActivity::Tab::Recent);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
void onGoToSettings() {
|
||||
|
||||
@ -61,6 +61,11 @@ bool checkFileExtension(const String& fileName, const char* extension) {
|
||||
return localFile.endsWith(localExtension);
|
||||
}
|
||||
|
||||
bool readableFileExtension(const std::string& fileName) {
|
||||
return (StringUtils::checkFileExtension(fileName, ".epub") || StringUtils::checkFileExtension(fileName, ".xtch") ||
|
||||
StringUtils::checkFileExtension(fileName, ".xtc") || StringUtils::checkFileExtension(fileName, ".txt"));
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> splitFileName(const std::string& name) {
|
||||
size_t lastDot = name.find_last_of('.');
|
||||
if (lastDot == std::string::npos) {
|
||||
|
||||
@ -19,6 +19,11 @@ std::string sanitizeFilename(const std::string& name, size_t maxLength = 100);
|
||||
bool checkFileExtension(const std::string& fileName, const char* extension);
|
||||
bool checkFileExtension(const String& fileName, const char* extension);
|
||||
|
||||
/**
|
||||
* Check if the given filename ends with an extension we can open.
|
||||
*/
|
||||
bool readableFileExtension(const std::string& fileName);
|
||||
|
||||
/**
|
||||
* Split a filename into base name and extension.
|
||||
* If there is no extension, the second element of the pair will be an empty string.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user