From 5457c8d8cdf82b585359649c603a40efc9604caa Mon Sep 17 00:00:00 2001 From: Timothy Werquin Date: Thu, 3 Oct 2024 21:56:24 +0200 Subject: [PATCH] Documentation updates WIP --- Readme.md | 4 +- {vendor/libYaft => apps/yaft}/Readme.md | 0 libs/rm2fb/Readme.md | 167 ++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) rename {vendor/libYaft => apps/yaft}/Readme.md (100%) diff --git a/Readme.md b/Readme.md index a51ced2..00d74df 100644 --- a/Readme.md +++ b/Readme.md @@ -8,7 +8,7 @@ Collection of reMarkable related apps, utilities and libraries. Projects -------- -### rm2fb +### [rm2fb](libs/rm2fb) [![2.15: supported](https://img.shields.io/badge/2.15-supported-brightgreen)](https://support.remarkable.com/s/article/Software-release-2-15-October-2022) [![3.3: supported](https://img.shields.io/badge/3.3-supported-brightgreen)](https://support.remarkable.com/s/article/Software-release-3-3) [![3.5: supported](https://img.shields.io/badge/3.5-supported-brightgreen)](https://support.remarkable.com/s/article/Software-release-3-5) @@ -31,7 +31,7 @@ More usage information can be found in the yaft [Readme](apps/yaft). ### Rocket -Launcher that uses the power button to show. +Launcher that uses the power button to toggle. diff --git a/vendor/libYaft/Readme.md b/apps/yaft/Readme.md similarity index 100% rename from vendor/libYaft/Readme.md rename to apps/yaft/Readme.md diff --git a/libs/rm2fb/Readme.md b/libs/rm2fb/Readme.md index c159c40..1a35180 100644 --- a/libs/rm2fb/Readme.md +++ b/libs/rm2fb/Readme.md @@ -1,6 +1,173 @@ reMarkable 2 - Framebuffer ========================== +SWTCON +------ + +The SWTCON is the software timing controller for the e-ink display in the +remarkable. It's used instead of a hardware one that's embedded in the iMX +processor. Its main job is to take in updates to the framebuffer and drive +the e-ink display with the correct voltages in the correct order to achieve +that change. These sequences are called waveforms, they depend on the +temperature, current state of the display and required speed. + +The SWTCON is embedded inside of xochtil, which means we have to 'hook' into it +to be able to draw to the screen from other apps. There are a few functions of +interest in xochitl: + * `createInstance`: Creates the QT EPDObject that owns the SWTCON state and the + software framebuffer (stored inside a QImage). + * `createThreads`: Called by `createInstance`, allocates the required buffers, + locks and semaphores and then starts the generator and vsync threads. + * `generatorThreadRoutine`: A thread that's responsible of taking in + framebuffer updates and generating update frames that will get sent to the + display. + * `vsyncThreadRoutine`: Takes in generated update frames and 'pans' the display + to show the with the correct timing. + * `waitForStartup`: Function called by create instance to wait for the SWTCON + threads to start. + +Of course I just made up the names of these functions based on their behaviour. +The exact implementation of these functions differs between versions, and +some are inlined into each other in later (3.5+) xochitl versions. + +
+ +In pseudo code these functions look like: + +```cpp +EPDObject* +createInstance() { + if (!QLockFile::tryLock("/tmp/epframebuffer.lock")) { + LogError(); + } + + QImage screenBuffer; + createThreads(screenBuffer.bits()); + + wait_for_startup(); + + puts("SWTCON initialized \\o/"); + + return new EPDObject(screenBuffer); +} + +void +wait_for_startup() { + // clear the framebuffer, not in later xochitl versions. + QImage::fill(param_1 + 0x20); + + // Post and wait until the global is flipped. + initGlobal = 1; + pthread_mutex_lock((pthread_mutex_t *)&DAT_008e4a6c); + pthread_cond_broadcast((pthread_cond_t *)&DAT_008e4a88); + pthread_mutex_unlock((pthread_mutex_t *)&DAT_008e4a6c); + + while (initGlobal == 1) { + usleep(1000); + } +} + +void +createThreads(void* buffer) { + allocateBuffers(buffer); // mallocs a backbuffer, memsets it, ... + loadWaveforms(); + + int fd = open("/dev/fb0"); + mmap(fd, ...); + ioctl(fd); // Set var info, get fix info, ... + + updateTemperature(); // Used to select correct waveform + + pthread_mutex_init(&VsyncMutex1, NULL); + pthread_mutex_init(&VsyncMutex2, NULL); + pthread_cond_init(&VsyncCond1, NULL); + + pthread_create(&VsyncPThread, NULL, vsyncThreadRoutine, NULL); + pthread_setname_np(VsyncPThread,"vsync-flip"); + setPriority(VsyncPThread,99); + + pthread_mutex_init(&GenMutex1,(pthread_mutexattr_t *)0x0); + pthread_mutex_init(&GenMutex2,(pthread_mutexattr_t *)0x0); + pthread_cond_init(&GenCond1,(pthread_condattr_t *)0x0); + + pthread_create(&GenPThread, NULL, generatorThreadRoutine, NULL); + pthread_setname_np(GenPThread,"framegen"); + setPriority(GenPThread,0x62); +} + +// Inlined into 'do_update' +void +updateGeneratorThread(void) + +{ + pthread_mutex_lock((pthread_mutex_t *)&GenMutex2); + updateGlobal = 0; + pthread_cond_broadcast((pthread_cond_t *)&GenCond1); + pthread_mutex_unlock((pthread_mutex_t *)&GenMutex2); + return; +} + + +int +do_update(UpdateParams* params) { + auto updateListElem = makeUpdate(params); + // There's some processing of the update here, and the affected area + // is copied to a separate buffer. + + bool syncFlagSet = params->updateFlags & 0x2; + pthread_mutex_lock(&GenMutex1); + // There's some of processing here. I suspect to combine consequtive + // overlapping updates. + std::list::push_back(GlobalList, updateListElem); + pthread_mutex_unlock(&GenMutex1); + + updateGeneratorThread(); + + if (syncFlagSet != 0) { + while (!std::list::empty()) { + usleep(1000); + } + } + + return 1; +} + +void +EPDObject::update(EPDObject *this, QRect *area, int waveform, int flags) +{ + auto rect = this->image.rect(); + rect &= area; + if ((rect.x0 <= rect.x1) && (rect.y0 <= rect.y1)) { + UpdateParams params; + switch(waveform) { + case 0: + case 3: + params.waveform = 2; + break; + default: + params.waveform = 0; + break; + case 2: + params.waveform = 3; + break; + case 4: + if (this->someFlag) { + params.waveform = 0; + } else { + params.waveform = 8; + } + break; + case 5: + params.waveform = 1; + } + params.updateFlags = flags; + do_update(¶ms); + } +} +``` +
+ + Waveform modes --------------