Close

A Much Needed Refactor

A project log for FLOSS Book Serving System

An open-source ereader that can display books from an open, self-hosted server

guyrandy-jean-gillesGuyrandy Jean-Gilles 10/20/2023 at 04:490 Comments

I'm still waiting on the latest hardware revision to manufacture, so in the mean time I've been refactoring the code to be more modular and follow separation of concerns. The requirement that forced this task was writing firmware for the GDEY042T81-FT02 touchscreen sub-assemblies from Good Display. Previously, the project relied on the structure of code from Waveshare for the GDEW042T2. Moving away from Waveshare's structure to thin abstractions will make porting Good Display's vendor code to this project much easier.

Here's an example. The project now has an abstraction layer for the e-paper aptly called "display.c/h" that contains the following function:


#include "gdew042t2.h"
...
static bool displayInit(void)
{
    if(!gdew042t2Init()){
    logError("Failed to initialize display");
        return 0;
    }
    ...
}

"display.c" is the only file that includes "gdew042t2.h" in the entire project. Any other source files that need display functions include "display.h". This way, I only need to modify "display.c" to port the project to GDEY042T81. If all goes well, none of the function declarations need to change once the port is complete.

The files "gdew042t2.c/h" contain the specific implementations for that e-paper display. For example, the above function "gdew042t2Init" contains:

#include "gpio.h"
...
bool gdew042t2Init(void)
{
    // setup GPIO
    gpioSetMode(RESET_PIN, GPIO_OUTPUT);
    gpioSetMode(DC_PIN, GPIO_OUTPUT);
    gpioSetMode(CS_PIN, GPIO_OUTPUT);
    gpioSetMode(POWER_PIN, GPIO_OUTPUT);
    gpioSetMode(BUSY_PIN, GPIO_INPUT);
    ...
}

 "gpio.h" is also an abstraction layer for low level GPIO manipulation. I.e the function "gpioSetMode" is:

#include "raspberrypi.h"
...
void gpioSetMode(uint32_t pin, uint8_t mode){
	return rpiGpioSetMode((uint8_t)pin, mode);
} 

If you guessed that "raspberrypi.h" was another abstraction layer, you're right. The above "gpioSetMode" is a thin wrapper for the bcm2835 library.

#include <bcm2835.h>
void rpiGpioSetMode(uint8_t pin, uint8_t mode)
{
	if (mode == RPI_GPIO_INPUT){
		bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
		return;
	}
	bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
}

It's abstraction layers all the way down! You might think this over kill, but code is read more than it's written. And I want to churn as little as possible. "raspberrypi.c/h" will probably never change for the rest of the project's history. "gdew042t2.c/h" will also probably never change again. Moving that code into separate files prevents churn and makes porting much easier as described above.

For the latest status updates please visit the project's Gitlab repository.

Discussions