shithub: m8c

Download patch

ref: 8b427a838b845bd22138c344e96ec758f744fbea
parent: 2b6fc5bbfd99477a4a4da8088fc2f5e915816b5b
author: Jonne Kokkonen <jonne.kokkonen@gmail.com>
date: Sat Mar 22 07:11:09 EDT 2025

more unified function naming, move backends and fonts to their own directories

--- a/src/SDL2_inprint.h
+++ b/src/SDL2_inprint.h
@@ -4,13 +4,13 @@
 #ifndef SDL2_inprint_h
 #define SDL2_inprint_h
 
-#include "inline_font.h"
+#include "fonts/inline_font.h"
 #include <SDL3/SDL.h>
 
-extern void prepare_inline_font(struct inline_font *font);
-extern void kill_inline_font(void);
+extern void inline_font_initialize(struct inline_font *font);
+extern void inline_font_close(void);
 
-extern void inrenderer(SDL_Renderer *renderer);
+extern void inline_font_set_renderer(SDL_Renderer *renderer);
 extern void infont(SDL_Texture *font);
 extern void incolor1(const SDL_Color *color);
 extern void incolor(Uint32 color); /* Color must be in 0x00RRGGBB format ! */
--- a/src/audio.c
+++ b/src/audio.c
@@ -23,7 +23,7 @@
     SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
                  "Error getting available audio stream bytes: %s, destroying audio",
                  SDL_GetError());
-    audio_destroy();
+    audio_close();
     return;
   }
 
@@ -35,14 +35,14 @@
     SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
                  "Error getting available audio stream bytes: %s, destroying audio",
                  SDL_GetError());
-    audio_destroy();
+    audio_close();
   }
   SDL_free(src_audio_data);
 }
 
-void toggle_audio(const char *output_device_name, unsigned int audio_buffer_size) {
+void audio_toggle(const char *output_device_name, unsigned int audio_buffer_size) {
   if (!audio_initialized) {
-    audio_init(output_device_name, audio_buffer_size);
+    audio_initialize(output_device_name, audio_buffer_size);
     return;
   }
   if (audio_paused) {
@@ -56,7 +56,7 @@
   SDL_Log(audio_paused ? "Audio paused" : "Audio resumed");
 }
 
-int audio_init(const char *output_device_name, const unsigned int audio_buffer_size) {
+int audio_initialize(const char *output_device_name, const unsigned int audio_buffer_size) {
 
   // wait for system to initialize possible new audio devices
   SDL_Delay(500);
@@ -147,7 +147,7 @@
   return 1;
 }
 
-void audio_destroy() {
+void audio_close() {
   if (!audio_initialized)
     return;
   SDL_Log("Closing audio devices");
--- a/src/audio.h
+++ b/src/audio.h
@@ -3,9 +3,9 @@
 #ifndef AUDIO_H
 #define AUDIO_H
 
-int audio_init(const char *output_device_name, unsigned int audio_buffer_size);
-void toggle_audio(const char *output_device_name, unsigned int audio_buffer_size);
-void process_audio();
-void audio_destroy();
+int audio_initialize(const char *output_device_name, unsigned int audio_buffer_size);
+void audio_toggle(const char *output_device_name, unsigned int audio_buffer_size);
+void audio_process();
+void audio_close();
 
 #endif
--- /dev/null
+++ b/src/backends/queue.c
@@ -1,0 +1,55 @@
+#include "queue.h"
+#include <SDL3/SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Initialize the message queue
+void init_queue(message_queue_s *queue) {
+    queue->front = 0;
+    queue->rear = 0;
+    queue->mutex = SDL_CreateMutex();
+    queue->cond = SDL_CreateCondition();
+}
+
+void destroy_queue(message_queue_s *queue) {
+  SDL_DestroyMutex(queue->mutex);
+  SDL_DestroyCondition(queue->cond);
+}
+
+// Push a message to the queue
+void push_message(message_queue_s *queue, const unsigned char *message, size_t length) {
+    SDL_LockMutex(queue->mutex);
+
+    if ((queue->rear + 1) % MAX_QUEUE_SIZE == queue->front) {
+        SDL_LogError(SDL_LOG_CATEGORY_SYSTEM,"Queue is full, cannot add message.");
+    } else {
+        // Allocate space for the message and store it
+        queue->messages[queue->rear] = SDL_malloc(length);
+        SDL_memcpy(queue->messages[queue->rear], message, length);
+        queue->lengths[queue->rear] = length;
+        queue->rear = (queue->rear + 1) % MAX_QUEUE_SIZE;
+        SDL_SignalCondition(queue->cond);  // Signal consumer thread
+    }
+
+    SDL_UnlockMutex(queue->mutex);
+}
+
+// Pop a message from the queue
+unsigned char *pop_message(message_queue_s *queue, size_t *length) {
+  SDL_LockMutex(queue->mutex);
+
+  // Check if the queue is empty
+  if (queue->front == queue->rear) {
+    SDL_UnlockMutex(queue->mutex);
+    return NULL;  // Return NULL if there are no messages
+  }
+
+  // Otherwise, retrieve the message and its length
+  *length = queue->lengths[queue->front];
+  unsigned char *message = queue->messages[queue->front];
+  queue->front = (queue->front + 1) % MAX_QUEUE_SIZE;
+
+  SDL_UnlockMutex(queue->mutex);
+  return message;
+}
\ No newline at end of file
--- /dev/null
+++ b/src/backends/queue.h
@@ -1,0 +1,26 @@
+//
+// Created by jonne on 3/17/25.
+//
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+#include <SDL3/SDL.h>
+
+#define MAX_QUEUE_SIZE 4096
+
+typedef struct {
+  unsigned char *messages[MAX_QUEUE_SIZE];
+  size_t lengths[MAX_QUEUE_SIZE]; // Store lengths of each message
+  int front;
+  int rear;
+  SDL_Mutex *mutex;
+  SDL_Condition *cond;
+} message_queue_s;
+
+// Initialize the message queue
+void init_queue(message_queue_s *queue);
+unsigned char *pop_message(message_queue_s *queue, size_t *length);
+void push_message(message_queue_s *queue, const unsigned char *message, size_t length);
+
+#endif // QUEUE_H
--- /dev/null
+++ b/src/backends/ringbuffer.c
@@ -1,0 +1,55 @@
+#include "ringbuffer.h"
+#include <SDL3/SDL.h>
+
+RingBuffer *ring_buffer_create(uint32_t size) {
+  RingBuffer *rb = SDL_malloc(sizeof(*rb));
+  rb->buffer = SDL_malloc(sizeof(*rb->buffer) * size);
+  rb->head = 0;
+  rb->tail = 0;
+  rb->max_size = size;
+  rb->size = 0;
+  return rb;
+}
+
+void ring_buffer_free(RingBuffer *rb) {
+  SDL_free(rb->buffer);
+  SDL_free(rb);
+}
+
+uint32_t ring_buffer_empty(RingBuffer *rb) { return rb->size == 0; }
+
+uint32_t ring_buffer_full(RingBuffer *rb) { return rb->size == rb->max_size; }
+
+uint32_t ring_buffer_push(RingBuffer *rb, const uint8_t *data, uint32_t length) {
+  if (ring_buffer_full(rb)) {
+    return -1; // buffer full, push fails
+  }
+  uint32_t space1 = rb->max_size - rb->tail;
+  uint32_t n = length <= rb->max_size - rb->size ? length : rb->max_size - rb->size;
+  if (n <= space1) {
+    SDL_memcpy(rb->buffer + rb->tail, data, n);
+  } else {
+    SDL_memcpy(rb->buffer + rb->tail, data, space1);
+    SDL_memcpy(rb->buffer, data + space1, n - space1);
+  }
+  rb->tail = (rb->tail + n) % rb->max_size;
+  rb->size += n;
+  return n; // push successful, returns number of bytes pushed
+}
+
+uint32_t ring_buffer_pop(RingBuffer *rb, uint8_t *data, uint32_t length) {
+  if (ring_buffer_empty(rb)) {
+    return -1; // buffer empty, pop fails
+  }
+  uint32_t space1 = rb->max_size - rb->head;
+  uint32_t n = length <= rb->size ? length : rb->size;
+  if (n <= space1) {
+    SDL_memcpy(data, rb->buffer + rb->head, n);
+  } else {
+    SDL_memcpy(data, rb->buffer + rb->head, space1);
+    SDL_memcpy(data + space1, rb->buffer, n - space1);
+  }
+  rb->head = (rb->head + n) % rb->max_size;
+  rb->size -= n;
+  return n; // pop successful, returns number of bytes popped
+}
--- /dev/null
+++ b/src/backends/ringbuffer.h
@@ -1,0 +1,24 @@
+#ifndef M8C_RINGBUFFER_H
+#define M8C_RINGBUFFER_H
+
+#include <stdint.h>
+
+typedef struct {
+  uint8_t *buffer;
+  uint32_t head;
+  uint32_t tail;
+  uint32_t max_size;
+  uint32_t size;
+} RingBuffer;
+
+RingBuffer *ring_buffer_create(uint32_t size);
+
+uint32_t ring_buffer_empty(RingBuffer *rb);
+
+uint32_t ring_buffer_pop(RingBuffer *rb, uint8_t *data, uint32_t length);
+
+uint32_t ring_buffer_push(RingBuffer *rb, const uint8_t *data, uint32_t length);
+
+void ring_buffer_free(RingBuffer *rb);
+
+#endif // M8C_RINGBUFFER_H
--- /dev/null
+++ b/src/backends/rtmidi.c
@@ -1,0 +1,244 @@
+// Copyright 2021 Jonne Kokkonen
+// Released under the MIT licence, https://opensource.org/licenses/MIT
+#ifdef USE_RTMIDI
+
+#ifdef DEBUG
+#define RTMIDI_DEBUG
+#endif
+
+#include "rtmidi.h"
+#include "../command.h"
+#include "../config.h"
+#include "queue.h"
+#include <SDL3/SDL.h>
+#include <rtmidi_c.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+RtMidiInPtr midi_in;
+RtMidiOutPtr midi_out;
+message_queue_s queue;
+
+const unsigned char m8_sysex_header[5] = {0xF0, 0x00, 0x02, 0x61, 0x00};
+const unsigned int m8_sysex_header_size = sizeof(m8_sysex_header);
+const unsigned char sysex_message_end = 0xF7;
+
+bool message_is_m8_sysex(const unsigned char *message) {
+  if (memcmp(m8_sysex_header, message, m8_sysex_header_size) == 0) {
+    return true;
+  }
+  return false;
+}
+
+void midi_decode(const uint8_t *encoded_data, size_t length, uint8_t **decoded_data,
+                 size_t *decoded_length) {
+  if (length < m8_sysex_header_size) {
+    // Invalid data
+    *decoded_data = NULL;
+    *decoded_length = 0;
+    return;
+  }
+
+  // Skip header "F0 00 02 61" and the first MSB byte
+  size_t pos = m8_sysex_header_size + 1;
+
+  // Calculate expected output size (ignoring EOT if present)
+  const size_t expected_output_size =
+      (length - m8_sysex_header_size) - ((length - m8_sysex_header_size) / 8);
+  if (encoded_data[length - 1] == sysex_message_end) {
+    length--; // Ignore the EOT byte
+  }
+
+  // Allocate memory for decoded output
+  *decoded_data = (uint8_t *)SDL_malloc(expected_output_size);
+  if (*decoded_data == NULL) {
+    *decoded_length = 0;
+    return;
+  }
+
+  uint8_t bitCounter = 0;
+  uint8_t bitByteCounter = 0;
+  uint8_t *out = *decoded_data;
+  *decoded_length = 0;
+
+  while (pos < length) {
+    // Extract MSB from the "bit field" position
+    uint8_t msb = (encoded_data[bitByteCounter * 8 + m8_sysex_header_size] >> bitCounter) & 0x01;
+
+    // Extract LSB from data byte
+    uint8_t lsb = encoded_data[pos] & 0x7F;
+
+    // Reconstruct original byte, skipping the MSB bytes in output
+    *out = (msb << 7) | lsb;
+    out++;
+    (*decoded_length)++;
+
+    bitCounter++;
+    pos++;
+
+    if (bitCounter == 7) {
+      bitCounter = 0;
+      bitByteCounter++;
+      pos++; // Skip the MSB byte
+    }
+  }
+}
+
+static void midi_callback(double delta_time, const unsigned char *message, size_t message_size,
+                          void *user_data) {
+  if (message_size < 5 || !message_is_m8_sysex(message))
+    return;
+
+  unsigned char *decoded_data;
+  size_t decoded_length;
+  midi_decode(message, message_size, &decoded_data, &decoded_length);
+
+  // printf("Original data: ");
+  for (size_t i = 0; i < message_size; i++) {
+    // printf("%02X ", message[i]);
+  }
+
+  if (decoded_data) {
+    // printf("\nDecoded MIDI Data: ");
+    for (size_t i = 0; i < decoded_length; i++) {
+      // printf("%02X ", decoded_data[i]);
+    }
+    // printf("\n");
+    push_message(&queue, decoded_data, decoded_length);
+    SDL_free(decoded_data);
+  } else {
+    printf("Decoding failed.\n");
+  }
+}
+
+int initialize_rtmidi(void) {
+  SDL_Log("init rtmidi");
+  midi_in = rtmidi_in_create(RTMIDI_API_UNSPECIFIED, "m8c_in", 1024);
+  midi_out = rtmidi_out_create(RTMIDI_API_UNSPECIFIED, "m8c_out");
+  if (midi_in == NULL || midi_out == NULL) {
+    return 0;
+  }
+  return 1;
+}
+
+int m8_connect(const int verbose, const char *preferred_device) {
+
+  init_queue(&queue);
+
+  int midi_in_initialized = 0;
+  int midi_out_initialized = 0;
+
+  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "init_serial called");
+  if (midi_in == NULL || midi_out == NULL) {
+    initialize_rtmidi();
+  };
+  const unsigned int ports_total_in = rtmidi_get_port_count(midi_in);
+  if (verbose)
+    SDL_Log("Number of MIDI in ports: %d", ports_total_in);
+  for (unsigned int port_number = 0; port_number < ports_total_in; port_number++) {
+    int port_name_length_in;
+    rtmidi_get_port_name(midi_in, port_number, NULL, &port_name_length_in);
+    char port_name[port_name_length_in];
+    rtmidi_get_port_name(midi_in, port_number, &port_name[0], &port_name_length_in);
+    if (verbose)
+      SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "MIDI IN port %d, name: %s", port_number, port_name);
+    if (strncmp("M8", port_name, 2) == 0) {
+      if (verbose)
+        SDL_Log("Found M8 Input in MIDI port %d", port_number);
+      rtmidi_in_ignore_types(midi_in, false, true, true);
+      rtmidi_open_port(midi_in, port_number, "M8");
+      midi_in_initialized = 1;
+      rtmidi_open_port(midi_out, port_number, "M8");
+      midi_out_initialized = 1;
+    }
+  }
+  return (midi_in_initialized && midi_out_initialized);
+}
+
+int check_serial_port(void) {
+  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "check_serial_port called");
+  return 0;
+}
+
+int reset_display(void) {
+  SDL_Log("Reset display\n");
+  const unsigned char reset_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'R', 0xF7};
+  const int result = rtmidi_out_send_message(midi_out, &reset_sysex[0], sizeof(reset_sysex));
+  if (result != 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, code %d", result);
+    return 0;
+  }
+  return 1;
+}
+
+int enable_and_reset_display(void) {
+  rtmidi_in_set_callback(midi_in, midi_callback, NULL);
+  const unsigned char enable_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'E', 0xF7};
+  int result = rtmidi_out_send_message(midi_out, &enable_sysex[0], sizeof(enable_sysex));
+  if (result != 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to enable display");
+    return 0;
+  }
+  result = reset_display();
+  return result;
+}
+
+int disconnect(void) {
+  const unsigned char disconnect_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'D', 0xF7};
+  const int result =
+      rtmidi_out_send_message(midi_out, &disconnect_sysex[0], sizeof(disconnect_sysex));
+  if (result != 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to send disconnect");
+  }
+  SDL_Log("Freeing MIDI ports");
+  rtmidi_in_free(midi_in);
+  rtmidi_out_free(midi_out);
+  return !result;
+}
+
+int send_msg_controller(const unsigned char input) {
+  const unsigned char input_sysex[9] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'C', input, 0xF7};
+  const int result = rtmidi_out_send_message(midi_out, &input_sysex[0], sizeof(input_sysex));
+  if (result != 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to send key input message");
+    return 0;
+  }
+  return 1;
+}
+
+int send_msg_keyjazz(const unsigned char note, unsigned char velocity) {
+  if (velocity > 0x7F) {
+    velocity = 0x7F;
+  }
+  const unsigned char keyjazz_sysex[10] = {0xF0, 0x00, 0x02, 0x61,     0x00,
+                                           0x00, 'K',  note, velocity, 0xF7};
+  const int result = rtmidi_out_send_message(midi_out, &keyjazz_sysex[0], sizeof(keyjazz_sysex));
+  if (result != 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to send keyjazz input message");
+    return 0;
+  }
+  return 1;
+}
+
+int process_serial(config_params_s conf) {
+  unsigned char *command;
+  size_t length = 0;
+  while ((command = pop_message(&queue, &length)) != NULL) {
+    process_command(command, length);
+  }
+  return 1;
+}
+
+int m8_close() {
+  if (queue.mutex != NULL) {
+    SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Destroying command queue");
+    SDL_DestroyMutex(queue.mutex);
+    SDL_DestroyCondition(queue.cond);
+  }
+  return disconnect();
+}
+
+int m8_list_devices() {return 0;}
+
+#endif
--- /dev/null
+++ b/src/backends/rtmidi.h
@@ -1,0 +1,22 @@
+// Copyright 2021 Jonne Kokkonen
+// Released under the MIT licence, https://opensource.org/licenses/MIT
+#ifndef _MIDI_H_
+#define _MIDI_H_
+#ifdef USE_RTMIDI
+
+#include "../config.h"
+
+int initialize_rtmidi(void);
+int m8_connect(int verbose, const char *preferred_device);
+int m8_list_devices(void);
+int check_serial_port(void);
+int reset_display(void);
+int enable_and_reset_display(void);
+int disconnect(void);
+int send_msg_controller(const unsigned char input);
+int send_msg_keyjazz(const unsigned char note, unsigned char velocity);
+int process_serial(config_params_s conf);
+int m8_close();
+
+#endif
+#endif
\ No newline at end of file
--- /dev/null
+++ b/src/backends/serialport.c
@@ -1,0 +1,336 @@
+// Copyright 2021 Jonne Kokkonen
+// Released under the MIT licence, https://opensource.org/licenses/MIT
+
+// Contains portions of code from libserialport's examples released to the
+// public domain
+
+#ifdef USE_LIBSERIALPORT
+#include <SDL3/SDL.h>
+#include <libserialport.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../command.h"
+#include "../config.h"
+#include "serialport.h"
+#include "slip.h"
+
+struct sp_port *m8_port = NULL;
+// allocate memory for serial buffers
+static uint8_t serial_buffer[serial_read_size] = {0};
+static uint8_t slip_buffer[serial_read_size] = {0};
+static slip_handler_s slip;
+static uint16_t zero_byte_packets = 0; // used to detect device disconnection
+
+// Helper function for error handling
+static int check(enum sp_return result);
+
+static int detect_m8_serial_device(const struct sp_port *m8_port) {
+  // Check the connection method - we want USB serial devices
+  const enum sp_transport transport = sp_get_port_transport(m8_port);
+
+  if (transport == SP_TRANSPORT_USB) {
+    // Get the USB vendor and product IDs.
+    int usb_vid, usb_pid;
+    sp_get_port_usb_vid_pid(m8_port, &usb_vid, &usb_pid);
+
+    if (usb_vid == 0x16C0 && usb_pid == 0x048A)
+      return 1;
+  }
+
+  return 0;
+}
+
+int m8_list_devices() {
+  struct sp_port **port_list;
+  const enum sp_return result = sp_list_ports(&port_list);
+
+  if (result != SP_OK) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "sp_list_ports() failed!\n");
+    abort();
+  }
+
+  for (int i = 0; port_list[i] != NULL; i++) {
+    const struct sp_port *port = port_list[i];
+
+    if (detect_m8_serial_device(port)) {
+      SDL_Log("Found M8 device: %s", sp_get_port_name(port));
+    }
+  }
+
+  sp_free_port_list(port_list);
+  return 0;
+}
+
+// Checks for connected devices and whether the specified device still exists
+int check_serial_port() {
+
+  int device_found = 0;
+
+  /* A pointer to a null-terminated array of pointers to
+   * struct sp_port, which will contain the ports found.*/
+  struct sp_port **port_list;
+
+  /* Call sp_list_ports() to get the ports. The port_list
+   * pointer will be updated to refer to the array created. */
+  const enum sp_return result = sp_list_ports(&port_list);
+
+  if (result != SP_OK) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "sp_list_ports() failed!\n");
+    abort();
+  }
+
+  /* Iterate through the ports. When port_list[i] is NULL
+   * this indicates the end of the list. */
+  for (int i = 0; port_list[i] != NULL; i++) {
+    const struct sp_port *port = port_list[i];
+
+    if (detect_m8_serial_device(port)) {
+      if (strcmp(sp_get_port_name(port), sp_get_port_name(m8_port)) == 0)
+        device_found = 1;
+    }
+  }
+
+  sp_free_port_list(port_list);
+  return device_found;
+}
+
+int m8_connect(const int verbose, const char *preferred_device) {
+  if (m8_port != NULL) {
+    // Port is already initialized
+    return 1;
+  }
+
+  // settings for the slip packet handler
+  static const slip_descriptor_s slip_descriptor = {
+      .buf = slip_buffer,
+      .buf_size = sizeof(slip_buffer),
+      .recv_message = process_command, // the function where complete slip
+                                       // packets are processed further
+  };
+
+  slip_init(&slip, &slip_descriptor);
+
+  /* A pointer to a null-terminated array of pointers to
+   * struct sp_port, which will contain the ports found.*/
+  struct sp_port **port_list;
+
+  if (verbose)
+    SDL_Log("Looking for USB serial devices.\n");
+
+  /* Call sp_list_ports() to get the ports. The port_list
+   * pointer will be updated to refer to the array created. */
+  enum sp_return result = sp_list_ports(&port_list);
+
+  if (result != SP_OK) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "sp_list_ports() failed!\n");
+    abort();
+  }
+
+  /* Iterate through the ports. When port_list[i] is NULL
+   * this indicates the end of the list. */
+  for (int i = 0; port_list[i] != NULL; i++) {
+    const struct sp_port *port = port_list[i];
+
+    if (detect_m8_serial_device(port)) {
+      char *port_name = sp_get_port_name(port);
+      SDL_Log("Found M8 in %s.\n", port_name);
+      sp_copy_port(port, &m8_port);
+      if (preferred_device != NULL && strcmp(preferred_device, port_name) == 0) {
+        SDL_Log("Found preferred device, breaking");
+        break;
+      }
+    }
+  }
+
+  sp_free_port_list(port_list);
+
+  if (m8_port != NULL) {
+    // Open the serial port and configure it
+    SDL_Log("Opening port.");
+
+    result = sp_open(m8_port, SP_MODE_READ_WRITE);
+    if (check(result) != SP_OK)
+      return 0;
+
+    result = sp_set_baudrate(m8_port, 115200);
+    if (check(result) != SP_OK)
+      return 0;
+
+    result = sp_set_bits(m8_port, 8);
+    if (check(result) != SP_OK)
+      return 0;
+
+    result = sp_set_parity(m8_port, SP_PARITY_NONE);
+    if (check(result) != SP_OK)
+      return 0;
+
+    result = sp_set_stopbits(m8_port, 1);
+    if (check(result) != SP_OK)
+      return 0;
+
+    result = sp_set_flowcontrol(m8_port, SP_FLOWCONTROL_NONE);
+    if (check(result) != SP_OK)
+      return 0;
+  } else {
+    if (verbose) {
+      SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "Cannot find a M8.\n");
+    }
+    return 0;
+  }
+
+  return 1;
+}
+
+// Helper function for error handling.
+static int check(const enum sp_return result) {
+
+  char *error_message;
+
+  switch (result) {
+  case SP_ERR_ARG:
+    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid argument.\n");
+    break;
+  case SP_ERR_FAIL:
+    error_message = sp_last_error_message();
+    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Failed: %s\n", error_message);
+    sp_free_error_message(error_message);
+    break;
+  case SP_ERR_SUPP:
+    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Not supported.\n");
+    break;
+  case SP_ERR_MEM:
+    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Couldn't allocate memory.\n");
+    break;
+  case SP_OK:
+  default:
+    break;
+  }
+  return result;
+}
+
+int reset_display() {
+  SDL_Log("Reset display\n");
+
+  const char buf[1] = {'R'};
+  const int result = sp_blocking_write(m8_port, buf, 1, 5);
+  if (result != 1) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, code %d", result);
+    return 0;
+  }
+  return 1;
+}
+
+int enable_and_reset_display() {
+
+  SDL_Log("Enabling and resetting M8 display\n");
+
+  const char buf[1] = {'E'};
+  int result = sp_blocking_write(m8_port, buf, 1, 5);
+  if (result != 1) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error enabling M8 display, code %d", result);
+    return 0;
+  }
+
+  result = reset_display();
+
+  return result;
+}
+
+int disconnect() {
+
+  SDL_Log("Disconnecting M8\n");
+
+  const char buf[1] = {'D'};
+
+  int result = sp_blocking_write(m8_port, buf, 1, 5);
+  if (result != 1) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending disconnect, code %d", result);
+    result = 0;
+  }
+  sp_close(m8_port);
+  sp_free_port(m8_port);
+  m8_port = NULL;
+  return result;
+}
+
+int serial_read(uint8_t *serial_buf, const int count) {
+  return sp_nonblocking_read(m8_port, serial_buf, count);
+}
+
+int send_msg_controller(const uint8_t input) {
+  const char buf[2] = {'C', input};
+  const size_t nbytes = 2;
+  const int result = sp_blocking_write(m8_port, buf, nbytes, 5);
+  if (result != nbytes) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending input, code %d", result);
+    return -1;
+  }
+  return 1;
+}
+
+int send_msg_keyjazz(const uint8_t note, uint8_t velocity) {
+  if (velocity > 0x7F)
+    velocity = 0x7F;
+  const char buf[3] = {'K', note, velocity};
+  const size_t nbytes = 3;
+  const int result = sp_blocking_write(m8_port, buf, nbytes, 5);
+  if (result != nbytes) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending keyjazz, code %d", result);
+    return -1;
+  }
+
+  return 1;
+}
+
+int process_serial(config_params_s conf) {
+  while (1) {
+    // read serial port
+    const int bytes_read = serial_read(serial_buffer, serial_read_size);
+    if (bytes_read < 0) {
+      SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Error %d reading serial.", bytes_read);
+      disconnect();
+      return -1;
+      break;
+    }
+    if (bytes_read > 0) {
+      // input from device: reset the zero byte counter and create a
+      // pointer to the serial buffer
+      zero_byte_packets = 0;
+      const uint8_t *cur = serial_buffer;
+      const uint8_t *end = serial_buffer + bytes_read;
+      while (cur < end) {
+        // process the incoming bytes into commands and draw them
+        const int n = slip_read_byte(&slip, *cur++);
+        if (n != SLIP_NO_ERROR) {
+          if (n == SLIP_ERROR_INVALID_PACKET) {
+            reset_display();
+          } else {
+            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SLIP error %d\n", n);
+          }
+        }
+      }
+    } else {
+      // zero byte packet, increment counter
+      zero_byte_packets++;
+      if (zero_byte_packets > conf.wait_packets) {
+        zero_byte_packets = 0;
+
+        // try opening the serial port to check if it's alive
+        if (check_serial_port()) {
+          // the device is still there, carry on
+          break;
+        }
+        disconnect();
+        return 0;
+      }
+      break;
+    }
+  }
+  return 1;
+}
+
+int m8_close() {
+  return disconnect();
+}
+#endif
--- /dev/null
+++ b/src/backends/serialport.h
@@ -1,0 +1,27 @@
+// Copyright 2021 Jonne Kokkonen
+// Released under the MIT licence, https://opensource.org/licenses/MIT
+
+#ifndef _SERIAL_H_
+#define _SERIAL_H_
+#ifdef USE_LIBSERIALPORT
+
+#include "../config.h"
+#include <stdint.h>
+
+// maximum amount of bytes to read from the serial in one read()
+#define serial_read_size 1024
+
+int m8_connect(int verbose, const char *preferred_device);
+int m8_close();
+int m8_list_devices();
+int check_serial_port();
+int reset_display();
+int enable_and_reset_display();
+int disconnect();
+int serial_read(uint8_t *serial_buf, int count);
+int send_msg_controller(uint8_t input);
+int send_msg_keyjazz(uint8_t note, uint8_t velocity);
+int process_serial(config_params_s conf);
+
+#endif
+#endif
--- /dev/null
+++ b/src/backends/slip.c
@@ -1,0 +1,114 @@
+/*
+MIT License
+
+Copyright (c) 2018 Marcin Borowicz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/* This code is originally by marcinbor85, https://github.com/marcinbor85/slip
+It has been simplified a bit as CRC checking etc. is not required in this
+program. */
+
+#include "slip.h"
+
+#include <assert.h>
+#include <stddef.h>
+
+static void reset_rx(slip_handler_s *slip) {
+  assert(slip != NULL);
+
+  slip->state = SLIP_STATE_NORMAL;
+  slip->size = 0;
+}
+
+slip_error_t slip_init(slip_handler_s *slip, const slip_descriptor_s *descriptor) {
+  assert(slip != NULL);
+  assert(descriptor != NULL);
+  assert(descriptor->buf != NULL);
+  assert(descriptor->recv_message != NULL);
+
+  slip->descriptor = descriptor;
+  reset_rx(slip);
+
+  return SLIP_NO_ERROR;
+}
+
+static slip_error_t put_byte_to_buffer(slip_handler_s *slip, const uint8_t byte) {
+  slip_error_t error = SLIP_NO_ERROR;
+
+  assert(slip != NULL);
+
+  if (slip->size >= slip->descriptor->buf_size) {
+    error = SLIP_ERROR_BUFFER_OVERFLOW;
+    reset_rx(slip);
+  } else {
+    slip->descriptor->buf[slip->size++] = byte;
+    slip->state = SLIP_STATE_NORMAL;
+  }
+
+  return error;
+}
+
+slip_error_t slip_read_byte(slip_handler_s *slip, uint8_t byte) {
+  slip_error_t error = SLIP_NO_ERROR;
+
+  assert(slip != NULL);
+
+  switch (slip->state) {
+  case SLIP_STATE_NORMAL:
+    switch (byte) {
+    case SLIP_SPECIAL_BYTE_END:
+      if (!slip->descriptor->recv_message(slip->descriptor->buf, slip->size)) {
+        error = SLIP_ERROR_INVALID_PACKET;
+      }
+      reset_rx(slip);
+      break;
+    case SLIP_SPECIAL_BYTE_ESC:
+      slip->state = SLIP_STATE_ESCAPED;
+      break;
+    default:
+      error = put_byte_to_buffer(slip, byte);
+      break;
+    }
+    break;
+
+  case SLIP_STATE_ESCAPED:
+    switch (byte) {
+    case SLIP_ESCAPED_BYTE_END:
+      byte = SLIP_SPECIAL_BYTE_END;
+      break;
+    case SLIP_ESCAPED_BYTE_ESC:
+      byte = SLIP_SPECIAL_BYTE_ESC;
+      break;
+    default:
+      error = SLIP_ERROR_UNKNOWN_ESCAPED_BYTE;
+      reset_rx(slip);
+      break;
+    }
+
+    if (error != SLIP_NO_ERROR)
+      break;
+
+    error = put_byte_to_buffer(slip, byte);
+    break;
+  }
+
+  return error;
+}
--- /dev/null
+++ b/src/backends/slip.h
@@ -1,0 +1,67 @@
+/*
+MIT License
+
+Copyright (c) 2018 Marcin Borowicz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/* This code is originally by marcinbor85, https://github.com/marcinbor85/slip
+It has been simplified a bit as CRC checking etc. is not required in this
+program. */
+
+#ifndef SLIP_H_
+#define SLIP_H_
+
+#include <stdint.h>
+
+#define SLIP_SPECIAL_BYTE_END           0xC0
+#define SLIP_SPECIAL_BYTE_ESC           0xDB
+
+#define SLIP_ESCAPED_BYTE_END           0xDC
+#define SLIP_ESCAPED_BYTE_ESC           0xDD
+
+typedef enum {
+        SLIP_STATE_NORMAL = 0x00,
+        SLIP_STATE_ESCAPED
+} slip_state_t;
+
+typedef struct {
+        uint8_t *buf;
+        uint32_t buf_size;
+        int (*recv_message)(uint8_t *data, uint32_t size);
+} slip_descriptor_s;
+
+typedef struct {
+        slip_state_t state;
+        uint32_t size;
+        const slip_descriptor_s *descriptor;
+} slip_handler_s;
+
+typedef enum {
+        SLIP_NO_ERROR = 0x00,
+        SLIP_ERROR_BUFFER_OVERFLOW,
+        SLIP_ERROR_UNKNOWN_ESCAPED_BYTE,
+        SLIP_ERROR_INVALID_PACKET
+} slip_error_t;
+
+slip_error_t slip_init(slip_handler_s *slip, const slip_descriptor_s *descriptor);
+slip_error_t slip_read_byte(slip_handler_s *slip, uint8_t byte);
+
+#endif
\ No newline at end of file
--- /dev/null
+++ b/src/backends/usb.c
@@ -1,0 +1,361 @@
+// Copyright 2021 Jonne Kokkonen
+// Released under the MIT licence, https://opensource.org/licenses/MIT
+
+// Contains portions of code from libserialport's examples released to the
+// public domain
+#ifdef USE_LIBUSB
+
+#include <SDL3/SDL.h>
+#include <libusb.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int ep_out_addr = 0x03;
+static int ep_in_addr = 0x83;
+
+#define ACM_CTRL_DTR 0x01
+#define ACM_CTRL_RTS 0x02
+
+#define M8_VID 0x16c0
+#define M8_PID 0x048a
+
+libusb_context *ctx = NULL;
+libusb_device_handle *devh = NULL;
+
+static int do_exit = 0;
+
+int list_devices() {
+  int r;
+  r = libusb_init(&ctx);
+  if (r < 0) {
+    SDL_Log("libusb_init failed: %s", libusb_error_name(r));
+    return 0;
+  }
+
+  libusb_device **device_list = NULL;
+  int count = libusb_get_device_list(ctx, &device_list);
+  for (size_t idx = 0; idx < count; ++idx) {
+    libusb_device *device = device_list[idx];
+    struct libusb_device_descriptor desc;
+    int rc = libusb_get_device_descriptor(device, &desc);
+    if (rc < 0) {
+      SDL_Log("Error");
+      libusb_free_device_list(device_list, 1);
+      return rc;
+    }
+
+    if (desc.idVendor == M8_VID && desc.idProduct == M8_PID) {
+      SDL_Log("Found M8 device: %d:%d\n", libusb_get_port_number(device),
+              libusb_get_bus_number(device));
+    }
+  }
+  libusb_free_device_list(device_list, 1);
+  return 0;
+}
+
+int usb_loop(void *data) {
+  SDL_SetThreadPriority(SDL_THREAD_PRIORITY_TIME_CRITICAL);
+  while (!do_exit) {
+    int rc = libusb_handle_events(ctx);
+    if (rc != LIBUSB_SUCCESS) {
+      SDL_Log("Audio loop error: %s\n", libusb_error_name(rc));
+      break;
+    }
+  }
+  return 0;
+}
+
+static SDL_Thread *usb_thread;
+
+static void LIBUSB_CALL xfr_cb_in(struct libusb_transfer *transfer) {
+  int *completed = transfer->user_data;
+  *completed = 1;
+}
+
+int bulk_transfer(int endpoint, uint8_t *serial_buf, int count, unsigned int timeout_ms) {
+  if (devh == NULL) {
+    return -1;
+  }
+
+  int completed = 0;
+
+  struct libusb_transfer *transfer;
+  transfer = libusb_alloc_transfer(0);
+  libusb_fill_bulk_transfer(transfer, devh, endpoint, serial_buf, count, xfr_cb_in, &completed,
+                            timeout_ms);
+  int r = libusb_submit_transfer(transfer);
+
+  if (r < 0) {
+    SDL_Log("Error");
+    libusb_free_transfer(transfer);
+    return r;
+  }
+
+retry:
+  libusb_lock_event_waiters(ctx);
+  while (!completed) {
+    if (!libusb_event_handler_active(ctx)) {
+      libusb_unlock_event_waiters(ctx);
+      goto retry;
+    }
+    libusb_wait_for_event(ctx, NULL);
+  }
+  libusb_unlock_event_waiters(ctx);
+
+  int actual_length = transfer->actual_length;
+
+  libusb_free_transfer(transfer);
+
+  return actual_length;
+}
+
+int blocking_write(void *buf, int count, unsigned int timeout_ms) {
+  return bulk_transfer(ep_out_addr, buf, count, timeout_ms);
+}
+
+int serial_read(uint8_t *serial_buf, int count) {
+  return bulk_transfer(ep_in_addr, serial_buf, count, 1);
+}
+
+int check_serial_port() {
+  // Reading will fail anyway when the device is not present anymore
+  return 1;
+}
+
+int init_interface() {
+
+  if (devh == NULL) {
+    SDL_Log("Device not initialised!");
+    return 0;
+  }
+
+  int rc;
+
+  for (int if_num = 0; if_num < 2; if_num++) {
+    if (libusb_kernel_driver_active(devh, if_num)) {
+      SDL_Log("Detaching kernel driver for interface %d", if_num);
+      libusb_detach_kernel_driver(devh, if_num);
+    }
+    rc = libusb_claim_interface(devh, if_num);
+    if (rc < 0) {
+      SDL_Log("Error claiming interface: %s", libusb_error_name(rc));
+      return 0;
+    }
+  }
+
+  /* Start configuring the device:
+   * - set line state
+   */
+  SDL_Log("Setting line state");
+  rc = libusb_control_transfer(devh, 0x21, 0x22, ACM_CTRL_DTR | ACM_CTRL_RTS, 0, NULL, 0, 0);
+  if (rc < 0) {
+    SDL_Log("Error during control transfer: %s", libusb_error_name(rc));
+    return 0;
+  }
+
+  /* - set line encoding: here 115200 8N1
+   * 115200 = 0x01C200 ~> 0x00, 0xC2, 0x01, 0x00 in little endian
+   */
+  SDL_Log("Set line encoding");
+  unsigned char encoding[] = {0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08};
+  rc = libusb_control_transfer(devh, 0x21, 0x20, 0, 0, encoding, sizeof(encoding), 0);
+  if (rc < 0) {
+    SDL_Log("Error during control transfer: %s", libusb_error_name(rc));
+    return 0;
+  }
+
+  usb_thread = SDL_CreateThread(&usb_loop, "USB", NULL);
+
+  return 1;
+}
+
+int init_serial_with_file_descriptor(int file_descriptor) {
+  SDL_Log("Initialising serial with file descriptor");
+
+  if (file_descriptor <= 0) {
+    SDL_Log("Invalid file descriptor: %d", file_descriptor);
+    return 0;
+  }
+
+  int r;
+  r = libusb_set_option(NULL, LIBUSB_OPTION_NO_DEVICE_DISCOVERY, NULL);
+  if (r != LIBUSB_SUCCESS) {
+    SDL_Log("libusb_set_option failed: %s", libusb_error_name(r));
+    return 0;
+  }
+  r = libusb_init(&ctx);
+  if (r < 0) {
+    SDL_Log("libusb_init failed: %s", libusb_error_name(r));
+    return 0;
+  }
+  r = libusb_wrap_sys_device(ctx, (intptr_t)file_descriptor, &devh);
+  if (r < 0) {
+    SDL_Log("libusb_wrap_sys_device failed: %s", libusb_error_name(r));
+    return 0;
+  } else if (devh == NULL) {
+    SDL_Log("libusb_wrap_sys_device returned invalid handle");
+    return 0;
+  }
+  SDL_Log("USB device init success");
+
+  return init_interface();
+}
+
+int init_serial(int verbose, char *preferred_device) {
+
+  if (devh != NULL) {
+    return 1;
+  }
+
+  int r;
+  r = libusb_init(&ctx);
+  if (r < 0) {
+    SDL_Log("libusb_init failed: %s", libusb_error_name(r));
+    return 0;
+  }
+  if (preferred_device == NULL) {
+    devh = libusb_open_device_with_vid_pid(ctx, M8_VID, M8_PID);
+  } else {
+    char *port;
+    char *saveptr = NULL;
+    char *bus;
+    port = SDL_strtokr(preferred_device, ":", &saveptr);
+    bus = SDL_strtokr(NULL, ":", &saveptr);
+    libusb_device **device_list = NULL;
+    int count = libusb_get_device_list(ctx, &device_list);
+    for (size_t idx = 0; idx < count; ++idx) {
+      libusb_device *device = device_list[idx];
+      struct libusb_device_descriptor desc;
+      r = libusb_get_device_descriptor(device, &desc);
+      if (r < 0) {
+        SDL_Log("libusb_get_device_descriptor failed: %s", libusb_error_name(r));
+        libusb_free_device_list(device_list, 1);
+        return 0;
+      }
+
+      if (desc.idVendor == M8_VID && desc.idProduct == M8_PID) {
+        SDL_Log("Searching for port %s and bus %s", port, bus);
+        if (libusb_get_port_number(device) == SDL_atoi(port) &&
+            libusb_get_bus_number(device) == SDL_atoi(bus)) {
+          SDL_Log("Preferred device found, connecting");
+          r = libusb_open(device, &devh);
+          if (r < 0) {
+            SDL_Log("libusb_open failed: %s", libusb_error_name(r));
+            return 0;
+          }
+        }
+      }
+    }
+    libusb_free_device_list(device_list, 1);
+    if (devh == NULL) {
+      SDL_Log("Preferred device %s not found, using first available", preferred_device);
+      devh = libusb_open_device_with_vid_pid(ctx, M8_VID, M8_PID);
+    }
+  }
+  if (devh == NULL) {
+    SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM,
+                 "libusb_open_device_with_vid_pid returned invalid handle");
+    return 0;
+  }
+  SDL_Log("USB device init success");
+
+  return init_interface();
+}
+
+int reset_display() {
+  int result;
+
+  SDL_Log("Reset display\n");
+
+  char buf[1] = {'R'};
+
+  result = blocking_write(buf, 1, 5);
+  if (result != 1) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, code %d", result);
+    return 0;
+  }
+  return 1;
+}
+
+int enable_and_reset_display() {
+  int result;
+
+  SDL_Log("Enabling and resetting M8 display\n");
+
+  char buf[1] = {'E'};
+  result = blocking_write(buf, 1, 5);
+  if (result != 1) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error enabling M8 display, code %d", result);
+    return 0;
+  }
+
+  SDL_Delay(5);
+  result = reset_display();
+  return result;
+}
+
+int disconnect() {
+
+  char buf[1] = {'D'};
+  int result;
+
+  SDL_Log("Disconnecting M8\n");
+
+  result = blocking_write(buf, 1, 5);
+  if (result != 1) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending disconnect, code %d", result);
+    return -1;
+  }
+
+  int rc;
+
+  if (devh != NULL) {
+
+    for (int if_num = 0; if_num < 2; if_num++) {
+      rc = libusb_release_interface(devh, if_num);
+      if (rc < 0) {
+        SDL_Log("Error releasing interface: %s", libusb_error_name(rc));
+        return 0;
+      }
+    }
+
+    do_exit = 1;
+
+    libusb_close(devh);
+  }
+
+  SDL_WaitThread(usb_thread, NULL);
+
+  libusb_exit(ctx);
+
+  return 1;
+}
+
+int send_msg_controller(uint8_t input) {
+  char buf[2] = {'C', input};
+  int nbytes = 2;
+  int result;
+  result = blocking_write(buf, nbytes, 5);
+  if (result != nbytes) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending input, code %d", result);
+    return -1;
+  }
+  return 1;
+}
+
+int send_msg_keyjazz(uint8_t note, uint8_t velocity) {
+  if (velocity > 0x7F)
+    velocity = 0x7F;
+  char buf[3] = {'K', note, velocity};
+  int nbytes = 3;
+  int result;
+  result = blocking_write(buf, nbytes, 5);
+  if (result != nbytes) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending keyjazz, code %d", result);
+    return -1;
+  }
+
+  return 1;
+}
+
+#endif
--- /dev/null
+++ b/src/backends/usb.h
@@ -1,0 +1,9 @@
+#ifndef M8C_USB_H_
+#define M8C_USB_H_
+#ifdef USE_LIBUSB
+
+#include <libusb.h>
+extern libusb_device_handle *devh;
+int init_serial_with_file_descriptor(int file_descriptor);
+#endif // USE_LIBUSB
+#endif // M8C_USB_H_
--- /dev/null
+++ b/src/backends/usb_audio.c
@@ -1,0 +1,200 @@
+#ifdef USE_LIBUSB
+
+#include "ringbuffer.h"
+#include "usb.h"
+#include <SDL3/SDL.h>
+#include <errno.h>
+#include <libusb.h>
+
+#define EP_ISO_IN 0x85
+#define IFACE_NUM 4
+
+#define NUM_TRANSFERS 64
+#define PACKET_SIZE 180
+#define NUM_PACKETS 2
+
+SDL_AudioDeviceID sdl_audio_device_id = 0;
+RingBuffer *audio_buffer = NULL;
+
+static void audio_callback(void *userdata, Uint8 *stream, int len) {
+  uint32_t read_len = ring_buffer_pop(audio_buffer, stream, len);
+
+  if (read_len == -1) {
+    SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Buffer underflow!");
+  }
+
+  // If we didn't read the full len bytes, fill the rest with zeros
+  if (read_len < len) {
+    SDL_memset(&stream[read_len], 0, len - read_len);
+  }
+}
+
+static void cb_xfr(struct libusb_transfer *xfr) {
+  unsigned int i;
+
+  for (i = 0; i < xfr->num_iso_packets; i++) {
+    struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
+
+    if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
+      SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "XFR callback error (status %d: %s)", pack->status,
+                   libusb_error_name(pack->status));
+      /* This doesn't happen, so bail out if it does. */
+      return;
+    }
+
+    const uint8_t *data = libusb_get_iso_packet_buffer_simple(xfr, i);
+    if (sdl_audio_device_id != 0) {
+      uint32_t actual = ring_buffer_push(audio_buffer, data, pack->actual_length);
+      if (actual == -1) {
+        SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Buffer overflow!");
+      }
+    }
+  }
+
+  if (libusb_submit_transfer(xfr) < 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "error re-submitting URB\n");
+    SDL_free(xfr->buffer);
+  }
+}
+
+static struct libusb_transfer *xfr[NUM_TRANSFERS];
+
+static int benchmark_in() {
+  int i;
+
+  for (i = 0; i < NUM_TRANSFERS; i++) {
+    xfr[i] = libusb_alloc_transfer(NUM_PACKETS);
+    if (!xfr[i]) {
+      SDL_Log("Could not allocate transfer");
+      return -ENOMEM;
+    }
+
+    Uint8 *buffer = SDL_malloc(PACKET_SIZE * NUM_PACKETS);
+
+    libusb_fill_iso_transfer(xfr[i], devh, EP_ISO_IN, buffer, PACKET_SIZE * NUM_PACKETS,
+                             NUM_PACKETS, cb_xfr, NULL, 0);
+    libusb_set_iso_packet_lengths(xfr[i], PACKET_SIZE);
+
+    libusb_submit_transfer(xfr[i]);
+  }
+
+  return 1;
+}
+
+int audio_init(int audio_buffer_size, const char *output_device_name) {
+  SDL_Log("USB audio setup");
+
+  int rc;
+
+  rc = libusb_kernel_driver_active(devh, IFACE_NUM);
+  if (rc == 1) {
+    SDL_Log("Detaching kernel driver");
+    rc = libusb_detach_kernel_driver(devh, IFACE_NUM);
+    if (rc < 0) {
+      SDL_Log("Could not detach kernel driver: %s\n", libusb_error_name(rc));
+      return rc;
+    }
+  }
+
+  rc = libusb_claim_interface(devh, IFACE_NUM);
+  if (rc < 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error claiming interface: %s\n", libusb_error_name(rc));
+    return rc;
+  }
+
+  rc = libusb_set_interface_alt_setting(devh, IFACE_NUM, 1);
+  if (rc < 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error setting alt setting: %s\n", libusb_error_name(rc));
+    return rc;
+  }
+
+  if (!SDL_WasInit(SDL_INIT_AUDIO)) {
+    if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
+      SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Init audio failed %s", SDL_GetError());
+      return -1;
+    }
+  } else {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Audio was already initialised");
+  }
+
+  static SDL_AudioSpec audio_spec;
+  audio_spec.format = AUDIO_S16;
+  audio_spec.channels = 2;
+  audio_spec.freq = 44100;
+  audio_spec.samples = audio_buffer_size;
+  audio_spec.callback = audio_callback;
+
+  SDL_AudioSpec _obtained;
+  SDL_zero(_obtained);
+
+  SDL_Log("Current audio driver is %s and device %s", SDL_GetCurrentAudioDriver(),
+          output_device_name);
+
+  if (SDL_strcasecmp(SDL_GetCurrentAudioDriver(), "openslES") == 0 || output_device_name == NULL) {
+    SDL_Log("Using default audio device");
+    sdl_audio_device_id = SDL_OpenAudioDevice(NULL, 0, &audio_spec, &_obtained, 0);
+  } else {
+    sdl_audio_device_id = SDL_OpenAudioDevice(output_device_name, 0, &audio_spec, &_obtained, 0);
+  }
+
+  audio_buffer = ring_buffer_create(4 * _obtained.size);
+
+  SDL_Log("Obtained audio spec. Sample rate: %d, channels: %d, samples: %d, size: %d",
+          _obtained.freq, _obtained.channels, _obtained.samples, +_obtained.size);
+
+  SDL_PauseAudioDevice(sdl_audio_device_id, 0);
+
+  // Good to go
+  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Starting capture");
+  if ((rc = benchmark_in()) < 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Capture failed to start: %d", rc);
+    return rc;
+  }
+
+  SDL_Log("Successful init");
+  return 1;
+}
+
+int audio_destroy() {
+  if (devh == NULL) {
+    return -1;
+  }
+
+  SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "Closing audio");
+
+  int i, rc;
+
+  for (i = 0; i < NUM_TRANSFERS; i++) {
+    rc = libusb_cancel_transfer(xfr[i]);
+    if (rc < 0) {
+      SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error cancelling transfer: %s\n",
+                   libusb_error_name(rc));
+    }
+  }
+
+  SDL_Log("Freeing interface %d", IFACE_NUM);
+
+  rc = libusb_release_interface(devh, IFACE_NUM);
+  if (rc < 0) {
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error releasing interface: %s\n", libusb_error_name(rc));
+    return rc;
+  }
+
+  if (sdl_audio_device_id != 0) {
+    SDL_Log("Closing audio device %d", sdl_audio_device_id);
+    SDL_AudioDeviceID device = sdl_audio_device_id;
+    sdl_audio_device_id = 0;
+    SDL_CloseAudioDevice(device);
+  }
+
+  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Audio closed");
+
+  ring_buffer_free(audio_buffer);
+  return 1;
+}
+
+void toggle_audio(unsigned int audio_buffer_size, const char *output_device_name) {
+  SDL_Log("Libusb audio toggling not implemented yet");
+}
+
+#endif
--- a/src/command.c
+++ b/src/command.c
@@ -168,7 +168,7 @@
       set_m8_model(0);
     }
 
-    set_font_mode(recv_buf[5]);
+    renderer_set_font_mode(recv_buf[5]);
 
     return 1;
   }
--- a/src/config.c
+++ b/src/config.c
@@ -19,7 +19,7 @@
   }
 }
 
-config_params_s init_config(char *filename) {
+config_params_s config_initialize(char *filename) {
   config_params_s c;
 
   if (filename == NULL) {
@@ -182,7 +182,7 @@
 }
 
 // Read config
-void read_config(config_params_s *conf) {
+void config_read(config_params_s *conf) {
 
   char config_path[1024] = {0};
   snprintf(config_path, sizeof(config_path), "%s%s", SDL_GetPrefPath("", "m8c"), conf->filename);
--- a/src/config.h
+++ b/src/config.h
@@ -58,8 +58,8 @@
 
 } config_params_s;
 
-config_params_s init_config(char *filename);
-void read_config(config_params_s *conf);
+config_params_s config_initialize(char *filename);
+void config_read(config_params_s *conf);
 void read_audio_config(const ini_t *ini, config_params_s *conf);
 void read_graphics_config(const ini_t *ini, config_params_s *conf);
 void read_key_config(const ini_t *ini, config_params_s *conf);
--- a/src/font1.h
+++ /dev/null
@@ -1,56 +1,0 @@
-#ifndef FONT1_H_
-#define FONT1_H_
-
-#include "inline_font.h"
-
-struct inline_font font_v1_small = {
-    470,
-    7,
-    5,
-    7,
-    0,
-    0,
-    3,
-    24,
-    566,
-    {
-        0x42, 0x4D, 0x36, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
-        0x00, 0x00, 0x00, 0xD6, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
-        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
-        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x80, 0x00, 0x40, 0x34,
-        0x01, 0x80, 0x00, 0x40, 0x12, 0x1F, 0xFF, 0xFE, 0x1F, 0xFC, 0x9E, 0x08, 0x10, 0x00, 0x00,
-        0x8E, 0x8F, 0x9D, 0xEF, 0xC1, 0xD1, 0xFB, 0xA3, 0xF8, 0xC5, 0xD0, 0x6C, 0x7C, 0x47, 0x12,
-        0x31, 0xF7, 0xC6, 0x1C, 0x03, 0xE0, 0xFF, 0xFF, 0xFF, 0x93, 0xF1, 0x77, 0x22, 0xEA, 0xC7,
-        0xF0, 0x0C, 0x3E, 0x7F, 0xE3, 0xF1, 0xFF, 0xFE, 0x4F, 0x80, 0x00, 0x00, 0x15, 0xF9, 0xC8,
-        0x02, 0x40, 0x08, 0x40, 0x02, 0x11, 0x24, 0x02, 0x10, 0xC4, 0x91, 0x0A, 0x10, 0x20, 0x20,
-        0x10, 0x8C, 0x63, 0x18, 0x42, 0x31, 0x24, 0x65, 0x08, 0xC6, 0x30, 0x94, 0x42, 0x48, 0xAB,
-        0x71, 0x0C, 0x04, 0x14, 0x00, 0x00, 0x8C, 0x61, 0x18, 0x10, 0x31, 0x20, 0xB4, 0x4A, 0xC6,
-        0x3F, 0xFC, 0x02, 0x48, 0xD2, 0xAA, 0x0A, 0x22, 0x48, 0x80, 0x00, 0x80, 0x3E, 0x55, 0xD4,
-        0x02, 0x40, 0x08, 0x00, 0x01, 0x19, 0x24, 0x02, 0x10, 0xC4, 0x91, 0x08, 0x00, 0x6F, 0xB0,
-        0x97, 0x8C, 0x61, 0x18, 0x42, 0x71, 0x24, 0x69, 0x08, 0xC6, 0x30, 0xAC, 0x82, 0x48, 0xAA,
-        0xAA, 0x0A, 0x04, 0x24, 0x00, 0x00, 0xFC, 0x61, 0x1F, 0x93, 0xF1, 0x20, 0xA8, 0x4A, 0xC6,
-        0x31, 0x8C, 0x3E, 0x48, 0xCA, 0xA4, 0xF9, 0x22, 0x48, 0x80, 0x00, 0x80, 0x15, 0xF2, 0x24,
-        0x02, 0x42, 0xBE, 0x0F, 0x80, 0x95, 0x27, 0xFF, 0xFF, 0xFC, 0x5F, 0xF8, 0x00, 0xE0, 0x38,
-        0x55, 0xFF, 0xA1, 0x1F, 0x7A, 0x1F, 0x20, 0x71, 0x08, 0xCE, 0x3E, 0x8F, 0x9C, 0x48, 0xC6,
-        0x24, 0x79, 0x04, 0x44, 0x00, 0x00, 0x0C, 0x61, 0x18, 0x92, 0x31, 0x20, 0xA4, 0x4A, 0xC6,
-        0x31, 0x8C, 0x20, 0x48, 0xC6, 0xAA, 0x88, 0xA2, 0x4A, 0x80, 0x00, 0x80, 0x3F, 0x4D, 0x50,
-        0x02, 0x41, 0x08, 0x00, 0x00, 0x53, 0x20, 0x43, 0x18, 0x40, 0x31, 0x8A, 0x10, 0x6F, 0xB0,
-        0x37, 0x8C, 0x61, 0x18, 0x42, 0x11, 0x20, 0x69, 0x0A, 0xD6, 0x31, 0x8C, 0x60, 0x48, 0xC6,
-        0x2A, 0x88, 0x84, 0x84, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, 0xA2, 0x4F, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xF8, 0xC6, 0xB1, 0x8F, 0xE2, 0x48, 0xD8, 0x00, 0x82, 0x95, 0xFC, 0xC8,
-        0x82, 0x42, 0x88, 0x00, 0x00, 0x31, 0xE0, 0x43, 0x18, 0x40, 0x31, 0x88, 0x00, 0x20, 0x22,
-        0x31, 0x8C, 0x63, 0x18, 0x42, 0x31, 0x20, 0x65, 0x0D, 0xE6, 0x31, 0x8C, 0x60, 0x48, 0xC6,
-        0x31, 0x88, 0x45, 0x04, 0x28, 0x04, 0x04, 0x00, 0x10, 0x10, 0x10, 0x00, 0x20, 0x40, 0x00,
-        0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x48, 0xA4, 0x00, 0x82, 0x80, 0x40, 0x30,
-        0x81, 0x80, 0x00, 0x00, 0x00, 0x3F, 0x27, 0xFF, 0x1F, 0xFF, 0xEF, 0xF8, 0x00, 0x00, 0x01,
-        0xCE, 0x77, 0x9D, 0xEF, 0xFD, 0xD1, 0xF8, 0x63, 0x08, 0xC5, 0xDE, 0x77, 0x9F, 0xF8, 0xC6,
-        0x31, 0x8F, 0xC7, 0x0C, 0x10, 0x08, 0x04, 0x00, 0x10, 0x1C, 0x10, 0x20, 0xA0, 0xC0, 0x00,
-        0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3E, 0x4F, 0x80, 0x00,
-    }};
-#endif // FONT1_H_
\ No newline at end of file
--- a/src/font2.h
+++ /dev/null
@@ -1,85 +1,0 @@
-#ifndef FONT2_H_
-#define FONT2_H_
-#include "inline_font.h"
-
-struct inline_font font_v1_large = {
-    752,
-    9,
-    8,
-    9,
-    0,
-    -40,
-    4,
-    22,
-    1010,
-    {
-        0x42, 0x4D, 0xF2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
-        0x00, 0x00, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
-        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
-        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xFF, 0xFF, 0xE7,
-        0x7D, 0x84, 0xFF, 0xFC, 0x9F, 0xFF, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x00, 0x00, 0x00, 0x00,
-        0xFC, 0x00, 0x00, 0xE7, 0x01, 0xFC, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xE7, 0x81, 0x3C, 0x01,
-        0x81, 0x03, 0x00, 0x3F, 0x81, 0x3C, 0x00, 0x81, 0x3C, 0x00, 0x3C, 0x3C, 0x81, 0x3F, 0x84,
-        0x3C, 0x81, 0xE7, 0x81, 0xE7, 0x3C, 0x3C, 0xE7, 0x00, 0xF0, 0xFF, 0x0F, 0xFF, 0x80, 0xFF,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x24, 0x3C, 0x00,
-        0x3F, 0xFC, 0x3F, 0x00, 0x80, 0x00, 0x3F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xE7, 0x00, 0xFF,
-        0x00, 0x00, 0xFF, 0xFF, 0xDB, 0x00, 0x38, 0x39, 0xFF, 0xF9, 0xCF, 0xFF, 0xFF, 0xCF, 0xFF,
-        0xFF, 0x3F, 0x3C, 0xE7, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C, 0xE7, 0x3C, 0xFC, 0xFF, 0x9F, 0xFC,
-        0xFF, 0x9F, 0xFF, 0x3F, 0x3C, 0x3C, 0x3C, 0x39, 0x3F, 0x3F, 0x3C, 0x3C, 0xE7, 0x3C, 0x39,
-        0x3F, 0x3C, 0x3C, 0x3C, 0x3F, 0x39, 0x39, 0x3C, 0xE7, 0x3C, 0xC3, 0x18, 0x3C, 0xE7, 0x3F,
-        0xF3, 0xFC, 0xCF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3F, 0x3C, 0x3F, 0x9F, 0xFC, 0x3C, 0xE7,
-        0xFC, 0x39, 0xCF, 0x24, 0x3C, 0x3C, 0x3F, 0xFC, 0x3F, 0xFC, 0x9F, 0x3C, 0x1F, 0x24, 0x99,
-        0xFC, 0x9F, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x81, 0xE4, 0x9D, 0x30, 0xFF,
-        0xF3, 0xE7, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0x9F, 0x3C, 0xE7, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C,
-        0xE7, 0x3C, 0xFC, 0xE7, 0x9F, 0xF8, 0x81, 0x8F, 0xE7, 0x21, 0x3C, 0x3C, 0x3F, 0x3C, 0x3F,
-        0x3F, 0x3C, 0x3C, 0xE7, 0x3C, 0x33, 0x3F, 0x3C, 0x3C, 0x3C, 0x3F, 0x32, 0x33, 0xFC, 0xE7,
-        0x3C, 0x99, 0x00, 0x99, 0xE7, 0x9F, 0xF3, 0xF9, 0xCF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3F,
-        0x3C, 0x3F, 0x9F, 0xFC, 0x3C, 0xE7, 0xFC, 0x33, 0xCF, 0x24, 0x3C, 0x3C, 0x3F, 0xFC, 0x3F,
-        0xFC, 0x9F, 0x3C, 0x0F, 0x24, 0xC3, 0xFC, 0xCF, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF,
-        0xFF, 0xDB, 0xE4, 0xCF, 0x87, 0xFF, 0xF3, 0xE7, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xCF, 0x3C,
-        0xE7, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C, 0xE7, 0x3C, 0xFC, 0xFF, 0xFF, 0xF0, 0xFF, 0x87, 0xE7,
-        0x24, 0x3C, 0x3C, 0x3F, 0x3C, 0x3F, 0x3F, 0x3C, 0x3C, 0xE7, 0xFC, 0x27, 0x3F, 0x3C, 0x38,
-        0x3C, 0x3F, 0x24, 0x27, 0xFC, 0xE7, 0x3C, 0x3C, 0x24, 0xC3, 0xE7, 0xCF, 0xF3, 0xF3, 0xCF,
-        0xFF, 0xFF, 0xFF, 0x00, 0x3C, 0x3F, 0x3C, 0x00, 0x9F, 0x00, 0x3C, 0xE7, 0xFC, 0x07, 0xCF,
-        0x24, 0x3C, 0x3C, 0x00, 0x00, 0x3F, 0x00, 0x9F, 0x3C, 0x27, 0x24, 0xE7, 0x00, 0xE7, 0x3C,
-        0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF, 0xFF, 0xDB, 0x00, 0xE7, 0xC7, 0xFF, 0xF3, 0xE7, 0x33,
-        0x81, 0xFF, 0x81, 0xFF, 0xE7, 0x24, 0xE7, 0x00, 0x80, 0x00, 0x00, 0x00, 0xF3, 0x81, 0x00,
-        0xFF, 0xFF, 0xE0, 0xFF, 0x83, 0xE1, 0x24, 0x00, 0x01, 0x3F, 0x3C, 0x03, 0x03, 0x30, 0x00,
-        0xE7, 0xFC, 0x0F, 0x3F, 0x3C, 0x30, 0x3C, 0x01, 0x3C, 0x01, 0x81, 0xE7, 0x3C, 0x3C, 0x3C,
-        0xE7, 0x81, 0xE7, 0xF3, 0xE7, 0xCF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3C, 0x3F, 0x3C, 0x3C, 0x9F,
-        0x3C, 0x3C, 0xE7, 0xFC, 0x33, 0xCF, 0x24, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0x3F, 0x9F, 0x3C,
-        0x33, 0x24, 0xC3, 0x3C, 0xF3, 0x3C, 0xE7, 0x3C, 0x23, 0x00, 0x00, 0xCF, 0xFF, 0x81, 0x27,
-        0xF3, 0x93, 0xFF, 0xF3, 0xE7, 0x87, 0xE7, 0xFF, 0xFF, 0xFF, 0xF3, 0x3C, 0xE7, 0xFC, 0xFC,
-        0x3C, 0x3F, 0x3F, 0xF9, 0x3C, 0x3C, 0xE7, 0x9F, 0xF0, 0xFF, 0x87, 0xFC, 0x20, 0x3C, 0x3B,
-        0x3F, 0x3C, 0x3F, 0x3F, 0x3F, 0x3C, 0xE7, 0xFC, 0x27, 0x3F, 0x24, 0x24, 0x3C, 0x3C, 0x3C,
-        0x3C, 0x3F, 0xE7, 0x3C, 0x3C, 0x3C, 0xC3, 0x3C, 0xF3, 0xF3, 0xCF, 0xCF, 0xFF, 0xFF, 0xFF,
-        0xFC, 0x3C, 0x3F, 0x3C, 0x3C, 0x00, 0x3C, 0x3C, 0xE7, 0xFC, 0x39, 0xCF, 0x24, 0x3C, 0x3C,
-        0x3C, 0x3C, 0x3F, 0x3F, 0x9F, 0x3C, 0x39, 0x24, 0x99, 0x3C, 0xF9, 0x3C, 0xE7, 0x3C, 0x89,
-        0x00, 0x00, 0xCF, 0xC9, 0xDB, 0x27, 0xB9, 0x93, 0xE7, 0xF3, 0xE7, 0xCF, 0xE7, 0xFF, 0xFF,
-        0xFF, 0xF9, 0x3C, 0xE7, 0xFC, 0xFC, 0x3C, 0x3F, 0x3F, 0xFC, 0x3C, 0x3C, 0xFF, 0xFF, 0xF8,
-        0x81, 0x8F, 0xFC, 0x3C, 0x3C, 0x39, 0x3F, 0x3C, 0x3F, 0x3F, 0x3F, 0x3C, 0xE7, 0xFC, 0x33,
-        0x3F, 0x00, 0x0C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0xE7, 0x3C, 0x3C, 0x3C, 0x99, 0x3C, 0xF9,
-        0xF3, 0x9F, 0xCF, 0x27, 0xFF, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x87,
-        0x80, 0x3C, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x24, 0x3C,
-        0x3C, 0x00, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF, 0xC9, 0xFF, 0x00, 0x1C, 0xC7, 0xE7,
-        0xF9, 0xCF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3C, 0xE7, 0xFC, 0xFC, 0x3C, 0x3F, 0x3F,
-        0xFC, 0x9C, 0x3C, 0xFF, 0xFF, 0xFC, 0xFF, 0x9F, 0x3C, 0x3C, 0x99, 0x39, 0x3C, 0x39, 0x3F,
-        0x3F, 0x3C, 0x3C, 0xE7, 0xFC, 0x39, 0x3F, 0x18, 0x1C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xE7,
-        0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xF3, 0x3F, 0xCF, 0x8F, 0xFF, 0x9F, 0xFF, 0x3F, 0xFF,
-        0xFC, 0xFF, 0x9F, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF,
-        0xC9, 0xFF, 0xE7, 0xBE, 0xFF, 0xE7, 0xFC, 0x9F, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
-        0x87, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81,
-        0x81, 0xC3, 0x03, 0x81, 0x03, 0x00, 0x00, 0x81, 0x3C, 0x00, 0x00, 0x3C, 0x3F, 0x3C, 0x3C,
-        0x81, 0x01, 0x81, 0x01, 0x81, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0xF0, 0xFF, 0x0F,
-        0xDF, 0xFF, 0x3F, 0xFF, 0x3F, 0xFF, 0xFC, 0xFF, 0x80, 0xFF, 0x3F, 0xE7, 0xFC, 0x3F, 0x0F,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
-        0xE7, 0x00, 0xFF, 0x00, 0x00,
-    }};
-#endif // FONT2_H_
\ No newline at end of file
--- a/src/font3.h
+++ /dev/null
@@ -1,93 +1,0 @@
-#ifndef FONT3_H_
-#define FONT3_H_
-
-#include "inline_font.h"
-
-struct inline_font font_v2_small = {
-    846,
-    9,
-    9,
-    9,
-    0,
-    -2,
-    5,
-    38,
-    1118,
-    {
-        0x42, 0x4D, 0x5E, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
-        0x00, 0x00, 0x00, 0x4E, 0x03, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0xCC, 0x03, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
-        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
-        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x7E,
-        0xF7, 0xC4, 0x3B, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFB, 0xFD, 0xFE, 0x00, 0x00,
-        0x00, 0x00, 0x1F, 0xE0, 0x00, 0x03, 0xFC, 0x00, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xDE, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x30, 0x03, 0xFC, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0,
-        0x07, 0xF3, 0xF8, 0x00, 0xFF, 0x01, 0x3F, 0x80, 0x1E, 0xF0, 0x07, 0xBD, 0xFC, 0xFE, 0x00,
-        0x00, 0x3C, 0x7F, 0xEE, 0x3F, 0xFC, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFC,
-        0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x07, 0x73, 0xF8, 0x00, 0xFF, 0xFF, 0x3F, 0xC0, 0x00,
-        0x00, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x07, 0xFC, 0x00, 0x00, 0xFF,
-        0xFF, 0xF7, 0x60, 0x0B, 0xD3, 0xD7, 0xFF, 0xFD, 0xBF, 0xFF, 0xFD, 0xEF, 0xFF, 0xFF, 0xFE,
-        0xFE, 0xFE, 0xF7, 0xBF, 0xFF, 0xDF, 0xEF, 0xF3, 0xFB, 0xFC, 0xFE, 0xFF, 0x7F, 0xDF, 0xFF,
-        0x3F, 0xFF, 0x3F, 0xFE, 0xFF, 0x7F, 0x3F, 0x9F, 0xEF, 0xD7, 0xFB, 0xFD, 0xFC, 0xFE, 0xF7,
-        0xFF, 0x9F, 0xAF, 0xF7, 0xF3, 0xF1, 0xFC, 0xFF, 0x7E, 0xBF, 0x7F, 0xDE, 0xF7, 0xF7, 0x5C,
-        0xF9, 0x7D, 0xFF, 0x5F, 0xFD, 0xFF, 0xDF, 0xBF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x9F, 0xEF,
-        0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0xAF, 0xF7, 0x73, 0xF9, 0xFC, 0xFF, 0xFF,
-        0x3F, 0xFF, 0xCF, 0xF7, 0xF3, 0x7D, 0xDD, 0x7D, 0xFF, 0x3F, 0xDF, 0xCF, 0xF7, 0xF7, 0xFC,
-        0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x1E, 0xED, 0xC3, 0xEF, 0xFF, 0xFB, 0xDF, 0xFF, 0xFD, 0xFF,
-        0xFF, 0xFF, 0xFF, 0x7E, 0xFE, 0xF7, 0xBF, 0xFF, 0xDF, 0xEF, 0xF3, 0xFB, 0xFC, 0xFE, 0xFF,
-        0x3F, 0xDF, 0xFE, 0x38, 0x0F, 0x1F, 0xDE, 0x80, 0x7F, 0x3F, 0x9F, 0xEF, 0xE7, 0xFB, 0xFD,
-        0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0x6F, 0xF7, 0xF3, 0xE9, 0xFC, 0xFF, 0x7D, 0x3E, 0xFF, 0xDE,
-        0xF7, 0xF6, 0xED, 0x75, 0xBB, 0xFF, 0x6F, 0xFD, 0xFF, 0xBF, 0xBF, 0xFF, 0xFF, 0xFF, 0x7F,
-        0x3F, 0x9F, 0xEF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0x6F, 0xF7, 0x73, 0xF9,
-        0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xCF, 0xF7, 0xF3, 0xBD, 0xDD, 0xBB, 0xFF, 0x4F, 0xDF, 0xCF,
-        0xF7, 0xF7, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x7E, 0xEE, 0xFB, 0xD7, 0xFF, 0xFB, 0xDF,
-        0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0xFE, 0xF7, 0xBF, 0xFF, 0xDF, 0xEF, 0xF3, 0xFB,
-        0xFC, 0xFE, 0xFF, 0x7F, 0xFF, 0xFC, 0x3F, 0xFF, 0x0F, 0xDE, 0xBA, 0x7F, 0x3F, 0x9F, 0xEF,
-        0xE7, 0xFB, 0xFD, 0xFC, 0xFE, 0xF7, 0xFF, 0x9E, 0xEF, 0xF7, 0xF3, 0xD9, 0xFC, 0xFF, 0x7B,
-        0x3D, 0xFF, 0xDE, 0xF7, 0xF5, 0xF5, 0xAD, 0xD7, 0xFF, 0x77, 0xFD, 0xFF, 0x7F, 0xBF, 0xFF,
-        0xFF, 0xFF, 0x00, 0x3F, 0x9F, 0xEF, 0xE0, 0x00, 0x0C, 0x00, 0xFE, 0xF7, 0xFF, 0x80, 0xEF,
-        0xF7, 0x73, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0xC0, 0x0F, 0xF7, 0xF3, 0xDD, 0xDD, 0xC7, 0x00,
-        0x71, 0xDF, 0xCF, 0xF7, 0xF7, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x60, 0x0F, 0x7D, 0xBB,
-        0xFF, 0xFB, 0xDF, 0xDD, 0xE0, 0x3F, 0xF8, 0x0F, 0xFF, 0xDE, 0xEE, 0xF7, 0x80, 0x00, 0x00,
-        0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x3F, 0xFF, 0x07, 0xC0, 0x82, 0x00,
-        0x00, 0x1F, 0xEF, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0xF7, 0xFF, 0x81, 0xEF, 0xF7, 0x73, 0xB9,
-        0xFC, 0x00, 0x7F, 0x00, 0x00, 0x1E, 0xF7, 0xF3, 0xF9, 0xDD, 0xEF, 0x00, 0x7B, 0xFD, 0xFE,
-        0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x9F, 0xEF, 0xE7, 0xF3, 0xFD, 0xFC, 0xFE, 0xF7,
-        0xFF, 0x9F, 0x6F, 0xF7, 0x73, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0xDF, 0xEF, 0xF7, 0xF3, 0xED,
-        0xDD, 0xBB, 0x7F, 0x7E, 0x5F, 0xCF, 0xF7, 0xF3, 0x3C, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x6E,
-        0xFF, 0xBE, 0x7F, 0xFF, 0xFB, 0xDF, 0xEB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFE, 0xF7,
-        0xFF, 0xBF, 0xCF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0x7F, 0x7F, 0xFF, 0xFC, 0x3F, 0xFF, 0x0F,
-        0xFC, 0xFA, 0x7F, 0x3E, 0xDF, 0xEF, 0xE7, 0xFB, 0xFD, 0xFE, 0xFE, 0xF7, 0xFF, 0x9E, 0xEF,
-        0xF6, 0xB3, 0x79, 0xFC, 0xFE, 0x7F, 0x3F, 0x9F, 0xFE, 0xF7, 0xF3, 0xF9, 0xFD, 0xD7, 0x7F,
-        0x7D, 0xFD, 0xFD, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x9F, 0xEF, 0xE7, 0xF3, 0xFD,
-        0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0xAF, 0xF7, 0x73, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0xDF, 0xEF,
-        0xF7, 0xF3, 0xF5, 0xDD, 0x7D, 0x7F, 0x7F, 0x9F, 0xCF, 0xF7, 0xF4, 0xDC, 0x00, 0x00, 0x7F,
-        0xB7, 0xC0, 0x0E, 0xF1, 0xDD, 0xBD, 0xFF, 0xFB, 0xDF, 0xF7, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xF6, 0xFE, 0xF7, 0xFF, 0xBF, 0xCF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0x7F, 0x3F, 0xDF, 0xFE,
-        0x38, 0x0F, 0x1F, 0xFC, 0x82, 0x7F, 0x3E, 0xDF, 0xEF, 0xE7, 0xFB, 0xFD, 0xFE, 0xFE, 0xF7,
-        0xFF, 0x9F, 0x6F, 0xF5, 0xD2, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0x9F, 0xFE, 0xF7, 0xF3, 0xF9,
-        0xFD, 0xBB, 0x7F, 0x7E, 0xFD, 0xFB, 0xFF, 0xBB, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0xCF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x07, 0xF3, 0xF9, 0xDC, 0xFE, 0x7F, 0x00, 0x1F, 0xCF, 0xF7, 0xF7, 0xFC,
-        0x00, 0x00, 0x7F, 0xB7, 0xF7, 0x60, 0x05, 0xED, 0xBD, 0xFF, 0xFD, 0xBF, 0xEB, 0xFD, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFA, 0xFE, 0xF7, 0xFF, 0xBF, 0xCF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0x7F,
-        0x7F, 0xFF, 0xFF, 0x3F, 0xFF, 0x3D, 0xFC, 0xFE, 0x7F, 0x3E, 0xDF, 0xEF, 0xD7, 0xFB, 0xFD,
-        0xFE, 0xFE, 0xF7, 0xFF, 0x9F, 0xAF, 0xF3, 0xE1, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0x9F, 0xFE,
-        0xF7, 0xF3, 0xF9, 0xFD, 0x7D, 0x7F, 0x7F, 0x7D, 0xF7, 0xFF, 0xBD, 0x7F, 0xFF, 0xBF, 0xFF,
-        0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xCF,
-        0xF7, 0xF7, 0xFC, 0x00, 0x00, 0x7F, 0xB7, 0xF7, 0x7E, 0xF1, 0xF6, 0x7D, 0xFF, 0xFE, 0x7F,
-        0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x07, 0x80, 0x00, 0x0F, 0xE0, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00,
-        0x30, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0x9F, 0xCF, 0xF7, 0xF3, 0xF8, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x07, 0xF3, 0xF9, 0xFC, 0xFE, 0x7F, 0x00, 0x3C, 0x6F, 0xFE, 0x3E, 0xFF,
-        0xFF, 0x7F, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xC0, 0x0F, 0xF0, 0x07, 0xFC, 0x00, 0x00,
-    }};
-#endif // FONT3_H_
\ No newline at end of file
--- a/src/font4.h
+++ /dev/null
@@ -1,108 +1,0 @@
-#ifndef FONT4_H_
-#define FONT4_H_
-
-#include "inline_font.h"
-
-struct inline_font font_v2_large = {
-    940,
-    10,
-    10,
-    10,
-    0,
-    -2,
-    4,
-    38,
-    1346,
-    {
-        0x42, 0x4D, 0x42, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
-        0x00, 0x00, 0x00, 0xAC, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
-        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
-        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCF,
-        0xCF, 0x3E, 0x60, 0xCF, 0xFF, 0xF9, 0x3F, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xE7, 0xF3, 0xFC,
-        0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x3F, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x03, 0x3F, 0x00, 0x18, 0x00, 0x01, 0x80, 0x0F, 0xF8, 0x04,
-        0xFC, 0x00, 0x00, 0x13, 0xF2, 0x00, 0x3F, 0x0F, 0xC8, 0x04, 0xFF, 0x83, 0x0F, 0xC0, 0x07,
-        0xCF, 0x80, 0x7C, 0xF3, 0xF0, 0xFC, 0x00, 0x40, 0x0F, 0x0F, 0xFC, 0xE1, 0xFF, 0xF0, 0x03,
-        0xFF, 0x80, 0x00, 0x18, 0x02, 0x00, 0x80, 0x33, 0xF0, 0x04, 0xFC, 0x00, 0x00, 0x13, 0xE0,
-        0x00, 0x33, 0x0F, 0xC8, 0x04, 0xFF, 0xFF, 0x0F, 0xF0, 0x07, 0x80, 0x80, 0x43, 0xF8, 0x00,
-        0xFC, 0x00, 0x40, 0x00, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCC,
-        0x01, 0x1E, 0x40, 0x0F, 0xFF, 0xF1, 0x1F, 0xFF, 0xFF, 0x3C, 0xFF, 0xFF, 0xE7, 0xF1, 0xFC,
-        0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x3F, 0xFC, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x03, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00,
-        0xFC, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x3F, 0x0F, 0x80, 0x00, 0xFF, 0x06, 0x0F, 0x80, 0x03,
-        0xCF, 0x00, 0x38, 0x71, 0xE0, 0x78, 0x00, 0x00, 0x0F, 0x0F, 0xF8, 0xE1, 0xFF, 0xF0, 0x03,
-        0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xF0, 0x00, 0xFC, 0x00, 0x00, 0x03, 0xC4,
-        0x00, 0x33, 0x0F, 0xC0, 0x00, 0xFF, 0xFF, 0x0F, 0xF0, 0x03, 0x00, 0x00, 0x01, 0xF0, 0x00,
-        0x78, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00,
-        0x00, 0x8F, 0xCE, 0x1F, 0xFF, 0xE3, 0x8F, 0xFF, 0xFF, 0x3C, 0xFF, 0xFF, 0xFF, 0xF8, 0xFC,
-        0xFC, 0xF3, 0xCF, 0xFF, 0xF3, 0xFC, 0xFF, 0x0F, 0xCF, 0xF0, 0xFC, 0xFF, 0x33, 0xFC, 0xFF,
-        0xE7, 0x80, 0x79, 0xFF, 0xFC, 0xFF, 0x3F, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0xCF, 0xF3, 0xF0,
-        0xFC, 0xF3, 0xFF, 0xC3, 0xC4, 0xFF, 0x3F, 0x0F, 0x03, 0xF0, 0xFF, 0x3C, 0x0F, 0x1F, 0xF3,
-        0xCF, 0x3F, 0x30, 0x30, 0xC2, 0x31, 0xFF, 0x23, 0xFF, 0x3F, 0xF1, 0xF9, 0xFF, 0xFF, 0xFF,
-        0xFF, 0x3F, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0xF3, 0xFF, 0xF0, 0xFC, 0xF3, 0xFF, 0xC3, 0x8F,
-        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0x01, 0x80, 0x0F, 0xFF, 0xF3, 0x3F, 0x3F, 0x08, 0xF3, 0x32,
-        0x31, 0xFF, 0x03, 0xF3, 0xF0, 0xFF, 0x3F, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x03,
-        0xCC, 0xC7, 0xCE, 0x1F, 0xFF, 0xE7, 0xCF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFC, 0x7C,
-        0xFC, 0xF3, 0xCF, 0xFF, 0xF3, 0xFC, 0xFF, 0x0F, 0xCF, 0xF0, 0xFC, 0xFF, 0x33, 0xFC, 0xFF,
-        0xC7, 0x80, 0x78, 0xFF, 0x3C, 0xC0, 0x3F, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0xCF, 0xF3, 0xF0,
-        0xFC, 0xF3, 0xFF, 0xC3, 0x8C, 0xFF, 0x3F, 0x0E, 0x03, 0xF0, 0xFF, 0x38, 0x0E, 0x3F, 0xF3,
-        0xCF, 0x3F, 0x23, 0x10, 0x03, 0x03, 0xFF, 0x31, 0xFF, 0x3F, 0xE3, 0xF9, 0xFF, 0xFF, 0xFF,
-        0xFF, 0x00, 0x0F, 0xC3, 0xFC, 0xFC, 0x00, 0x33, 0xF8, 0x00, 0xFC, 0xF3, 0xFF, 0xC0, 0x1F,
-        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0x00, 0x00, 0x0F, 0xF8, 0x03, 0x3F, 0x3F, 0x0C, 0x73, 0x33,
-        0x03, 0x80, 0x20, 0x73, 0xF0, 0xFF, 0x3F, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCE,
-        0x00, 0xE3, 0xC0, 0x0F, 0xFF, 0xE7, 0xCF, 0xCE, 0x78, 0x07, 0xFF, 0x80, 0x7F, 0xFE, 0x3C,
-        0xCC, 0xF3, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
-        0x87, 0xFF, 0xF8, 0x7F, 0x04, 0xC0, 0x00, 0x00, 0x03, 0xFC, 0xFC, 0x00, 0x00, 0x03, 0x00,
-        0x00, 0xF3, 0xFF, 0xC0, 0x1C, 0xFF, 0x33, 0x0C, 0x43, 0xF0, 0x01, 0x31, 0x00, 0x18, 0x03,
-        0xCF, 0x3F, 0x07, 0x82, 0x13, 0x87, 0x80, 0x38, 0xFF, 0x3F, 0xC7, 0xF9, 0xFF, 0xFF, 0xFF,
-        0xFF, 0x00, 0x0F, 0xC3, 0xFC, 0xFC, 0x00, 0x33, 0xF0, 0x00, 0xFC, 0xF3, 0xFF, 0xC0, 0x3F,
-        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xF0, 0x07, 0x3F, 0x3F, 0x0E, 0x33, 0x33,
-        0x03, 0x00, 0x38, 0x13, 0xF0, 0xFF, 0x3F, 0x08, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCC,
-        0x01, 0xF1, 0xE0, 0xCF, 0xFF, 0xE7, 0xCF, 0xC4, 0x78, 0x07, 0xFF, 0x80, 0x7F, 0xFF, 0x1C,
-        0xCC, 0xF3, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
-        0x07, 0xFF, 0xF8, 0x3F, 0x00, 0xCC, 0x00, 0x00, 0x33, 0xFC, 0xFC, 0x00, 0x00, 0x03, 0x00,
-        0x00, 0xF3, 0xFF, 0xC0, 0x1C, 0xFF, 0x21, 0x08, 0xC3, 0xF0, 0x00, 0x33, 0x00, 0x00, 0x07,
-        0xCF, 0x3F, 0x0F, 0xC3, 0x33, 0x87, 0x00, 0x3C, 0x7F, 0x3F, 0x8F, 0xF9, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xFF, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0x00, 0x33, 0xF0, 0xFC, 0xF3, 0xFF, 0xC3, 0x1F,
-        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xF3, 0xFF, 0x3F, 0x3F, 0x0F, 0x13, 0x32,
-        0x31, 0x3F, 0x3F, 0x03, 0xF0, 0xFF, 0x3F, 0x00, 0x70, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00,
-        0xCF, 0xF8, 0xE6, 0x7F, 0xFF, 0xE7, 0xCF, 0xF1, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x8C,
-        0xFC, 0xF3, 0xFF, 0xCF, 0xF0, 0xFC, 0x3F, 0xCF, 0xFF, 0xF0, 0xFC, 0x3F, 0x33, 0xFC, 0xFF,
-        0x87, 0x80, 0x78, 0x7F, 0xF0, 0xCC, 0x3F, 0x0F, 0x93, 0xFC, 0xFC, 0x3F, 0xCF, 0xF3, 0xFC,
-        0xFC, 0xF3, 0xFF, 0xC3, 0x8C, 0xFF, 0x00, 0x01, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xFF,
-        0xCF, 0x3F, 0x0F, 0xC3, 0xF3, 0x03, 0x3F, 0x3E, 0x3F, 0x3F, 0x1F, 0xF9, 0xE6, 0x7F, 0xFF,
-        0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0xFF, 0x03, 0x8F,
-        0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x0F, 0x83, 0x30,
-        0x78, 0x3F, 0x00, 0x03, 0xF0, 0xFF, 0x3F, 0x22, 0x70, 0x00, 0x00, 0x3F, 0xC9, 0xF0, 0x00,
-        0x00, 0xFC, 0x66, 0x73, 0xFF, 0xE3, 0x8F, 0xF1, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC4,
-        0xFC, 0xF3, 0xFF, 0xCF, 0xF0, 0xFC, 0x3F, 0xCF, 0xFF, 0xF0, 0xFC, 0x3F, 0x33, 0xFC, 0xFF,
-        0xC7, 0x80, 0x78, 0xF3, 0xF0, 0xFC, 0x3F, 0x0F, 0x93, 0xFC, 0xF8, 0x3F, 0xCF, 0xF3, 0xFC,
-        0xFC, 0xF3, 0xFF, 0xC3, 0xC4, 0xFF, 0x0C, 0x03, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xFF,
-        0xCF, 0x3F, 0x0F, 0xC3, 0xF2, 0x31, 0x3F, 0x3F, 0x1F, 0x3E, 0x3F, 0xF9, 0xE0, 0x7F, 0xFF,
-        0x3F, 0x00, 0x40, 0x18, 0x02, 0x00, 0x80, 0x73, 0xF8, 0x00, 0x01, 0xC3, 0xFF, 0x03, 0xC7,
-        0xCF, 0x00, 0x40, 0x18, 0x04, 0x01, 0x80, 0x20, 0x08, 0x00, 0x00, 0x3F, 0x0F, 0xC3, 0x30,
-        0xFC, 0x3F, 0x00, 0x03, 0xF0, 0xFF, 0x3F, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xC9, 0xFC, 0xCE,
-        0x00, 0x9E, 0x20, 0x73, 0xFF, 0xF1, 0x1F, 0xC4, 0x7F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
-        0x00, 0x03, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
-        0xE7, 0xFF, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-        0xFC, 0x00, 0x3F, 0xC3, 0xE0, 0xFF, 0x1E, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x3F, 0x0F, 0xC3, 0xF0, 0x78, 0x3F, 0x00, 0x0F, 0x0C, 0x7F, 0xE1, 0xF0, 0xFF, 0xFE,
-        0x3F, 0xFF, 0xCF, 0xFF, 0xFF, 0xFC, 0xFF, 0xF0, 0x0F, 0xFC, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF,
-        0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xC9, 0xFC, 0xCF,
-        0xCF, 0x9F, 0x30, 0xF3, 0xFF, 0xF9, 0x3F, 0xCE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
-        0x00, 0x03, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xF8, 0x06, 0x01, 0x80, 0x40, 0x38, 0x00, 0x03, 0x80, 0x20, 0x08, 0x00,
-        0xFC, 0x00, 0x3F, 0xC3, 0xF0, 0xFF, 0x3F, 0x0F, 0xC8, 0x04, 0x01, 0x80, 0x40, 0x18, 0x00,
-        0x00, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x00, 0x0F, 0x0C, 0xFF, 0xE1, 0xF9, 0xFF, 0xFE,
-        0x7F, 0xFF, 0xCF, 0xFF, 0xFF, 0xFC, 0xFF, 0xF8, 0x0F, 0xFC, 0xFF, 0xF3, 0xFF, 0xC3, 0xFF,
-        0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00,
-    }};
-#endif // FONT4_H_
\ No newline at end of file
--- a/src/font5.h
+++ /dev/null
@@ -1,143 +1,0 @@
-#ifndef FONT5_H_
-#define FONT5_H_
-
-#include "inline_font.h"
-
-struct inline_font font_v2_huge = {
-    1128,
-    12,
-    12,
-    12,
-    0,
-    -54,
-    4,
-    24,
-    1874,
-    {
-        0x42, 0x4D, 0x52, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
-        0x00, 0x00, 0x00, 0x68, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
-        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
-        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF,
-        0xFF, 0x9F, 0xFF, 0xFC, 0x1C, 0xFF, 0xFF, 0xF3, 0xE7, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF,
-        0xF9, 0xFF, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0xFF,
-        0xC0, 0x00, 0xFF, 0xCF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xF8, 0x03, 0x3F,
-        0xC0, 0x01, 0x80, 0x00, 0x01, 0x80, 0x03, 0xFF, 0x80, 0x13, 0xFC, 0x00, 0x00, 0x01, 0x3F,
-        0xC8, 0x00, 0x3F, 0xC3, 0xFC, 0x80, 0x13, 0xFF, 0x80, 0xC3, 0xFC, 0x00, 0x1F, 0x9F, 0x80,
-        0x1F, 0x9F, 0x3F, 0xC3, 0xFC, 0x00, 0x10, 0x00, 0xC0, 0xFF, 0xFC, 0xE0, 0x7F, 0xFF, 0x00,
-        0x0F, 0xFF, 0x80, 0x00, 0x01, 0x80, 0x08, 0x00, 0x80, 0x0C, 0xFF, 0x00, 0x13, 0xFC, 0x00,
-        0x00, 0x01, 0x3F, 0x80, 0x00, 0x39, 0xC3, 0xFC, 0x80, 0x13, 0xFF, 0xFF, 0xC3, 0xFF, 0x00,
-        0x1E, 0x00, 0x80, 0x10, 0xFF, 0x80, 0x03, 0xFC, 0x00, 0x10, 0x00, 0x00, 0x03, 0xFF, 0x00,
-        0x0F, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE6, 0x70, 0x01, 0x9F, 0x18, 0x08, 0xFF,
-        0xFF, 0xE3, 0xE3, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xF9, 0xFF, 0x1F, 0xF0, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0xFF, 0xCF, 0xFF, 0x8F,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x03, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x03, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0xC3, 0xF8, 0x00,
-        0x03, 0xFF, 0x01, 0x83, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x0F, 0x0F, 0x1F, 0x81, 0xF8, 0x00,
-        0x00, 0x00, 0xC0, 0xFF, 0xF8, 0xE0, 0x7F, 0xFF, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x0C, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0x10, 0x00, 0x39,
-        0xC3, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xC3, 0xFF, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7F, 0x00,
-        0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0xFF,
-        0xFF, 0xFF, 0xE6, 0x70, 0x00, 0x8F, 0x11, 0xC1, 0xFF, 0xFF, 0xC7, 0xF1, 0xFF, 0xFF, 0xF9,
-        0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xF3, 0xFC, 0xF9, 0xF3, 0xFF, 0xFF, 0xCF, 0xFC, 0xFF,
-        0xC3, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xCF, 0x9F, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0xF9,
-        0xFF, 0xFC, 0x3F, 0x13, 0xFF, 0x3F, 0xC3, 0xF0, 0x3F, 0xC3, 0xFF, 0x3F, 0x03, 0xF1, 0xFF,
-        0xCF, 0x9F, 0x3F, 0xCE, 0x07, 0x0F, 0x08, 0xF1, 0xFF, 0xC8, 0xFF, 0xCF, 0xFF, 0xF1, 0xFE,
-        0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xFC, 0xFF, 0xFF,
-        0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3E, 0x3F, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC3, 0xFF, 0xFF,
-        0xC3, 0xFF, 0xFF, 0xCC, 0xFF, 0x3F, 0xC2, 0x3F, 0x39, 0xC8, 0xF1, 0xFF, 0xCC, 0x7F, 0x3F,
-        0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0x9C, 0xC7,
-        0x13, 0xE3, 0xFF, 0xFF, 0xCF, 0xF9, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7,
-        0xF3, 0xFC, 0xF9, 0xF3, 0xFF, 0xFF, 0xCF, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF,
-        0xCF, 0x9F, 0xCF, 0xFF, 0xCF, 0xC0, 0x3F, 0x3F, 0xFF, 0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0x3F,
-        0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3E, 0x33, 0xFF, 0x3F,
-        0xC3, 0xE0, 0x3F, 0xC3, 0xFF, 0x3E, 0x03, 0xE3, 0xFF, 0xCF, 0x9F, 0x3F, 0xCC, 0x63, 0x06,
-        0x0C, 0x63, 0xFF, 0xCC, 0x7F, 0xCF, 0xFF, 0xE3, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F,
-        0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xFC, 0xFF, 0xFF, 0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3C,
-        0x7F, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC0, 0x01, 0x80, 0x03, 0xFF, 0xFF, 0xCC, 0xFF, 0x3F,
-        0xC3, 0x1F, 0x39, 0xCC, 0x63, 0xFF, 0xCE, 0x3F, 0x3F, 0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00,
-        0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x1F, 0x9C, 0xE3, 0xF3, 0xC1, 0xFF, 0xFF, 0xCF, 0xF9,
-        0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xF3, 0xFC, 0xF9, 0xF3, 0xFF, 0xFF,
-        0xCF, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0x8F, 0xC0,
-        0x3F, 0x1F, 0xF9, 0xF3, 0x80, 0x3F, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F,
-        0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3C, 0x73, 0xFF, 0x3F, 0xC3, 0xC4, 0x3F, 0xC3, 0xFF, 0x3C,
-        0x43, 0xC7, 0xFF, 0xCF, 0x9F, 0x3F, 0xC8, 0xF1, 0x20, 0x4E, 0x07, 0xFF, 0xCE, 0x3F, 0xCF,
-        0xFF, 0xC7, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFC, 0x3F, 0xF3, 0xFC, 0x00,
-        0x00, 0x03, 0x80, 0x03, 0xFC, 0xF9, 0xFF, 0xFC, 0x00, 0xFF, 0x9F, 0x39, 0xC3, 0xFC, 0x3F,
-        0xC0, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x0C, 0xFF, 0x3F, 0xC3, 0x8F, 0x39, 0xCE, 0x07, 0x80,
-        0x0F, 0x1F, 0x3F, 0xC3, 0xFF, 0x3F, 0xC2, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE6,
-        0x78, 0x00, 0xF1, 0xF1, 0x88, 0xFF, 0xFF, 0xCF, 0xF9, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xC0,
-        0x3F, 0xFF, 0xF1, 0xF3, 0x9C, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-        0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x0F, 0xF8, 0x13, 0x80, 0x00,
-        0x00, 0x00, 0x3F, 0xF3, 0xFC, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF9, 0xFF, 0xFC, 0x00,
-        0xF3, 0xFF, 0x39, 0xC3, 0x8C, 0x3F, 0xC0, 0x01, 0x3C, 0xC0, 0x01, 0x80, 0x0F, 0x9F, 0x3F,
-        0xC1, 0xF8, 0x30, 0xCF, 0x0F, 0x80, 0x0F, 0x1F, 0xCF, 0xFF, 0x8F, 0xFE, 0x7F, 0xFF, 0xFF,
-        0xFF, 0xFF, 0x00, 0x03, 0xFC, 0x3F, 0xF3, 0xFC, 0x00, 0x00, 0x03, 0x00, 0x03, 0xFC, 0xF9,
-        0xFF, 0xFC, 0x01, 0xFF, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFF, 0x00,
-        0x1C, 0xFF, 0x3F, 0xC3, 0xC7, 0x39, 0xCE, 0x07, 0x00, 0x0F, 0x8F, 0x3F, 0xC3, 0xFF, 0x3F,
-        0xC0, 0x1F, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE6, 0x70, 0x01, 0xF8, 0xF8, 0x1C, 0xFF,
-        0xFF, 0xCF, 0xF9, 0xF3, 0x9F, 0xC0, 0x3F, 0xFF, 0xC0, 0x3F, 0xFF, 0xF8, 0xF3, 0x9C, 0xF9,
-        0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xCF,
-        0xFE, 0x0F, 0xFF, 0xFF, 0x07, 0xFC, 0x03, 0x9C, 0x00, 0x00, 0x03, 0x3F, 0xF3, 0xFC, 0x00,
-        0x00, 0x00, 0x30, 0x00, 0x00, 0xF9, 0xFF, 0xFC, 0x00, 0xF3, 0xFF, 0x30, 0xC3, 0x1C, 0x3F,
-        0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x1F, 0x9F, 0x3F, 0xC3, 0xFC, 0x39, 0xCF, 0x0F, 0x00,
-        0x0F, 0x8F, 0xCF, 0xFF, 0x1F, 0xFE, 0x79, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F,
-        0xF3, 0xFC, 0x3F, 0xCC, 0xFF, 0x3F, 0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x38, 0xFF, 0x9F, 0x39,
-        0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0xC3, 0xE3, 0x39,
-        0xCC, 0x63, 0x3F, 0xCF, 0xC7, 0x3F, 0xC3, 0xFF, 0x3F, 0xC8, 0x9F, 0x00, 0x00, 0x00, 0x3F,
-        0xFF, 0xFF, 0x80, 0x13, 0x9F, 0xFC, 0x7E, 0x0F, 0xFF, 0xFF, 0xCF, 0xF9, 0xF1, 0x1F, 0xF9,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x73, 0xFC, 0xF9, 0xFF, 0xFC, 0xFF, 0xC3, 0xFC, 0x3F,
-        0xF3, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F, 0xCF, 0xFF, 0xCF, 0xFF, 0x0F, 0xC0, 0x3F, 0x0F, 0xFF,
-        0xC3, 0x9C, 0x3F, 0xC3, 0xF9, 0x3F, 0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xF3, 0xFC, 0xF9,
-        0xFF, 0xFC, 0x3C, 0x73, 0xFF, 0x20, 0x42, 0x3C, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
-        0xFF, 0x9F, 0x3F, 0xC3, 0xFC, 0x3F, 0xCE, 0x07, 0x3F, 0xCF, 0xC7, 0xCF, 0xFE, 0x3F, 0xFE,
-        0x78, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xCC, 0xFF, 0x3F,
-        0xC0, 0x00, 0xF9, 0xFF, 0xFC, 0x3C, 0x7F, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
-        0xC3, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0xC3, 0xF1, 0x39, 0xC8, 0xF1, 0x3F, 0xCF, 0xE3, 0x3F,
-        0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x13, 0x9F, 0x8E,
-        0x3C, 0xE7, 0xFF, 0xFF, 0xCF, 0xF9, 0xF8, 0x3F, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
-        0x33, 0xFC, 0xF9, 0xFF, 0xFC, 0xFF, 0xC3, 0xFC, 0x3F, 0xF3, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F,
-        0xCF, 0x9F, 0xFF, 0xFF, 0x8F, 0xC0, 0x3F, 0x1F, 0xFF, 0xC3, 0x9C, 0x3F, 0xC3, 0xF9, 0x3F,
-        0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xF3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3E, 0x33, 0xFF, 0x06,
-        0x00, 0x7C, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xFF, 0x9F, 0x3F, 0xC3, 0xFC, 0x3F,
-        0xCC, 0x63, 0x3F, 0xCF, 0xE3, 0xCF, 0xFC, 0x7F, 0xFE, 0x7C, 0x63, 0xFF, 0xFF, 0xFF, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0x00, 0x00, 0x01, 0xE1, 0xFF, 0xF0, 0x3E,
-        0x3F, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
-        0xC3, 0xF8, 0x39, 0xC1, 0xF8, 0x3F, 0xC0, 0x00, 0x3F, 0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00,
-        0x00, 0x00, 0x3F, 0xF3, 0x3F, 0xE6, 0x70, 0x00, 0x8F, 0x1C, 0xE7, 0x3F, 0xFF, 0xC7, 0xF1,
-        0xF8, 0x3F, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x13, 0xFC, 0xF9, 0xFF, 0xFC, 0xFF,
-        0xC3, 0xFC, 0x3F, 0xF3, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F, 0xCF, 0x9F, 0xFF, 0xFF, 0xCF, 0xFF,
-        0xFF, 0x3F, 0x3F, 0xC3, 0x9C, 0x3F, 0xC3, 0xF9, 0x3F, 0xF3, 0xF8, 0x3F, 0xF3, 0xFF, 0x3F,
-        0xF3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3F, 0x13, 0xFF, 0x0F, 0x00, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
-        0xC3, 0xFC, 0x3F, 0xFF, 0x9F, 0x3F, 0xC3, 0xFC, 0x3F, 0xC8, 0xF1, 0x3F, 0xCF, 0xF1, 0xCF,
-        0xF8, 0xFF, 0xFE, 0x7E, 0x07, 0xFF, 0xFC, 0xFF, 0x00, 0x10, 0x01, 0x80, 0x08, 0x00, 0x80,
-        0x1C, 0xFF, 0x80, 0x03, 0xFF, 0xE1, 0xFF, 0xF0, 0x3F, 0x1F, 0x9F, 0x00, 0x10, 0x01, 0x80,
-        0x10, 0x01, 0x80, 0x08, 0x00, 0x80, 0x00, 0x00, 0x3F, 0xC3, 0xFC, 0x39, 0xC3, 0xFC, 0x3F,
-        0xC0, 0x00, 0x3F, 0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xF3, 0x3F, 0xE6,
-        0x78, 0x00, 0x8F, 0x9C, 0x07, 0x3F, 0xFF, 0xE3, 0xE3, 0xF1, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFC, 0x3F,
-        0x83, 0xFF, 0x1F, 0x81, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
-        0xC3, 0xFC, 0x3F, 0xC1, 0xF8, 0x3F, 0xC0, 0x00, 0xC0, 0xF1, 0xFF, 0xE0, 0x7F, 0x0F, 0xFF,
-        0xF8, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0xFF, 0xF3, 0xFF, 0xFF,
-        0xFF, 0xFF, 0x3F, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0x00,
-        0x0F, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xF3, 0x3F, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x0F, 0x3F,
-        0xFF, 0xF3, 0xE7, 0xF3, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01,
-        0xF0, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x18, 0x01, 0x80, 0x10, 0x03, 0x80, 0x00, 0x03, 0x80,
-        0x08, 0x00, 0x80, 0x03, 0xFC, 0x00, 0x0F, 0xFC, 0x3F, 0xC3, 0xFF, 0x3F, 0xC3, 0xFC, 0x80,
-        0x10, 0x01, 0x80, 0x10, 0x01, 0x80, 0x00, 0x00, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
-        0xC0, 0x00, 0xC0, 0xF3, 0xFF, 0xE0, 0x7F, 0x9F, 0xFF, 0xF9, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF,
-        0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0xFC, 0x3F, 0xFE, 0x1F, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00,
-    }};
-#endif // FONT5_H_
\ No newline at end of file
--- /dev/null
+++ b/src/fonts/font1.h
@@ -1,0 +1,56 @@
+#ifndef FONT1_H_
+#define FONT1_H_
+
+#include "inline_font.h"
+
+struct inline_font font_v1_small = {
+    470,
+    7,
+    5,
+    7,
+    0,
+    0,
+    3,
+    24,
+    566,
+    {
+        0x42, 0x4D, 0x36, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
+        0x00, 0x00, 0x00, 0xD6, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
+        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x80, 0x00, 0x40, 0x34,
+        0x01, 0x80, 0x00, 0x40, 0x12, 0x1F, 0xFF, 0xFE, 0x1F, 0xFC, 0x9E, 0x08, 0x10, 0x00, 0x00,
+        0x8E, 0x8F, 0x9D, 0xEF, 0xC1, 0xD1, 0xFB, 0xA3, 0xF8, 0xC5, 0xD0, 0x6C, 0x7C, 0x47, 0x12,
+        0x31, 0xF7, 0xC6, 0x1C, 0x03, 0xE0, 0xFF, 0xFF, 0xFF, 0x93, 0xF1, 0x77, 0x22, 0xEA, 0xC7,
+        0xF0, 0x0C, 0x3E, 0x7F, 0xE3, 0xF1, 0xFF, 0xFE, 0x4F, 0x80, 0x00, 0x00, 0x15, 0xF9, 0xC8,
+        0x02, 0x40, 0x08, 0x40, 0x02, 0x11, 0x24, 0x02, 0x10, 0xC4, 0x91, 0x0A, 0x10, 0x20, 0x20,
+        0x10, 0x8C, 0x63, 0x18, 0x42, 0x31, 0x24, 0x65, 0x08, 0xC6, 0x30, 0x94, 0x42, 0x48, 0xAB,
+        0x71, 0x0C, 0x04, 0x14, 0x00, 0x00, 0x8C, 0x61, 0x18, 0x10, 0x31, 0x20, 0xB4, 0x4A, 0xC6,
+        0x3F, 0xFC, 0x02, 0x48, 0xD2, 0xAA, 0x0A, 0x22, 0x48, 0x80, 0x00, 0x80, 0x3E, 0x55, 0xD4,
+        0x02, 0x40, 0x08, 0x00, 0x01, 0x19, 0x24, 0x02, 0x10, 0xC4, 0x91, 0x08, 0x00, 0x6F, 0xB0,
+        0x97, 0x8C, 0x61, 0x18, 0x42, 0x71, 0x24, 0x69, 0x08, 0xC6, 0x30, 0xAC, 0x82, 0x48, 0xAA,
+        0xAA, 0x0A, 0x04, 0x24, 0x00, 0x00, 0xFC, 0x61, 0x1F, 0x93, 0xF1, 0x20, 0xA8, 0x4A, 0xC6,
+        0x31, 0x8C, 0x3E, 0x48, 0xCA, 0xA4, 0xF9, 0x22, 0x48, 0x80, 0x00, 0x80, 0x15, 0xF2, 0x24,
+        0x02, 0x42, 0xBE, 0x0F, 0x80, 0x95, 0x27, 0xFF, 0xFF, 0xFC, 0x5F, 0xF8, 0x00, 0xE0, 0x38,
+        0x55, 0xFF, 0xA1, 0x1F, 0x7A, 0x1F, 0x20, 0x71, 0x08, 0xCE, 0x3E, 0x8F, 0x9C, 0x48, 0xC6,
+        0x24, 0x79, 0x04, 0x44, 0x00, 0x00, 0x0C, 0x61, 0x18, 0x92, 0x31, 0x20, 0xA4, 0x4A, 0xC6,
+        0x31, 0x8C, 0x20, 0x48, 0xC6, 0xAA, 0x88, 0xA2, 0x4A, 0x80, 0x00, 0x80, 0x3F, 0x4D, 0x50,
+        0x02, 0x41, 0x08, 0x00, 0x00, 0x53, 0x20, 0x43, 0x18, 0x40, 0x31, 0x8A, 0x10, 0x6F, 0xB0,
+        0x37, 0x8C, 0x61, 0x18, 0x42, 0x11, 0x20, 0x69, 0x0A, 0xD6, 0x31, 0x8C, 0x60, 0x48, 0xC6,
+        0x2A, 0x88, 0x84, 0x84, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, 0xA2, 0x4F, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xF8, 0xC6, 0xB1, 0x8F, 0xE2, 0x48, 0xD8, 0x00, 0x82, 0x95, 0xFC, 0xC8,
+        0x82, 0x42, 0x88, 0x00, 0x00, 0x31, 0xE0, 0x43, 0x18, 0x40, 0x31, 0x88, 0x00, 0x20, 0x22,
+        0x31, 0x8C, 0x63, 0x18, 0x42, 0x31, 0x20, 0x65, 0x0D, 0xE6, 0x31, 0x8C, 0x60, 0x48, 0xC6,
+        0x31, 0x88, 0x45, 0x04, 0x28, 0x04, 0x04, 0x00, 0x10, 0x10, 0x10, 0x00, 0x20, 0x40, 0x00,
+        0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x48, 0xA4, 0x00, 0x82, 0x80, 0x40, 0x30,
+        0x81, 0x80, 0x00, 0x00, 0x00, 0x3F, 0x27, 0xFF, 0x1F, 0xFF, 0xEF, 0xF8, 0x00, 0x00, 0x01,
+        0xCE, 0x77, 0x9D, 0xEF, 0xFD, 0xD1, 0xF8, 0x63, 0x08, 0xC5, 0xDE, 0x77, 0x9F, 0xF8, 0xC6,
+        0x31, 0x8F, 0xC7, 0x0C, 0x10, 0x08, 0x04, 0x00, 0x10, 0x1C, 0x10, 0x20, 0xA0, 0xC0, 0x00,
+        0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3E, 0x4F, 0x80, 0x00,
+    }};
+#endif // FONT1_H_
\ No newline at end of file
--- /dev/null
+++ b/src/fonts/font2.h
@@ -1,0 +1,85 @@
+#ifndef FONT2_H_
+#define FONT2_H_
+#include "inline_font.h"
+
+struct inline_font font_v1_large = {
+    752,
+    9,
+    8,
+    9,
+    0,
+    -40,
+    4,
+    22,
+    1010,
+    {
+        0x42, 0x4D, 0xF2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
+        0x00, 0x00, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
+        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xFF, 0xFF, 0xE7,
+        0x7D, 0x84, 0xFF, 0xFC, 0x9F, 0xFF, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0xFC, 0x00, 0x00, 0xE7, 0x01, 0xFC, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xE7, 0x81, 0x3C, 0x01,
+        0x81, 0x03, 0x00, 0x3F, 0x81, 0x3C, 0x00, 0x81, 0x3C, 0x00, 0x3C, 0x3C, 0x81, 0x3F, 0x84,
+        0x3C, 0x81, 0xE7, 0x81, 0xE7, 0x3C, 0x3C, 0xE7, 0x00, 0xF0, 0xFF, 0x0F, 0xFF, 0x80, 0xFF,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x24, 0x3C, 0x00,
+        0x3F, 0xFC, 0x3F, 0x00, 0x80, 0x00, 0x3F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xE7, 0x00, 0xFF,
+        0x00, 0x00, 0xFF, 0xFF, 0xDB, 0x00, 0x38, 0x39, 0xFF, 0xF9, 0xCF, 0xFF, 0xFF, 0xCF, 0xFF,
+        0xFF, 0x3F, 0x3C, 0xE7, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C, 0xE7, 0x3C, 0xFC, 0xFF, 0x9F, 0xFC,
+        0xFF, 0x9F, 0xFF, 0x3F, 0x3C, 0x3C, 0x3C, 0x39, 0x3F, 0x3F, 0x3C, 0x3C, 0xE7, 0x3C, 0x39,
+        0x3F, 0x3C, 0x3C, 0x3C, 0x3F, 0x39, 0x39, 0x3C, 0xE7, 0x3C, 0xC3, 0x18, 0x3C, 0xE7, 0x3F,
+        0xF3, 0xFC, 0xCF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3F, 0x3C, 0x3F, 0x9F, 0xFC, 0x3C, 0xE7,
+        0xFC, 0x39, 0xCF, 0x24, 0x3C, 0x3C, 0x3F, 0xFC, 0x3F, 0xFC, 0x9F, 0x3C, 0x1F, 0x24, 0x99,
+        0xFC, 0x9F, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x81, 0xE4, 0x9D, 0x30, 0xFF,
+        0xF3, 0xE7, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0x9F, 0x3C, 0xE7, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C,
+        0xE7, 0x3C, 0xFC, 0xE7, 0x9F, 0xF8, 0x81, 0x8F, 0xE7, 0x21, 0x3C, 0x3C, 0x3F, 0x3C, 0x3F,
+        0x3F, 0x3C, 0x3C, 0xE7, 0x3C, 0x33, 0x3F, 0x3C, 0x3C, 0x3C, 0x3F, 0x32, 0x33, 0xFC, 0xE7,
+        0x3C, 0x99, 0x00, 0x99, 0xE7, 0x9F, 0xF3, 0xF9, 0xCF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3F,
+        0x3C, 0x3F, 0x9F, 0xFC, 0x3C, 0xE7, 0xFC, 0x33, 0xCF, 0x24, 0x3C, 0x3C, 0x3F, 0xFC, 0x3F,
+        0xFC, 0x9F, 0x3C, 0x0F, 0x24, 0xC3, 0xFC, 0xCF, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF,
+        0xFF, 0xDB, 0xE4, 0xCF, 0x87, 0xFF, 0xF3, 0xE7, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xCF, 0x3C,
+        0xE7, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C, 0xE7, 0x3C, 0xFC, 0xFF, 0xFF, 0xF0, 0xFF, 0x87, 0xE7,
+        0x24, 0x3C, 0x3C, 0x3F, 0x3C, 0x3F, 0x3F, 0x3C, 0x3C, 0xE7, 0xFC, 0x27, 0x3F, 0x3C, 0x38,
+        0x3C, 0x3F, 0x24, 0x27, 0xFC, 0xE7, 0x3C, 0x3C, 0x24, 0xC3, 0xE7, 0xCF, 0xF3, 0xF3, 0xCF,
+        0xFF, 0xFF, 0xFF, 0x00, 0x3C, 0x3F, 0x3C, 0x00, 0x9F, 0x00, 0x3C, 0xE7, 0xFC, 0x07, 0xCF,
+        0x24, 0x3C, 0x3C, 0x00, 0x00, 0x3F, 0x00, 0x9F, 0x3C, 0x27, 0x24, 0xE7, 0x00, 0xE7, 0x3C,
+        0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF, 0xFF, 0xDB, 0x00, 0xE7, 0xC7, 0xFF, 0xF3, 0xE7, 0x33,
+        0x81, 0xFF, 0x81, 0xFF, 0xE7, 0x24, 0xE7, 0x00, 0x80, 0x00, 0x00, 0x00, 0xF3, 0x81, 0x00,
+        0xFF, 0xFF, 0xE0, 0xFF, 0x83, 0xE1, 0x24, 0x00, 0x01, 0x3F, 0x3C, 0x03, 0x03, 0x30, 0x00,
+        0xE7, 0xFC, 0x0F, 0x3F, 0x3C, 0x30, 0x3C, 0x01, 0x3C, 0x01, 0x81, 0xE7, 0x3C, 0x3C, 0x3C,
+        0xE7, 0x81, 0xE7, 0xF3, 0xE7, 0xCF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3C, 0x3F, 0x3C, 0x3C, 0x9F,
+        0x3C, 0x3C, 0xE7, 0xFC, 0x33, 0xCF, 0x24, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0x3F, 0x9F, 0x3C,
+        0x33, 0x24, 0xC3, 0x3C, 0xF3, 0x3C, 0xE7, 0x3C, 0x23, 0x00, 0x00, 0xCF, 0xFF, 0x81, 0x27,
+        0xF3, 0x93, 0xFF, 0xF3, 0xE7, 0x87, 0xE7, 0xFF, 0xFF, 0xFF, 0xF3, 0x3C, 0xE7, 0xFC, 0xFC,
+        0x3C, 0x3F, 0x3F, 0xF9, 0x3C, 0x3C, 0xE7, 0x9F, 0xF0, 0xFF, 0x87, 0xFC, 0x20, 0x3C, 0x3B,
+        0x3F, 0x3C, 0x3F, 0x3F, 0x3F, 0x3C, 0xE7, 0xFC, 0x27, 0x3F, 0x24, 0x24, 0x3C, 0x3C, 0x3C,
+        0x3C, 0x3F, 0xE7, 0x3C, 0x3C, 0x3C, 0xC3, 0x3C, 0xF3, 0xF3, 0xCF, 0xCF, 0xFF, 0xFF, 0xFF,
+        0xFC, 0x3C, 0x3F, 0x3C, 0x3C, 0x00, 0x3C, 0x3C, 0xE7, 0xFC, 0x39, 0xCF, 0x24, 0x3C, 0x3C,
+        0x3C, 0x3C, 0x3F, 0x3F, 0x9F, 0x3C, 0x39, 0x24, 0x99, 0x3C, 0xF9, 0x3C, 0xE7, 0x3C, 0x89,
+        0x00, 0x00, 0xCF, 0xC9, 0xDB, 0x27, 0xB9, 0x93, 0xE7, 0xF3, 0xE7, 0xCF, 0xE7, 0xFF, 0xFF,
+        0xFF, 0xF9, 0x3C, 0xE7, 0xFC, 0xFC, 0x3C, 0x3F, 0x3F, 0xFC, 0x3C, 0x3C, 0xFF, 0xFF, 0xF8,
+        0x81, 0x8F, 0xFC, 0x3C, 0x3C, 0x39, 0x3F, 0x3C, 0x3F, 0x3F, 0x3F, 0x3C, 0xE7, 0xFC, 0x33,
+        0x3F, 0x00, 0x0C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0xE7, 0x3C, 0x3C, 0x3C, 0x99, 0x3C, 0xF9,
+        0xF3, 0x9F, 0xCF, 0x27, 0xFF, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x87,
+        0x80, 0x3C, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x24, 0x3C,
+        0x3C, 0x00, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF, 0xC9, 0xFF, 0x00, 0x1C, 0xC7, 0xE7,
+        0xF9, 0xCF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3C, 0xE7, 0xFC, 0xFC, 0x3C, 0x3F, 0x3F,
+        0xFC, 0x9C, 0x3C, 0xFF, 0xFF, 0xFC, 0xFF, 0x9F, 0x3C, 0x3C, 0x99, 0x39, 0x3C, 0x39, 0x3F,
+        0x3F, 0x3C, 0x3C, 0xE7, 0xFC, 0x39, 0x3F, 0x18, 0x1C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xE7,
+        0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xF3, 0x3F, 0xCF, 0x8F, 0xFF, 0x9F, 0xFF, 0x3F, 0xFF,
+        0xFC, 0xFF, 0x9F, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xE7, 0x3C, 0xFF, 0x00, 0x00, 0xCF,
+        0xC9, 0xFF, 0xE7, 0xBE, 0xFF, 0xE7, 0xFC, 0x9F, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+        0x87, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81,
+        0x81, 0xC3, 0x03, 0x81, 0x03, 0x00, 0x00, 0x81, 0x3C, 0x00, 0x00, 0x3C, 0x3F, 0x3C, 0x3C,
+        0x81, 0x01, 0x81, 0x01, 0x81, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0xF0, 0xFF, 0x0F,
+        0xDF, 0xFF, 0x3F, 0xFF, 0x3F, 0xFF, 0xFC, 0xFF, 0x80, 0xFF, 0x3F, 0xE7, 0xFC, 0x3F, 0x0F,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+        0xE7, 0x00, 0xFF, 0x00, 0x00,
+    }};
+#endif // FONT2_H_
\ No newline at end of file
--- /dev/null
+++ b/src/fonts/font3.h
@@ -1,0 +1,93 @@
+#ifndef FONT3_H_
+#define FONT3_H_
+
+#include "inline_font.h"
+
+struct inline_font font_v2_small = {
+    846,
+    9,
+    9,
+    9,
+    0,
+    -2,
+    5,
+    38,
+    1118,
+    {
+        0x42, 0x4D, 0x5E, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
+        0x00, 0x00, 0x00, 0x4E, 0x03, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0xCC, 0x03, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
+        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x7E,
+        0xF7, 0xC4, 0x3B, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFB, 0xFD, 0xFE, 0x00, 0x00,
+        0x00, 0x00, 0x1F, 0xE0, 0x00, 0x03, 0xFC, 0x00, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xDE, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x30, 0x03, 0xFC, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0,
+        0x07, 0xF3, 0xF8, 0x00, 0xFF, 0x01, 0x3F, 0x80, 0x1E, 0xF0, 0x07, 0xBD, 0xFC, 0xFE, 0x00,
+        0x00, 0x3C, 0x7F, 0xEE, 0x3F, 0xFC, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFC,
+        0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x07, 0x73, 0xF8, 0x00, 0xFF, 0xFF, 0x3F, 0xC0, 0x00,
+        0x00, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x07, 0xFC, 0x00, 0x00, 0xFF,
+        0xFF, 0xF7, 0x60, 0x0B, 0xD3, 0xD7, 0xFF, 0xFD, 0xBF, 0xFF, 0xFD, 0xEF, 0xFF, 0xFF, 0xFE,
+        0xFE, 0xFE, 0xF7, 0xBF, 0xFF, 0xDF, 0xEF, 0xF3, 0xFB, 0xFC, 0xFE, 0xFF, 0x7F, 0xDF, 0xFF,
+        0x3F, 0xFF, 0x3F, 0xFE, 0xFF, 0x7F, 0x3F, 0x9F, 0xEF, 0xD7, 0xFB, 0xFD, 0xFC, 0xFE, 0xF7,
+        0xFF, 0x9F, 0xAF, 0xF7, 0xF3, 0xF1, 0xFC, 0xFF, 0x7E, 0xBF, 0x7F, 0xDE, 0xF7, 0xF7, 0x5C,
+        0xF9, 0x7D, 0xFF, 0x5F, 0xFD, 0xFF, 0xDF, 0xBF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x9F, 0xEF,
+        0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0xAF, 0xF7, 0x73, 0xF9, 0xFC, 0xFF, 0xFF,
+        0x3F, 0xFF, 0xCF, 0xF7, 0xF3, 0x7D, 0xDD, 0x7D, 0xFF, 0x3F, 0xDF, 0xCF, 0xF7, 0xF7, 0xFC,
+        0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x1E, 0xED, 0xC3, 0xEF, 0xFF, 0xFB, 0xDF, 0xFF, 0xFD, 0xFF,
+        0xFF, 0xFF, 0xFF, 0x7E, 0xFE, 0xF7, 0xBF, 0xFF, 0xDF, 0xEF, 0xF3, 0xFB, 0xFC, 0xFE, 0xFF,
+        0x3F, 0xDF, 0xFE, 0x38, 0x0F, 0x1F, 0xDE, 0x80, 0x7F, 0x3F, 0x9F, 0xEF, 0xE7, 0xFB, 0xFD,
+        0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0x6F, 0xF7, 0xF3, 0xE9, 0xFC, 0xFF, 0x7D, 0x3E, 0xFF, 0xDE,
+        0xF7, 0xF6, 0xED, 0x75, 0xBB, 0xFF, 0x6F, 0xFD, 0xFF, 0xBF, 0xBF, 0xFF, 0xFF, 0xFF, 0x7F,
+        0x3F, 0x9F, 0xEF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0x6F, 0xF7, 0x73, 0xF9,
+        0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xCF, 0xF7, 0xF3, 0xBD, 0xDD, 0xBB, 0xFF, 0x4F, 0xDF, 0xCF,
+        0xF7, 0xF7, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x7E, 0xEE, 0xFB, 0xD7, 0xFF, 0xFB, 0xDF,
+        0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0xFE, 0xF7, 0xBF, 0xFF, 0xDF, 0xEF, 0xF3, 0xFB,
+        0xFC, 0xFE, 0xFF, 0x7F, 0xFF, 0xFC, 0x3F, 0xFF, 0x0F, 0xDE, 0xBA, 0x7F, 0x3F, 0x9F, 0xEF,
+        0xE7, 0xFB, 0xFD, 0xFC, 0xFE, 0xF7, 0xFF, 0x9E, 0xEF, 0xF7, 0xF3, 0xD9, 0xFC, 0xFF, 0x7B,
+        0x3D, 0xFF, 0xDE, 0xF7, 0xF5, 0xF5, 0xAD, 0xD7, 0xFF, 0x77, 0xFD, 0xFF, 0x7F, 0xBF, 0xFF,
+        0xFF, 0xFF, 0x00, 0x3F, 0x9F, 0xEF, 0xE0, 0x00, 0x0C, 0x00, 0xFE, 0xF7, 0xFF, 0x80, 0xEF,
+        0xF7, 0x73, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0xC0, 0x0F, 0xF7, 0xF3, 0xDD, 0xDD, 0xC7, 0x00,
+        0x71, 0xDF, 0xCF, 0xF7, 0xF7, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x60, 0x0F, 0x7D, 0xBB,
+        0xFF, 0xFB, 0xDF, 0xDD, 0xE0, 0x3F, 0xF8, 0x0F, 0xFF, 0xDE, 0xEE, 0xF7, 0x80, 0x00, 0x00,
+        0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x3F, 0xFF, 0x07, 0xC0, 0x82, 0x00,
+        0x00, 0x1F, 0xEF, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0xF7, 0xFF, 0x81, 0xEF, 0xF7, 0x73, 0xB9,
+        0xFC, 0x00, 0x7F, 0x00, 0x00, 0x1E, 0xF7, 0xF3, 0xF9, 0xDD, 0xEF, 0x00, 0x7B, 0xFD, 0xFE,
+        0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x9F, 0xEF, 0xE7, 0xF3, 0xFD, 0xFC, 0xFE, 0xF7,
+        0xFF, 0x9F, 0x6F, 0xF7, 0x73, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0xDF, 0xEF, 0xF7, 0xF3, 0xED,
+        0xDD, 0xBB, 0x7F, 0x7E, 0x5F, 0xCF, 0xF7, 0xF3, 0x3C, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0x6E,
+        0xFF, 0xBE, 0x7F, 0xFF, 0xFB, 0xDF, 0xEB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFE, 0xF7,
+        0xFF, 0xBF, 0xCF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0x7F, 0x7F, 0xFF, 0xFC, 0x3F, 0xFF, 0x0F,
+        0xFC, 0xFA, 0x7F, 0x3E, 0xDF, 0xEF, 0xE7, 0xFB, 0xFD, 0xFE, 0xFE, 0xF7, 0xFF, 0x9E, 0xEF,
+        0xF6, 0xB3, 0x79, 0xFC, 0xFE, 0x7F, 0x3F, 0x9F, 0xFE, 0xF7, 0xF3, 0xF9, 0xFD, 0xD7, 0x7F,
+        0x7D, 0xFD, 0xFD, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x9F, 0xEF, 0xE7, 0xF3, 0xFD,
+        0xFC, 0xFE, 0xF7, 0xFF, 0x9F, 0xAF, 0xF7, 0x73, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0xDF, 0xEF,
+        0xF7, 0xF3, 0xF5, 0xDD, 0x7D, 0x7F, 0x7F, 0x9F, 0xCF, 0xF7, 0xF4, 0xDC, 0x00, 0x00, 0x7F,
+        0xB7, 0xC0, 0x0E, 0xF1, 0xDD, 0xBD, 0xFF, 0xFB, 0xDF, 0xF7, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xF6, 0xFE, 0xF7, 0xFF, 0xBF, 0xCF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0x7F, 0x3F, 0xDF, 0xFE,
+        0x38, 0x0F, 0x1F, 0xFC, 0x82, 0x7F, 0x3E, 0xDF, 0xEF, 0xE7, 0xFB, 0xFD, 0xFE, 0xFE, 0xF7,
+        0xFF, 0x9F, 0x6F, 0xF5, 0xD2, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0x9F, 0xFE, 0xF7, 0xF3, 0xF9,
+        0xFD, 0xBB, 0x7F, 0x7E, 0xFD, 0xFB, 0xFF, 0xBB, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0xCF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x07, 0xF3, 0xF9, 0xDC, 0xFE, 0x7F, 0x00, 0x1F, 0xCF, 0xF7, 0xF7, 0xFC,
+        0x00, 0x00, 0x7F, 0xB7, 0xF7, 0x60, 0x05, 0xED, 0xBD, 0xFF, 0xFD, 0xBF, 0xEB, 0xFD, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFA, 0xFE, 0xF7, 0xFF, 0xBF, 0xCF, 0xE7, 0xFB, 0xFF, 0xFC, 0xFE, 0x7F,
+        0x7F, 0xFF, 0xFF, 0x3F, 0xFF, 0x3D, 0xFC, 0xFE, 0x7F, 0x3E, 0xDF, 0xEF, 0xD7, 0xFB, 0xFD,
+        0xFE, 0xFE, 0xF7, 0xFF, 0x9F, 0xAF, 0xF3, 0xE1, 0xF9, 0xFC, 0xFE, 0x7F, 0x3F, 0x9F, 0xFE,
+        0xF7, 0xF3, 0xF9, 0xFD, 0x7D, 0x7F, 0x7F, 0x7D, 0xF7, 0xFF, 0xBD, 0x7F, 0xFF, 0xBF, 0xFF,
+        0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xCF,
+        0xF7, 0xF7, 0xFC, 0x00, 0x00, 0x7F, 0xB7, 0xF7, 0x7E, 0xF1, 0xF6, 0x7D, 0xFF, 0xFE, 0x7F,
+        0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x07, 0x80, 0x00, 0x0F, 0xE0, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00,
+        0x30, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0x9F, 0xCF, 0xF7, 0xF3, 0xF8, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x07, 0xF3, 0xF9, 0xFC, 0xFE, 0x7F, 0x00, 0x3C, 0x6F, 0xFE, 0x3E, 0xFF,
+        0xFF, 0x7F, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xC0, 0x0F, 0xF0, 0x07, 0xFC, 0x00, 0x00,
+    }};
+#endif // FONT3_H_
\ No newline at end of file
--- /dev/null
+++ b/src/fonts/font4.h
@@ -1,0 +1,108 @@
+#ifndef FONT4_H_
+#define FONT4_H_
+
+#include "inline_font.h"
+
+struct inline_font font_v2_large = {
+    940,
+    10,
+    10,
+    10,
+    0,
+    -2,
+    4,
+    38,
+    1346,
+    {
+        0x42, 0x4D, 0x42, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
+        0x00, 0x00, 0x00, 0xAC, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
+        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCF,
+        0xCF, 0x3E, 0x60, 0xCF, 0xFF, 0xF9, 0x3F, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xE7, 0xF3, 0xFC,
+        0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x3F, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x03, 0x3F, 0x00, 0x18, 0x00, 0x01, 0x80, 0x0F, 0xF8, 0x04,
+        0xFC, 0x00, 0x00, 0x13, 0xF2, 0x00, 0x3F, 0x0F, 0xC8, 0x04, 0xFF, 0x83, 0x0F, 0xC0, 0x07,
+        0xCF, 0x80, 0x7C, 0xF3, 0xF0, 0xFC, 0x00, 0x40, 0x0F, 0x0F, 0xFC, 0xE1, 0xFF, 0xF0, 0x03,
+        0xFF, 0x80, 0x00, 0x18, 0x02, 0x00, 0x80, 0x33, 0xF0, 0x04, 0xFC, 0x00, 0x00, 0x13, 0xE0,
+        0x00, 0x33, 0x0F, 0xC8, 0x04, 0xFF, 0xFF, 0x0F, 0xF0, 0x07, 0x80, 0x80, 0x43, 0xF8, 0x00,
+        0xFC, 0x00, 0x40, 0x00, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCC,
+        0x01, 0x1E, 0x40, 0x0F, 0xFF, 0xF1, 0x1F, 0xFF, 0xFF, 0x3C, 0xFF, 0xFF, 0xE7, 0xF1, 0xFC,
+        0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x3F, 0xFC, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x03, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00,
+        0xFC, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x3F, 0x0F, 0x80, 0x00, 0xFF, 0x06, 0x0F, 0x80, 0x03,
+        0xCF, 0x00, 0x38, 0x71, 0xE0, 0x78, 0x00, 0x00, 0x0F, 0x0F, 0xF8, 0xE1, 0xFF, 0xF0, 0x03,
+        0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xF0, 0x00, 0xFC, 0x00, 0x00, 0x03, 0xC4,
+        0x00, 0x33, 0x0F, 0xC0, 0x00, 0xFF, 0xFF, 0x0F, 0xF0, 0x03, 0x00, 0x00, 0x01, 0xF0, 0x00,
+        0x78, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00,
+        0x00, 0x8F, 0xCE, 0x1F, 0xFF, 0xE3, 0x8F, 0xFF, 0xFF, 0x3C, 0xFF, 0xFF, 0xFF, 0xF8, 0xFC,
+        0xFC, 0xF3, 0xCF, 0xFF, 0xF3, 0xFC, 0xFF, 0x0F, 0xCF, 0xF0, 0xFC, 0xFF, 0x33, 0xFC, 0xFF,
+        0xE7, 0x80, 0x79, 0xFF, 0xFC, 0xFF, 0x3F, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0xCF, 0xF3, 0xF0,
+        0xFC, 0xF3, 0xFF, 0xC3, 0xC4, 0xFF, 0x3F, 0x0F, 0x03, 0xF0, 0xFF, 0x3C, 0x0F, 0x1F, 0xF3,
+        0xCF, 0x3F, 0x30, 0x30, 0xC2, 0x31, 0xFF, 0x23, 0xFF, 0x3F, 0xF1, 0xF9, 0xFF, 0xFF, 0xFF,
+        0xFF, 0x3F, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0xF3, 0xFF, 0xF0, 0xFC, 0xF3, 0xFF, 0xC3, 0x8F,
+        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0x01, 0x80, 0x0F, 0xFF, 0xF3, 0x3F, 0x3F, 0x08, 0xF3, 0x32,
+        0x31, 0xFF, 0x03, 0xF3, 0xF0, 0xFF, 0x3F, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x03,
+        0xCC, 0xC7, 0xCE, 0x1F, 0xFF, 0xE7, 0xCF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFC, 0x7C,
+        0xFC, 0xF3, 0xCF, 0xFF, 0xF3, 0xFC, 0xFF, 0x0F, 0xCF, 0xF0, 0xFC, 0xFF, 0x33, 0xFC, 0xFF,
+        0xC7, 0x80, 0x78, 0xFF, 0x3C, 0xC0, 0x3F, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0xCF, 0xF3, 0xF0,
+        0xFC, 0xF3, 0xFF, 0xC3, 0x8C, 0xFF, 0x3F, 0x0E, 0x03, 0xF0, 0xFF, 0x38, 0x0E, 0x3F, 0xF3,
+        0xCF, 0x3F, 0x23, 0x10, 0x03, 0x03, 0xFF, 0x31, 0xFF, 0x3F, 0xE3, 0xF9, 0xFF, 0xFF, 0xFF,
+        0xFF, 0x00, 0x0F, 0xC3, 0xFC, 0xFC, 0x00, 0x33, 0xF8, 0x00, 0xFC, 0xF3, 0xFF, 0xC0, 0x1F,
+        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0x00, 0x00, 0x0F, 0xF8, 0x03, 0x3F, 0x3F, 0x0C, 0x73, 0x33,
+        0x03, 0x80, 0x20, 0x73, 0xF0, 0xFF, 0x3F, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCE,
+        0x00, 0xE3, 0xC0, 0x0F, 0xFF, 0xE7, 0xCF, 0xCE, 0x78, 0x07, 0xFF, 0x80, 0x7F, 0xFE, 0x3C,
+        0xCC, 0xF3, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
+        0x87, 0xFF, 0xF8, 0x7F, 0x04, 0xC0, 0x00, 0x00, 0x03, 0xFC, 0xFC, 0x00, 0x00, 0x03, 0x00,
+        0x00, 0xF3, 0xFF, 0xC0, 0x1C, 0xFF, 0x33, 0x0C, 0x43, 0xF0, 0x01, 0x31, 0x00, 0x18, 0x03,
+        0xCF, 0x3F, 0x07, 0x82, 0x13, 0x87, 0x80, 0x38, 0xFF, 0x3F, 0xC7, 0xF9, 0xFF, 0xFF, 0xFF,
+        0xFF, 0x00, 0x0F, 0xC3, 0xFC, 0xFC, 0x00, 0x33, 0xF0, 0x00, 0xFC, 0xF3, 0xFF, 0xC0, 0x3F,
+        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xF0, 0x07, 0x3F, 0x3F, 0x0E, 0x33, 0x33,
+        0x03, 0x00, 0x38, 0x13, 0xF0, 0xFF, 0x3F, 0x08, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xCC,
+        0x01, 0xF1, 0xE0, 0xCF, 0xFF, 0xE7, 0xCF, 0xC4, 0x78, 0x07, 0xFF, 0x80, 0x7F, 0xFF, 0x1C,
+        0xCC, 0xF3, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
+        0x07, 0xFF, 0xF8, 0x3F, 0x00, 0xCC, 0x00, 0x00, 0x33, 0xFC, 0xFC, 0x00, 0x00, 0x03, 0x00,
+        0x00, 0xF3, 0xFF, 0xC0, 0x1C, 0xFF, 0x21, 0x08, 0xC3, 0xF0, 0x00, 0x33, 0x00, 0x00, 0x07,
+        0xCF, 0x3F, 0x0F, 0xC3, 0x33, 0x87, 0x00, 0x3C, 0x7F, 0x3F, 0x8F, 0xF9, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0x0F, 0xC3, 0xFC, 0xFC, 0x3F, 0x00, 0x33, 0xF0, 0xFC, 0xF3, 0xFF, 0xC3, 0x1F,
+        0xCF, 0x33, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xF3, 0xFF, 0x3F, 0x3F, 0x0F, 0x13, 0x32,
+        0x31, 0x3F, 0x3F, 0x03, 0xF0, 0xFF, 0x3F, 0x00, 0x70, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00,
+        0xCF, 0xF8, 0xE6, 0x7F, 0xFF, 0xE7, 0xCF, 0xF1, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x8C,
+        0xFC, 0xF3, 0xFF, 0xCF, 0xF0, 0xFC, 0x3F, 0xCF, 0xFF, 0xF0, 0xFC, 0x3F, 0x33, 0xFC, 0xFF,
+        0x87, 0x80, 0x78, 0x7F, 0xF0, 0xCC, 0x3F, 0x0F, 0x93, 0xFC, 0xFC, 0x3F, 0xCF, 0xF3, 0xFC,
+        0xFC, 0xF3, 0xFF, 0xC3, 0x8C, 0xFF, 0x00, 0x01, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xFF,
+        0xCF, 0x3F, 0x0F, 0xC3, 0xF3, 0x03, 0x3F, 0x3E, 0x3F, 0x3F, 0x1F, 0xF9, 0xE6, 0x7F, 0xFF,
+        0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0xFF, 0x03, 0x8F,
+        0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x0F, 0x83, 0x30,
+        0x78, 0x3F, 0x00, 0x03, 0xF0, 0xFF, 0x3F, 0x22, 0x70, 0x00, 0x00, 0x3F, 0xC9, 0xF0, 0x00,
+        0x00, 0xFC, 0x66, 0x73, 0xFF, 0xE3, 0x8F, 0xF1, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC4,
+        0xFC, 0xF3, 0xFF, 0xCF, 0xF0, 0xFC, 0x3F, 0xCF, 0xFF, 0xF0, 0xFC, 0x3F, 0x33, 0xFC, 0xFF,
+        0xC7, 0x80, 0x78, 0xF3, 0xF0, 0xFC, 0x3F, 0x0F, 0x93, 0xFC, 0xF8, 0x3F, 0xCF, 0xF3, 0xFC,
+        0xFC, 0xF3, 0xFF, 0xC3, 0xC4, 0xFF, 0x0C, 0x03, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xFF,
+        0xCF, 0x3F, 0x0F, 0xC3, 0xF2, 0x31, 0x3F, 0x3F, 0x1F, 0x3E, 0x3F, 0xF9, 0xE0, 0x7F, 0xFF,
+        0x3F, 0x00, 0x40, 0x18, 0x02, 0x00, 0x80, 0x73, 0xF8, 0x00, 0x01, 0xC3, 0xFF, 0x03, 0xC7,
+        0xCF, 0x00, 0x40, 0x18, 0x04, 0x01, 0x80, 0x20, 0x08, 0x00, 0x00, 0x3F, 0x0F, 0xC3, 0x30,
+        0xFC, 0x3F, 0x00, 0x03, 0xF0, 0xFF, 0x3F, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xC9, 0xFC, 0xCE,
+        0x00, 0x9E, 0x20, 0x73, 0xFF, 0xF1, 0x1F, 0xC4, 0x7F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
+        0x00, 0x03, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
+        0xE7, 0xFF, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+        0xFC, 0x00, 0x3F, 0xC3, 0xE0, 0xFF, 0x1E, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x3F, 0x0F, 0xC3, 0xF0, 0x78, 0x3F, 0x00, 0x0F, 0x0C, 0x7F, 0xE1, 0xF0, 0xFF, 0xFE,
+        0x3F, 0xFF, 0xCF, 0xFF, 0xFF, 0xFC, 0xFF, 0xF0, 0x0F, 0xFC, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF,
+        0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xC9, 0xFC, 0xCF,
+        0xCF, 0x9F, 0x30, 0xF3, 0xFF, 0xF9, 0x3F, 0xCE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
+        0x00, 0x03, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xF8, 0x06, 0x01, 0x80, 0x40, 0x38, 0x00, 0x03, 0x80, 0x20, 0x08, 0x00,
+        0xFC, 0x00, 0x3F, 0xC3, 0xF0, 0xFF, 0x3F, 0x0F, 0xC8, 0x04, 0x01, 0x80, 0x40, 0x18, 0x00,
+        0x00, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x00, 0x0F, 0x0C, 0xFF, 0xE1, 0xF9, 0xFF, 0xFE,
+        0x7F, 0xFF, 0xCF, 0xFF, 0xFF, 0xFC, 0xFF, 0xF8, 0x0F, 0xFC, 0xFF, 0xF3, 0xFF, 0xC3, 0xFF,
+        0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0x00,
+    }};
+#endif // FONT4_H_
\ No newline at end of file
--- /dev/null
+++ b/src/fonts/font5.h
@@ -1,0 +1,143 @@
+#ifndef FONT5_H_
+#define FONT5_H_
+
+#include "inline_font.h"
+
+struct inline_font font_v2_huge = {
+    1128,
+    12,
+    12,
+    12,
+    0,
+    -54,
+    4,
+    24,
+    1874,
+    {
+        0x42, 0x4D, 0x52, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7C,
+        0x00, 0x00, 0x00, 0x68, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00,
+        0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+        0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF,
+        0xFF, 0x9F, 0xFF, 0xFC, 0x1C, 0xFF, 0xFF, 0xF3, 0xE7, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF,
+        0xF9, 0xFF, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0xFF,
+        0xC0, 0x00, 0xFF, 0xCF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xF8, 0x03, 0x3F,
+        0xC0, 0x01, 0x80, 0x00, 0x01, 0x80, 0x03, 0xFF, 0x80, 0x13, 0xFC, 0x00, 0x00, 0x01, 0x3F,
+        0xC8, 0x00, 0x3F, 0xC3, 0xFC, 0x80, 0x13, 0xFF, 0x80, 0xC3, 0xFC, 0x00, 0x1F, 0x9F, 0x80,
+        0x1F, 0x9F, 0x3F, 0xC3, 0xFC, 0x00, 0x10, 0x00, 0xC0, 0xFF, 0xFC, 0xE0, 0x7F, 0xFF, 0x00,
+        0x0F, 0xFF, 0x80, 0x00, 0x01, 0x80, 0x08, 0x00, 0x80, 0x0C, 0xFF, 0x00, 0x13, 0xFC, 0x00,
+        0x00, 0x01, 0x3F, 0x80, 0x00, 0x39, 0xC3, 0xFC, 0x80, 0x13, 0xFF, 0xFF, 0xC3, 0xFF, 0x00,
+        0x1E, 0x00, 0x80, 0x10, 0xFF, 0x80, 0x03, 0xFC, 0x00, 0x10, 0x00, 0x00, 0x03, 0xFF, 0x00,
+        0x0F, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE6, 0x70, 0x01, 0x9F, 0x18, 0x08, 0xFF,
+        0xFF, 0xE3, 0xE3, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xF9, 0xFF, 0x1F, 0xF0, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0xFF, 0xCF, 0xFF, 0x8F,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x03, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x03, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0xC3, 0xF8, 0x00,
+        0x03, 0xFF, 0x01, 0x83, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x0F, 0x0F, 0x1F, 0x81, 0xF8, 0x00,
+        0x00, 0x00, 0xC0, 0xFF, 0xF8, 0xE0, 0x7F, 0xFF, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x0C, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0x10, 0x00, 0x39,
+        0xC3, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xC3, 0xFF, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7F, 0x00,
+        0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0xFF,
+        0xFF, 0xFF, 0xE6, 0x70, 0x00, 0x8F, 0x11, 0xC1, 0xFF, 0xFF, 0xC7, 0xF1, 0xFF, 0xFF, 0xF9,
+        0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xF3, 0xFC, 0xF9, 0xF3, 0xFF, 0xFF, 0xCF, 0xFC, 0xFF,
+        0xC3, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xCF, 0x9F, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0xF9,
+        0xFF, 0xFC, 0x3F, 0x13, 0xFF, 0x3F, 0xC3, 0xF0, 0x3F, 0xC3, 0xFF, 0x3F, 0x03, 0xF1, 0xFF,
+        0xCF, 0x9F, 0x3F, 0xCE, 0x07, 0x0F, 0x08, 0xF1, 0xFF, 0xC8, 0xFF, 0xCF, 0xFF, 0xF1, 0xFE,
+        0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xFC, 0xFF, 0xFF,
+        0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3E, 0x3F, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC3, 0xFF, 0xFF,
+        0xC3, 0xFF, 0xFF, 0xCC, 0xFF, 0x3F, 0xC2, 0x3F, 0x39, 0xC8, 0xF1, 0xFF, 0xCC, 0x7F, 0x3F,
+        0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0x9C, 0xC7,
+        0x13, 0xE3, 0xFF, 0xFF, 0xCF, 0xF9, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7,
+        0xF3, 0xFC, 0xF9, 0xF3, 0xFF, 0xFF, 0xCF, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF,
+        0xCF, 0x9F, 0xCF, 0xFF, 0xCF, 0xC0, 0x3F, 0x3F, 0xFF, 0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0x3F,
+        0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3E, 0x33, 0xFF, 0x3F,
+        0xC3, 0xE0, 0x3F, 0xC3, 0xFF, 0x3E, 0x03, 0xE3, 0xFF, 0xCF, 0x9F, 0x3F, 0xCC, 0x63, 0x06,
+        0x0C, 0x63, 0xFF, 0xCC, 0x7F, 0xCF, 0xFF, 0xE3, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F,
+        0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xFC, 0xFF, 0xFF, 0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3C,
+        0x7F, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC0, 0x01, 0x80, 0x03, 0xFF, 0xFF, 0xCC, 0xFF, 0x3F,
+        0xC3, 0x1F, 0x39, 0xCC, 0x63, 0xFF, 0xCE, 0x3F, 0x3F, 0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00,
+        0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x1F, 0x9C, 0xE3, 0xF3, 0xC1, 0xFF, 0xFF, 0xCF, 0xF9,
+        0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xF3, 0xFC, 0xF9, 0xF3, 0xFF, 0xFF,
+        0xCF, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xC3, 0xFC, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0x8F, 0xC0,
+        0x3F, 0x1F, 0xF9, 0xF3, 0x80, 0x3F, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F,
+        0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3C, 0x73, 0xFF, 0x3F, 0xC3, 0xC4, 0x3F, 0xC3, 0xFF, 0x3C,
+        0x43, 0xC7, 0xFF, 0xCF, 0x9F, 0x3F, 0xC8, 0xF1, 0x20, 0x4E, 0x07, 0xFF, 0xCE, 0x3F, 0xCF,
+        0xFF, 0xC7, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFC, 0x3F, 0xF3, 0xFC, 0x00,
+        0x00, 0x03, 0x80, 0x03, 0xFC, 0xF9, 0xFF, 0xFC, 0x00, 0xFF, 0x9F, 0x39, 0xC3, 0xFC, 0x3F,
+        0xC0, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x0C, 0xFF, 0x3F, 0xC3, 0x8F, 0x39, 0xCE, 0x07, 0x80,
+        0x0F, 0x1F, 0x3F, 0xC3, 0xFF, 0x3F, 0xC2, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE6,
+        0x78, 0x00, 0xF1, 0xF1, 0x88, 0xFF, 0xFF, 0xCF, 0xF9, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xC0,
+        0x3F, 0xFF, 0xF1, 0xF3, 0x9C, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+        0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x0F, 0xF8, 0x13, 0x80, 0x00,
+        0x00, 0x00, 0x3F, 0xF3, 0xFC, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF9, 0xFF, 0xFC, 0x00,
+        0xF3, 0xFF, 0x39, 0xC3, 0x8C, 0x3F, 0xC0, 0x01, 0x3C, 0xC0, 0x01, 0x80, 0x0F, 0x9F, 0x3F,
+        0xC1, 0xF8, 0x30, 0xCF, 0x0F, 0x80, 0x0F, 0x1F, 0xCF, 0xFF, 0x8F, 0xFE, 0x7F, 0xFF, 0xFF,
+        0xFF, 0xFF, 0x00, 0x03, 0xFC, 0x3F, 0xF3, 0xFC, 0x00, 0x00, 0x03, 0x00, 0x03, 0xFC, 0xF9,
+        0xFF, 0xFC, 0x01, 0xFF, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFF, 0x00,
+        0x1C, 0xFF, 0x3F, 0xC3, 0xC7, 0x39, 0xCE, 0x07, 0x00, 0x0F, 0x8F, 0x3F, 0xC3, 0xFF, 0x3F,
+        0xC0, 0x1F, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE6, 0x70, 0x01, 0xF8, 0xF8, 0x1C, 0xFF,
+        0xFF, 0xCF, 0xF9, 0xF3, 0x9F, 0xC0, 0x3F, 0xFF, 0xC0, 0x3F, 0xFF, 0xF8, 0xF3, 0x9C, 0xF9,
+        0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xCF,
+        0xFE, 0x0F, 0xFF, 0xFF, 0x07, 0xFC, 0x03, 0x9C, 0x00, 0x00, 0x03, 0x3F, 0xF3, 0xFC, 0x00,
+        0x00, 0x00, 0x30, 0x00, 0x00, 0xF9, 0xFF, 0xFC, 0x00, 0xF3, 0xFF, 0x30, 0xC3, 0x1C, 0x3F,
+        0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x1F, 0x9F, 0x3F, 0xC3, 0xFC, 0x39, 0xCF, 0x0F, 0x00,
+        0x0F, 0x8F, 0xCF, 0xFF, 0x1F, 0xFE, 0x79, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F,
+        0xF3, 0xFC, 0x3F, 0xCC, 0xFF, 0x3F, 0xC3, 0xFC, 0xF9, 0xFF, 0xFC, 0x38, 0xFF, 0x9F, 0x39,
+        0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0xC3, 0xE3, 0x39,
+        0xCC, 0x63, 0x3F, 0xCF, 0xC7, 0x3F, 0xC3, 0xFF, 0x3F, 0xC8, 0x9F, 0x00, 0x00, 0x00, 0x3F,
+        0xFF, 0xFF, 0x80, 0x13, 0x9F, 0xFC, 0x7E, 0x0F, 0xFF, 0xFF, 0xCF, 0xF9, 0xF1, 0x1F, 0xF9,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x73, 0xFC, 0xF9, 0xFF, 0xFC, 0xFF, 0xC3, 0xFC, 0x3F,
+        0xF3, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F, 0xCF, 0xFF, 0xCF, 0xFF, 0x0F, 0xC0, 0x3F, 0x0F, 0xFF,
+        0xC3, 0x9C, 0x3F, 0xC3, 0xF9, 0x3F, 0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xF3, 0xFC, 0xF9,
+        0xFF, 0xFC, 0x3C, 0x73, 0xFF, 0x20, 0x42, 0x3C, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
+        0xFF, 0x9F, 0x3F, 0xC3, 0xFC, 0x3F, 0xCE, 0x07, 0x3F, 0xCF, 0xC7, 0xCF, 0xFE, 0x3F, 0xFE,
+        0x78, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F, 0xF3, 0xFC, 0x3F, 0xCC, 0xFF, 0x3F,
+        0xC0, 0x00, 0xF9, 0xFF, 0xFC, 0x3C, 0x7F, 0x9F, 0x39, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
+        0xC3, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0xC3, 0xF1, 0x39, 0xC8, 0xF1, 0x3F, 0xCF, 0xE3, 0x3F,
+        0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x13, 0x9F, 0x8E,
+        0x3C, 0xE7, 0xFF, 0xFF, 0xCF, 0xF9, 0xF8, 0x3F, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+        0x33, 0xFC, 0xF9, 0xFF, 0xFC, 0xFF, 0xC3, 0xFC, 0x3F, 0xF3, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F,
+        0xCF, 0x9F, 0xFF, 0xFF, 0x8F, 0xC0, 0x3F, 0x1F, 0xFF, 0xC3, 0x9C, 0x3F, 0xC3, 0xF9, 0x3F,
+        0xF3, 0xFC, 0x3F, 0xF3, 0xFF, 0x3F, 0xF3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3E, 0x33, 0xFF, 0x06,
+        0x00, 0x7C, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xFF, 0x9F, 0x3F, 0xC3, 0xFC, 0x3F,
+        0xCC, 0x63, 0x3F, 0xCF, 0xE3, 0xCF, 0xFC, 0x7F, 0xFE, 0x7C, 0x63, 0xFF, 0xFF, 0xFF, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0x00, 0x00, 0x01, 0xE1, 0xFF, 0xF0, 0x3E,
+        0x3F, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+        0xC3, 0xF8, 0x39, 0xC1, 0xF8, 0x3F, 0xC0, 0x00, 0x3F, 0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00,
+        0x00, 0x00, 0x3F, 0xF3, 0x3F, 0xE6, 0x70, 0x00, 0x8F, 0x1C, 0xE7, 0x3F, 0xFF, 0xC7, 0xF1,
+        0xF8, 0x3F, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x13, 0xFC, 0xF9, 0xFF, 0xFC, 0xFF,
+        0xC3, 0xFC, 0x3F, 0xF3, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F, 0xCF, 0x9F, 0xFF, 0xFF, 0xCF, 0xFF,
+        0xFF, 0x3F, 0x3F, 0xC3, 0x9C, 0x3F, 0xC3, 0xF9, 0x3F, 0xF3, 0xF8, 0x3F, 0xF3, 0xFF, 0x3F,
+        0xF3, 0xFC, 0xF9, 0xFF, 0xFC, 0x3F, 0x13, 0xFF, 0x0F, 0x00, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
+        0xC3, 0xFC, 0x3F, 0xFF, 0x9F, 0x3F, 0xC3, 0xFC, 0x3F, 0xC8, 0xF1, 0x3F, 0xCF, 0xF1, 0xCF,
+        0xF8, 0xFF, 0xFE, 0x7E, 0x07, 0xFF, 0xFC, 0xFF, 0x00, 0x10, 0x01, 0x80, 0x08, 0x00, 0x80,
+        0x1C, 0xFF, 0x80, 0x03, 0xFF, 0xE1, 0xFF, 0xF0, 0x3F, 0x1F, 0x9F, 0x00, 0x10, 0x01, 0x80,
+        0x10, 0x01, 0x80, 0x08, 0x00, 0x80, 0x00, 0x00, 0x3F, 0xC3, 0xFC, 0x39, 0xC3, 0xFC, 0x3F,
+        0xC0, 0x00, 0x3F, 0xC3, 0xFF, 0x3F, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xF3, 0x3F, 0xE6,
+        0x78, 0x00, 0x8F, 0x9C, 0x07, 0x3F, 0xFF, 0xE3, 0xE3, 0xF1, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFC, 0x3F,
+        0x83, 0xFF, 0x1F, 0x81, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+        0xC3, 0xFC, 0x3F, 0xC1, 0xF8, 0x3F, 0xC0, 0x00, 0xC0, 0xF1, 0xFF, 0xE0, 0x7F, 0x0F, 0xFF,
+        0xF8, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0xFF, 0xF3, 0xFF, 0xFF,
+        0xFF, 0xFF, 0x3F, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0x00,
+        0x0F, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xF3, 0x3F, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x0F, 0x3F,
+        0xFF, 0xF3, 0xE7, 0xF3, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01,
+        0xF0, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x18, 0x01, 0x80, 0x10, 0x03, 0x80, 0x00, 0x03, 0x80,
+        0x08, 0x00, 0x80, 0x03, 0xFC, 0x00, 0x0F, 0xFC, 0x3F, 0xC3, 0xFF, 0x3F, 0xC3, 0xFC, 0x80,
+        0x10, 0x01, 0x80, 0x10, 0x01, 0x80, 0x00, 0x00, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F,
+        0xC0, 0x00, 0xC0, 0xF3, 0xFF, 0xE0, 0x7F, 0x9F, 0xFF, 0xF9, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF,
+        0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0xFC, 0x3F, 0xFE, 0x1F, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00,
+    }};
+#endif // FONT5_H_
\ No newline at end of file
--- /dev/null
+++ b/src/fonts/inline_font.h
@@ -1,0 +1,17 @@
+#ifndef INLINE_FONT_H_
+#define INLINE_FONT_H_
+
+struct inline_font {
+  const int width;
+  const int height;
+  const int glyph_x;
+  const int glyph_y;
+  const int screen_offset_x;
+  const int screen_offset_y;
+  const int text_offset_y;
+  const int waveform_max_height;
+  const long image_size;
+  const unsigned char image_data[];
+};
+
+#endif
--- a/src/fx_cube.c
+++ b/src/fx_cube.c
@@ -4,6 +4,8 @@
 
 #include <math.h>
 
+// Handle screensaver cube effect
+
 static SDL_Texture *texture_cube;
 static SDL_Texture *texture_text;
 static SDL_Renderer *fx_renderer;
--- a/src/inline_font.h
+++ /dev/null
@@ -1,17 +1,0 @@
-#ifndef INLINE_FONT_H_
-#define INLINE_FONT_H_
-
-struct inline_font {
-  const int width;
-  const int height;
-  const int glyph_x;
-  const int glyph_y;
-  const int screen_offset_x;
-  const int screen_offset_y;
-  const int text_offset_y;
-  const int waveform_max_height;
-  const long image_size;
-  const unsigned char image_data[];
-};
-
-#endif
--- a/src/inprint2.c
+++ b/src/inprint2.c
@@ -2,7 +2,7 @@
 // https://github.com/driedfruit/SDL_inprint Released into public domain.
 // Modified to support multiple fonts & adding a background to text.
 
-#include "inline_font.h"
+#include "fonts/inline_font.h"
 #include <SDL3/SDL.h>
 
 #define CHARACTERS_PER_ROW 94
@@ -17,7 +17,7 @@
 static struct inline_font *selected_inline_font;
 static Uint16 selected_font_w, selected_font_h;
 
-void prepare_inline_font(struct inline_font *font) {
+void inline_font_initialize(struct inline_font *font) {
 
   selected_font_w = font->width;
   selected_font_h = font->height;
@@ -43,12 +43,12 @@
   selected_font = inline_font;
 }
 
-void kill_inline_font(void) {
+void inline_font_close(void) {
   SDL_DestroyTexture(inline_font);
   inline_font = NULL;
 }
 
-void inrenderer(SDL_Renderer *renderer) { selected_renderer = renderer; }
+void inline_font_set_renderer(SDL_Renderer *renderer) { selected_renderer = renderer; }
 
 void infont(SDL_Texture *font) {
 
--- a/src/input.c
+++ b/src/input.c
@@ -1,7 +1,10 @@
 #include "input.h"
+#include "backends/rtmidi.h"
+#include "backends/serialport.h"
 #include "config.h"
 #include "gamecontrollers.h"
 #include "render.h"
+#include "audio.h"
 #include <SDL3/SDL.h>
 
 uint8_t keyjazz_enabled = 0;
@@ -12,6 +15,55 @@
 
 static input_msg_s key = {normal, 0, 0, 0};
 
+int input_process(config_params_s conf, enum app_state *app_state) {
+  static uint8_t prev_input = 0;
+  static uint8_t prev_note = 0;
+
+  // get current inputs
+  const input_msg_s input = input_get_msg(&conf);
+
+  switch (input.type) {
+  case normal:
+    if (input.value != prev_input) {
+      prev_input = input.value;
+      send_msg_controller(input.value);
+    }
+    break;
+  case keyjazz:
+    if (input.value != 0) {
+      if (input.eventType == SDL_EVENT_KEY_DOWN && input.value != prev_input) {
+        send_msg_keyjazz(input.value, input.value2);
+        prev_note = input.value;
+      } else if (input.eventType == SDL_EVENT_KEY_UP && input.value == prev_note) {
+        send_msg_keyjazz(0xFF, 0);
+      }
+    }
+    prev_input = input.value;
+    break;
+  case special:
+    if (input.value != prev_input) {
+      prev_input = input.value;
+      switch (input.value) {
+      case msg_quit:
+        SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Received msg_quit from input device.");
+        *app_state = 0;
+        break;
+      case msg_reset_display:
+        reset_display();
+        break;
+      case msg_toggle_audio:
+        conf.audio_enabled = !conf.audio_enabled;
+        audio_toggle(conf.audio_device_name, conf.audio_buffer_size);
+        break;
+      default:
+        break;
+      }
+      break;
+    }
+  }
+  return 1;
+}
+
 uint8_t toggle_input_keyjazz() {
   keyjazz_enabled = !keyjazz_enabled;
   SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, keyjazz_enabled ? "Keyjazz enabled" : "Keyjazz disabled");
@@ -289,7 +341,7 @@
 }
 
 // Returns the currently pressed keys to main
-input_msg_s get_input_msg(config_params_s *conf) {
+input_msg_s input_get_msg(config_params_s *conf) {
 
   key = (input_msg_s){normal, 0, 0, 0};
 
--- a/src/input.h
+++ b/src/input.h
@@ -7,6 +7,8 @@
 #include "config.h"
 #include <stdint.h>
 
+enum app_state { QUIT, WAIT_FOR_DEVICE, RUN };
+
 typedef enum input_buttons_t {
   INPUT_UP,
   INPUT_DOWN,
@@ -46,6 +48,7 @@
   uint32_t eventType;
 } input_msg_s;
 
-input_msg_s get_input_msg(config_params_s *conf);
+input_msg_s input_get_msg(config_params_s *conf);
+int input_process(config_params_s conf, enum app_state *app_state);
 
 #endif
--- a/src/main.c
+++ b/src/main.c
@@ -10,78 +10,26 @@
 
 #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 "midi.h"
 #include "render.h"
-#include "serial.h"
 
-enum state { QUIT, WAIT_FOR_DEVICE, RUN };
+enum app_state app_state = WAIT_FOR_DEVICE;
 
-enum state run = WAIT_FOR_DEVICE;
-uint8_t need_display_reset = 0;
+// Handle CTRL+C / SIGINT, SIGKILL etc.
+void signal_handler(int unused) { app_state = QUIT; }
 
-// Handles CTRL+C / SIGINT
-void signal_handler() { run = QUIT; }
-
-int process_inputs(config_params_s conf) {
-  static uint8_t prev_input = 0;
-  static uint8_t prev_note = 0;
-
-  // get current inputs
-  const input_msg_s input = get_input_msg(&conf);
-
-  switch (input.type) {
-  case normal:
-    if (input.value != prev_input) {
-      prev_input = input.value;
-      send_msg_controller(input.value);
-    }
-    break;
-  case keyjazz:
-    if (input.value != 0) {
-      if (input.eventType == SDL_EVENT_KEY_DOWN && input.value != prev_input) {
-        send_msg_keyjazz(input.value, input.value2);
-        prev_note = input.value;
-      } else if (input.eventType == SDL_EVENT_KEY_UP && input.value == prev_note) {
-        send_msg_keyjazz(0xFF, 0);
-      }
-    }
-    prev_input = input.value;
-    break;
-  case special:
-    if (input.value != prev_input) {
-      prev_input = input.value;
-      switch (input.value) {
-      case msg_quit:
-        SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Received msg_quit from input device.");
-        run = 0;
-        break;
-      case msg_reset_display:
-        reset_display();
-        break;
-      case msg_toggle_audio:
-        conf.audio_enabled = !conf.audio_enabled;
-        toggle_audio(conf.audio_device_name, conf.audio_buffer_size);
-        break;
-      default:
-        break;
-      }
-      break;
-    }
-  }
-  return 1;
-}
-
 int main(const int argc, char *argv[]) {
 
   char *preferred_device = NULL;
+  unsigned char m8_connected = 0;
 
-#ifdef USE_LIBSERIALPORT // Device selection should be only available with libserialport
   if (argc == 2 && SDL_strcmp(argv[1], "--list") == 0) {
-    return list_devices();
+    return m8_list_devices();
   }
 
   if (argc == 3 && SDL_strcmp(argv[1], "--dev") == 0) {
@@ -88,7 +36,6 @@
     preferred_device = argv[2];
     SDL_Log("Using preferred device %s.\n", preferred_device);
   }
-#endif
 
   char *config_filename = NULL;
   if (argc == 3 && SDL_strcmp(argv[1], "--config") == 0) {
@@ -96,13 +43,11 @@
     SDL_Log("Using config file %s.\n", config_filename);
   }
 
-  // Initialize the config to defaults read in the params from the
-  // configfile if present
-  config_params_s conf = init_config(config_filename);
-  read_config(&conf);
+  // 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);
 
-  uint8_t port_inited = 0;
-
   signal(SIGINT, signal_handler);
   signal(SIGTERM, signal_handler);
 #ifdef SIGQUIT
@@ -112,63 +57,61 @@
   // 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) {
-    port_inited = init_serial(1, preferred_device);
-    if (port_inited == 0) {
+    m8_connected = m8_connect(1, preferred_device);
+    if (m8_connected == 0) {
       return 1;
     }
   }
 
   // initialize all SDL systems
-  if (initialize_sdl(conf.init_fullscreen) == false) {
+  if (renderer_initialize(conf.init_fullscreen) == false) {
     SDL_Quit();
     return 1;
   }
-  run = QUIT;
+  app_state = QUIT;
 
   // initial scan for (existing) gamepads
   gamecontrollers_initialize();
 
-#ifdef DEBUG_MSG
+#ifdef DEBUG
   SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
 #endif
 
   // main loop begin
   do {
-    // try to init serial port
-    port_inited = init_serial(1, preferred_device);
-    // if port init was successful, try to enable and reset display
-    if (port_inited == 1 && enable_and_reset_display() == 1) {
-      // if audio routing is enabled, try to initialize audio devices
+    // 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_init(conf.audio_device_name, conf.audio_buffer_size);
+        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();
       }
-      run = RUN;
+      app_state = RUN;
     } else {
-      SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected on begin loop.");
+      SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected on initial check.");
       if (conf.wait_for_device == 1) {
-        run = WAIT_FOR_DEVICE;
+        app_state = WAIT_FOR_DEVICE;
       } else {
-        run = QUIT;
+        app_state = QUIT;
       }
     }
 
     // wait until device is connected
     if (conf.wait_for_device == 1) {
-      static uint32_t ticks_poll_device = 0;
-      static uint32_t ticks_update_screen = 0;
+      static Uint64 ticks_poll_device = 0;
+      static Uint64 ticks_update_screen = 0;
 
-      if (port_inited == 0) {
+      if (m8_connected == 0) {
         screensaver_init();
       }
 
-      while (run == WAIT_FOR_DEVICE) {
+      while (app_state == WAIT_FOR_DEVICE) {
         // get current input
-        const input_msg_s input = get_input_msg(&conf);
+        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.");
-          run = QUIT;
+          app_state = QUIT;
         }
 
         if (SDL_GetTicks() - ticks_update_screen > 16) {
@@ -178,13 +121,13 @@
         }
 
         // Poll for M8 device every second
-        if (port_inited == 0 && SDL_GetTicks() - ticks_poll_device > 1000) {
+        if (m8_connected == 0 && SDL_GetTicks() - ticks_poll_device > 1000) {
           ticks_poll_device = SDL_GetTicks();
-          if (run == WAIT_FOR_DEVICE && init_serial(0, preferred_device) == 1) {
+          if (app_state == WAIT_FOR_DEVICE && m8_connect(0, preferred_device) == 1) {
 
             if (conf.audio_enabled == 1) {
-              if (audio_init(conf.audio_device_name, conf.audio_buffer_size) == 0) {
-                SDL_Log("Cannot initialize audio");
+              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;
               }
             }
@@ -192,12 +135,12 @@
             const int result = enable_and_reset_display();
             // Device was found; enable display and proceed to the main loop
             if (result == 1) {
-              run = RUN;
-              port_inited = 1;
+              app_state = RUN;
+              m8_connected = 1;
               screensaver_destroy();
             } else {
               SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected.");
-              run = QUIT;
+              app_state = QUIT;
               screensaver_destroy();
             }
           }
@@ -206,13 +149,13 @@
       }
     } else {
       // classic startup behaviour, exit if device is not found
-      if (port_inited == 0) {
+      if (m8_connected == 0) {
         if (conf.audio_enabled == 1) {
-          audio_destroy();
+          audio_close();
         }
         gamecontrollers_close();
-        close_renderer();
-        kill_inline_font();
+        renderer_close();
+        inline_font_close();
         SDL_Quit();
         return -1;
       }
@@ -219,29 +162,31 @@
     }
 
     // main loop
-    while (run == RUN) {
-      process_inputs(conf);
+    while (app_state == RUN) {
+      input_process(conf, &app_state);
       const int result = process_serial(conf);
       if (result == 0) {
-        port_inited = 0;
-        run = WAIT_FOR_DEVICE;
-        audio_destroy();
+        // Device disconnected
+        m8_connected = 0;
+        app_state = WAIT_FOR_DEVICE;
+        audio_close();
       } else if (result == -1) {
-        run = QUIT;
+        // Fatal error
+        app_state = QUIT;
       }
       render_screen();
       SDL_Delay(conf.idle_ms);
     }
-  } while (run > QUIT);
-  // main loop end
+  } while (app_state > QUIT);
+  // Main loop end
 
-  // exit, clean up
+  // Exit, clean up
   SDL_Log("Shutting down");
-  audio_destroy();
+  audio_close();
   gamecontrollers_close();
-  close_renderer();
-  if (port_inited == 1)
-    destroy_serial();
+  renderer_close();
+  if (m8_connected == 1)
+    m8_close();
   SDL_Quit();
   return 0;
 }
--- a/src/midi.c
+++ /dev/null
@@ -1,238 +1,0 @@
-// Copyright 2021 Jonne Kokkonen
-// Released under the MIT licence, https://opensource.org/licenses/MIT
-#ifdef USE_RTMIDI
-
-#include "midi.h"
-#include "command.h"
-#include "config.h"
-#include "queue.h"
-#include <SDL3/SDL.h>
-#include <rtmidi_c.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-
-RtMidiInPtr midi_in;
-RtMidiOutPtr midi_out;
-message_queue_s queue;
-
-const unsigned char m8_sysex_header[5] = {0xF0, 0x00, 0x02, 0x61, 0x00};
-const unsigned int m8_sysex_header_size = sizeof(m8_sysex_header);
-const unsigned char sysex_message_end = 0xF7;
-
-bool message_is_m8_sysex(const unsigned char *message) {
-  if (memcmp(m8_sysex_header, message, m8_sysex_header_size) == 0) {
-    return true;
-  }
-  return false;
-}
-
-void midi_decode(const uint8_t *encoded_data, size_t length, uint8_t **decoded_data,
-                 size_t *decoded_length) {
-  if (length < m8_sysex_header_size) {
-    // Invalid data
-    *decoded_data = NULL;
-    *decoded_length = 0;
-    return;
-  }
-
-  // Skip header "F0 00 02 61" and the first MSB byte
-  size_t pos = m8_sysex_header_size + 1;
-
-  // Calculate expected output size (ignoring EOT if present)
-  const size_t expected_output_size =
-      (length - m8_sysex_header_size) - ((length - m8_sysex_header_size) / 8);
-  if (encoded_data[length - 1] == sysex_message_end) {
-    length--; // Ignore the EOT byte
-  }
-
-  // Allocate memory for decoded output
-  *decoded_data = (uint8_t *)SDL_malloc(expected_output_size);
-  if (*decoded_data == NULL) {
-    *decoded_length = 0;
-    return;
-  }
-
-  uint8_t bitCounter = 0;
-  uint8_t bitByteCounter = 0;
-  uint8_t *out = *decoded_data;
-  *decoded_length = 0;
-
-  while (pos < length) {
-    // Extract MSB from the "bit field" position
-    uint8_t msb = (encoded_data[bitByteCounter * 8 + m8_sysex_header_size] >> bitCounter) & 0x01;
-
-    // Extract LSB from data byte
-    uint8_t lsb = encoded_data[pos] & 0x7F;
-
-    // Reconstruct original byte, skipping the MSB bytes in output
-    *out = (msb << 7) | lsb;
-    out++;
-    (*decoded_length)++;
-
-    bitCounter++;
-    pos++;
-
-    if (bitCounter == 7) {
-      bitCounter = 0;
-      bitByteCounter++;
-      pos++; // Skip the MSB byte
-    }
-  }
-}
-
-static void midi_callback(double delta_time, const unsigned char *message, size_t message_size,
-                          void *user_data) {
-  if (message_size < 5 || !message_is_m8_sysex(message))
-    return;
-
-  unsigned char *decoded_data;
-  size_t decoded_length;
-  midi_decode(message, message_size, &decoded_data, &decoded_length);
-
-  // printf("Original data: ");
-  for (size_t i = 0; i < message_size; i++) {
-    // printf("%02X ", message[i]);
-  }
-
-  if (decoded_data) {
-    // printf("\nDecoded MIDI Data: ");
-    for (size_t i = 0; i < decoded_length; i++) {
-      // printf("%02X ", decoded_data[i]);
-    }
-    // printf("\n");
-    push_message(&queue, decoded_data, decoded_length);
-    SDL_free(decoded_data);
-  } else {
-    printf("Decoding failed.\n");
-  }
-}
-
-int initialize_rtmidi(void) {
-  SDL_Log("init rtmidi");
-  midi_in = rtmidi_in_create(RTMIDI_API_UNSPECIFIED, "m8c_in", 1024);
-  midi_out = rtmidi_out_create(RTMIDI_API_UNSPECIFIED, "m8c_out");
-  if (midi_in == NULL || midi_out == NULL) {
-    return 0;
-  }
-  return 1;
-}
-
-int init_serial(const int verbose, const char *preferred_device) {
-
-  init_queue(&queue);
-
-  int midi_in_initialized = 0;
-  int midi_out_initialized = 0;
-
-  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "init_serial called");
-  if (midi_in == NULL || midi_out == NULL) {
-    initialize_rtmidi();
-  };
-  const unsigned int ports_total_in = rtmidi_get_port_count(midi_in);
-  if (verbose)
-    SDL_Log("Number of MIDI in ports: %d", ports_total_in);
-  for (unsigned int port_number = 0; port_number < ports_total_in; port_number++) {
-    int port_name_length_in;
-    rtmidi_get_port_name(midi_in, port_number, NULL, &port_name_length_in);
-    char port_name[port_name_length_in];
-    rtmidi_get_port_name(midi_in, port_number, &port_name[0], &port_name_length_in);
-    if (verbose)
-      SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "MIDI IN port %d, name: %s", port_number, port_name);
-    if (strncmp("M8", port_name, 2) == 0) {
-      if (verbose)
-        SDL_Log("Found M8 Input in MIDI port %d", port_number);
-      rtmidi_in_ignore_types(midi_in, false, true, true);
-      rtmidi_open_port(midi_in, port_number, "M8");
-      midi_in_initialized = 1;
-      rtmidi_open_port(midi_out, port_number, "M8");
-      midi_out_initialized = 1;
-    }
-  }
-  return (midi_in_initialized && midi_out_initialized);
-}
-
-int check_serial_port(void) {
-  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "check_serial_port called");
-  return 0;
-}
-
-int reset_display(void) {
-  SDL_Log("Reset display\n");
-  const unsigned char reset_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'R', 0xF7};
-  const int result = rtmidi_out_send_message(midi_out, &reset_sysex[0], sizeof(reset_sysex));
-  if (result != 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, code %d", result);
-    return 0;
-  }
-  return 1;
-}
-
-int enable_and_reset_display(void) {
-  rtmidi_in_set_callback(midi_in, midi_callback, NULL);
-  const unsigned char enable_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'E', 0xF7};
-  int result = rtmidi_out_send_message(midi_out, &enable_sysex[0], sizeof(enable_sysex));
-  if (result != 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to enable display");
-    return 0;
-  }
-  result = reset_display();
-  return result;
-}
-
-int disconnect(void) {
-  const unsigned char disconnect_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'D', 0xF7};
-  const int result =
-      rtmidi_out_send_message(midi_out, &disconnect_sysex[0], sizeof(disconnect_sysex));
-  if (result != 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to send disconnect");
-  }
-  SDL_Log("Freeing MIDI ports");
-  rtmidi_in_free(midi_in);
-  rtmidi_out_free(midi_out);
-  return !result;
-}
-
-int send_msg_controller(const unsigned char input) {
-  const unsigned char input_sysex[9] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'C', input, 0xF7};
-  const int result = rtmidi_out_send_message(midi_out, &input_sysex[0], sizeof(input_sysex));
-  if (result != 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to send key input message");
-    return 0;
-  }
-  return 1;
-}
-
-int send_msg_keyjazz(const unsigned char note, unsigned char velocity) {
-  if (velocity > 0x7F) {
-    velocity = 0x7F;
-  }
-  const unsigned char keyjazz_sysex[10] = {0xF0, 0x00, 0x02, 0x61,     0x00,
-                                           0x00, 'K',  note, velocity, 0xF7};
-  const int result = rtmidi_out_send_message(midi_out, &keyjazz_sysex[0], sizeof(keyjazz_sysex));
-  if (result != 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to send keyjazz input message");
-    return 0;
-  }
-  return 1;
-}
-
-int process_serial(config_params_s conf) {
-  unsigned char *command;
-  size_t length = 0;
-  while ((command = pop_message(&queue, &length)) != NULL) {
-    process_command(command, length);
-  }
-  return 1;
-}
-
-int destroy_serial() {
-  if (queue.mutex != NULL) {
-    SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Destroying command queue");
-    SDL_DestroyMutex(queue.mutex);
-    SDL_DestroyCondition(queue.cond);
-  }
-  return disconnect();
-}
-
-#endif
--- a/src/midi.h
+++ /dev/null
@@ -1,23 +1,0 @@
-// Copyright 2021 Jonne Kokkonen
-// Released under the MIT licence, https://opensource.org/licenses/MIT
-#ifndef _MIDI_H_
-#define _MIDI_H_
-#ifdef USE_RTMIDI
-
-#include "config.h"
-#include <stdint.h>
-
-int initialize_rtmidi(void);
-int init_serial(int verbose, const char *preferred_device);
-int list_devices(void);
-int check_serial_port(void);
-int reset_display(void);
-int enable_and_reset_display(void);
-int disconnect(void);
-int send_msg_controller(const unsigned char input);
-int send_msg_keyjazz(const unsigned char note, unsigned char velocity);
-int process_serial(config_params_s conf);
-int destroy_serial();
-
-#endif
-#endif
\ No newline at end of file
--- a/src/queue.c
+++ /dev/null
@@ -1,55 +1,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <SDL3/SDL.h>
-#include "queue.h"
-
-// Initialize the message queue
-void init_queue(message_queue_s *queue) {
-    queue->front = 0;
-    queue->rear = 0;
-    queue->mutex = SDL_CreateMutex();
-    queue->cond = SDL_CreateCondition();
-}
-
-void destroy_queue(message_queue_s *queue) {
-  SDL_DestroyMutex(queue->mutex);
-  SDL_DestroyCondition(queue->cond);
-}
-
-// Push a message to the queue
-void push_message(message_queue_s *queue, const unsigned char *message, size_t length) {
-    SDL_LockMutex(queue->mutex);
-
-    if ((queue->rear + 1) % MAX_QUEUE_SIZE == queue->front) {
-        SDL_LogError(SDL_LOG_CATEGORY_SYSTEM,"Queue is full, cannot add message.");
-    } else {
-        // Allocate space for the message and store it
-        queue->messages[queue->rear] = SDL_malloc(length);
-        memcpy(queue->messages[queue->rear], message, length);
-        queue->lengths[queue->rear] = length;
-        queue->rear = (queue->rear + 1) % MAX_QUEUE_SIZE;
-        SDL_SignalCondition(queue->cond);  // Signal consumer thread
-    }
-
-    SDL_UnlockMutex(queue->mutex);
-}
-
-// Pop a message from the queue
-unsigned char *pop_message(message_queue_s *queue, size_t *length) {
-  SDL_LockMutex(queue->mutex);
-
-  // Check if the queue is empty
-  if (queue->front == queue->rear) {
-    SDL_UnlockMutex(queue->mutex);
-    return NULL;  // Return NULL if there are no messages
-  }
-
-  // Otherwise, retrieve the message and its length
-  *length = queue->lengths[queue->front];
-  unsigned char *message = queue->messages[queue->front];
-  queue->front = (queue->front + 1) % MAX_QUEUE_SIZE;
-
-  SDL_UnlockMutex(queue->mutex);
-  return message;
-}
\ No newline at end of file
--- a/src/queue.h
+++ /dev/null
@@ -1,26 +1,0 @@
-//
-// Created by jonne on 3/17/25.
-//
-
-#ifndef QUEUE_H
-#define QUEUE_H
-
-#include <SDL3/SDL.h>
-
-#define MAX_QUEUE_SIZE 4096
-
-typedef struct {
-  unsigned char *messages[MAX_QUEUE_SIZE];
-  size_t lengths[MAX_QUEUE_SIZE]; // Store lengths of each message
-  int front;
-  int rear;
-  SDL_Mutex *mutex;
-  SDL_Condition *cond;
-} message_queue_s;
-
-// Initialize the message queue
-void init_queue(message_queue_s *queue);
-unsigned char *pop_message(message_queue_s *queue, size_t *length);
-void push_message(message_queue_s *queue, const unsigned char *message, size_t length);
-
-#endif // QUEUE_H
--- a/src/render.c
+++ b/src/render.c
@@ -10,12 +10,12 @@
 #include "command.h"
 #include "fx_cube.h"
 
-#include "font1.h"
-#include "font2.h"
-#include "font3.h"
-#include "font4.h"
-#include "font5.h"
-#include "inline_font.h"
+#include "fonts/font1.h"
+#include "fonts/font2.h"
+#include "fonts/font3.h"
+#include "fonts/font4.h"
+#include "fonts/font5.h"
+#include "fonts/inline_font.h"
 
 #include <stdlib.h>
 
@@ -44,7 +44,7 @@
 static uint8_t dirty = 0;
 
 // Initializes SDL and creates a renderer and required surfaces
-int initialize_sdl(const unsigned int init_fullscreen) {
+int renderer_initialize(const unsigned int init_fullscreen) {
 
   if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMEPAD) == false) {
     SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "SDL_Init: %s\n", SDL_GetError());
@@ -74,9 +74,9 @@
 
   SDL_RenderClear(rend);
 
-  set_font_mode(0);
+  renderer_set_font_mode(0);
 
-  SDL_SetLogPriorities(SDL_LOG_PRIORITY_DEBUG);
+  SDL_SetLogPriorities(SDL_LOG_PRIORITY_INFO);
 
   dirty = 1;
 
@@ -84,9 +84,9 @@
 }
 
 static void change_font(struct inline_font *font) {
-  kill_inline_font();
-  inrenderer(rend);
-  prepare_inline_font(font);
+  inline_font_close();
+  inline_font_set_renderer(rend);
+  inline_font_initialize(font);
 }
 
 static void check_and_adjust_window_and_texture_size(const int new_width, const int new_height) {
@@ -126,7 +126,7 @@
   }
 }
 
-void set_font_mode(int mode) {
+void renderer_set_font_mode(int mode) {
   if (mode < 0 || mode > 2) {
     // bad font mode
     return;
@@ -146,8 +146,8 @@
   SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Font mode %i, Screen offset %i", mode, screen_offset_y);
 }
 
-void close_renderer() {
-  kill_inline_font();
+void renderer_close() {
+  inline_font_close();
   SDL_DestroyTexture(main_texture);
   SDL_DestroyRenderer(rend);
   SDL_DestroyWindow(win);
@@ -321,7 +321,7 @@
 }
 
 void screensaver_init() {
-  set_font_mode(1);
+  renderer_set_font_mode(1);
   fx_cube_init(rend, (SDL_Color){255, 255, 255, 255}, texture_width, texture_height,
                fonts[font_mode]->glyph_x);
   SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Screensaver initialized");
@@ -334,6 +334,6 @@
 
 void screensaver_destroy() {
   fx_cube_destroy();
-  set_font_mode(0);
+  renderer_set_font_mode(0);
   SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Screensaver destroyed");
 }
--- a/src/render.h
+++ b/src/render.h
@@ -7,15 +7,14 @@
 #include <stdint.h>
 #include "command.h"
 
-int initialize_sdl(unsigned int init_fullscreen);
-void close_renderer();
+int renderer_initialize(unsigned int init_fullscreen);
+void renderer_close();
 
 void draw_waveform(struct draw_oscilloscope_waveform_command *command);
 void draw_rectangle(struct draw_rectangle_command *command);
 int draw_character(struct draw_character_command *command);
-void set_font_mode(int mode);
+void renderer_set_font_mode(int mode);
 void set_m8_model(unsigned int model);
-void view_changed(int view);
 
 void render_screen();
 void toggle_fullscreen();
--- a/src/ringbuffer.c
+++ /dev/null
@@ -1,55 +1,0 @@
-#include "ringbuffer.h"
-#include <SDL3/SDL.h>
-
-RingBuffer *ring_buffer_create(uint32_t size) {
-  RingBuffer *rb = SDL_malloc(sizeof(*rb));
-  rb->buffer = SDL_malloc(sizeof(*rb->buffer) * size);
-  rb->head = 0;
-  rb->tail = 0;
-  rb->max_size = size;
-  rb->size = 0;
-  return rb;
-}
-
-void ring_buffer_free(RingBuffer *rb) {
-  SDL_free(rb->buffer);
-  SDL_free(rb);
-}
-
-uint32_t ring_buffer_empty(RingBuffer *rb) { return rb->size == 0; }
-
-uint32_t ring_buffer_full(RingBuffer *rb) { return rb->size == rb->max_size; }
-
-uint32_t ring_buffer_push(RingBuffer *rb, const uint8_t *data, uint32_t length) {
-  if (ring_buffer_full(rb)) {
-    return -1; // buffer full, push fails
-  }
-  uint32_t space1 = rb->max_size - rb->tail;
-  uint32_t n = length <= rb->max_size - rb->size ? length : rb->max_size - rb->size;
-  if (n <= space1) {
-    SDL_memcpy(rb->buffer + rb->tail, data, n);
-  } else {
-    SDL_memcpy(rb->buffer + rb->tail, data, space1);
-    SDL_memcpy(rb->buffer, data + space1, n - space1);
-  }
-  rb->tail = (rb->tail + n) % rb->max_size;
-  rb->size += n;
-  return n; // push successful, returns number of bytes pushed
-}
-
-uint32_t ring_buffer_pop(RingBuffer *rb, uint8_t *data, uint32_t length) {
-  if (ring_buffer_empty(rb)) {
-    return -1; // buffer empty, pop fails
-  }
-  uint32_t space1 = rb->max_size - rb->head;
-  uint32_t n = length <= rb->size ? length : rb->size;
-  if (n <= space1) {
-    SDL_memcpy(data, rb->buffer + rb->head, n);
-  } else {
-    SDL_memcpy(data, rb->buffer + rb->head, space1);
-    SDL_memcpy(data + space1, rb->buffer, n - space1);
-  }
-  rb->head = (rb->head + n) % rb->max_size;
-  rb->size -= n;
-  return n; // pop successful, returns number of bytes popped
-}
--- a/src/ringbuffer.h
+++ /dev/null
@@ -1,24 +1,0 @@
-#ifndef M8C_RINGBUFFER_H
-#define M8C_RINGBUFFER_H
-
-#include <stdint.h>
-
-typedef struct {
-  uint8_t *buffer;
-  uint32_t head;
-  uint32_t tail;
-  uint32_t max_size;
-  uint32_t size;
-} RingBuffer;
-
-RingBuffer *ring_buffer_create(uint32_t size);
-
-uint32_t ring_buffer_empty(RingBuffer *rb);
-
-uint32_t ring_buffer_pop(RingBuffer *rb, uint8_t *data, uint32_t length);
-
-uint32_t ring_buffer_push(RingBuffer *rb, const uint8_t *data, uint32_t length);
-
-void ring_buffer_free(RingBuffer *rb);
-
-#endif // M8C_RINGBUFFER_H
--- a/src/serial.c
+++ /dev/null
@@ -1,338 +1,0 @@
-// Copyright 2021 Jonne Kokkonen
-// Released under the MIT licence, https://opensource.org/licenses/MIT
-
-// Contains portions of code from libserialport's examples released to the
-// public domain
-
-#ifdef USE_LIBSERIALPORT
-#include <SDL3/SDL.h>
-#include <libserialport.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "command.h"
-#include "serial.h"
-#include "slip.h"
-#include "config.h"
-
-struct sp_port *m8_port = NULL;
-// allocate memory for serial buffers
-static uint8_t serial_buffer[serial_read_size] = {0};
-static uint8_t slip_buffer[serial_read_size] = {0};
-static slip_handler_s slip;
-static uint16_t zero_byte_packets = 0; // used to detect device disconnection
-
-// Helper function for error handling
-static int check(enum sp_return result);
-
-static int detect_m8_serial_device(const struct sp_port *m8_port) {
-  // Check the connection method - we want USB serial devices
-  const enum sp_transport transport = sp_get_port_transport(m8_port);
-
-  if (transport == SP_TRANSPORT_USB) {
-    // Get the USB vendor and product IDs.
-    int usb_vid, usb_pid;
-    sp_get_port_usb_vid_pid(m8_port, &usb_vid, &usb_pid);
-
-    if (usb_vid == 0x16C0 && usb_pid == 0x048A)
-      return 1;
-  }
-
-  return 0;
-}
-
-int list_devices() {
-  struct sp_port **port_list;
-  const enum sp_return result = sp_list_ports(&port_list);
-
-  if (result != SP_OK) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "sp_list_ports() failed!\n");
-    abort();
-  }
-
-  for (int i = 0; port_list[i] != NULL; i++) {
-    const struct sp_port *port = port_list[i];
-
-    if (detect_m8_serial_device(port)) {
-      SDL_Log("Found M8 device: %s", sp_get_port_name(port));
-    }
-  }
-
-  sp_free_port_list(port_list);
-  return 0;
-}
-
-// Checks for connected devices and whether the specified device still exists
-int check_serial_port() {
-
-  int device_found = 0;
-
-  /* A pointer to a null-terminated array of pointers to
-   * struct sp_port, which will contain the ports found.*/
-  struct sp_port **port_list;
-
-  /* Call sp_list_ports() to get the ports. The port_list
-   * pointer will be updated to refer to the array created. */
-  const enum sp_return result = sp_list_ports(&port_list);
-
-  if (result != SP_OK) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "sp_list_ports() failed!\n");
-    abort();
-  }
-
-  /* Iterate through the ports. When port_list[i] is NULL
-   * this indicates the end of the list. */
-  for (int i = 0; port_list[i] != NULL; i++) {
-    const struct sp_port *port = port_list[i];
-
-    if (detect_m8_serial_device(port)) {
-      if (strcmp(sp_get_port_name(port), sp_get_port_name(m8_port)) == 0)
-        device_found = 1;
-    }
-  }
-
-  sp_free_port_list(port_list);
-  return device_found;
-}
-
-int init_serial(const int verbose, const char *preferred_device) {
-  if (m8_port != NULL) {
-    // Port is already initialized
-    return 1;
-  }
-
-  // settings for the slip packet handler
-  static const slip_descriptor_s slip_descriptor = {
-      .buf = slip_buffer,
-      .buf_size = sizeof(slip_buffer),
-      .recv_message = process_command, // the function where complete slip
-                                       // packets are processed further
-  };
-
-  slip_init(&slip, &slip_descriptor);
-
-  /* A pointer to a null-terminated array of pointers to
-   * struct sp_port, which will contain the ports found.*/
-  struct sp_port **port_list;
-
-  if (verbose)
-    SDL_Log("Looking for USB serial devices.\n");
-
-  /* Call sp_list_ports() to get the ports. The port_list
-   * pointer will be updated to refer to the array created. */
-  enum sp_return result = sp_list_ports(&port_list);
-
-  if (result != SP_OK) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "sp_list_ports() failed!\n");
-    abort();
-  }
-
-  /* Iterate through the ports. When port_list[i] is NULL
-   * this indicates the end of the list. */
-  for (int i = 0; port_list[i] != NULL; i++) {
-    const struct sp_port *port = port_list[i];
-
-    if (detect_m8_serial_device(port)) {
-      char *port_name = sp_get_port_name(port);
-      SDL_Log("Found M8 in %s.\n", port_name);
-      sp_copy_port(port, &m8_port);
-      if (preferred_device != NULL && strcmp(preferred_device, port_name) == 0) {
-        SDL_Log("Found preferred device, breaking");
-        break;
-      }
-    }
-  }
-
-  sp_free_port_list(port_list);
-
-  if (m8_port != NULL) {
-    // Open the serial port and configure it
-    SDL_Log("Opening port.");
-
-    result = sp_open(m8_port, SP_MODE_READ_WRITE);
-    if (check(result) != SP_OK)
-      return 0;
-
-    result = sp_set_baudrate(m8_port, 115200);
-    if (check(result) != SP_OK)
-      return 0;
-
-    result = sp_set_bits(m8_port, 8);
-    if (check(result) != SP_OK)
-      return 0;
-
-    result = sp_set_parity(m8_port, SP_PARITY_NONE);
-    if (check(result) != SP_OK)
-      return 0;
-
-    result = sp_set_stopbits(m8_port, 1);
-    if (check(result) != SP_OK)
-      return 0;
-
-    result = sp_set_flowcontrol(m8_port, SP_FLOWCONTROL_NONE);
-    if (check(result) != SP_OK)
-      return 0;
-  } else {
-    if (verbose) {
-      SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "Cannot find a M8.\n");
-    }
-    return 0;
-  }
-
-  return 1;
-}
-
-// Helper function for error handling.
-static int check(const enum sp_return result) {
-
-  char *error_message;
-
-  switch (result) {
-  case SP_ERR_ARG:
-    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid argument.\n");
-    break;
-  case SP_ERR_FAIL:
-    error_message = sp_last_error_message();
-    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Failed: %s\n", error_message);
-    sp_free_error_message(error_message);
-    break;
-  case SP_ERR_SUPP:
-    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Not supported.\n");
-    break;
-  case SP_ERR_MEM:
-    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Couldn't allocate memory.\n");
-    break;
-  case SP_OK:
-  default:
-    break;
-  }
-  return result;
-}
-
-int reset_display() {
-  SDL_Log("Reset display\n");
-
-  const char buf[1] = {'R'};
-  const int result = sp_blocking_write(m8_port, buf, 1, 5);
-  if (result != 1) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, code %d", result);
-    return 0;
-  }
-  return 1;
-}
-
-int enable_and_reset_display() {
-
-  SDL_Log("Enabling and resetting M8 display\n");
-
-  const char buf[1] = {'E'};
-  int result = sp_blocking_write(m8_port, buf, 1, 5);
-  if (result != 1) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error enabling M8 display, code %d", result);
-    return 0;
-  }
-
-  result = reset_display();
-
-  return result;
-}
-
-int disconnect() {
-
-  SDL_Log("Disconnecting M8\n");
-
-  const char buf[1] = {'D'};
-
-  int result = sp_blocking_write(m8_port, buf, 1, 5);
-  if (result != 1) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending disconnect, code %d", result);
-    result = 0;
-  }
-  sp_close(m8_port);
-  sp_free_port(m8_port);
-  m8_port = NULL;
-  return result;
-}
-
-int serial_read(uint8_t *serial_buf, const int count) {
-  return sp_nonblocking_read(m8_port, serial_buf, count);
-}
-
-int send_msg_controller(const uint8_t input) {
-  const char buf[2] = {'C', input};
-  const size_t nbytes = 2;
-  const int result = sp_blocking_write(m8_port, buf, nbytes, 5);
-  if (result != nbytes) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending input, code %d", result);
-    return -1;
-  }
-  return 1;
-}
-
-int send_msg_keyjazz(const uint8_t note, uint8_t velocity) {
-  if (velocity > 0x7F)
-    velocity = 0x7F;
-  const char buf[3] = {'K', note, velocity};
-  const size_t nbytes = 3;
-  const int result = sp_blocking_write(m8_port, buf, nbytes, 5);
-  if (result != nbytes) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending keyjazz, code %d", result);
-    return -1;
-  }
-
-  return 1;
-}
-
-int process_serial(config_params_s conf) {
-  while (1) {
-    // read serial port
-    const int bytes_read = serial_read(serial_buffer, serial_read_size);
-    if (bytes_read < 0) {
-      SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Error %d reading serial.", bytes_read);
-      disconnect();
-      return -1;
-      break;
-    }
-    if (bytes_read > 0) {
-      // input from device: reset the zero byte counter and create a
-      // pointer to the serial buffer
-      zero_byte_packets = 0;
-      const uint8_t *cur = serial_buffer;
-      const uint8_t *end = serial_buffer + bytes_read;
-      while (cur < end) {
-        // process the incoming bytes into commands and draw them
-        const int n = slip_read_byte(&slip, *cur++);
-        if (n != SLIP_NO_ERROR) {
-          if (n == SLIP_ERROR_INVALID_PACKET) {
-            reset_display();
-          } else {
-            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SLIP error %d\n", n);
-          }
-        }
-      }
-    } else {
-      // zero byte packet, increment counter
-      zero_byte_packets++;
-      if (zero_byte_packets > conf.wait_packets) {
-        zero_byte_packets = 0;
-
-        // try opening the serial port to check if it's alive
-        if (check_serial_port()) {
-          // the device is still there, carry on
-          break;
-        }
-        disconnect();
-        return 0;
-      }
-      break;
-    }
-  }
-  return 1;
-}
-
-int destroy_serial() {
-  return disconnect();
-}
-#endif
--- a/src/serial.h
+++ /dev/null
@@ -1,27 +1,0 @@
-// Copyright 2021 Jonne Kokkonen
-// Released under the MIT licence, https://opensource.org/licenses/MIT
-
-#ifndef _SERIAL_H_
-#define _SERIAL_H_
-#ifdef USE_LIBSERIALPORT
-
-#include <stdint.h>
-#include "config.h"
-
-// maximum amount of bytes to read from the serial in one read()
-#define serial_read_size 1024
-
-int init_serial(int verbose, const char *preferred_device);
-int destroy_serial();
-int list_devices();
-int check_serial_port();
-int reset_display();
-int enable_and_reset_display();
-int disconnect();
-int serial_read(uint8_t *serial_buf, int count);
-int send_msg_controller(uint8_t input);
-int send_msg_keyjazz(uint8_t note, uint8_t velocity);
-int process_serial(config_params_s conf);
-
-#endif
-#endif
--- a/src/slip.c
+++ /dev/null
@@ -1,114 +1,0 @@
-/*
-MIT License
-
-Copyright (c) 2018 Marcin Borowicz
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-/* This code is originally by marcinbor85, https://github.com/marcinbor85/slip
-It has been simplified a bit as CRC checking etc. is not required in this
-program. */
-
-#include "slip.h"
-
-#include <assert.h>
-#include <stddef.h>
-
-static void reset_rx(slip_handler_s *slip) {
-  assert(slip != NULL);
-
-  slip->state = SLIP_STATE_NORMAL;
-  slip->size = 0;
-}
-
-slip_error_t slip_init(slip_handler_s *slip, const slip_descriptor_s *descriptor) {
-  assert(slip != NULL);
-  assert(descriptor != NULL);
-  assert(descriptor->buf != NULL);
-  assert(descriptor->recv_message != NULL);
-
-  slip->descriptor = descriptor;
-  reset_rx(slip);
-
-  return SLIP_NO_ERROR;
-}
-
-static slip_error_t put_byte_to_buffer(slip_handler_s *slip, const uint8_t byte) {
-  slip_error_t error = SLIP_NO_ERROR;
-
-  assert(slip != NULL);
-
-  if (slip->size >= slip->descriptor->buf_size) {
-    error = SLIP_ERROR_BUFFER_OVERFLOW;
-    reset_rx(slip);
-  } else {
-    slip->descriptor->buf[slip->size++] = byte;
-    slip->state = SLIP_STATE_NORMAL;
-  }
-
-  return error;
-}
-
-slip_error_t slip_read_byte(slip_handler_s *slip, uint8_t byte) {
-  slip_error_t error = SLIP_NO_ERROR;
-
-  assert(slip != NULL);
-
-  switch (slip->state) {
-  case SLIP_STATE_NORMAL:
-    switch (byte) {
-    case SLIP_SPECIAL_BYTE_END:
-      if (!slip->descriptor->recv_message(slip->descriptor->buf, slip->size)) {
-        error = SLIP_ERROR_INVALID_PACKET;
-      }
-      reset_rx(slip);
-      break;
-    case SLIP_SPECIAL_BYTE_ESC:
-      slip->state = SLIP_STATE_ESCAPED;
-      break;
-    default:
-      error = put_byte_to_buffer(slip, byte);
-      break;
-    }
-    break;
-
-  case SLIP_STATE_ESCAPED:
-    switch (byte) {
-    case SLIP_ESCAPED_BYTE_END:
-      byte = SLIP_SPECIAL_BYTE_END;
-      break;
-    case SLIP_ESCAPED_BYTE_ESC:
-      byte = SLIP_SPECIAL_BYTE_ESC;
-      break;
-    default:
-      error = SLIP_ERROR_UNKNOWN_ESCAPED_BYTE;
-      reset_rx(slip);
-      break;
-    }
-
-    if (error != SLIP_NO_ERROR)
-      break;
-
-    error = put_byte_to_buffer(slip, byte);
-    break;
-  }
-
-  return error;
-}
--- a/src/slip.h
+++ /dev/null
@@ -1,67 +1,0 @@
-/*
-MIT License
-
-Copyright (c) 2018 Marcin Borowicz
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-/* This code is originally by marcinbor85, https://github.com/marcinbor85/slip
-It has been simplified a bit as CRC checking etc. is not required in this
-program. */
-
-#ifndef SLIP_H_
-#define SLIP_H_
-
-#include <stdint.h>
-
-#define SLIP_SPECIAL_BYTE_END           0xC0
-#define SLIP_SPECIAL_BYTE_ESC           0xDB
-
-#define SLIP_ESCAPED_BYTE_END           0xDC
-#define SLIP_ESCAPED_BYTE_ESC           0xDD
-
-typedef enum {
-        SLIP_STATE_NORMAL = 0x00,
-        SLIP_STATE_ESCAPED
-} slip_state_t;
-
-typedef struct {
-        uint8_t *buf;
-        uint32_t buf_size;
-        int (*recv_message)(uint8_t *data, uint32_t size);
-} slip_descriptor_s;
-
-typedef struct {
-        slip_state_t state;
-        uint32_t size;
-        const slip_descriptor_s *descriptor;
-} slip_handler_s;
-
-typedef enum {
-        SLIP_NO_ERROR = 0x00,
-        SLIP_ERROR_BUFFER_OVERFLOW,
-        SLIP_ERROR_UNKNOWN_ESCAPED_BYTE,
-        SLIP_ERROR_INVALID_PACKET
-} slip_error_t;
-
-slip_error_t slip_init(slip_handler_s *slip, const slip_descriptor_s *descriptor);
-slip_error_t slip_read_byte(slip_handler_s *slip, uint8_t byte);
-
-#endif
\ No newline at end of file
--- a/src/usb.c
+++ /dev/null
@@ -1,363 +1,0 @@
-// Copyright 2021 Jonne Kokkonen
-// Released under the MIT licence, https://opensource.org/licenses/MIT
-
-// Contains portions of code from libserialport's examples released to the
-// public domain
-#ifdef USE_LIBUSB
-
-#include <SDL3/SDL.h>
-#include <libusb.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "usb.h"
-
-static int ep_out_addr = 0x03;
-static int ep_in_addr = 0x83;
-
-#define ACM_CTRL_DTR 0x01
-#define ACM_CTRL_RTS 0x02
-
-#define M8_VID 0x16c0
-#define M8_PID 0x048a
-
-libusb_context *ctx = NULL;
-libusb_device_handle *devh = NULL;
-
-static int do_exit = 0;
-
-int list_devices() {
-  int r;
-  r = libusb_init(&ctx);
-  if (r < 0) {
-    SDL_Log("libusb_init failed: %s", libusb_error_name(r));
-    return 0;
-  }
-
-  libusb_device **device_list = NULL;
-  int count = libusb_get_device_list(ctx, &device_list);
-  for (size_t idx = 0; idx < count; ++idx) {
-    libusb_device *device = device_list[idx];
-    struct libusb_device_descriptor desc;
-    int rc = libusb_get_device_descriptor(device, &desc);
-    if (rc < 0) {
-      SDL_Log("Error");
-      libusb_free_device_list(device_list, 1);
-      return rc;
-    }
-
-    if (desc.idVendor == M8_VID && desc.idProduct == M8_PID) {
-      SDL_Log("Found M8 device: %d:%d\n", libusb_get_port_number(device),
-              libusb_get_bus_number(device));
-    }
-  }
-  libusb_free_device_list(device_list, 1);
-  return 0;
-}
-
-int usb_loop(void *data) {
-  SDL_SetThreadPriority(SDL_THREAD_PRIORITY_TIME_CRITICAL);
-  while (!do_exit) {
-    int rc = libusb_handle_events(ctx);
-    if (rc != LIBUSB_SUCCESS) {
-      SDL_Log("Audio loop error: %s\n", libusb_error_name(rc));
-      break;
-    }
-  }
-  return 0;
-}
-
-static SDL_Thread *usb_thread;
-
-static void LIBUSB_CALL xfr_cb_in(struct libusb_transfer *transfer) {
-  int *completed = transfer->user_data;
-  *completed = 1;
-}
-
-int bulk_transfer(int endpoint, uint8_t *serial_buf, int count, unsigned int timeout_ms) {
-  if (devh == NULL) {
-    return -1;
-  }
-
-  int completed = 0;
-
-  struct libusb_transfer *transfer;
-  transfer = libusb_alloc_transfer(0);
-  libusb_fill_bulk_transfer(transfer, devh, endpoint, serial_buf, count, xfr_cb_in, &completed,
-                            timeout_ms);
-  int r = libusb_submit_transfer(transfer);
-
-  if (r < 0) {
-    SDL_Log("Error");
-    libusb_free_transfer(transfer);
-    return r;
-  }
-
-retry:
-  libusb_lock_event_waiters(ctx);
-  while (!completed) {
-    if (!libusb_event_handler_active(ctx)) {
-      libusb_unlock_event_waiters(ctx);
-      goto retry;
-    }
-    libusb_wait_for_event(ctx, NULL);
-  }
-  libusb_unlock_event_waiters(ctx);
-
-  int actual_length = transfer->actual_length;
-
-  libusb_free_transfer(transfer);
-
-  return actual_length;
-}
-
-int blocking_write(void *buf, int count, unsigned int timeout_ms) {
-  return bulk_transfer(ep_out_addr, buf, count, timeout_ms);
-}
-
-int serial_read(uint8_t *serial_buf, int count) {
-  return bulk_transfer(ep_in_addr, serial_buf, count, 1);
-}
-
-int check_serial_port() {
-  // Reading will fail anyway when the device is not present anymore
-  return 1;
-}
-
-int init_interface() {
-
-  if (devh == NULL) {
-    SDL_Log("Device not initialised!");
-    return 0;
-  }
-
-  int rc;
-
-  for (int if_num = 0; if_num < 2; if_num++) {
-    if (libusb_kernel_driver_active(devh, if_num)) {
-      SDL_Log("Detaching kernel driver for interface %d", if_num);
-      libusb_detach_kernel_driver(devh, if_num);
-    }
-    rc = libusb_claim_interface(devh, if_num);
-    if (rc < 0) {
-      SDL_Log("Error claiming interface: %s", libusb_error_name(rc));
-      return 0;
-    }
-  }
-
-  /* Start configuring the device:
-   * - set line state
-   */
-  SDL_Log("Setting line state");
-  rc = libusb_control_transfer(devh, 0x21, 0x22, ACM_CTRL_DTR | ACM_CTRL_RTS, 0, NULL, 0, 0);
-  if (rc < 0) {
-    SDL_Log("Error during control transfer: %s", libusb_error_name(rc));
-    return 0;
-  }
-
-  /* - set line encoding: here 115200 8N1
-   * 115200 = 0x01C200 ~> 0x00, 0xC2, 0x01, 0x00 in little endian
-   */
-  SDL_Log("Set line encoding");
-  unsigned char encoding[] = {0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08};
-  rc = libusb_control_transfer(devh, 0x21, 0x20, 0, 0, encoding, sizeof(encoding), 0);
-  if (rc < 0) {
-    SDL_Log("Error during control transfer: %s", libusb_error_name(rc));
-    return 0;
-  }
-
-  usb_thread = SDL_CreateThread(&usb_loop, "USB", NULL);
-
-  return 1;
-}
-
-int init_serial_with_file_descriptor(int file_descriptor) {
-  SDL_Log("Initialising serial with file descriptor");
-
-  if (file_descriptor <= 0) {
-    SDL_Log("Invalid file descriptor: %d", file_descriptor);
-    return 0;
-  }
-
-  int r;
-  r = libusb_set_option(NULL, LIBUSB_OPTION_NO_DEVICE_DISCOVERY, NULL);
-  if (r != LIBUSB_SUCCESS) {
-    SDL_Log("libusb_set_option failed: %s", libusb_error_name(r));
-    return 0;
-  }
-  r = libusb_init(&ctx);
-  if (r < 0) {
-    SDL_Log("libusb_init failed: %s", libusb_error_name(r));
-    return 0;
-  }
-  r = libusb_wrap_sys_device(ctx, (intptr_t)file_descriptor, &devh);
-  if (r < 0) {
-    SDL_Log("libusb_wrap_sys_device failed: %s", libusb_error_name(r));
-    return 0;
-  } else if (devh == NULL) {
-    SDL_Log("libusb_wrap_sys_device returned invalid handle");
-    return 0;
-  }
-  SDL_Log("USB device init success");
-
-  return init_interface();
-}
-
-int init_serial(int verbose, char *preferred_device) {
-
-  if (devh != NULL) {
-    return 1;
-  }
-
-  int r;
-  r = libusb_init(&ctx);
-  if (r < 0) {
-    SDL_Log("libusb_init failed: %s", libusb_error_name(r));
-    return 0;
-  }
-  if (preferred_device == NULL) {
-    devh = libusb_open_device_with_vid_pid(ctx, M8_VID, M8_PID);
-  } else {
-    char *port;
-    char *saveptr = NULL;
-    char *bus;
-    port = SDL_strtokr(preferred_device, ":", &saveptr);
-    bus = SDL_strtokr(NULL, ":", &saveptr);
-    libusb_device **device_list = NULL;
-    int count = libusb_get_device_list(ctx, &device_list);
-    for (size_t idx = 0; idx < count; ++idx) {
-      libusb_device *device = device_list[idx];
-      struct libusb_device_descriptor desc;
-      r = libusb_get_device_descriptor(device, &desc);
-      if (r < 0) {
-        SDL_Log("libusb_get_device_descriptor failed: %s", libusb_error_name(r));
-        libusb_free_device_list(device_list, 1);
-        return 0;
-      }
-
-      if (desc.idVendor == M8_VID && desc.idProduct == M8_PID) {
-        SDL_Log("Searching for port %s and bus %s", port, bus);
-        if (libusb_get_port_number(device) == SDL_atoi(port) &&
-            libusb_get_bus_number(device) == SDL_atoi(bus)) {
-          SDL_Log("Preferred device found, connecting");
-          r = libusb_open(device, &devh);
-          if (r < 0) {
-            SDL_Log("libusb_open failed: %s", libusb_error_name(r));
-            return 0;
-          }
-        }
-      }
-    }
-    libusb_free_device_list(device_list, 1);
-    if (devh == NULL) {
-      SDL_Log("Preferred device %s not found, using first available", preferred_device);
-      devh = libusb_open_device_with_vid_pid(ctx, M8_VID, M8_PID);
-    }
-  }
-  if (devh == NULL) {
-    SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM,
-                 "libusb_open_device_with_vid_pid returned invalid handle");
-    return 0;
-  }
-  SDL_Log("USB device init success");
-
-  return init_interface();
-}
-
-int reset_display() {
-  int result;
-
-  SDL_Log("Reset display\n");
-
-  char buf[1] = {'R'};
-
-  result = blocking_write(buf, 1, 5);
-  if (result != 1) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, code %d", result);
-    return 0;
-  }
-  return 1;
-}
-
-int enable_and_reset_display() {
-  int result;
-
-  SDL_Log("Enabling and resetting M8 display\n");
-
-  char buf[1] = {'E'};
-  result = blocking_write(buf, 1, 5);
-  if (result != 1) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error enabling M8 display, code %d", result);
-    return 0;
-  }
-
-  SDL_Delay(5);
-  result = reset_display();
-  return result;
-}
-
-int disconnect() {
-
-  char buf[1] = {'D'};
-  int result;
-
-  SDL_Log("Disconnecting M8\n");
-
-  result = blocking_write(buf, 1, 5);
-  if (result != 1) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending disconnect, code %d", result);
-    return -1;
-  }
-
-  int rc;
-
-  if (devh != NULL) {
-
-    for (int if_num = 0; if_num < 2; if_num++) {
-      rc = libusb_release_interface(devh, if_num);
-      if (rc < 0) {
-        SDL_Log("Error releasing interface: %s", libusb_error_name(rc));
-        return 0;
-      }
-    }
-
-    do_exit = 1;
-
-    libusb_close(devh);
-  }
-
-  SDL_WaitThread(usb_thread, NULL);
-
-  libusb_exit(ctx);
-
-  return 1;
-}
-
-int send_msg_controller(uint8_t input) {
-  char buf[2] = {'C', input};
-  int nbytes = 2;
-  int result;
-  result = blocking_write(buf, nbytes, 5);
-  if (result != nbytes) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending input, code %d", result);
-    return -1;
-  }
-  return 1;
-}
-
-int send_msg_keyjazz(uint8_t note, uint8_t velocity) {
-  if (velocity > 0x7F)
-    velocity = 0x7F;
-  char buf[3] = {'K', note, velocity};
-  int nbytes = 3;
-  int result;
-  result = blocking_write(buf, nbytes, 5);
-  if (result != nbytes) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error sending keyjazz, code %d", result);
-    return -1;
-  }
-
-  return 1;
-}
-
-#endif
--- a/src/usb.h
+++ /dev/null
@@ -1,9 +1,0 @@
-#ifndef M8C_USB_H_
-#define M8C_USB_H_
-#ifdef USE_LIBUSB
-
-#include <libusb.h>
-extern libusb_device_handle *devh;
-int init_serial_with_file_descriptor(int file_descriptor);
-#endif // USE_LIBUSB
-#endif // M8C_USB_H_
--- a/src/usb_audio.c
+++ /dev/null
@@ -1,200 +1,0 @@
-#ifdef USE_LIBUSB
-
-#include "ringbuffer.h"
-#include "usb.h"
-#include <SDL3/SDL.h>
-#include <errno.h>
-#include <libusb.h>
-
-#define EP_ISO_IN 0x85
-#define IFACE_NUM 4
-
-#define NUM_TRANSFERS 64
-#define PACKET_SIZE 180
-#define NUM_PACKETS 2
-
-SDL_AudioDeviceID sdl_audio_device_id = 0;
-RingBuffer *audio_buffer = NULL;
-
-static void audio_callback(void *userdata, Uint8 *stream, int len) {
-  uint32_t read_len = ring_buffer_pop(audio_buffer, stream, len);
-
-  if (read_len == -1) {
-    SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Buffer underflow!");
-  }
-
-  // If we didn't read the full len bytes, fill the rest with zeros
-  if (read_len < len) {
-    SDL_memset(&stream[read_len], 0, len - read_len);
-  }
-}
-
-static void cb_xfr(struct libusb_transfer *xfr) {
-  unsigned int i;
-
-  for (i = 0; i < xfr->num_iso_packets; i++) {
-    struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
-
-    if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
-      SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "XFR callback error (status %d: %s)", pack->status,
-                   libusb_error_name(pack->status));
-      /* This doesn't happen, so bail out if it does. */
-      return;
-    }
-
-    const uint8_t *data = libusb_get_iso_packet_buffer_simple(xfr, i);
-    if (sdl_audio_device_id != 0) {
-      uint32_t actual = ring_buffer_push(audio_buffer, data, pack->actual_length);
-      if (actual == -1) {
-        SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Buffer overflow!");
-      }
-    }
-  }
-
-  if (libusb_submit_transfer(xfr) < 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "error re-submitting URB\n");
-    SDL_free(xfr->buffer);
-  }
-}
-
-static struct libusb_transfer *xfr[NUM_TRANSFERS];
-
-static int benchmark_in() {
-  int i;
-
-  for (i = 0; i < NUM_TRANSFERS; i++) {
-    xfr[i] = libusb_alloc_transfer(NUM_PACKETS);
-    if (!xfr[i]) {
-      SDL_Log("Could not allocate transfer");
-      return -ENOMEM;
-    }
-
-    Uint8 *buffer = SDL_malloc(PACKET_SIZE * NUM_PACKETS);
-
-    libusb_fill_iso_transfer(xfr[i], devh, EP_ISO_IN, buffer, PACKET_SIZE * NUM_PACKETS,
-                             NUM_PACKETS, cb_xfr, NULL, 0);
-    libusb_set_iso_packet_lengths(xfr[i], PACKET_SIZE);
-
-    libusb_submit_transfer(xfr[i]);
-  }
-
-  return 1;
-}
-
-int audio_init(int audio_buffer_size, const char *output_device_name) {
-  SDL_Log("USB audio setup");
-
-  int rc;
-
-  rc = libusb_kernel_driver_active(devh, IFACE_NUM);
-  if (rc == 1) {
-    SDL_Log("Detaching kernel driver");
-    rc = libusb_detach_kernel_driver(devh, IFACE_NUM);
-    if (rc < 0) {
-      SDL_Log("Could not detach kernel driver: %s\n", libusb_error_name(rc));
-      return rc;
-    }
-  }
-
-  rc = libusb_claim_interface(devh, IFACE_NUM);
-  if (rc < 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error claiming interface: %s\n", libusb_error_name(rc));
-    return rc;
-  }
-
-  rc = libusb_set_interface_alt_setting(devh, IFACE_NUM, 1);
-  if (rc < 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error setting alt setting: %s\n", libusb_error_name(rc));
-    return rc;
-  }
-
-  if (!SDL_WasInit(SDL_INIT_AUDIO)) {
-    if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
-      SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Init audio failed %s", SDL_GetError());
-      return -1;
-    }
-  } else {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Audio was already initialised");
-  }
-
-  static SDL_AudioSpec audio_spec;
-  audio_spec.format = AUDIO_S16;
-  audio_spec.channels = 2;
-  audio_spec.freq = 44100;
-  audio_spec.samples = audio_buffer_size;
-  audio_spec.callback = audio_callback;
-
-  SDL_AudioSpec _obtained;
-  SDL_zero(_obtained);
-
-  SDL_Log("Current audio driver is %s and device %s", SDL_GetCurrentAudioDriver(),
-          output_device_name);
-
-  if (SDL_strcasecmp(SDL_GetCurrentAudioDriver(), "openslES") == 0 || output_device_name == NULL) {
-    SDL_Log("Using default audio device");
-    sdl_audio_device_id = SDL_OpenAudioDevice(NULL, 0, &audio_spec, &_obtained, 0);
-  } else {
-    sdl_audio_device_id = SDL_OpenAudioDevice(output_device_name, 0, &audio_spec, &_obtained, 0);
-  }
-
-  audio_buffer = ring_buffer_create(4 * _obtained.size);
-
-  SDL_Log("Obtained audio spec. Sample rate: %d, channels: %d, samples: %d, size: %d",
-          _obtained.freq, _obtained.channels, _obtained.samples, +_obtained.size);
-
-  SDL_PauseAudioDevice(sdl_audio_device_id, 0);
-
-  // Good to go
-  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Starting capture");
-  if ((rc = benchmark_in()) < 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Capture failed to start: %d", rc);
-    return rc;
-  }
-
-  SDL_Log("Successful init");
-  return 1;
-}
-
-int audio_destroy() {
-  if (devh == NULL) {
-    return -1;
-  }
-
-  SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "Closing audio");
-
-  int i, rc;
-
-  for (i = 0; i < NUM_TRANSFERS; i++) {
-    rc = libusb_cancel_transfer(xfr[i]);
-    if (rc < 0) {
-      SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error cancelling transfer: %s\n",
-                   libusb_error_name(rc));
-    }
-  }
-
-  SDL_Log("Freeing interface %d", IFACE_NUM);
-
-  rc = libusb_release_interface(devh, IFACE_NUM);
-  if (rc < 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error releasing interface: %s\n", libusb_error_name(rc));
-    return rc;
-  }
-
-  if (sdl_audio_device_id != 0) {
-    SDL_Log("Closing audio device %d", sdl_audio_device_id);
-    SDL_AudioDeviceID device = sdl_audio_device_id;
-    sdl_audio_device_id = 0;
-    SDL_CloseAudioDevice(device);
-  }
-
-  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Audio closed");
-
-  ring_buffer_free(audio_buffer);
-  return 1;
-}
-
-void toggle_audio(unsigned int audio_buffer_size, const char *output_device_name) {
-  SDL_Log("Libusb audio toggling not implemented yet");
-}
-
-#endif
--