ref: 33858fb5e004863ff58b525ebf596a038bf849aa
dir: /src/main.c/
// Copyright 2021 Jonne Kokkonen
// Released under the MIT licence, https://opensource.org/licenses/MIT
/* Uncomment this line to enable debug messages or call make with `make
CFLAGS=-DDEBUG_MSG` */
// #define DEBUG_MSG
#include <SDL3/SDL.h>
#include <signal.h>
#include "SDL2_inprint.h"
#include "audio.h"
#include "backends/rtmidi.h"
#include "backends/serialport.h"
#include "command.h"
#include "config.h"
#include "gamecontrollers.h"
#include "input.h"
#include "render.h"
enum app_state app_state = WAIT_FOR_DEVICE;
// Handle CTRL+C / SIGINT, SIGKILL etc.
void signal_handler(int unused) { (void)unused; app_state = QUIT; }
int main(const int argc, char *argv[]) {
char *preferred_device = NULL;
unsigned char m8_connected = 0;
if (argc == 2 && SDL_strcmp(argv[1], "--list") == 0) {
return m8_list_devices();
}
if (argc == 3 && SDL_strcmp(argv[1], "--dev") == 0) {
preferred_device = argv[2];
SDL_Log("Using preferred device %s.\n", preferred_device);
}
char *config_filename = NULL;
if (argc == 3 && SDL_strcmp(argv[1], "--config") == 0) {
config_filename = argv[2];
SDL_Log("Using config file %s.\n", config_filename);
}
// Initialize the config to defaults
config_params_s conf = config_initialize(config_filename);
// Read in the params from the configfile if present
config_read(&conf);
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
#ifdef SIGQUIT
signal(SIGQUIT, signal_handler);
#endif
// First device detection to avoid SDL init if it isn't necessary. To be run
// only if we shouldn't wait for M8 to be connected.
if (conf.wait_for_device == 0) {
m8_connected = m8_connect(1, preferred_device);
if (m8_connected == 0) {
return 1;
}
}
// initialize all SDL systems
if (renderer_initialize(conf.init_fullscreen) == false) {
SDL_Quit();
return 1;
}
app_state = QUIT;
// initial scan for (existing) gamepads
gamecontrollers_initialize();
#ifndef NDEBUG
SDL_SetLogPriorities(SDL_LOG_PRIORITY_DEBUG);
SDL_LogDebug(SDL_LOG_CATEGORY_TEST,"Running a Debug build");
#endif
// main loop begin
do {
// try to init connection to M8
m8_connected = m8_connect(1, preferred_device);
if (m8_connected == 1 && enable_and_reset_display() == 1) {
if (conf.audio_enabled == 1) {
audio_initialize(conf.audio_device_name, conf.audio_buffer_size);
// if audio is enabled, reset the display for second time to avoid glitches
reset_display();
}
app_state = RUN;
} else {
SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected on initial check.");
if (conf.wait_for_device == 1) {
app_state = WAIT_FOR_DEVICE;
} else {
app_state = QUIT;
}
}
// wait until device is connected
if (conf.wait_for_device == 1) {
static Uint64 ticks_poll_device = 0;
static Uint64 ticks_update_screen = 0;
if (m8_connected == 0) {
screensaver_init();
}
while (app_state == WAIT_FOR_DEVICE) {
// get current input
const input_msg_s input = input_get_msg(&conf);
if (input.type == special && input.value == msg_quit) {
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Input message QUIT.");
app_state = QUIT;
}
if (SDL_GetTicks() - ticks_update_screen > 16) {
ticks_update_screen = SDL_GetTicks();
screensaver_draw();
render_screen();
}
// Poll for M8 device every second
if (m8_connected == 0 && SDL_GetTicks() - ticks_poll_device > 1000) {
ticks_poll_device = SDL_GetTicks();
if (app_state == WAIT_FOR_DEVICE && m8_connect(0, preferred_device) == 1) {
if (conf.audio_enabled == 1) {
if (audio_initialize(conf.audio_device_name, conf.audio_buffer_size) == 0) {
SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Cannot initialize audio");
conf.audio_enabled = 0;
}
}
const int result = enable_and_reset_display();
// Device was found; enable display and proceed to the main loop
if (result == 1) {
app_state = RUN;
m8_connected = 1;
screensaver_destroy();
} else {
SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected.");
app_state = QUIT;
screensaver_destroy();
}
}
}
SDL_Delay(conf.idle_ms);
}
} else {
// classic startup behaviour, exit if device is not found
if (m8_connected == 0) {
if (conf.audio_enabled == 1) {
audio_close();
}
gamecontrollers_close();
renderer_close();
inline_font_close();
SDL_Quit();
return -1;
}
}
// main loop
while (app_state == RUN) {
input_process(conf, &app_state);
const int result = process_serial(conf);
if (result == 0) {
// Device disconnected
m8_connected = 0;
app_state = WAIT_FOR_DEVICE;
audio_close();
} else if (result == -1) {
// Fatal error
app_state = QUIT;
}
render_screen();
SDL_Delay(conf.idle_ms);
}
} while (app_state > QUIT);
// Main loop end
// Exit, clean up
SDL_Log("Shutting down");
audio_close();
gamecontrollers_close();
renderer_close();
if (m8_connected == 1)
m8_close();
SDL_Quit();
return 0;
}