Login
1 branch 0 tags
Ben (Desktop/Arch) lvgl 67cbd91 1 month ago 12 Commits
moon / firmware / sdl_src / main.c
#include <SDL.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "../src/main.h"
#include "../src/moon.h"
#include "../src/lvgl_port.h"

#define SCREEN_SCALE  4

static uint32_t framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT];
static float audio_phase = 0.0f;

// Audio callback - fill buf with your PCM data (signed 16-bit stereo)
static void audio_callback(void *userdata, uint8_t *buf, int len) {
	(void)userdata;
	int16_t *samples = (int16_t *)buf;
	int num_samples = len / sizeof(int16_t) / 2; // stereo

	// Simple 440Hz test tone
	float freq = 440.0f;
	float phase_inc = 2.0f * 3.14159f * freq / AUDIO_FREQ;

	for (int i = 0; i < num_samples; i++) {
		int16_t sample = (int16_t)(sinf(audio_phase) * 200);
		samples[i * 2]     = sample; // left
		samples[i * 2 + 1] = sample; // right
		audio_phase += phase_inc;
	}
}

void blit_buf(const void *buf, int yStartArg, int yEndArg) {
	const int yStart = MIN(SCREEN_HEIGHT, MAX(0,yStartArg));
	const int yEnd   = MIN(SCREEN_HEIGHT, MAX(yStart, yEndArg));

	const int size = (yEnd - yStart) * SCREEN_WIDTH * 4;
	void *fbStart = &framebuffer[yStart * SCREEN_WIDTH];
	memcpy(fbStart, buf, size);
}

int main(int argc, char *argv[]) {
	(void)argc;
	(void)argv;

	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
		SDL_Log("SDL_Init failed: %s", SDL_GetError());
		return 1;
	}

	SDL_Window *window = SDL_CreateWindow("Moon",
		SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
		SCREEN_WIDTH * SCREEN_SCALE, SCREEN_HEIGHT * SCREEN_SCALE,
		0);
	if (!window) {
		SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
		return 1;
	}

	SDL_Renderer *renderer = SDL_CreateRenderer(window, -1,
		SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
	if (!renderer) {
		SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
		return 1;
	}

	SDL_Texture *texture = SDL_CreateTexture(renderer,
		SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
		SCREEN_WIDTH, SCREEN_HEIGHT);
	if (!texture) {
		SDL_Log("SDL_CreateTexture failed: %s", SDL_GetError());
		return 1;
	}

	SDL_AudioSpec want = {
		.freq = AUDIO_FREQ,
		.format = AUDIO_S16SYS,
		.channels = 2,
		.samples = AUDIO_SAMPLES,
		.callback = audio_callback,
	};
	SDL_AudioSpec have;
	SDL_AudioDeviceID audio_dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
	if (!audio_dev) {
		SDL_Log("SDL_OpenAudioDevice failed: %s", SDL_GetError());
		return 1;
	}
	SDL_PauseAudioDevice(audio_dev, 0);

	// Initialize LVGL and display driver
	lvgl_port_init();

	bool running = true;
	Uint32 last_tick = SDL_GetTicks();

	setup();
	while (running) {
		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			if (event.type == SDL_QUIT) {
				running = false;
			} else if (event.type == SDL_KEYDOWN) {
				switch (event.key.keysym.sym) {
				case SDLK_ESCAPE:
					running = false;
					break;
				case SDLK_UP:
					button_state |= BUTTON_STATE_UP;
					break;
				case SDLK_DOWN:
					button_state |= BUTTON_STATE_DOWN;
					break;
				case SDLK_RETURN:
					button_state |= BUTTON_STATE_OK;
					break;
				case SDLK_BACKSPACE:
					button_state |= BUTTON_STATE_BACK;
					break;
				}
			} else if (event.type == SDL_KEYUP) {
				switch (event.key.keysym.sym) {
				case SDLK_UP:
					button_state &= ~BUTTON_STATE_UP;
					break;
				case SDLK_DOWN:
					button_state &= ~BUTTON_STATE_DOWN;
					break;
				case SDLK_RETURN:
					button_state &= ~BUTTON_STATE_OK;
					break;
				case SDLK_BACKSPACE:
					button_state &= ~BUTTON_STATE_BACK;
					break;
				}
			}
		}

		// Update LVGL tick
		Uint32 now = SDL_GetTicks();
		Uint32 elapsed = now - last_tick;
		last_tick = now;
		lv_tick_inc(elapsed);

		// Run application loop
		loop();

		// Handle LVGL tasks (includes rendering)
		lv_timer_handler();

		SDL_UpdateTexture(texture, NULL, framebuffer,
			SCREEN_WIDTH * sizeof(uint32_t));
		SDL_RenderClear(renderer);
		SDL_RenderCopy(renderer, texture, NULL, NULL);
		SDL_RenderPresent(renderer);
	}

	SDL_CloseAudioDevice(audio_dev);
	SDL_DestroyTexture(texture);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	SDL_Quit();
	return 0;
}