Login
1 branch 0 tags
Ben (Desktop/Arch) AGENTS.md b60dcff 29 days ago 82 Commits
moon / esp32 / main / backlight.c
#include "backlight.h"
#include "../src/moon.h"
#include "buttons.h"
#include "pinout.h"
#include "st7735.h"
#include "utils.h"

#include "driver/ledc.h"

#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO (PIN_LED)  // Pin 15
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT  // Resolution: 2^13 = 8192 levels
#define LEDC_FREQUENCY (8192)            // Frequency in Hertz

#define BRIGHTNESS_UPDATE_INTERVAL 12

static uint32_t backlight_last_update = 0;
static uint8_t backlight_goal = 0;
static uint8_t backlight_current = 0;

void backlight_init(void) {
	// 1. Prepare and then apply the LEDC PWM timer configuration
	ledc_timer_config_t ledc_timer = {.speed_mode = LEDC_MODE,
	                                  .timer_num = LEDC_TIMER,
	                                  .duty_resolution = LEDC_DUTY_RES,
	                                  .freq_hz = LEDC_FREQUENCY,
	                                  .clk_cfg = LEDC_AUTO_CLK};
	ledc_timer_config(&ledc_timer);

	// 2. Prepare and then apply the LEDC PWM channel configuration
	ledc_channel_config_t ledc_channel = {.speed_mode = LEDC_MODE,
	                                      .channel = LEDC_CHANNEL,
	                                      .timer_sel = LEDC_TIMER,
	                                      .intr_type = LEDC_INTR_DISABLE,
	                                      .gpio_num = LEDC_OUTPUT_IO,
	                                      .duty = 0,  // Start at 0% brightness
	                                      .hpoint = 0};
	ledc_channel_config(&ledc_channel);
}

void set_backlight_brightness(uint8_t level) {
	if (level == 0 && !st7735_is_sleeping()) {
		st7735_sleep();
	} else if (level > 0 && st7735_is_sleeping()) {
		st7735_wake();
	}

	uint32_t duty = (uint32_t)level << 5;

	ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty);
	ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
}

void update_backlight_brightness(void) {
	while (backlight_goal > DISPLAY_DIM_BRIGHTNESS &&
	       buttons_duration_released > DISPLAY_DIM_AFTER_MS_INACTIVITY) {
		buttons_duration_released -= DISPLAY_DIM_AFTER_MS_STEP;
		backlight_goal--;
	}

	while (backlight_goal > DISPLAY_SLEEP_BRIGHTNESS &&
	       buttons_duration_released > DISPLAY_SLEEP_AFTER_MS_INACTIVITY) {
		buttons_duration_released -= DISPLAY_SLEEP_AFTER_MS_STEP;
		backlight_goal--;
	}

	if (backlight_goal == backlight_current) {
		return;
	}

	const uint32_t now = get_millis();
	const uint8_t dir = (backlight_goal - backlight_current) > 0 ? 1 : -1;
	while ((backlight_last_update + BRIGHTNESS_UPDATE_INTERVAL) < now) {
		backlight_last_update += BRIGHTNESS_UPDATE_INTERVAL;
		backlight_current += dir;
		if (backlight_goal == backlight_current) {
			break;
		}
	}

	set_backlight_brightness(backlight_current);
}

void set_display_brightness(uint8_t level) {
	backlight_last_update = get_millis();
	backlight_goal = level;
}