~ruther/CTU-FEE-B0B35APO-Semestral-project

9b7c2ce09fcd648a9ab5c348ac724db42d3bda2d — František Boháček 4 years ago 91a6432
refactor: split imageviewer to more functions and files
M image-viewer/include/image_viewer.h => image-viewer/include/image_viewer.h +2 -34
@@ 4,38 4,13 @@
#include "cursor.h"
#include "display_utils.h"
#include "image.h"
#include "image_viewer_def.h"
#include "image_viewer_handlers.h"
#include "logger.h"
#include "mzapo_led_strip.h"
#include "mzapo_rgb_led.h"
#include <stdbool.h>

typedef enum {
  MOD_CURSOR,
  MOD_IMAGE,
  MOD_COUNT,
} image_viewer_mode_t;

typedef struct {
  cursor_t cursor;

  image_t image;

  image_zoom_t scale;
  image_region_t image_region;
  image_region_t display_region;

  image_viewer_mode_t mode;

  display_t *display;
  bool running;

  mzapo_ledstrip_t ledstrip;
  mzapo_rgb_led_t rgb_leds;

  logger_t *logger;
  image_error_t error;
} image_viewer_t;

/**
 * @brief Create image viewer
 *


@@ 64,11 39,4 @@ void image_viewer_destroy(image_viewer_t *viewer);
 */
void image_viewer_start_loop(image_viewer_t *viewer, void *reg_knobs_base);

/**
 * @brief Display image on display
 *
 * @param viewer
 */
void image_viewer_display_image(image_viewer_t *viewer);

#endif // __IMAGE_VIEWER_H__

A image-viewer/include/image_viewer_def.h => image-viewer/include/image_viewer_def.h +37 -0
@@ 0,0 1,37 @@
#ifndef __IMAGE_VIEWER_DEF_H__
#define __IMAGE_VIEWER_DEF_H__

#include "image.h"
#include "cursor.h"
#include "mzapo_pheripherals.h"

typedef enum {
  MOD_CURSOR,
  MOD_IMAGE,
  MOD_COUNT,
} image_viewer_mode_t;

typedef struct {
  cursor_t cursor;

  image_t image;

  image_zoom_t scale;
  image_region_t image_region;
  image_region_t display_region;

  image_viewer_mode_t mode;

  display_t *display;
  bool running;

  mzapo_ledstrip_t ledstrip;
  mzapo_rgb_led_t rgb_leds;

  logger_t *logger;
  image_error_t error;

  bool should_render;
} image_viewer_t;

#endif // __IMAGE_VIEWER_DEF_H__

A image-viewer/include/image_viewer_handlers.h => image-viewer/include/image_viewer_handlers.h +11 -0
@@ 0,0 1,11 @@
#ifndef __IMAGE_VIEWER_HANDLERS_H__
#define __IMAGE_VIEWER_HANDLERS_H__

#include "input.h"
#include "image_viewer_def.h"

void image_viewer_register_commands(image_viewer_t *viewer,
                                    commands_t *commands);

void image_viewer_display_image(image_viewer_t *viewer);
#endif // __IMAGE_VIEWER_HANDLERS_H__

M image-viewer/src/image_viewer.c => image-viewer/src/image_viewer.c +4 -251
@@ 11,13 11,12 @@
#include "mzapo_rgb_led.h"
#include <time.h>
#include <stdlib.h>
#include "keyboard_const.h"
#include "rotation_const.h"

#define COMMANDS_NUM 30
#define CURSOR_SHOW_DURATION 3 // seconds

#define MAX_ZOOM 10
#define MIN_ZOOM 0.02

void loader_callback(void *state, double p) {
  mzapo_ledstrip_t *ledstrip = (mzapo_ledstrip_t*)state;
  ledstrip_progress_bar_step(ledstrip, p * LED_STRIP_COUNT);


@@ 33,7 32,8 @@ image_viewer_t image_viewer_create(char *filename, display_t *display, logger_t 
    .display_region = image_region_create(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT),
    .image_region = image_region_create(0, 0, 0, 0),
    .ledstrip = ledstrip,
    .rgb_leds = rgb_leds
    .rgb_leds = rgb_leds,
    .should_render = true,
  };

  viewer.error = image_loader_load(&viewer.image, loader_callback, &ledstrip);


@@ 53,248 53,6 @@ void image_viewer_destroy(image_viewer_t *viewer) {
  image_destroy(&viewer->image);
}

void command_handler_move_cursor(void *data, direction_t direction, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;

  cursor_hide(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
  int32_t x = viewer->scale.x, y = viewer->scale.y;
  bool move_cursor = false;
  switch (viewer->mode) {
  case MOD_CURSOR:
    if (!cursor_move(&viewer->cursor,
                     image_get_zoom_region(&viewer->image, viewer->scale),
                     direction, amount / viewer->scale.scale)) {
      direction_move_xy(direction, &x,
                        &y,
                        amount / viewer->scale.scale);
      move_cursor = true;
    }
    break;
  case MOD_IMAGE:
    logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__, "Moving image");
    direction_move_xy(direction, &x,
                      &y,
                      amount / viewer->scale.scale);
    move_cursor = true;
    break;
  default:
    break;
  }

  if (x < 0) {
    x = 0;
  }
  if (y < 0) {
    y = 0;
  }

  viewer->scale.x = x;
  viewer->scale.y = y;

  if (move_cursor) {
    cursor_move(&viewer->cursor,
                image_get_zoom_region(&viewer->image, viewer->scale), direction,
                amount / viewer->scale.scale);
  }

  image_viewer_display_image(viewer);
  cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
  display_render(viewer->display);

  ledstrip_turn_on(&viewer->ledstrip, ((double)viewer->cursor.x / viewer->image.width) * LED_STRIP_COUNT, 1);
}

void command_handler_move_left(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t*)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor to left by %d", amount);
  command_handler_move_cursor(data, LEFT, amount);
}

void command_handler_move_right(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor to right by %d", amount);
  command_handler_move_cursor(data, RIGHT, amount);
}

void command_handler_move_up(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor up by %d", amount);
  command_handler_move_cursor(data, UP, amount);
}

void command_handler_move_down(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor down by %d", amount);
  command_handler_move_cursor(data, DOWN, amount);
}


void command_handler_exit(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  viewer->running = false;
}

void zoom(image_viewer_t *viewer, int amount) {
  double zoom = viewer->scale.scale;
  double new_zoom = zoom * (1 + amount * 0.05);

  if (new_zoom > MAX_ZOOM) {
    logger_warn(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
                "Cannot zoom more than %f", MAX_ZOOM);
    new_zoom = MAX_ZOOM;
  }

  if (new_zoom < MIN_ZOOM) {
    logger_warn(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
                "Cannot zoom less than %f", MIN_ZOOM);
    new_zoom = MIN_ZOOM;
  }

  image_zoom_t tmp = {
    .scale = new_zoom,
    .x = viewer->scale.x,
    .y = viewer->scale.y,
  };

  image_region_t current_region = image_get_zoom_region(&viewer->image, viewer->scale);
  image_region_t new_region =
      image_get_zoom_region(&viewer->image, tmp);

  uint16_t scaled_w = (uint16_t)(zoom * viewer->image.width),
    scaled_h = (uint16_t)(zoom * viewer->image.height);

  int32_t beg_x = ((double)DISPLAY_WIDTH - (double)(scaled_w)) / 2;
  int32_t beg_y = ((double)DISPLAY_HEIGHT - (double)(scaled_h)) / 2;

  if (beg_x < 0) {
    beg_x = 0;
  }

  if (beg_y < 0) {
    beg_y = 0;
  }

  if (scaled_w > DISPLAY_WIDTH) {
    scaled_w = DISPLAY_WIDTH;
  }

  if (scaled_h > DISPLAY_HEIGHT) {
    scaled_h = DISPLAY_HEIGHT;
  }

  int32_t diff_w = current_region.width - new_region.width;
  int32_t diff_h = current_region.height - new_region.height;

  double side_percentage_x =
      (double)(viewer->cursor.x - current_region.x) / current_region.width;
  double side_percentage_y =
      (double)(viewer->cursor.y - current_region.y) / current_region.height;

  tmp.x += side_percentage_x * diff_w;
  tmp.y += side_percentage_y * diff_h;
  viewer->scale = tmp;

  image_viewer_display_image(viewer);
  cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
}

void command_handler_zoom_in(void *data, int amount) {
  // hide cursor, zoom, show cursor
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Zooming in by %d", amount);

  zoom(viewer, amount);
}

void command_handler_zoom_out(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Zooming out by %d", amount);

  zoom(viewer, -amount);
}

void command_handler_zoom_reset(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Zoom reset by %d", amount);
  viewer->scale = image_get_initial_zoom(&viewer->image);
  image_viewer_display_image(viewer);
  cursor_center(&viewer->cursor, viewer->image_region);
  cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
}

void command_handler_change_mode(void *data, int amount) {
  if (!amount) {
    return;
  }

  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Changing mode");


  uint8_t mode = viewer->mode;
  mode++;
  if (mode >= MOD_COUNT) {
    mode %= MOD_COUNT;
  }

  if (mode == MOD_IMAGE) {
    rgb_led_set_green(&viewer->rgb_leds, LED_LEFT);
    rgb_led_set_green(&viewer->rgb_leds, LED_RIGHT);
  } else {
    rgb_led_clear(&viewer->rgb_leds, LED_LEFT);
    rgb_led_clear(&viewer->rgb_leds, LED_RIGHT);
  }

  viewer->mode = mode;
}

void image_viewer_register_commands(image_viewer_t *viewer, commands_t *commands) {
  commands_register(commands, IN_KEYBOARD, 'h', &command_handler_move_left,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'j', &command_handler_move_down,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'k', &command_handler_move_up,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'l', &command_handler_move_right,
                    viewer);

  commands_register(commands, IN_KEYBOARD, 'e', &command_handler_exit,
                    viewer);

  commands_register(commands, IN_KEYBOARD, 'z', &command_handler_zoom_in,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'x', &command_handler_zoom_out,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'r', &command_handler_zoom_reset,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'm', &command_handler_change_mode,
                    viewer);

  commands_register(commands, IN_ENCODER_ROTATE, 0, &command_handler_move_right,
                    viewer);
  commands_register(commands, IN_ENCODER_ROTATE, 1,
                    &command_handler_move_down, viewer);
  commands_register(commands, IN_ENCODER_ROTATE, 2, &command_handler_zoom_in,
                    viewer);

  commands_register(commands, IN_ENCODER_CLICK, 0, &command_handler_exit,
                    viewer);

  commands_register(commands, IN_ENCODER_CLICK, 1, &command_handler_change_mode,
                    viewer);

  commands_register(commands, IN_ENCODER_CLICK, 2, &command_handler_zoom_reset,
                    viewer);
}

void image_viewer_start_loop(image_viewer_t *viewer, void *reg_knobs_base) {
  command_t command_array[COMMANDS_NUM];
  commands_t commands = commands_create(command_array, COMMANDS_NUM, reg_knobs_base);


@@ 318,8 76,3 @@ void image_viewer_start_loop(image_viewer_t *viewer, void *reg_knobs_base) {
  }
}

void image_viewer_display_image(image_viewer_t *viewer) {
  cursor_hide(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
  viewer->scale = image_write_to_display(&viewer->image, viewer->display, viewer->scale);
  display_render(viewer->display);
}

A image-viewer/src/image_viewer_handlers.c => image-viewer/src/image_viewer_handlers.c +273 -0
@@ 0,0 1,273 @@
#include "image_viewer_handlers.h"
#include "cursor.h"
#include "keyboard_const.h"
#include "rotation_const.h"

#define MAX_ZOOM 10
#define MIN_ZOOM 0.02


void image_viewer_display_image(image_viewer_t *viewer) {
  cursor_hide(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
  viewer->scale =
      image_write_to_display(&viewer->image, viewer->display, viewer->scale);
  display_render(viewer->display);
}

static void image_viewer_handle_moved_cursor(image_viewer_t *viewer,
                                             bool move_cursor,
                                             direction_t direction, int amount,
                                             int32_t x, int32_t y) {
  if (x < 0) {
    x = 0;
  }
  if (y < 0) {
    y = 0;
  }

  viewer->scale.x = x;
  viewer->scale.y = y;

  if (move_cursor) {
    cursor_move(&viewer->cursor,
                image_get_zoom_region(&viewer->image, viewer->scale), direction,
                amount / viewer->scale.scale);
  }

  image_viewer_display_image(viewer);
  cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
  display_render(viewer->display);

  ledstrip_turn_on(
      &viewer->ledstrip,
      ((double)viewer->cursor.x / viewer->image.width) * LED_STRIP_COUNT, 1);
}

static void command_handler_move_cursor(void *data, direction_t direction, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;

  cursor_hide(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
  int32_t x = viewer->scale.x, y = viewer->scale.y;
  bool move_cursor = false;
  switch (viewer->mode) {
  case MOD_CURSOR:
    if (!cursor_move(&viewer->cursor,
                     image_get_zoom_region(&viewer->image, viewer->scale),
                     direction, amount / viewer->scale.scale)) {
      direction_move_xy(direction, &x,
                        &y,
                        amount / viewer->scale.scale);
      move_cursor = true;
    }
    break;
  case MOD_IMAGE:
    logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__, "Moving image");
    direction_move_xy(direction, &x,
                      &y,
                      amount / viewer->scale.scale);
    move_cursor = true;
    break;
  default:
    break;
  }

  image_viewer_handle_moved_cursor(viewer, move_cursor, direction, amount, x,
                                   y);
}


static void command_handler_move_left(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t*)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor to left by %d", amount);
  command_handler_move_cursor(data, LEFT, amount);
}

static void command_handler_move_right(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor to right by %d", amount);
  command_handler_move_cursor(data, RIGHT, amount);
}

static void command_handler_move_up(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor up by %d", amount);
  command_handler_move_cursor(data, UP, amount);
}

static void command_handler_move_down(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Moving cursor down by %d", amount);
  command_handler_move_cursor(data, DOWN, amount);
}


static void command_handler_exit(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  viewer->running = false;
}

static image_zoom_t zoom_get_new(image_viewer_t *viewer, int amount) {
  double zoom = viewer->scale.scale;
  double new_zoom = zoom * (1 + amount * 0.05);

  if (new_zoom > MAX_ZOOM) {
    logger_warn(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
                "Cannot zoom more than %f", MAX_ZOOM);
    new_zoom = MAX_ZOOM;
  }

  if (new_zoom < MIN_ZOOM) {
    logger_warn(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
                "Cannot zoom less than %f", MIN_ZOOM);
    new_zoom = MIN_ZOOM;
  }

  image_zoom_t tmp = {
      .scale = new_zoom,
      .x = viewer->scale.x,
      .y = viewer->scale.y,
  };
  return tmp;
}

static void zoom(image_viewer_t *viewer, int amount) {
  double zoom = viewer->scale.scale;
  image_region_t current_region = image_get_zoom_region(&viewer->image, viewer->scale);
  image_zoom_t tmp = zoom_get_new(viewer, amount);
  image_region_t new_region =
      image_get_zoom_region(&viewer->image, tmp);

  uint16_t scaled_w = (uint16_t)(zoom * viewer->image.width),
    scaled_h = (uint16_t)(zoom * viewer->image.height);

  int32_t beg_x = ((double)DISPLAY_WIDTH - (double)(scaled_w)) / 2;
  int32_t beg_y = ((double)DISPLAY_HEIGHT - (double)(scaled_h)) / 2;

  if (beg_x < 0) {
    beg_x = 0;
  }

  if (beg_y < 0) {
    beg_y = 0;
  }

  if (scaled_w > DISPLAY_WIDTH) {
    scaled_w = DISPLAY_WIDTH;
  }

  if (scaled_h > DISPLAY_HEIGHT) {
    scaled_h = DISPLAY_HEIGHT;
  }

  int32_t diff_w = current_region.width - new_region.width;
  int32_t diff_h = current_region.height - new_region.height;

  double side_percentage_x =
      (double)(viewer->cursor.x - current_region.x) / current_region.width;
  double side_percentage_y =
      (double)(viewer->cursor.y - current_region.y) / current_region.height;

  tmp.x += side_percentage_x * diff_w;
  tmp.y += side_percentage_y * diff_h;
  viewer->scale = tmp;

  image_viewer_display_image(viewer);
  cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
}

static void command_handler_zoom_in(void *data, int amount) {
  // hide cursor, zoom, show cursor
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Zooming in by %d", amount);

  zoom(viewer, amount);
}

static void command_handler_zoom_out(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Zooming out by %d", amount);

  zoom(viewer, -amount);
}

static void command_handler_zoom_reset(void *data, int amount) {
  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Zoom reset by %d", amount);
  viewer->scale = image_get_initial_zoom(&viewer->image);
  image_viewer_display_image(viewer);
  cursor_center(&viewer->cursor, viewer->image_region);
  cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
}

static void command_handler_change_mode(void *data, int amount) {
  if (!amount) {
    return;
  }

  image_viewer_t *viewer = (image_viewer_t *)data;
  logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
               "Changing mode");


  uint8_t mode = viewer->mode;
  mode++;
  if (mode >= MOD_COUNT) {
    mode %= MOD_COUNT;
  }

  if (mode == MOD_IMAGE) {
    rgb_led_set_green(&viewer->rgb_leds, LED_LEFT);
    rgb_led_set_green(&viewer->rgb_leds, LED_RIGHT);
  } else {
    rgb_led_clear(&viewer->rgb_leds, LED_LEFT);
    rgb_led_clear(&viewer->rgb_leds, LED_RIGHT);
  }

  viewer->mode = mode;
}

void image_viewer_register_commands(image_viewer_t *viewer, commands_t *commands) {
  commands_register(commands, IN_KEYBOARD, KEYBOARD_LEFT, &command_handler_move_left,
                    viewer);
  commands_register(commands, IN_KEYBOARD, KEYBOARD_DOWN, &command_handler_move_down,
                    viewer);
  commands_register(commands, IN_KEYBOARD, KEYBOARD_UP, &command_handler_move_up,
                    viewer);
  commands_register(commands, IN_KEYBOARD, KEYBOARD_RIGHT, &command_handler_move_right,
                    viewer);

  commands_register(commands, IN_KEYBOARD, 'e', &command_handler_exit,
                    viewer);

  commands_register(commands, IN_KEYBOARD, KEYBOARD_ZOOM_IN, &command_handler_zoom_in,
                    viewer);
  commands_register(commands, IN_KEYBOARD, KEYBOARD_ZOOM_OUT, &command_handler_zoom_out,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'r', &command_handler_zoom_reset,
                    viewer);
  commands_register(commands, IN_KEYBOARD, 'm', &command_handler_change_mode,
                    viewer);

  commands_register(commands, IN_ENCODER_ROTATE, ROTATION_ENCODER_HORIZONTAL, &command_handler_move_right,
                    viewer);
  commands_register(commands, IN_ENCODER_ROTATE, ROTATION_ENCODER_VERTICAL,
                    &command_handler_move_down, viewer);
  commands_register(commands, IN_ENCODER_ROTATE, ROTATION_ENCODER_ZOOM, &command_handler_zoom_in,
                    viewer);

  commands_register(commands, IN_ENCODER_CLICK, 0, &command_handler_exit,
                    viewer);

  commands_register(commands, IN_ENCODER_CLICK, 1, &command_handler_change_mode,
                    viewer);

  commands_register(commands, IN_ENCODER_CLICK, 2, &command_handler_zoom_reset,
                    viewer);
}

M image-viewer/src/main.c => image-viewer/src/main.c +48 -49
@@ 29,95 29,94 @@
#endif

typedef enum {
  SUCCESS,
  TOO_FEW_ARGUMENTS,
  IMAGE_ERROR
  ERROR_SUCCESS,
  ERROR_TOO_FEW_ARGUMENTS,
  ERROR_IMAGE_ERROR
} error_t;

int main(int argc, char *argv[])
{
#ifdef COMPUTER
  mzapo_sdl_init();
#endif

  /* Try to acquire lock the first */
  if (serialize_lock(1) <= 0) {
    printf("System is occupied\n");

    if (1) {
      printf("Waitting\n");
      /* Wait till application holding lock releases IT or exits */
      serialize_lock(0);
    }
  }

  mzapo_rgb_led_t led = mzapo_create_rgb_led();

error_t image_viewer_start(logger_t *logger, char *file_name, mzapo_rgb_led_t led) {
  struct termios oldstdin;
  file_set_nonblocking(STDIN_FILENO, &oldstdin);

  logger_t logger = logger_create(LOG_DEBUG, stdout, stdout, stderr, stderr, NULL);

  if (argc < 2) {
    logger_error(&logger, __FILE__, __FUNCTION__, __LINE__, "Not enough arguments.");
    rgb_led_set_red(&led, LED_LEFT);
    return TOO_FEW_ARGUMENTS;
  }

  logger_debug(&logger, __FILE__, __FUNCTION__, __LINE__,
              "Initializing display...", argv[1]);
  display_t display = mzapo_create_display();
  logger_debug(&logger, __FILE__, __FUNCTION__, __LINE__,
              "Display initialized...", argv[1]);

  logger_info(&logger, __FILE__, __FUNCTION__, __LINE__,
              "Image %s will be loaded.", argv[1]);
  logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
              "Image %s will be loaded.", file_name);

  mzapo_ledstrip_t ledstrip = mzapo_create_ledstrip();

  rgb_led_set_green(&led, LED_LEFT);
  rgb_led_set_green(&led, LED_RIGHT);
  image_viewer_t viewer = image_viewer_create(argv[1], &display, &logger, ledstrip, led);
  image_viewer_t viewer = image_viewer_create(file_name, &display, logger, ledstrip, led);
  rgb_led_clear(&led, LED_LEFT);
  rgb_led_clear(&led, LED_RIGHT);

  if (viewer.error != IMERR_SUCCESS) {
    image_error_log(&logger, viewer.error);
    image_error_log(logger, viewer.error);
    rgb_led_set_red(&led, LED_RIGHT);
    return IMAGE_ERROR;
    return ERROR_IMAGE_ERROR;
  }

  logger_info(&logger, __FILE__, __FUNCTION__, __LINE__,
  logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
              "Loaded image of size %d %d", viewer.image.width,
              viewer.image.height);

  logger_debug(&logger, __FILE__, __FUNCTION__, __LINE__,
               "Displaying image...", argv[1]);
  logger_debug(logger, __FILE__, __FUNCTION__, __LINE__,
               "Displaying image...", file_name);

  image_viewer_display_image(&viewer);

  logger_debug(&logger, __FILE__, __FUNCTION__, __LINE__,
               "Starting image viewer...", argv[1]);
  logger_debug(logger, __FILE__, __FUNCTION__, __LINE__,
               "Starting image viewer...", file_name);
  file_set_nonblocking(STDIN_FILENO, &oldstdin);
  image_viewer_start_loop(&viewer, mzapo_get_knobs_address());

  logger_info(&logger, __FILE__, __FUNCTION__, __LINE__,
              "Cleaning up...", argv[1]);
  logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
              "Cleaning up...", file_name);

  display_deinit(&display);
  image_viewer_destroy(&viewer);

  file_set_blocking(STDIN_FILENO, &oldstdin);
  ledstrip_clear(&ledstrip);
  return ERROR_SUCCESS;
}

int main(int argc, char *argv[])
{
#ifdef COMPUTER
  mzapo_sdl_init();
#endif

  /* Try to acquire lock the first */
  if (serialize_lock(1) <= 0) {
    printf("System is occupied\n");

    if (1) {
      printf("Waitting\n");
      /* Wait till application holding lock releases IT or exits */
      serialize_lock(0);
    }
  }

  mzapo_rgb_led_t led = mzapo_create_rgb_led();
  logger_t logger = logger_create(LOG_DEBUG, stdout, stdout, stderr, stderr, NULL);

  if (argc < 2) {
    logger_error(&logger, __FILE__, __FUNCTION__, __LINE__, "Not enough arguments.");
    rgb_led_set_red(&led, LED_LEFT);
    return ERROR_TOO_FEW_ARGUMENTS;
  }

  error_t error = image_viewer_start(&logger, argv[1], led);
  /* Release the lock */
  serialize_unlock();

  logger_info(&logger, __FILE__, __FUNCTION__, __LINE__, "Application quit",
              argv[1]);

  ledstrip_clear(&ledstrip);

#ifdef COMPUTER
  mzapo_sdl_deinit();
#endif
  return SUCCESS;
  return error;
}