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

bf6fdbf6fa10f949bf9af21d5acadbbf4a167707 — František Boháček 1 year, 9 months ago ecf65d4
chore: add sdl project directly
D .gitmodules => .gitmodules +0 -3
@@ 1,3 0,0 @@
[submodule "mzapo-sdl"]
	path = mzapo-sdl
	url = git@gitlab.fel.cvut.cz:bohacfr2/mzapo_sdl.git

D mzapo-sdl => mzapo-sdl +0 -1
@@ 1,1 0,0 @@
Subproject commit fee42a20ea8c95e81865fddfb392851836a5b689

A mzapo-sdl/.gitignore => mzapo-sdl/.gitignore +6 -0
@@ 0,0 1,6 @@
connect.gdb

obj/
bin/

.cache/

A mzapo-sdl/Makefile => mzapo-sdl/Makefile +36 -0
@@ 0,0 1,36 @@
SRC_DIR=./src
OBJ_DIR=./obj
BIN_DIR?=./bin
INC_DIR=-I./include

NAME=mzapo_sdl
BINARY=$(BIN_DIR)/lib$(NAME).so

SRC=$(wildcard $(SRC_DIR)/*.c)
OBJ=$(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC))

CFLAGS=$(INC_DIR) -Wall -Werror -g -O0
CFLAGS+=$(shell sdl2-config --cflags)

.PHONY: all clean

all: $(BINARY)
	cp img/mzapo.png $(BIN_DIR)

$(BINARY): $(OBJ) | $(BIN_DIR)
	$(CC) -shared $(LDFLAGS) $^ $(LDLIBS) -o $@

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
	$(CC) $(CFLAGS) -c -fPIC $< -o $@

$(BIN_DIR) $(OBJ_DIR):
	echo $(BIN_DIR)
	mkdir -p $@

dep: depend

clean:
	$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
	$(RM) -rv .cache

-include $(OBJ:.o=.d)

A mzapo-sdl/img/mzapo.png => mzapo-sdl/img/mzapo.png +0 -0
A mzapo-sdl/include/image_load.h => mzapo-sdl/include/image_load.h +20 -0
@@ 0,0 1,20 @@
#ifndef __IMAGE_LOAD_H__
#define __IMAGE_LOAD_H__

#include <stdint.h>

typedef struct {
  uint8_t r;
  uint8_t g;
  uint8_t b;
} __attribute__((__packed__)) buffer_pixel_t;

typedef struct {
  uint32_t width;
  uint32_t height;
  buffer_pixel_t *data;
} image_t;

image_t image_load_png(char *path);

#endif // __IMAGE_LOAD_H__

A mzapo-sdl/include/mzapo_regs.h => mzapo-sdl/include/mzapo_regs.h +101 -0
@@ 0,0 1,101 @@
/*******************************************************************
  Simple program to check LCD functionality on MicroZed
  based MZ_APO board designed by Petr Porazil at PiKRON

  mzapo_regs.h       - definition of the MZ_APO design registers

  (C) Copyright 2017 by Pavel Pisa
      e-mail:   pisa@cmp.felk.cvut.cz
      homepage: http://cmp.felk.cvut.cz/~pisa
      company:  http://www.pikron.com/
      license:  any combination of GPL, LGPL, MPL or BSD licenses

 *******************************************************************/

#ifndef MZAPO_REGS_H
#define MZAPO_REGS_H

/*
  Complete description of the educational MZ_APO design registers
  can be found at

    https://cw.fel.cvut.cz/wiki/courses/b35apo/documentation/mz_apo/start

  The peripherals VHDL sources can be found in the repository

    http://rtime.felk.cvut.cz/gitweb/fpga/zynq/canbench-sw.git/tree/refs/heads/microzed_apo:/system/ip

*/

/* SPI connected knobs and LEDs registers and keyboard */

#define SPILED_REG_BASE_PHYS  0x43c40000
#define SPILED_REG_SIZE       0x00004000

#define SPILED_REG_LED_LINE_o           0x004
#define SPILED_REG_LED_RGB1_o           0x010
#define SPILED_REG_LED_RGB2_o           0x014
#define SPILED_REG_LED_KBDWR_DIRECT_o   0x018

#define SPILED_REG_KBDRD_KNOBS_DIRECT_o 0x020
#define SPILED_REG_KNOBS_8BIT_o         0x024

/* Parallel LCD registers */

#define PARLCD_REG_BASE_PHYS  0x43c00000
#define PARLCD_REG_SIZE       0x00004000

#define PARLCD_REG_CR_o                 0x0000
#define PARLCD_REG_CR_RESET_m                  0x00000002
#define PARLCD_REG_CMD_o                0x0008
#define PARLCD_REG_DATA_o               0x000C

/* RC model servos and optional PS2 peripheral */

#define SERVOPS2_REG_BASE_PHYS 0x43c50000
#define SERVOPS2_REG_SIZE      0x4000

#define SERVOPS2_REG_CR_o               0x0000
#define SERVOPS2_REG_PWMPER_o           0x000C
#define SERVOPS2_REG_PWM1_o             0x0010
#define SERVOPS2_REG_PWM2_o             0x0014
#define SERVOPS2_REG_PWM3_o             0x0018
#define SERVOPS2_REG_PWM4_o             0x001C

/* Simple audio PWM output */

#define AUDIOPWM_REG_BASE_PHYS 0x43c60000
#define AUDIOPWM_REG_SIZE      0x4000

#define AUDIOPWM_REG_CR_o               0x0000
#define AUDIOPWM_REG_PWMPER_o           0x0008
#define AUDIOPWM_REG_PWM_o              0x000C

/* Optional DC Motor Simple Driver Peripherals for PSR Subject */

#define DCSPDRV_REG_BASE_PHYS_0 0x43c20000
#define DCSPDRV_REG_BASE_PHYS_1 0x43c30000
#define DCSPDRV_REG_SIZE      0x4000

#define DCSPDRV_REG_CR_o                0x0000
#define DCSPDRV_REG_CR_PWM_A_DIRECT_m          0x00000010
#define DCSPDRV_REG_CR_PWM_B_DIRECT_m          0x00000020
#define DCSPDRV_REG_CR_PWM_ENABLE_m            0x00000040
#define DCSPDRV_REG_CR_IRC_RESET_m             0x00000100

#define DCSPDRV_REG_SR_o                0x0004
#define DCSPDRV_REG_SR_IRC_A_MON_m             0x00000100
#define DCSPDRV_REG_SR_IRC_B_MON_m             0x00000200
#define DCSPDRV_REG_SR_IRC_IRQ_MON_m           0x00000400

#define DCSPDRV_REG_PERIOD_o            0x0008
#define DCSPDRV_REG_PERIOD_MASK_m              0x3fffffff

#define DCSPDRV_REG_DUTY_o              0x000C
#define DCSPDRV_REG_DUTY_MASK_m                0x3fffffff
#define DCSPDRV_REG_DUTY_DIR_A_m               0x40000000
#define DCSPDRV_REG_DUTY_DIR_B_m               0x80000000

#define DCSPDRV_REG_IRC_o               0x0010

#endif /*MZAPO_REGS_H*/

A mzapo-sdl/include/mzapo_sdl.h => mzapo-sdl/include/mzapo_sdl.h +48 -0
@@ 0,0 1,48 @@
#ifndef __MZAPO_SDL_H__
#define __MZAPO_SDL_H__

#include <stdint.h>

#define RGB_LEDS_COUNT 2

typedef struct {
  uint8_t r;
  uint8_t g;
  uint8_t b;
} __attribute__((__packed__)) mzapo_sdl_rgb_led;

typedef struct {
  mzapo_sdl_rgb_led left;
  uint8_t offset;
  mzapo_sdl_rgb_led right;
} __attribute__((__packed__)) mzapo_sdl_rgb_leds;

typedef uint32_t mzapo_sdl_ledstrip;

typedef void (*display_command_fn)(uint16_t cmd);
typedef void (*display_data_fn)(uint16_t data);

typedef struct {
  display_command_fn cmd;
  display_data_fn data;
} __attribute__((__packed__)) mzapo_sdl_display;

typedef struct {
  uint32_t offset1;
  
  mzapo_sdl_ledstrip ledstrip;
  uint64_t offset2;
  mzapo_sdl_rgb_leds leds;
  uint8_t offset3;
  uint32_t reg_kbdrd_direct;
  uint64_t offset4;
  uint32_t reg_knobs_direct;
  uint32_t reg_knobs_8bit;
} __attribute__((__packed__)) mzapo_sdl_knobs_keyboard_rgb;

void mzapo_sdl_init();
void mzapo_sdl_deinit();

void *mzapo_sdl_map_phys(uint64_t region_base, uint64_t region_size);

#endif // __MZAPO_SDL_H__

A mzapo-sdl/include/sdl.h => mzapo-sdl/include/sdl.h +21 -0
@@ 0,0 1,21 @@
#ifndef __SDL_H__
#define __SDL_H__

#include <assert.h>

#include <SDL.h>
#include <SDL_image.h>
#include <stdint.h>
#include <stdbool.h>

#include "SDL_surface.h"
#include "SDL_video.h"


int sdl_init(uint16_t w, uint16_t h);
void sdl_close();

void sdl_redraw(uint16_t w, uint16_t h, uint8_t *img);

bool sdl_poll_event(SDL_Event *event);
#endif // __SDL_H__

A mzapo-sdl/include/sdl_utils.h => mzapo-sdl/include/sdl_utils.h +48 -0
@@ 0,0 1,48 @@
#ifndef __SDL_UTILS_H__
#define __SDL_UTILS_H__

#include "image_load.h"
#include <stdint.h>

#define DISPLAY_WIDTH 480
#define DISPLAY_HEIGHT 320

#define WINDOW_WIDTH 760
#define WINDOW_HEIGHT 1000

#define LCD_START_X 114
#define LCD_START_Y 346

#define RGB_LEFT_LED_START_X 136
#define RGB_LEFT_LED_START_Y 817

#define RGB_RIGHT_LED_START_X 587
#define RGB_RIGHT_LED_START_Y 811

#define RGB_LED_WIDTH 25
#define RGB_LED_HEIGHT 25

#define LEDSTRIP_START_X 103
#define LEDSTRIP_START_Y 968

#define LEDSTRIP_WIDTH 10
#define LEDSTRIP_HEIGHT 10

#define LEDSTRIP_STEP_X 16
#define LEDSTRIP_STEP_Y -5.0/31.0

extern buffer_pixel_t buffer[WINDOW_WIDTH * WINDOW_HEIGHT];

void sdl_utils_init();
void sdl_utils_deinit();

void sdl_utils_render_buffer();

void sdl_utils_clear_buffer();

void sdl_utils_draw_image();
void sdl_utils_draw_ledstrip(uint32_t values);
void sdl_utils_draw_display(uint16_t *buffer);
void sdl_utils_draw_rgb_leds(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2);

#endif // __SDL_UTILS_H__

A mzapo-sdl/src/image_load.c => mzapo-sdl/src/image_load.c +95 -0
@@ 0,0 1,95 @@
#include "image_load.h"
#include "sdl.h"
#include <png.h>

image_t image_load_png(char *path) {
  FILE *infile = fopen(path, "r");
  image_t empty = {0, 0, NULL};
  if (infile == NULL) {
    return empty;
  }

  png_structp png =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png == NULL) {
    return empty;
  }

  png_infop info = png_create_info_struct(png);
  if (info == NULL) {
    return empty;
  }

  png_init_io(png, infile);
  png_read_info(png, info);

  uint32_t width = png_get_image_width(png, info);
  uint32_t height = png_get_image_height(png, info);
  png_byte color_type = png_get_color_type(png, info);
  png_byte bit_depth = png_get_bit_depth(png, info);

  if (bit_depth == 16) {
    png_set_strip_16(png);
  }

  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_palette_to_rgb(png);
  }

  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
    png_set_expand_gray_1_2_4_to_8(png);
  }

  if (png_get_valid(png, info, PNG_INFO_tRNS))
    png_set_tRNS_to_alpha(png);

  if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY ||
      color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
  }

  if (color_type == PNG_COLOR_TYPE_GRAY ||
      color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    png_set_gray_to_rgb(png);
  }

  png_read_update_info(png, info);

  png_bytep *row_pointers = malloc(sizeof(png_bytep) * height);
  if (row_pointers == NULL) {
    png_destroy_read_struct(&png, &info, NULL);
    fclose(infile);
    return empty;
  }

  for (int i = 0; i < height; i++) {
    row_pointers[i] = malloc(png_get_rowbytes(png, info));
  }

  png_read_image(png, row_pointers);

  fclose(infile);
  png_destroy_read_struct(&png, &info, NULL);

  buffer_pixel_t *pixels =
      malloc(sizeof(buffer_pixel_t) * width * height);
  if (pixels == NULL) {
    png_destroy_read_struct(&png, &info, NULL);
    free(row_pointers);
    fclose(infile);
    return empty;
  }

  for (int y = 0; y < height; y++) {
    png_bytep row = row_pointers[y];
    for (int x = 0; x < width; x++) {
      png_bytep px = &(row[x * 4]);
      pixels[y * width + x].r = px[0];
      pixels[y * width + x].g = px[1];
      pixels[y * width + x].b = px[2];
    }
  }

  image_t image = {.width = width, .height = height, .data = pixels};
  return image;
}

A mzapo-sdl/src/mzapo_sdl.c => mzapo-sdl/src/mzapo_sdl.c +105 -0
@@ 0,0 1,105 @@
#include "mzapo_sdl.h"
#include "mzapo_regs.h"
#include "sdl_utils.h"
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>

static pthread_t sdl_thread;
static bool running;

static bool display_draw = false;
static uint16_t display_x = 0, display_y = 0;

static uint16_t display_buffer[DISPLAY_WIDTH * DISPLAY_HEIGHT];

static void *mzapo_sdl_thread_init(void *state);

static void mzapo_display_cmd(uint16_t cmd);
static void mzapo_display_data(uint16_t data);

mzapo_sdl_display display = {.cmd = mzapo_display_cmd, .data = mzapo_display_data};
mzapo_sdl_knobs_keyboard_rgb sdl_knobs_keyboard_rgb = {
  .reg_knobs_direct = 0, .reg_kbdrd_direct = 0,
    .reg_knobs_8bit = 0, .ledstrip = 0 };

void mzapo_sdl_init() {
  running = true;

  sdl_knobs_keyboard_rgb.leds.left.r = 0;
  sdl_knobs_keyboard_rgb.leds.left.g = 0;
  sdl_knobs_keyboard_rgb.leds.left.b = 0;

  sdl_knobs_keyboard_rgb.leds.right.r = 0;
  sdl_knobs_keyboard_rgb.leds.right.g = 0;
  sdl_knobs_keyboard_rgb.leds.right.b = 0;

  for (int i = 0; i < DISPLAY_HEIGHT * DISPLAY_WIDTH; i++) {
    display_buffer[i] = 0;
  }

  pthread_create(&sdl_thread, NULL, mzapo_sdl_thread_init, NULL);
}

void mzapo_sdl_deinit() {
  running = false;
  pthread_join(sdl_thread, NULL);
}

void *mzapo_sdl_map_phys(uint64_t region_base, uint64_t region_size) {
  switch (region_base) {
  case PARLCD_REG_BASE_PHYS:
    return &display;
  case SPILED_REG_BASE_PHYS:
    return &sdl_knobs_keyboard_rgb;
  default:
    return NULL;
  }
}

static void *mzapo_sdl_thread_init(void *state) {
  sdl_utils_init();
  while (running) {
    sdl_utils_clear_buffer();

    sdl_utils_draw_image();

    sdl_utils_draw_rgb_leds(sdl_knobs_keyboard_rgb.leds.left.r,
                            sdl_knobs_keyboard_rgb.leds.left.g,
                            sdl_knobs_keyboard_rgb.leds.left.b,
                            sdl_knobs_keyboard_rgb.leds.right.r,
                            sdl_knobs_keyboard_rgb.leds.right.g,
                            sdl_knobs_keyboard_rgb.leds.right.b);

    sdl_utils_draw_ledstrip(sdl_knobs_keyboard_rgb.ledstrip);

    sdl_utils_draw_display(display_buffer);

    sdl_utils_render_buffer();
  }

  return NULL;
}

static void mzapo_display_cmd(uint16_t cmd) {
  switch(cmd) {
  case 0x2C:
    display_x = 0;
    display_y = 0;
    display_draw = true;
    break;
  }
}

static void mzapo_display_data(uint16_t data) {
  if (display_draw && display_y < DISPLAY_HEIGHT) {
    display_buffer[display_y * DISPLAY_WIDTH + display_x] = data;

    display_x ++;

    if (display_x >= DISPLAY_WIDTH) {
      display_x = 0;
      display_y ++;
    }
  }
}

A mzapo-sdl/src/sdl.c => mzapo-sdl/src/sdl.c +48 -0
@@ 0,0 1,48 @@
#include "sdl.h"

static SDL_Window *win = NULL;

int sdl_init(uint16_t w, uint16_t h) {
  int r = 0;
  r = SDL_Init(SDL_INIT_VIDEO);
  assert(win == NULL);
  win = SDL_CreateWindow("MZAPO SDL", SDL_WINDOWPOS_UNDEFINED,
                         SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_SHOWN);
  assert(win != NULL);
  SDL_SetWindowTitle(win, "MZAPO SDL");
  SDL_Surface *surface =
      SDL_CreateRGBSurface(32, 32, 24, 32 * 3, 0xff, 0xff00, 0xff0000, 0x0000);
  SDL_SetWindowIcon(win, surface);
  SDL_FreeSurface(surface);

  SDL_SetWindowResizable(win, SDL_FALSE);
  return r;
}

void sdl_close() {
  assert(win != NULL);
  SDL_DestroyWindow(win);
  SDL_Quit();
}

void sdl_redraw(uint16_t w, uint16_t h, uint8_t *img) {
  assert(img && win);
  SDL_Surface *scr = SDL_GetWindowSurface(win);

  for (int y = 0; y < scr->h && y < h; ++y) {
    for (int x = 0; x < scr->w && x < w; ++x) {
      const int idx = (y * scr->w + x) * scr->format->BytesPerPixel;
      Uint8 *px = (Uint8 *)scr->pixels + idx;
      uint64_t position_in_img = (y * w + x) * 3;
      *(px + scr->format->Rshift / 8) = *(img + position_in_img);
      *(px + scr->format->Gshift / 8) = *(img + position_in_img + 1);
      *(px + scr->format->Bshift / 8) = *(img + position_in_img + 2);
    }
  }
  SDL_UpdateWindowSurface(win);
  SDL_FreeSurface(scr);
}

bool sdl_poll_event(SDL_Event *event) {
  return SDL_PollEvent(event);
}

A mzapo-sdl/src/sdl_utils.c => mzapo-sdl/src/sdl_utils.c +104 -0
@@ 0,0 1,104 @@
#include "sdl_utils.h"
#include "image_load.h"
#include "sdl.h"
#include <limits.h>
#include <string.h>
#include <unistd.h>

#define IMG_PATH "./bin/mzapo.png"

buffer_pixel_t buffer[WINDOW_WIDTH * WINDOW_HEIGHT];
image_t image;

#define DISPLAY_MAX_RED 31u
#define DISPLAY_MAX_GREEN 63u
#define DISPLAY_MAX_BLUE 31u

void sdl_utils_init() {
  sdl_init(WINDOW_WIDTH, WINDOW_HEIGHT);
  printf(IMG_PATH);
  image = image_load_png(IMG_PATH);

  sdl_utils_clear_buffer();
}

void sdl_utils_deinit() {
  sdl_close();
}

void sdl_utils_render_buffer() {
  sdl_redraw(WINDOW_WIDTH, WINDOW_HEIGHT, (uint8_t*)buffer);
}

void sdl_utils_clear_buffer() {
  buffer_pixel_t black = {0, 0, 0};
  for (int i = 0; i < WINDOW_WIDTH * WINDOW_HEIGHT; i++) {
    buffer[i] = black;
  }
}

void sdl_utils_draw_image() {
  for (uint16_t y = 0; y < WINDOW_HEIGHT && y < image.height; y++) {
    for (uint16_t x = 0; x < WINDOW_WIDTH && x < image.width; x++) {
      buffer[WINDOW_WIDTH * y + x] = image.data[image.width * y + x];
    }
  }
}

static void sdl_utils_rectangle(uint16_t bx, uint16_t by, uint16_t w, uint16_t h, buffer_pixel_t color) {
  for (uint16_t iy = 0; iy < h; iy++) {
    for (uint16_t ix = 0; ix < w; ix++) {
      uint16_t x = ix + bx;
      uint16_t y = iy + by;

      buffer[y * WINDOW_WIDTH + x] = color;
    }
  }
}

void sdl_utils_draw_ledstrip(uint32_t values) {
  float x = LEDSTRIP_START_X;
  float y = LEDSTRIP_START_Y;

  buffer_pixel_t color = {.r = 95, .g = 63, .b = 25};
  for (int i = 0; i < 32; i++) {
    bool on = (values >> (31 - i)) & 1;

    if (on) {
      sdl_utils_rectangle(x, y, LEDSTRIP_WIDTH, LEDSTRIP_HEIGHT, color);
    }

    x += LEDSTRIP_STEP_X;
    y += LEDSTRIP_STEP_Y;
  }
}

void sdl_utils_draw_display(uint16_t *data) {
  for (int y = 0; y < DISPLAY_HEIGHT; y++) {
    for (int x = 0; x < DISPLAY_WIDTH; x++) {
      uint16_t pixel = data[y * DISPLAY_WIDTH + x];

      uint8_t r = (pixel >> 11) & 0x1F;
      uint8_t g = (pixel >> 5) & 0x3F;
      uint8_t b = (pixel) & 0x1F;

      buffer_pixel_t convert = {
          .r = ((double)r / DISPLAY_MAX_RED) * 255,
          .g = ((double)g / DISPLAY_MAX_GREEN) * 255,
          .b = ((double)b / DISPLAY_MAX_BLUE) * 255,
      };

      buffer[(LCD_START_Y + y) * WINDOW_WIDTH + LCD_START_X + x] = convert;
    }
  }
}

void sdl_utils_draw_rgb_leds(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2,
                             uint8_t g2, uint8_t b2) {
  buffer_pixel_t left = {.r = r1, .g = g1, .b = b1};
  buffer_pixel_t right = {.r = r2, .g = g2, .b = b2};
  sdl_utils_rectangle(RGB_LEFT_LED_START_X, RGB_LEFT_LED_START_Y, RGB_LED_WIDTH,
                      RGB_LED_HEIGHT, left);
  sdl_utils_rectangle(RGB_RIGHT_LED_START_X, RGB_RIGHT_LED_START_Y,
                      RGB_LED_WIDTH, RGB_LED_HEIGHT, right);
}

Do not follow this link